[alsa-devel] [RFC patch v3 1/4] ARM: at91: atmel-ssc: add platform device id table
Add platform device id to check whether the SSC controller support pdc or dam for data transfer
If match "at91rm9200_ssc", which support pdc for data transfer If match "at91sam9g45_ssc", which support dma for data transfer
Signed-off-by: Bo Shen voice.shen@atmel.com Acked-by: Nicolas Ferre nicolas.ferre@atmel.com --- Change since v2 No change Change since v1 No change --- arch/arm/mach-at91/at91rm9200.c | 6 +++--- arch/arm/mach-at91/at91rm9200_devices.c | 6 +++--- arch/arm/mach-at91/at91sam9260.c | 2 +- arch/arm/mach-at91/at91sam9260_devices.c | 2 +- arch/arm/mach-at91/at91sam9261.c | 6 +++--- arch/arm/mach-at91/at91sam9261_devices.c | 6 +++--- arch/arm/mach-at91/at91sam9263.c | 4 ++-- arch/arm/mach-at91/at91sam9263_devices.c | 4 ++-- arch/arm/mach-at91/at91sam9g45.c | 4 ++-- arch/arm/mach-at91/at91sam9g45_devices.c | 4 ++-- arch/arm/mach-at91/at91sam9rl.c | 4 ++-- arch/arm/mach-at91/at91sam9rl_devices.c | 4 ++-- drivers/misc/atmel-ssc.c | 23 +++++++++++++++++++++++ include/linux/atmel-ssc.h | 5 +++++ 14 files changed, 54 insertions(+), 26 deletions(-)
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index b4f0565..85d53c5 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -184,9 +184,9 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index a563189..59ceea1 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -752,7 +752,7 @@ static struct resource ssc0_resources[] = { };
static struct platform_device at91rm9200_ssc0_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -794,7 +794,7 @@ static struct resource ssc1_resources[] = { };
static struct platform_device at91rm9200_ssc1_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, @@ -836,7 +836,7 @@ static struct resource ssc2_resources[] = { };
static struct platform_device at91rm9200_ssc2_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 2, .dev = { .dma_mask = &ssc2_dmamask, diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index ad29f93..2c8aab0 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -210,7 +210,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk), /* more usart lookup table for DT entries */ diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 805ef95..9cfdc3f 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -742,7 +742,7 @@ static struct resource ssc_resources[] = { };
static struct platform_device at91sam9260_ssc_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc_dmamask, diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 8d999eb..4e8c56e 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -174,9 +174,9 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk), CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk), diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 9752f17..299637f 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -706,7 +706,7 @@ static struct resource ssc0_resources[] = { };
static struct platform_device at91sam9261_ssc0_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -748,7 +748,7 @@ static struct resource ssc1_resources[] = { };
static struct platform_device at91sam9261_ssc1_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, @@ -790,7 +790,7 @@ static struct resource ssc2_resources[] = { };
static struct platform_device at91sam9261_ssc2_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 2, .dev = { .dma_mask = &ssc2_dmamask, diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 6a01d03..95a5471 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -186,8 +186,8 @@ static struct clk *periph_clocks[] __initdata = { static struct clk_lookup periph_clocks_lookups[] = { /* One additional fake clock for macb_hclk */ CLKDEV_CON_ID("hclk", &macb_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk), CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 8dde220..df89a00 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -1199,7 +1199,7 @@ static struct resource ssc0_resources[] = { };
static struct platform_device at91sam9263_ssc0_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -1241,7 +1241,7 @@ static struct resource ssc1_resources[] = { };
static struct platform_device at91sam9263_ssc1_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 84af1b5..f4f96a6 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -239,8 +239,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk), CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk), CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk), diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index b159607..27e3bf6 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -1459,7 +1459,7 @@ static struct resource ssc0_resources[] = { };
static struct platform_device at91sam9g45_ssc0_device = { - .name = "ssc", + .name = "at91sam9g45_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -1501,7 +1501,7 @@ static struct resource ssc1_resources[] = { };
static struct platform_device at91sam9g45_ssc1_device = { - .name = "ssc", + .name = "at91sam9g45_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 72e9084..4110b54 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -184,8 +184,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), - CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk), CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index d6ca054..01220c7 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -832,7 +832,7 @@ static struct resource ssc0_resources[] = { };
static struct platform_device at91sam9rl_ssc0_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 0, .dev = { .dma_mask = &ssc0_dmamask, @@ -874,7 +874,7 @@ static struct resource ssc1_resources[] = { };
static struct platform_device at91sam9rl_ssc1_device = { - .name = "ssc", + .name = "at91rm9200_ssc", .id = 1, .dev = { .dma_mask = &ssc1_dmamask, diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index ac00f83..f40abd8 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -68,6 +68,26 @@ void ssc_free(struct ssc_device *ssc) } EXPORT_SYMBOL(ssc_free);
+static struct atmel_ssc_platform_data at91rm9200_config = { + .use_dma = 0, +}; + +static struct atmel_ssc_platform_data at91sam9g45_config = { + .use_dma = 1, +}; + +static const struct platform_device_id atmel_ssc_devtypes[] = { + { + .name = "at91rm9200_ssc", + .driver_data = (unsigned long) &at91rm9200_config, + }, { + .name = "at91sam9g45_ssc", + .driver_data = (unsigned long) &at91sam9g45_config, + }, { + /* sentinel */ + } +}; + static int ssc_probe(struct platform_device *pdev) { struct resource *regs; @@ -80,6 +100,8 @@ static int ssc_probe(struct platform_device *pdev) }
ssc->pdev = pdev; + ssc->pdata = (struct atmel_ssc_platform_data *) + platform_get_device_id(pdev)->driver_data;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { @@ -139,6 +161,7 @@ static struct platform_driver ssc_driver = { .name = "ssc", .owner = THIS_MODULE, }, + .id_table = atmel_ssc_devtypes, .probe = ssc_probe, .remove = __devexit_p(ssc_remove), }; diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h index 4eb3175..1ca0e32 100644 --- a/include/linux/atmel-ssc.h +++ b/include/linux/atmel-ssc.h @@ -5,10 +5,15 @@ #include <linux/list.h> #include <linux/io.h>
+struct atmel_ssc_platform_data { + int use_dma; +}; + struct ssc_device { struct list_head list; void __iomem *regs; struct platform_device *pdev; + struct atmel_ssc_platform_data *pdata; struct clk *clk; int user; int irq;
Add atmel-ssc for device tree support
Match "atmel,at91rm9200-ssc" for using pdc for data transfer Match "atmel,at91sam9g45-ssc" for using pdc for data transfer
Signed-off-by: Bo Shen voice.shen@atmel.com Acked-by: Nicolas Ferre nicolas.ferre@atmel.com --- Change since v2 No change Change since v1 change the underscore to dash in atmel-ssc binding document --- .../devicetree/bindings/misc/atmel-ssc.txt | 15 ++++++ arch/arm/boot/dts/at91sam9260.dtsi | 8 ++++ arch/arm/boot/dts/at91sam9263.dtsi | 16 +++++++ arch/arm/boot/dts/at91sam9g45.dtsi | 16 +++++++ arch/arm/boot/dts/at91sam9x5.dtsi | 8 ++++ arch/arm/mach-at91/at91rm9200.c | 3 ++ arch/arm/mach-at91/at91sam9260.c | 1 + arch/arm/mach-at91/at91sam9261.c | 3 ++ arch/arm/mach-at91/at91sam9263.c | 2 + arch/arm/mach-at91/at91sam9g45.c | 2 + arch/arm/mach-at91/at91sam9rl.c | 2 + arch/arm/mach-at91/at91sam9x5.c | 1 + drivers/misc/atmel-ssc.c | 49 ++++++++++++++++++-- 13 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/misc/atmel-ssc.txt
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt new file mode 100644 index 0000000..38e51ad --- /dev/null +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt @@ -0,0 +1,15 @@ +* Atmel SSC driver. + +Required properties: +- compatible: "atmel,at91rm9200-ssc" or "atmel,at91sam9g45-ssc" + - atmel,at91rm9200-ssc: support pdc transfer + - atmel,at91sam9g45-ssc: support dma transfer +- reg: Should contain SSC registers location and length +- interrupts: Should contain SSC interrupt + +Example: +ssc0: ssc@fffbc000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffbc000 0x4000>; + interrupts = <14 4 5>; +}; diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index d410581..aaa42d8 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -29,6 +29,7 @@ tcb0 = &tcb0; tcb1 = &tcb1; i2c0 = &i2c0; + ssc0 = &ssc0; }; cpus { cpu@0 { @@ -212,6 +213,13 @@ status = "disabled"; };
+ ssc0: ssc@fffbc000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffbc000 0x4000>; + interrupts = <14 4 5>; + status = "disable"; + }; + adc0: adc@fffe0000 { compatible = "atmel,at91sam9260-adc"; reg = <0xfffe0000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index 3e6e5c1..3b721ee 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -25,6 +25,8 @@ gpio4 = &pioE; tcb0 = &tcb0; i2c0 = &i2c0; + ssc0 = &ssc0; + ssc1 = &ssc1; }; cpus { cpu@0 { @@ -173,6 +175,20 @@ status = "disabled"; };
+ ssc0: ssc@fff98000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfff98000 0x4000>; + interrupts = <16 4 5>; + status = "disable"; + }; + + ssc1: ssc@fff9c000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfff9c000 0x4000>; + interrupts = <17 4 5>; + status = "disable"; + }; + macb0: ethernet@fffbc000 { compatible = "cdns,at32ap7000-macb", "cdns,macb"; reg = <0xfffbc000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 3add030..cd9af7c 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -31,6 +31,8 @@ tcb1 = &tcb1; i2c0 = &i2c0; i2c1 = &i2c1; + ssc0 = &ssc0; + ssc1 = &ssc1; }; cpus { cpu@0 { @@ -226,6 +228,20 @@ status = "disabled"; };
+ ssc0: ssc@fff9c000 { + compatible = "atmel,at91sam9g45-ssc"; + reg = <0xfff9c000 0x4000>; + interrupts = <16 4 5>; + status = "disable"; + }; + + ssc0: ssc@fffa0000 { + compatible = "atmel,at91sam9g45-ssc"; + reg = <0xfffa0000 0x4000>; + interrupts = <17 4 5>; + status = "disable"; + }; + adc0: adc@fffb0000 { compatible = "atmel,at91sam9260-adc"; reg = <0xfffb0000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 03fc136..69667d0 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -30,6 +30,7 @@ i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; + ssc0 = &ssc0; }; cpus { cpu@0 { @@ -87,6 +88,13 @@ interrupts = <1 4 7>; };
+ ssc0: ssc@f0010000 { + compatible = "atmel,at91sam9g45-ssc"; + reg = <0xf0010000 0x4000>; + interrupts = <28 4 5>; + status = "disable"; + }; + tcb0: timer@f8008000 { compatible = "atmel,at91sam9x5-tcb"; reg = <0xf8008000 0x100>; diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 85d53c5..6d65feb 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -187,6 +187,9 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID("pclk", "fffd0000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fffd4000.ssc", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fffd8000.ssc", &ssc2_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 2c8aab0..54d4aea 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -211,6 +211,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc_clk), + CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk), /* more usart lookup table for DT entries */ diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 4e8c56e..5c7a482 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -177,6 +177,9 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk), + CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc2_clk), CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk), diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 95a5471..1f523de 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -188,6 +188,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("hclk", &macb_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fff98000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc1_clk), CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk), CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index f4f96a6..a4282d3 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -241,6 +241,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk), CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fffa0000.ssc", &ssc1_clk), CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk), CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk), CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk), diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 4110b54..b683fdc 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), + CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc0_clk), + CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc1_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk), CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index e503538..18fbbb2 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c @@ -231,6 +231,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk), CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk), CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk), + CLKDEV_CON_DEV_ID("pclk", "f0010000.ssc", &ssc_clk), CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk), CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk), CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk), diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index f40abd8..a769719 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -18,6 +18,8 @@ #include <linux/slab.h> #include <linux/module.h>
+#include <linux/of.h> + /* Serialize access to ssc_list and user count */ static DEFINE_SPINLOCK(user_lock); static LIST_HEAD(ssc_list); @@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
spin_lock(&user_lock); list_for_each_entry(ssc, &ssc_list, list) { - if (ssc->pdev->id == ssc_num) { + if (ssc->pdev->dev.of_node) { + if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc") + == ssc_num) { + ssc_valid = 1; + break; + } + } else if (ssc->pdev->id == ssc_num) { ssc_valid = 1; break; } @@ -88,10 +96,41 @@ static const struct platform_device_id atmel_ssc_devtypes[] = { } };
+#ifdef CONFIG_OF +static const struct of_device_id atmel_ssc_dt_ids[] = { + { + .compatible = "atmel,at91rm9200-ssc", + .data = &at91rm9200_config, + }, { + .compatible = "atmel,at91sam9g45-ssc", + .data = &at91sam9g45_config, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids); +#endif + +static inline const struct atmel_ssc_platform_data * __init + atmel_ssc_get_driver_data(struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_ssc_dt_ids, pdev->dev.of_node); + if (match == NULL) + return NULL; + return match->data; + } + + return (struct atmel_ssc_platform_data *) + platform_get_device_id(pdev)->driver_data; +} + static int ssc_probe(struct platform_device *pdev) { struct resource *regs; struct ssc_device *ssc; + const struct atmel_ssc_platform_data *plat_dat;
ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL); if (!ssc) { @@ -100,8 +139,11 @@ static int ssc_probe(struct platform_device *pdev) }
ssc->pdev = pdev; - ssc->pdata = (struct atmel_ssc_platform_data *) - platform_get_device_id(pdev)->driver_data; + + plat_dat = atmel_ssc_get_driver_data(pdev); + if (!plat_dat) + return -ENODEV; + ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { @@ -160,6 +202,7 @@ static struct platform_driver ssc_driver = { .driver = { .name = "ssc", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_ssc_dt_ids), }, .id_table = atmel_ssc_devtypes, .probe = ssc_probe,
On Tue, Nov 06, 2012 at 01:57:52PM +0800, Bo Shen wrote:
Add atmel-ssc for device tree support
Match "atmel,at91rm9200-ssc" for using pdc for data transfer Match "atmel,at91sam9g45-ssc" for using pdc for data transfer
Applied, thanks.
Register dai and pcm directly fix issue when register dai and pcm directly Add device tree support
Signed-off-by: Bo Shen voice.shen@atmel.com Acked-by: Nicolas Ferre nicolas.ferre@atmel.com --- Change since v2 - Register dai and pcm directly according to Mark Brown's suggestion - using name to distinguish ssc register for audio or library if for audio, the name with dai subfix if for library, the name without dai subfix - fix the issue for sam9g20-wm8731 - when register dai and pcm cause the sam9g20-wm8731 doesn't work, so fix it - Add device tree support - Detail information reference atmel-ssc-dai.txt binding document Change since v1 No change --- .../devicetree/bindings/sound/atmel-ssc-dai.txt | 15 + arch/arm/mach-at91/at91sam9260.c | 2 +- arch/arm/mach-at91/at91sam9260_devices.c | 5 +- arch/arm/mach-at91/board-sam9g20ek.c | 6 - sound/soc/atmel/Kconfig | 3 +- sound/soc/atmel/atmel-pcm.c | 23 +- sound/soc/atmel/atmel-pcm.h | 3 + sound/soc/atmel/atmel_ssc_dai.c | 319 +++++++++----------- sound/soc/atmel/sam9g20_wm8731.c | 4 +- 9 files changed, 175 insertions(+), 205 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/atmel-ssc-dai.txt
diff --git a/Documentation/devicetree/bindings/sound/atmel-ssc-dai.txt b/Documentation/devicetree/bindings/sound/atmel-ssc-dai.txt new file mode 100644 index 0000000..48ec22a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/atmel-ssc-dai.txt @@ -0,0 +1,15 @@ +* Atmel SSC audio driver. + +Required properties: +- compatible: "atmel,at91rm9200-ssc-dai" or "atmel,at91sam9g45-ssc-dai" + - atmel,at91rm9200-ssc-dai: support pdc transfer + - atmel,at91sam9g45-ssc-dai: support dma transfer +- reg: Should contain SSC registers location and length +- interrupts: Should contain SSC interrupt + +Example: +ssc0: ssc@fffbc000 { + compatible = "atmel,at91rm9200-ssc-dai"; + reg = <0xfffbc000 0x4000>; + interrupts = <14 4 5>; +}; diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 54d4aea..859526d 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -210,7 +210,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), - CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc_clk), + CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc_dai.0", &ssc_clk), CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk), diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 9cfdc3f..c7ad6ee 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -725,7 +725,8 @@ static void __init at91_add_device_watchdog(void) {} * SSC -- Synchronous Serial Controller * -------------------------------------------------------------------- */
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE) +#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE) || \ + defined(CONFIG_SND_ATMEL_SOC) || defined(CONFIG_SND_ATMEL_SOC_MODULE) static u64 ssc_dmamask = DMA_BIT_MASK(32);
static struct resource ssc_resources[] = { @@ -742,7 +743,7 @@ static struct resource ssc_resources[] = { };
static struct platform_device at91sam9260_ssc_device = { - .name = "at91rm9200_ssc", + .name = "at91rm9200_ssc_dai", .id = 0, .dev = { .dma_mask = &ssc_dmamask, diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index 5b6a6f9..ebdbf42 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c @@ -353,11 +353,6 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = { }, };
-static struct platform_device sam9g20ek_pcm_device = { - .name = "atmel-pcm-audio", - .id = -1, -}; - static struct platform_device sam9g20ek_audio_device = { .name = "at91sam9g20ek-audio", .id = -1, @@ -365,7 +360,6 @@ static struct platform_device sam9g20ek_audio_device = {
static void __init ek_add_device_audio(void) { - platform_device_register(&sam9g20ek_pcm_device); platform_device_register(&sam9g20ek_audio_device); }
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 72b09cf..b51ba54 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -16,8 +16,7 @@ config SND_ATMEL_SOC_SSC
config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \ - AT91_PROGRAMMABLE_CLOCKS + depends on SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS select SND_ATMEL_SOC_SSC select SND_SOC_WM8731 help diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 9b84f98..1e9cd2c 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -473,28 +473,17 @@ static struct snd_soc_platform_driver atmel_soc_platform = { .resume = atmel_pcm_resume, };
-static int __devinit atmel_soc_platform_probe(struct platform_device *pdev) +int __devinit atmel_pcm_platform_register(struct device *dev) { - return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform); + return snd_soc_register_platform(dev, &atmel_soc_platform); } +EXPORT_SYMBOL(atmel_pcm_platform_register);
-static int __devexit atmel_soc_platform_remove(struct platform_device *pdev) +void __devexit atmel_pcm_platform_unregister(struct device *dev) { - snd_soc_unregister_platform(&pdev->dev); - return 0; + snd_soc_unregister_platform(dev); } - -static struct platform_driver atmel_pcm_driver = { - .driver = { - .name = "atmel-pcm-audio", - .owner = THIS_MODULE, - }, - - .probe = atmel_soc_platform_probe, - .remove = __devexit_p(atmel_soc_platform_remove), -}; - -module_platform_driver(atmel_pcm_driver); +EXPORT_SYMBOL(atmel_pcm_platform_unregister);
MODULE_AUTHOR("Sedji Gaouaou sedji.gaouaou@atmel.com"); MODULE_DESCRIPTION("Atmel PCM module"); diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h index 5e0a95e..e6d67b3 100644 --- a/sound/soc/atmel/atmel-pcm.h +++ b/sound/soc/atmel/atmel-pcm.h @@ -80,4 +80,7 @@ struct atmel_pcm_dma_params { #define ssc_readx(base, reg) (__raw_readl((base) + (reg))) #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg))
+int atmel_pcm_platform_register(struct device *dev); +void atmel_pcm_platform_unregister(struct device *dev); + #endif /* _ATMEL_PCM_H */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 354341e..81e3604 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -42,18 +42,13 @@ #include <sound/initval.h> #include <sound/soc.h>
+#include <linux/of.h> + #include <mach/hardware.h>
#include "atmel-pcm.h" #include "atmel_ssc_dai.h"
- -#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) -#define NUM_SSC_DEVICES 1 -#else -#define NUM_SSC_DEVICES 3 -#endif - /* * SSC PDC registers required by the PCM DMA engine. */ @@ -96,63 +91,24 @@ static struct atmel_ssc_mask ssc_rx_mask = { /* * DMA parameters. */ -static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { - {{ - .name = "SSC0 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, +static struct atmel_pcm_dma_params ssc_dma_params[2] = { { - .name = "SSC0 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - } }, -#if NUM_SSC_DEVICES == 3 - {{ - .name = "SSC1 PCM out", + .name = "SSC PCM out", .pdc = &pdc_tx_reg, .mask = &ssc_tx_mask, }, { - .name = "SSC1 PCM in", + .name = "SSC PCM in", .pdc = &pdc_rx_reg, .mask = &ssc_rx_mask, - } }, - {{ - .name = "SSC2 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, }, - { - .name = "SSC2 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - } }, -#endif };
- -static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { - { - .name = "ssc0", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), +static struct atmel_ssc_info ssc_info = { + .name = "ssc", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info.lock), .dir_mask = SSC_DIR_MASK_UNUSED, .initialized = 0, - }, -#if NUM_SSC_DEVICES == 3 - { - .name = "ssc1", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc2", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, -#endif };
@@ -205,7 +161,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + struct atmel_ssc_info *ssc_p = &ssc_info; int dir_mask;
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", @@ -234,7 +190,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + struct atmel_ssc_info *ssc_p = &ssc_info; struct atmel_pcm_dma_params *dma_params; int dir, dir_mask;
@@ -285,7 +241,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + struct atmel_ssc_info *ssc_p = &ssc_info;
ssc_p->daifmt = fmt; return 0; @@ -297,7 +253,7 @@ static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div) { - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + struct atmel_ssc_info *ssc_p = &ssc_info;
switch (div_id) { case ATMEL_SSC_CMR_DIV: @@ -336,8 +292,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - int id = dai->id; - struct atmel_ssc_info *ssc_p = &ssc_info[id]; + struct atmel_ssc_info *ssc_p = &ssc_info; struct atmel_pcm_dma_params *dma_params; int dir, channels, bits; u32 tfmr, rfmr, tcmr, rcmr; @@ -354,7 +309,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, else dir = 1;
- dma_params = &ssc_dma_params[id][dir]; + dma_params = &ssc_dma_params[dir]; dma_params->ssc = ssc_p->ssc; dma_params->substream = substream;
@@ -603,7 +558,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, static int atmel_ssc_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + struct atmel_ssc_info *ssc_p = &ssc_info; struct atmel_pcm_dma_params *dma_params; int dir;
@@ -631,7 +586,7 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) if (!cpu_dai->active) return 0;
- ssc_p = &ssc_info[cpu_dai->id]; + ssc_p = &ssc_info;
/* Save the status register before disabling transmit and receive */ ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); @@ -660,7 +615,7 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) if (!cpu_dai->active) return 0;
- ssc_p = &ssc_info[cpu_dai->id]; + ssc_p = &ssc_info;
/* restore SSC register settings */ ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); @@ -689,28 +644,10 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
static int atmel_ssc_probe(struct snd_soc_dai *dai) { - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; - int ret = 0; + struct atmel_ssc_info *ssc_p = &ssc_info;
snd_soc_dai_set_drvdata(dai, ssc_p);
- /* - * Request SSC device - */ - ssc_p->ssc = ssc_request(dai->id); - if (IS_ERR(ssc_p->ssc)) { - printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id); - ret = PTR_ERR(ssc_p->ssc); - } - - return ret; -} - -static int atmel_ssc_remove(struct snd_soc_dai *dai) -{ - struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai); - - ssc_free(ssc_p->ssc); return 0; }
@@ -728,11 +665,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { .set_clkdiv = atmel_ssc_set_dai_clkdiv, };
-static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = { - { - .name = "atmel-ssc-dai.0", +static struct snd_soc_dai_driver atmel_ssc_dai = { .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -746,118 +680,153 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = { .rates = ATMEL_SSC_RATES, .formats = ATMEL_SSC_FORMATS,}, .ops = &atmel_ssc_dai_ops, - }, -#if NUM_SSC_DEVICES == 3 - { - .name = "atmel-ssc-dai.1", - .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = &atmel_ssc_dai_ops, - }, +}; + +static struct atmel_ssc_platform_data at91rm9200_config = { + .use_dma = 0, +}; + +static struct atmel_ssc_platform_data at91sam9g45_config = { + .use_dma = 1, +}; + +#ifdef CONFIG_OF +static const struct of_device_id atmel_ssc_dai_dt_ids[] = { { - .name = "atmel-ssc-dai.2", - .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = &atmel_ssc_dai_ops, - }, -#endif + .compatible = "atmel,at91rm9200-ssc-dai", + .data = &at91rm9200_config, + }, { + .compatible = "atmel,at91sam9g45-ssc-dai", + .data = &at91sam9g45_config, + }, { + /* sentinel */ + } }; +MODULE_DEVICE_TABLE(of, atmel_ssc_dai_dt_ids); +#endif
-static __devinit int asoc_ssc_probe(struct platform_device *pdev) +static inline const struct atmel_ssc_platform_data * __init + atmel_ssc_get_driver_data(struct platform_device *pdev) { - BUG_ON(pdev->id < 0); - BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai)); - return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]); -} + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_ssc_dai_dt_ids, + pdev->dev.of_node); + if (match == NULL) + return NULL; + return match->data; + }
-static int __devexit asoc_ssc_remove(struct platform_device *pdev) -{ - snd_soc_unregister_dai(&pdev->dev); - return 0; + return (struct atmel_ssc_platform_data *) + platform_get_device_id(pdev)->driver_data; }
-static struct platform_driver asoc_ssc_driver = { - .driver = { - .name = "atmel-ssc-dai", - .owner = THIS_MODULE, - }, - - .probe = asoc_ssc_probe, - .remove = __devexit_p(asoc_ssc_remove), -}; - -/** - * atmel_ssc_set_audio - Allocate the specified SSC for audio use. - */ -int atmel_ssc_set_audio(int ssc_id) +static __devinit int asoc_ssc_probe(struct platform_device *pdev) { struct ssc_device *ssc; - static struct platform_device *dma_pdev; - struct platform_device *ssc_pdev; + struct resource *regs; + const struct atmel_ssc_platform_data *pdata; int ret;
- if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai)) + ssc = devm_kzalloc(&pdev->dev, sizeof(ssc), GFP_KERNEL); + if (!ssc) { + dev_err(&pdev->dev, "out of memory\n"); + return -ENOMEM; + } + + ssc->pdev = pdev; + + pdata = atmel_ssc_get_driver_data(pdev); + if (!pdata) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENODEV; + } + ssc->pdata = (struct atmel_ssc_platform_data *)pdata; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "no mmio resource defined\n"); + return -ENXIO; + } + + ssc->regs = devm_request_and_ioremap(&pdev->dev, regs); + if (!ssc->regs) { + dev_err(&pdev->dev, "ioremap failed\n"); return -EINVAL; + }
- /* Allocate a dummy device for DMA if we don't have one already */ - if (!dma_pdev) { - dma_pdev = platform_device_alloc("atmel-pcm-audio", -1); - if (!dma_pdev) - return -ENOMEM; + ssc->clk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(ssc->clk)) { + dev_err(&pdev->dev, "no pclk clock defined\n"); + return -EINVAL; + }
- ret = platform_device_add(dma_pdev); - if (ret < 0) { - platform_device_put(dma_pdev); - dma_pdev = NULL; - return ret; - } + /* disable all interrupts */ + clk_enable(ssc->clk); + ssc_writel(ssc->regs, IDR, ~0UL); + ssc_readl(ssc->regs, SR); + clk_disable(ssc->clk); + + ssc->irq = platform_get_irq(pdev, 0); + if (!ssc->irq) { + dev_err(&pdev->dev, "could not get irq\n"); + return -ENXIO; }
- ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id); - if (!ssc_pdev) - return -ENOMEM; + ssc_info.ssc = ssc;
- /* If we can grab the SSC briefly to parent the DAI device off it */ - ssc = ssc_request(ssc_id); - if (IS_ERR(ssc)) - pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n", - PTR_ERR(ssc)); - else { - ssc_pdev->dev.parent = &(ssc->pdev->dev); - ssc_free(ssc); + platform_set_drvdata(pdev, ssc); + + ret = snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai); + if (ret) { + dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); + goto err_unregister_dai; }
- ret = platform_device_add(ssc_pdev); - if (ret < 0) - platform_device_put(ssc_pdev); + ret = atmel_pcm_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); + goto err; + }; + + return 0;
+err_unregister_dai: + snd_soc_unregister_dai(&pdev->dev); +err: return ret; } -EXPORT_SYMBOL_GPL(atmel_ssc_set_audio); + +static int __devexit asoc_ssc_remove(struct platform_device *pdev) +{ + atmel_pcm_platform_unregister(&pdev->dev); + snd_soc_unregister_dai(&pdev->dev); + + return 0; +} + +static const struct platform_device_id atmel_ssc_dai_devtypes[] = { + { + .name = "at91rm9200_ssc_dai", + .driver_data = (unsigned long) &at91rm9200_config, + }, { + .name = "at91sam9g45_ssc_dai", + .driver_data = (unsigned long) &at91sam9g45_config, + }, { + /* sentinel */ + } +}; + +static struct platform_driver asoc_ssc_driver = { + .driver = { + .name = "atmel-ssc-dai", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_ssc_dai_dt_ids), + }, + .id_table = atmel_ssc_dai_devtypes, + .probe = asoc_ssc_probe, + .remove = __devexit_p(asoc_ssc_remove), +};
module_platform_driver(asoc_ssc_driver);
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index e5e27db..862cbcc 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -179,10 +179,10 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link at91sam9g20ek_dai = { .name = "WM8731", .stream_name = "WM8731 PCM", - .cpu_dai_name = "atmel-ssc-dai.0", + .cpu_dai_name = "at91rm9200_ssc_dai.0", .codec_dai_name = "wm8731-hifi", .init = at91sam9g20ek_wm8731_init, - .platform_name = "atmel-pcm-audio", + .platform_name = "at91rm9200_ssc_dai.0", .codec_name = "wm8731.0-001b", .ops = &at91sam9g20ek_ops, };
On Tue, Nov 06, 2012 at 01:57:53PM +0800, Bo Shen wrote:
static struct platform_device at91sam9260_ssc_device = {
- .name = "at91rm9200_ssc",
- .name = "at91rm9200_ssc_dai", .id = 0, .dev = {
No, this isn't converting things to device tree which presumably is the goal here and obviously just doing the rename doesn't accomplish an enormous amount. What I said was that you should instantiate the ASoC adaption when the machine driver needs to use them. You shouldn't even need a separate device for this.
Please do look at other platforms with similar hardware and do something similar to them.
On 11/6/2012 16:48, Mark Brown wrote:
On Tue, Nov 06, 2012 at 01:57:53PM +0800, Bo Shen wrote:
static struct platform_device at91sam9260_ssc_device = {
- .name = "at91rm9200_ssc",
- .name = "at91rm9200_ssc_dai", .id = 0, .dev = {
No, this isn't converting things to device tree which presumably is the goal here and obviously just doing the rename doesn't accomplish an enormous amount. What I said was that you should instantiate the ASoC adaption when the machine driver needs to use them. You shouldn't even need a separate device for this.
Maybe this is not the best solution, but just abstract audio as a separate device. The other's still keep as a ssc library.
Please do look at other platforms with similar hardware and do something similar to them.
I take some reference (e.g: freescale, marvell, invidia soc, this RFC implement is similar with them), but don't find the similar hardware with us. Please help provide the information who's HW is similar with us. Thanks.
BRs, Bo Shen
On Tue, Nov 06, 2012 at 05:32:32PM +0800, Bo Shen wrote:
On 11/6/2012 16:48, Mark Brown wrote:
On Tue, Nov 06, 2012 at 01:57:53PM +0800, Bo Shen wrote:
No, this isn't converting things to device tree which presumably is the goal here and obviously just doing the rename doesn't accomplish an enormous amount. What I said was that you should instantiate the ASoC adaption when the machine driver needs to use them. You shouldn't even need a separate device for this.
Maybe this is not the best solution, but just abstract audio as a separate device. The other's still keep as a ssc library.
It's not abstracting things, that's the whole problem. It's putting the internals of how the Linux audio stack is organised into the device tree. The point is that the SSC should be a library to all users.
Please do look at other platforms with similar hardware and do something similar to them.
I take some reference (e.g: freescale, marvell, invidia soc, this RFC implement is similar with them), but don't find the similar hardware with us. Please help provide the information who's HW is similar with us. Thanks.
A *huge* range of SoCs have generic serial ports - off the top of my head this includes at least OMAP, PXA and Freescale. The same issue also applies to DMA controllers which affects almost all SoCs.
On 11/6/2012 19:39, Mark Brown wrote:
On Tue, Nov 06, 2012 at 05:32:32PM +0800, Bo Shen wrote:
On 11/6/2012 16:48, Mark Brown wrote:
On Tue, Nov 06, 2012 at 01:57:53PM +0800, Bo Shen wrote:
No, this isn't converting things to device tree which presumably is the goal here and obviously just doing the rename doesn't accomplish an enormous amount. What I said was that you should instantiate the ASoC adaption when the machine driver needs to use them. You shouldn't even need a separate device for this.
Maybe this is not the best solution, but just abstract audio as a separate device. The other's still keep as a ssc library.
It's not abstracting things, that's the whole problem. It's putting the internals of how the Linux audio stack is organised into the device tree. The point is that the SSC should be a library to all users.
OK. I will keep the SSC as a library for all users.
Please do look at other platforms with similar hardware and do something similar to them.
I take some reference (e.g: freescale, marvell, invidia soc, this RFC implement is similar with them), but don't find the similar hardware with us. Please help provide the information who's HW is similar with us. Thanks.
A *huge* range of SoCs have generic serial ports - off the top of my head this includes at least OMAP, PXA and Freescale. The same issue also applies to DMA controllers which affects almost all SoCs.
Thanks for this information, I will try to implement the SSC framework like this. If it is finished, I will send out v4 patch series.
Thanks again.
BRs, Bo Shen
convert sam9g20-wm8731 to device tree support
Signed-off-by: Bo Shen voice.shen@atmel.com Acked-by: Nicolas Ferre nicolas.ferre@atmel.com --- Change since v2: No change Change since v1: Add sam9g20-wm8731 binding document --- .../bindings/sound/atmel-sam9g20-audio-wm8731.txt | 21 ++++++++ arch/arm/boot/dts/at91sam9260.dtsi | 2 +- arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 20 +++++++- sound/soc/atmel/sam9g20_wm8731.c | 51 +++++++++++++++++++- 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/atmel-sam9g20-audio-wm8731.txt
diff --git a/Documentation/devicetree/bindings/sound/atmel-sam9g20-audio-wm8731.txt b/Documentation/devicetree/bindings/sound/atmel-sam9g20-audio-wm8731.txt new file mode 100644 index 0000000..ad77fb0 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/atmel-sam9g20-audio-wm8731.txt @@ -0,0 +1,21 @@ +* Atmel sam9g20ek audio complex + +Required properties: + - compatible: "atmel,at91sam9g20-audio" + - atmel,model: The user-visible name of this sound complex. + - atmel,audio-routing: A list of the connections between audio components. + - atmel,ssc-controller: The phandle of the SSC controller + - atmel,audio-codec: The phandle of the WM8731 audio codec + +Example: +sound { + compatible = "atmel,at91sam9g20-audio"; + atmel,model = "wm8731 @ sam9g20ek"; + + atmel,audio-routing = + "Ext Spk", "LHPOUT", + "Int MIC", "MICIN"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8731>; +}; diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index aaa42d8..d322dae 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -214,7 +214,7 @@ };
ssc0: ssc@fffbc000 { - compatible = "atmel,at91rm9200-ssc"; + compatible = "atmel,at91rm9200-ssc-dai"; reg = <0xfffbc000 0x4000>; interrupts = <14 4 5>; status = "disable"; diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi index b06c0db..05706a3 100644 --- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi @@ -51,6 +51,10 @@ atmel,vbus-gpio = <&pioC 5 0>; status = "okay"; }; + + ssc0: ssc@fffbc000 { + status = "okay"; + }; };
nand0: nand@40000000 { @@ -114,8 +118,8 @@ reg = <0x50>; };
- wm8731@1b { - compatible = "wm8731"; + wm8731: wm8731@1b { + compatible = "wlf,wm8731"; reg = <0x1b>; }; }; @@ -139,4 +143,16 @@ gpio-key,wakeup; }; }; + + sound { + compatible = "atmel,at91sam9g20-audio"; + atmel,model = "wm8731 @ sam9g20ek"; + + atmel,audio-routing = + "Ext Spk", "LHPOUT", + "Int Mic", "MICIN"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8731>; + }; }; diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 862cbcc..36f0fb3 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -197,13 +197,17 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
static int __devinit at91sam9g20ek_audio_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; struct clk *pllb; struct snd_soc_card *card =&snd_soc_at91sam9g20ek; int ret;
- if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) + if (!np) { + if (!(machine_is_at91sam9g20ek() + || machine_is_at91sam9g20ek_2mmc())) return -ENODEV; - + } /* * Codec MCLK is supplied by PCK0 - set it up. */ @@ -230,6 +234,40 @@ static int __devinit at91sam9g20ek_audio_probe(struct platform_device *pdev) clk_set_rate(mclk, MCLK_RATE);
card->dev = &pdev->dev; + + /* Parse device node info */ + if (np) { + ret = snd_soc_of_parse_card_name(card, "atmel,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, + "atmel,audio-routing"); + if (ret) + goto err; + + /* Parse codec dai info */ + at91sam9g20ek_dai.codec_name = NULL; + codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "codec info missing\n"); + return -EINVAL; + } + at91sam9g20ek_dai.codec_of_node = codec_np; + at91sam9g20ek_dai.cpu_dai_name = NULL; + at91sam9g20ek_dai.platform_name = NULL; + cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "dai info missing\n"); + return -EINVAL; + } + at91sam9g20ek_dai.cpu_of_node = cpu_np; + at91sam9g20ek_dai.platform_of_node = cpu_np; + + of_node_put(codec_np); + of_node_put(cpu_np); + } + ret = snd_soc_register_card(card); if (ret) { printk(KERN_ERR "ASoC: snd_soc_register_card() failed\n"); @@ -255,10 +293,19 @@ static int __devexit at91sam9g20ek_audio_remove(struct platform_device *pdev) return 0; }
+#ifdef CONFIG_OF +static const struct of_device_id sam9g20ek_wm8731_dt_ids[] = { + { .compatible = "atmel,at91sam9g20-audio", }, + { } +}; +MODULE_DEVICE_TABLE(of, sam9g20ek_wm8731_dt_ids); +#endif + static struct platform_driver at91sam9g20ek_audio_driver = { .driver = { .name = "at91sam9g20ek-audio", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sam9g20ek_wm8731_dt_ids), }, .probe = at91sam9g20ek_audio_probe, .remove = __devexit_p(at91sam9g20ek_audio_remove),
participants (2)
-
Bo Shen
-
Mark Brown