[alsa-devel] [PATCH 0/2] ASoC: fsi: add DT support
Hi Mark
These patches adds device tree support on FSI driver These are based on mark/topic/fsi branch
Kuninori Morimoto (2): ASoC: fsi: don't use platform info pointer on probe() ASoC: fsi: add device tree support
.../devicetree/bindings/sound/renesas,fsi.txt | 23 +++++ sound/soc/sh/fsi.c | 98 ++++++++++++++++---- 2 files changed, 104 insertions(+), 17 deletions(-)
Best regards --- Kuninori Morimoto
Current FSI driver is using platform info pointer, but it is not good design for DT support. This patch made it not to use platform info pointer.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/fsi.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index f14c611..ef34ef8 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1918,16 +1918,15 @@ static int fsi_probe(struct platform_device *pdev) { struct fsi_master *master; const struct platform_device_id *id_entry; - struct sh_fsi_platform_info *info = pdev->dev.platform_data; - struct sh_fsi_port_info nul_info, *pinfo; + struct sh_fsi_platform_info info; struct fsi_priv *fsi; struct resource *res; unsigned int irq; int ret;
- nul_info.flags = 0; - nul_info.tx_id = 0; - nul_info.rx_id = 0; + memset(&info, 0, sizeof(info)); + if (pdev->dev.platform_data) + memcpy(&info, pdev->dev.platform_data, sizeof(info));
id_entry = pdev->id_entry; if (!id_entry) { @@ -1961,12 +1960,11 @@ static int fsi_probe(struct platform_device *pdev) spin_lock_init(&master->lock);
/* FSI A setting */ - pinfo = (info) ? &info->port_a : &nul_info; fsi = &master->fsia; fsi->base = master->base; fsi->master = master; - fsi_port_info_init(fsi, pinfo); - fsi_handler_init(fsi, pinfo); + fsi_port_info_init(fsi, &info.port_a); + fsi_handler_init(fsi, &info.port_a); ret = fsi_stream_probe(fsi, &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "FSIA stream probe failed\n"); @@ -1974,12 +1972,11 @@ static int fsi_probe(struct platform_device *pdev) }
/* FSI B setting */ - pinfo = (info) ? &info->port_b : &nul_info; fsi = &master->fsib; fsi->base = master->base + 0x40; fsi->master = master; - fsi_port_info_init(fsi, pinfo); - fsi_handler_init(fsi, pinfo); + fsi_port_info_init(fsi, &info.port_b); + fsi_handler_init(fsi, &info.port_b); ret = fsi_stream_probe(fsi, &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "FSIB stream probe failed\n");
On Thu, Dec 27, 2012 at 07:15:08PM -0800, Kuninori Morimoto wrote:
Current FSI driver is using platform info pointer, but it is not good design for DT support. This patch made it not to use platform info pointer.
Applied, thanks.
Support for loading the Renesas FSI driver via devicetree.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- .../devicetree/bindings/sound/renesas,fsi.txt | 23 ++++++ sound/soc/sh/fsi.c | 83 ++++++++++++++++++-- 2 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/renesas,fsi.txt
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt new file mode 100644 index 0000000..503a7a3 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/renesas,fsi.txt @@ -0,0 +1,23 @@ +Renesas FSI + +Required properties: +- compatible : "renesas,sh_fsi2" or "renesas,sh_fsi" +- reg : Should contain the register physical address and length +- interrupts : Should contain FSI interrupt +- fsia,flags : FSI-A flags [spdif/cpg/stream] +- fsia,tx_id : FSI-A DMAEngine ID if needed +- fsib,flags : FSI-B flags [spdif/cpg/stream] +- fsib,tx_id : FSI-B DMAEngine ID if needed + +FSI needs simple-card driver. see also simple-card.txt + +Example: + +sh_fsi2: sh_fsi2@0xec230000 { + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; + fsia,flags = "spdif", "cpg", "stream"; + fsia,tx_id = <23>; +}; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ef34ef8..7f30003 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -16,6 +16,8 @@ #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/scatterlist.h> #include <linux/sh_dma.h> #include <linux/slab.h> @@ -297,7 +299,7 @@ struct fsi_master { int irq; struct fsi_priv fsia; struct fsi_priv fsib; - struct fsi_core *core; + const struct fsi_core *core; spinlock_t lock; };
@@ -1887,6 +1889,45 @@ static struct snd_soc_platform_driver fsi_soc_platform = { /* * platform function */ +static void fsi_of_parse(char *name, + struct device_node *np, + struct sh_fsi_port_info *info, + struct device *dev) +{ + int num, i, j, ret; + char prop[128]; + const char *str; + unsigned long flags = 0; + struct { + char *name; + unsigned int val; + } of_parse_table[] = { + { "spdif", SH_FSI_FMT_SPDIF }, + { "cpg", SH_FSI_CLK_CPG }, + { "stream", SH_FSI_ENABLE_STREAM_MODE }, + }; + + sprintf(prop, "%s,flags", name); + num = of_property_count_strings(np, prop); + for (i = 0; i < num; i++) { + ret = of_property_read_string_index(np, prop, i, &str); + if (ret < 0) + return; + + for (j = 0; j < ARRAY_SIZE(of_parse_table); j++) { + if (strcmp(str, of_parse_table[j].name) == 0) + flags |= of_parse_table[j].val; + } + } + info->flags = flags; + + sprintf(prop, "%s,%s", name, "tx_id"); + of_property_read_u32(np, prop, &info->tx_id); + + dev_dbg(dev, "%s flags : %lx\n", name, info->flags); + dev_dbg(dev, "%s tx_id : %d\n", name, info->tx_id); +} + static void fsi_port_info_init(struct fsi_priv *fsi, struct sh_fsi_port_info *info) { @@ -1914,22 +1955,40 @@ static void fsi_handler_init(struct fsi_priv *fsi, } }
+static struct of_device_id fsi_of_match[]; static int fsi_probe(struct platform_device *pdev) { struct fsi_master *master; - const struct platform_device_id *id_entry; + struct device_node *np = pdev->dev.of_node; struct sh_fsi_platform_info info; + const struct fsi_core *core; struct fsi_priv *fsi; struct resource *res; unsigned int irq; int ret;
memset(&info, 0, sizeof(info)); - if (pdev->dev.platform_data) - memcpy(&info, pdev->dev.platform_data, sizeof(info));
- id_entry = pdev->id_entry; - if (!id_entry) { + core = NULL; + if (np) { + const struct of_device_id *of_id; + + of_id = of_match_device(fsi_of_match, &pdev->dev); + if (of_id) { + core = of_id->data; + fsi_of_parse("fsia", np, &info.port_a, &pdev->dev); + fsi_of_parse("fsib", np, &info.port_b, &pdev->dev); + } + } else { + const struct platform_device_id *id_entry = pdev->id_entry; + if (id_entry) + core = (struct fsi_core *)id_entry->driver_data; + + if (pdev->dev.platform_data) + memcpy(&info, pdev->dev.platform_data, sizeof(info)); + } + + if (!core) { dev_err(&pdev->dev, "unknown fsi device\n"); return -ENODEV; } @@ -1956,7 +2015,7 @@ static int fsi_probe(struct platform_device *pdev)
/* master setting */ master->irq = irq; - master->core = (struct fsi_core *)id_entry->driver_data; + master->core = core; spin_lock_init(&master->lock);
/* FSI A setting */ @@ -1987,7 +2046,7 @@ static int fsi_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, master);
ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0, - id_entry->name, master); + dev_name(&pdev->dev), master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); goto exit_fsib; @@ -2113,6 +2172,13 @@ static struct fsi_core fsi2_core = { .b_mclk = B_MST_CTLR, };
+static struct of_device_id fsi_of_match[] __devinitconst = { + { .compatible = "renesas,sh_fsi", .data = &fsi1_core}, + { .compatible = "renesas,sh_fsi2", .data = &fsi2_core}, + {}, +}; +MODULE_DEVICE_TABLE(of, fsi_of_match); + static struct platform_device_id fsi_id_table[] = { { "sh_fsi", (kernel_ulong_t)&fsi1_core }, { "sh_fsi2", (kernel_ulong_t)&fsi2_core }, @@ -2124,6 +2190,7 @@ static struct platform_driver fsi_driver = { .driver = { .name = "fsi-pcm-audio", .pm = &fsi_pm_ops, + .of_match_table = fsi_of_match, }, .probe = fsi_probe, .remove = fsi_remove,
On Thu, Dec 27, 2012 at 07:15:19PM -0800, Kuninori Morimoto wrote:
+- fsia,flags : FSI-A flags [spdif/cpg/stream] +- fsia,tx_id : FSI-A DMAEngine ID if needed +- fsib,flags : FSI-B flags [spdif/cpg/stream] +- fsib,tx_id : FSI-B DMAEngine ID if needed
The flags should be documented - what do these flags mean? The DMAEngine stuff is a bit fun but I don't think there's yet been any resolution of what to do with DMAEngine in DT yet...
+FSI needs simple-card driver. see also simple-card.txt
This isn't true, the driver can be used with any machine driver. It's true that many machines using the FSI driver can be supported with the simple-card driver but others are also fine.
{ "cpg", SH_FSI_CLK_CPG },
Is this definitely something that would be fixed by hardware design?
{ "stream", SH_FSI_ENABLE_STREAM_MODE },
Why wouldn't stream mode be desired?
Hi Mark
Thank you for checking patch
+- fsia,flags : FSI-A flags [spdif/cpg/stream] +- fsia,tx_id : FSI-A DMAEngine ID if needed +- fsib,flags : FSI-B flags [spdif/cpg/stream] +- fsib,tx_id : FSI-B DMAEngine ID if needed
The flags should be documented - what do these flags mean? The DMAEngine stuff is a bit fun but I don't think there's yet been any resolution of what to do with DMAEngine in DT yet...
I see. v2 will be - add document for flags - remove DMAEngine setting
{ "cpg", SH_FSI_CLK_CPG },
Is this definitely something that would be fixed by hardware design?
{ "stream", SH_FSI_ENABLE_STREAM_MODE },
Why wouldn't stream mode be desired?
Thanks. It will be more descriptive name in v2
Best regards --- Kuninori Morimoto
Support for loading the Renesas FSI driver via devicetree.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- v1 -> v2
- remove DMAEngine support from DT - add flags document - flags become more descriptive name
.../devicetree/bindings/sound/renesas,fsi.txt | 26 +++++++ sound/soc/sh/fsi.c | 71 +++++++++++++++++--- 2 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/renesas,fsi.txt
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt new file mode 100644 index 0000000..c5be003 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/renesas,fsi.txt @@ -0,0 +1,26 @@ +Renesas FSI + +Required properties: +- compatible : "renesas,sh_fsi2" or "renesas,sh_fsi" +- reg : Should contain the register physical address and length +- interrupts : Should contain FSI interrupt + +- fsia,spdif-connection : FSI is connected by S/PDFI +- fsia,stream-mode-support : FSI supports 16bit stream mode. +- fsia,use-internal-clock : FSI uses internal clock when master mode. + +- fsib,spdif-connection : same as fsia +- fsib,stream-mode-support : same as fsia +- fsib,use-internal-clock : same as fsia + +Example: + +sh_fsi2: sh_fsi2@0xec230000 { + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupts = <0 146 0x4>; + + fsia,spdif-connection; + fsia,stream-mode-support; + fsia,use-internal-clock; +}; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ef34ef8..9157612 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -16,6 +16,8 @@ #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/scatterlist.h> #include <linux/sh_dma.h> #include <linux/slab.h> @@ -297,7 +299,7 @@ struct fsi_master { int irq; struct fsi_priv fsia; struct fsi_priv fsib; - struct fsi_core *core; + const struct fsi_core *core; spinlock_t lock; };
@@ -1887,6 +1889,33 @@ static struct snd_soc_platform_driver fsi_soc_platform = { /* * platform function */ +static void fsi_of_parse(char *name, + struct device_node *np, + struct sh_fsi_port_info *info, + struct device *dev) +{ + int i; + char prop[128]; + unsigned long flags = 0; + struct { + char *name; + unsigned int val; + } of_parse_property[] = { + { "spdif-connection", SH_FSI_FMT_SPDIF }, + { "stream-mode-support", SH_FSI_ENABLE_STREAM_MODE }, + { "use-internal-clock", SH_FSI_CLK_CPG }, + }; + + for (i = 0; i < ARRAY_SIZE(of_parse_property); i++) { + sprintf(prop, "%s,%s", name, of_parse_property[i].name); + if (of_get_property(np, prop, NULL)) + flags |= of_parse_property[i].val; + } + info->flags = flags; + + dev_dbg(dev, "%s flags : %lx\n", name, info->flags); +} + static void fsi_port_info_init(struct fsi_priv *fsi, struct sh_fsi_port_info *info) { @@ -1914,22 +1943,40 @@ static void fsi_handler_init(struct fsi_priv *fsi, } }
+static struct of_device_id fsi_of_match[]; static int fsi_probe(struct platform_device *pdev) { struct fsi_master *master; - const struct platform_device_id *id_entry; + struct device_node *np = pdev->dev.of_node; struct sh_fsi_platform_info info; + const struct fsi_core *core; struct fsi_priv *fsi; struct resource *res; unsigned int irq; int ret;
memset(&info, 0, sizeof(info)); - if (pdev->dev.platform_data) - memcpy(&info, pdev->dev.platform_data, sizeof(info));
- id_entry = pdev->id_entry; - if (!id_entry) { + core = NULL; + if (np) { + const struct of_device_id *of_id; + + of_id = of_match_device(fsi_of_match, &pdev->dev); + if (of_id) { + core = of_id->data; + fsi_of_parse("fsia", np, &info.port_a, &pdev->dev); + fsi_of_parse("fsib", np, &info.port_b, &pdev->dev); + } + } else { + const struct platform_device_id *id_entry = pdev->id_entry; + if (id_entry) + core = (struct fsi_core *)id_entry->driver_data; + + if (pdev->dev.platform_data) + memcpy(&info, pdev->dev.platform_data, sizeof(info)); + } + + if (!core) { dev_err(&pdev->dev, "unknown fsi device\n"); return -ENODEV; } @@ -1956,7 +2003,7 @@ static int fsi_probe(struct platform_device *pdev)
/* master setting */ master->irq = irq; - master->core = (struct fsi_core *)id_entry->driver_data; + master->core = core; spin_lock_init(&master->lock);
/* FSI A setting */ @@ -1987,7 +2034,7 @@ static int fsi_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, master);
ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0, - id_entry->name, master); + dev_name(&pdev->dev), master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); goto exit_fsib; @@ -2113,6 +2160,13 @@ static struct fsi_core fsi2_core = { .b_mclk = B_MST_CTLR, };
+static struct of_device_id fsi_of_match[] __devinitconst = { + { .compatible = "renesas,sh_fsi", .data = &fsi1_core}, + { .compatible = "renesas,sh_fsi2", .data = &fsi2_core}, + {}, +}; +MODULE_DEVICE_TABLE(of, fsi_of_match); + static struct platform_device_id fsi_id_table[] = { { "sh_fsi", (kernel_ulong_t)&fsi1_core }, { "sh_fsi2", (kernel_ulong_t)&fsi2_core }, @@ -2124,6 +2178,7 @@ static struct platform_driver fsi_driver = { .driver = { .name = "fsi-pcm-audio", .pm = &fsi_pm_ops, + .of_match_table = fsi_of_match, }, .probe = fsi_probe, .remove = fsi_remove,
participants (2)
-
Kuninori Morimoto
-
Mark Brown