[alsa-devel] [PATCH 00/17] ASoC: Add Tegra DT, cleanup, and related
These patches add device tree bindings for all the Tegra ASoC components, and the WM8903 codec. Also included is some general Tegra driver cleanup, and a solution for the "snd_soc_dapm_nc_pin" open-coding.
The ASoC and arch/arm changes should be independent enought that they can be applied to their separate trees without issue to those trees standalone, and will meet in linux-next just fine.
The arch/arm .dts/*.dts changes depend on the .dtsi/.dts cleanup patches that I posted yesterday for context.
I tested this on:
Harmony, Seaboard: non-DT and DT: Tested audio capture & playback.
Trimslice: non-DT and DT: Tested audio playback. Capture appears to be broken before my patches.
Ventana: DT: Tested audio capture & playback.
Paz00: DT: Tested booting with the patches applied.
John Bonesio (2): ASoC: Add device tree binding for WM8903 ASoC: Tegra+WM8903 machine: Add device tree binding
Stephen Warren (15): arm/tegra: board-dt: audio: Enable clocks, fix AUXDATA arm/dt: Tegra: Clean up I2S and DAS nodes arm/dt: Tegra: Enable audio on WM8903 boards, disable others ASoC: Tegra: Move DAS configuration into machine drivers ASoC: Tegra PCM: Use module_platform_driver ASoC: Tegra DAS: Use devm_ APIs and module_platform_driver ASoC: Tegra I2S: Use devm_ APIs and module_platform_driver ASoC: Tegra I2S: Remove dependency on pdev->id ASoC: Tegra DAS: Add device tree binding ASoC: Tegra I2S: Add device tree binding ASoC: Tegra+WM8903 machine: Use devm_ APIs and module_platform_driver ASoC: Tegra TrimSlice machine: Use devm_ APIs and module_platform_driver ASoC: Implement "auto nc pins" feature ASoC: Tegra+WM903 machine: Use new auto_nc_codec_pins feature ASoC: TrimSlice machine: Use new auto_nc_codec_pins feature
.../bindings/sound/tegra-audio-wm8903.txt | 63 +++++++ .../devicetree/bindings/sound/tegra20-das.txt | 12 ++ .../devicetree/bindings/sound/tegra20-i2s.txt | 16 ++ Documentation/devicetree/bindings/sound/wm8903.txt | 48 +++++ arch/arm/boot/dts/tegra-harmony.dts | 29 +++- arch/arm/boot/dts/tegra-paz00.dts | 12 ++ arch/arm/boot/dts/tegra-seaboard.dts | 36 ++++ arch/arm/boot/dts/tegra-trimslice.dts | 12 ++ arch/arm/boot/dts/tegra-ventana.dts | 38 ++++ arch/arm/boot/dts/tegra20.dtsi | 10 +- arch/arm/mach-tegra/board-dt.c | 7 +- include/sound/soc-dapm.h | 1 + include/sound/soc.h | 1 + sound/soc/codecs/wm8903.c | 48 +++++- sound/soc/soc-core.c | 4 + sound/soc/soc-dapm.c | 73 ++++++++ sound/soc/tegra/tegra_das.c | 53 ++---- sound/soc/tegra/tegra_i2s.c | 164 ++++++----------- sound/soc/tegra/tegra_i2s.h | 1 + sound/soc/tegra/tegra_pcm.c | 13 +-- sound/soc/tegra/tegra_wm8903.c | 193 +++++++++++++------- sound/soc/tegra/trimslice.c | 45 +++--- 22 files changed, 620 insertions(+), 259 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt create mode 100644 Documentation/devicetree/bindings/sound/tegra20-das.txt create mode 100644 Documentation/devicetree/bindings/sound/tegra20-i2s.txt create mode 100644 Documentation/devicetree/bindings/sound/wm8903.txt
Certain clocks are required for core audio functionality. Set up the appropriate parenting relationships, and enable clocks that must be on permanently.
Fix the address of the I2S2 controller in the AUXDATA table.
Signed-off-by: Stephen Warren swarren@nvidia.com --- arch/arm/mach-tegra/board-dt.c | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-tegra/board-dt.c b/arch/arm/mach-tegra/board-dt.c index efb308e..343469c 100644 --- a/arch/arm/mach-tegra/board-dt.c +++ b/arch/arm/mach-tegra/board-dt.c @@ -62,7 +62,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL), OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_DVC_BASE, "tegra-i2c.3", NULL), OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.1", NULL), + OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL), OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0", &tegra_ehci1_device.dev.platform_data), @@ -79,6 +79,11 @@ static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = { { "usbd", "clk_m", 12000000, false }, { "usb2", "clk_m", 12000000, false }, { "usb3", "clk_m", 12000000, false }, + { "pll_a", "pll_p_out1", 56448000, true }, + { "pll_a_out0", "pll_a", 11289600, true }, + { "cdev1", NULL, 0, true }, + { "i2s1", "pll_a_out0", 11289600, false}, + { "i2s2", "pll_a_out0", 11289600, false}, { NULL, NULL, 0, 0}, };
On Tue, Nov 22, 2011 at 06:21:09PM -0700, Stephen Warren wrote:
OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_DVC_BASE, "tegra-i2c.3", NULL), OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
This looks like a straight bug fix which is independant of the below change?
Mark Brown wrote at Wednesday, November 23, 2011 3:39 AM:
On Tue, Nov 22, 2011 at 06:21:09PM -0700, Stephen Warren wrote:
OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_DVC_BASE, "tegra-i2c.3", NULL), OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
This looks like a straight bug fix which is independant of the below change?
That is true.
Olof/Colin, do you want me to split this up?
On Wed, Nov 23, 2011 at 09:44:54AM -0800, Stephen Warren wrote:
Mark Brown wrote at Wednesday, November 23, 2011 3:39 AM:
On Tue, Nov 22, 2011 at 06:21:09PM -0700, Stephen Warren wrote:
OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_DVC_BASE, "tegra-i2c.3", NULL), OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
This looks like a straight bug fix which is independant of the below change?
That is true.
Olof/Colin, do you want me to split this up?
Sure, it's good practice. Indicate if you want it in for 3.2, but given that this is the first user of the binding I am guessing no.
-Olof
The I2S and DAS nodes don't have children, and hence don't need to set address/size cells. Also, adjust the dma-channel property name to match the binding that will be implemented in the driver.
Signed-off-by: Stephen Warren swarren@nvidia.com --- arch/arm/boot/dts/tegra20.dtsi | 10 ++-------- 1 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 795b921..6a17240 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -45,26 +45,20 @@ };
i2s@70002800 { - #address-cells = <1>; - #size-cells = <0>; compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x200>; interrupts = < 45 >; - dma-channel = < 2 >; + nvidia,dma-channels = < 2 >; };
i2s@70002a00 { - #address-cells = <1>; - #size-cells = <0>; compatible = "nvidia,tegra20-i2s"; reg = <0x70002a00 0x200>; interrupts = < 35 >; - dma-channel = < 1 >; + nvidia,dma-channels = < 1 >; };
das@70000c00 { - #address-cells = <1>; - #size-cells = <0>; compatible = "nvidia,tegra20-das"; reg = <0x70000c00 0x80>; };
Add complete bindings to instantiate and configure the codec and top-level audio complex on all currently supported boards using the Tegra+WM8903 audio driver.
On those boards, disable the I2S2 controller since it isn't used.
On boards not using the WM8903 codec, disable all the audio devices; they can be re-enabled once the relevant codec and ASoC machine drivers have been ported to device-tree.
Signed-off-by: Stephen Warren swarren@nvidia.com --- arch/arm/boot/dts/tegra-harmony.dts | 29 ++++++++++++++++++++----- arch/arm/boot/dts/tegra-paz00.dts | 12 ++++++++++ arch/arm/boot/dts/tegra-seaboard.dts | 36 +++++++++++++++++++++++++++++++ arch/arm/boot/dts/tegra-trimslice.dts | 12 ++++++++++ arch/arm/boot/dts/tegra-ventana.dts | 38 +++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 6 deletions(-)
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts index 80afa1b..5cd596f 100644 --- a/arch/arm/boot/dts/tegra-harmony.dts +++ b/arch/arm/boot/dts/tegra-harmony.dts @@ -21,6 +21,8 @@ gpio-controller; #gpio-cells = <2>;
+ micdet-cfg = <0>; + micdet-delay = <100>; /* 0x8000 = Not configured */ gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >; }; @@ -38,13 +40,28 @@ clock-frequency = <400000>; };
- sound { - compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903"; + i2s@70002a00 { + status = "disable"; + };
- spkr-en-gpios = <&codec 2 0>; - hp-det-gpios = <&gpio 178 0>; - int-mic-en-gpios = <&gpio 184 0>; - ext-mic-en-gpios = <&gpio 185 0>; + sound { + compatible = "nvidia,tegra-audio-wm8903-harmony", + "nvidia,tegra-audio-wm8903"; + + nvidia,spkr-en-gpios = <&codec 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ + + nvidia,routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Bias", "Mic Jack", + "IN1L", "Mic Bias"; };
serial@70006000 { diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts index 4f6a8aa..7010982 100644 --- a/arch/arm/boot/dts/tegra-paz00.dts +++ b/arch/arm/boot/dts/tegra-paz00.dts @@ -37,6 +37,18 @@ clock-frequency = <400000>; };
+ i2s@70002800 { + status = "disable"; + }; + + i2s@70002a00 { + status = "disable"; + }; + + das@70000c00 { + status = "disable"; + }; + serial@70006000 { clock-frequency = <216000000>; }; diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts index f552bcc..dfbafd8 100644 --- a/arch/arm/boot/dts/tegra-seaboard.dts +++ b/arch/arm/boot/dts/tegra-seaboard.dts @@ -13,6 +13,20 @@
i2c@7000c000 { clock-frequency = <400000>; + + codec: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupts = < 347 >; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + /* 0x8000 = Not configured */ + gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >; + }; };
i2c@7000c400 { @@ -27,6 +41,28 @@ clock-frequency = <400000>; };
+ i2s@70002a00 { + status = "disable"; + }; + + sound { + compatible = "nvidia,tegra-audio-wm8903-seaboard", + "nvidia,tegra-audio-wm8903"; + + nvidia,spkr-en-gpios = <&codec 2 0>; + nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */ + + nvidia,routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Bias", "Mic Jack", + "IN1R", "Mic Bias"; + }; + serial@70006000 { status = "disable"; }; diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts index 3b3ee7d..2524768 100644 --- a/arch/arm/boot/dts/tegra-trimslice.dts +++ b/arch/arm/boot/dts/tegra-trimslice.dts @@ -26,6 +26,18 @@ status = "disable"; };
+ i2s@70002800 { + status = "disable"; + }; + + i2s@70002a00 { + status = "disable"; + }; + + das@70000c00 { + status = "disable"; + }; + serial@70006000 { clock-frequency = < 216000000 >; }; diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts index c7d3b87..c02534e 100644 --- a/arch/arm/boot/dts/tegra-ventana.dts +++ b/arch/arm/boot/dts/tegra-ventana.dts @@ -12,6 +12,20 @@
i2c@7000c000 { clock-frequency = <400000>; + + codec: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupts = < 347 >; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + /* 0x8000 = Not configured */ + gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >; + }; };
i2c@7000c400 { @@ -26,6 +40,30 @@ clock-frequency = <400000>; };
+ i2s@70002a00 { + status = "disable"; + }; + + sound { + compatible = "nvidia,tegra-audio-wm8903-ventana", + "nvidia,tegra-audio-wm8903"; + + nvidia,spkr-en-gpios = <&codec 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ + + nvidia,routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Bias", "Mic Jack", + "IN1L", "Mic Bias"; + }; + serial@70006000 { status = "disable"; };
Stephen Warren wrote at Tuesday, November 22, 2011 6:21 PM:
Add complete bindings to instantiate and configure the codec and top-level audio complex on all currently supported boards using the Tegra+WM8903 audio driver.
...
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
...
- sound {
compatible = "nvidia,tegra-audio-wm8903-harmony",
"nvidia,tegra-audio-wm8903";
Thinking about that more, I'd like to change this from nvidia,tegra-audio* to nvidia,tegra20-audio*. That's because the current ASoC machine driver, which is what matches that compatible flag, is slightly Tegra20-specific because it makes calls to the Tegra20-specific DAS driver. On Tegra30, this is replaced by a Tegra30 (and later?) AHUB driver. To avoid the Tegra+WM8903 ASoC machine driver module depending on both the Tegra20 DAS module and the Tegra30 AHUB module, I'd like to create separate ASoC machine drivers for the two Tegra chips, which parameterize a core machine driver (e.g. by passing an ops/vtable). This requires versioned compatible flags so that different drivers can be instantiated.
From: John Bonesio bones@secretlab.ca
This patch makes it so the wm8903 is initialized from it's device tree node.
swarren applied the following modifications: * Cleaned up DT parsing code * Documented DT binding * Set up wm8903->gpio_chip.of_node, extracted from another patch by John.
Signed-off-by: John Bonesio bones@secretlab.ca Signed-off-by: Grant Likely grant.likely@secretlab.ca Signed-off-by: Stephen Warren swarren@nvidia.com --- Documentation/devicetree/bindings/sound/wm8903.txt | 48 ++++++++++++++++++++ sound/soc/codecs/wm8903.c | 48 ++++++++++++++++++- 2 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/wm8903.txt
diff --git a/Documentation/devicetree/bindings/sound/wm8903.txt b/Documentation/devicetree/bindings/sound/wm8903.txt new file mode 100644 index 0000000..96edf6c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8903.txt @@ -0,0 +1,48 @@ +WM89033 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8903" + + - reg : the I2C address of the device. + + - gpio-controller : Indicates this device is a GPIO controller. + + - #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + +Optional properties: + + - interrupts : The interrupt line the codec is connected to. + + - irq-active-low : Indicates whether the IRQ output should be active low + (property present) or active high (property absent). + + - micdet-cfg : Default register value for R6 (Mic Bias). If absent, the + default is 0. + + - micdet-delay : The debounce delay for microphone detection in mS. If + absent, the default is 100. + + - gpio-cfg : A list of GPIO pin mux register values. The list must be 5 + entries long. If absent, no configuration of these registers is + performed. + +Example: + +codec: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupts = < 347 >; + + gpio-controller; + #gpio-cells = <2>; + + irq-active-low; + micdet-cfg = <0>; + micdet-delay = <100>; + /* 0x8000 = Not configured */ + gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >; +}; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 4ad8ebd..4c2c7ef 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1864,10 +1864,10 @@ static struct gpio_chip wm8903_template_chip = { .can_sleep = 1, };
-static void wm8903_init_gpio(struct snd_soc_codec *codec) +static void wm8903_init_gpio(struct snd_soc_codec *codec, + struct wm8903_platform_data *pdata) { struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); - struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev); int ret;
wm8903->gpio_chip = wm8903_template_chip; @@ -1879,6 +1879,8 @@ static void wm8903_init_gpio(struct snd_soc_codec *codec) else wm8903->gpio_chip.base = -1;
+ wm8903->gpio_chip.of_node = codec->dev->of_node; + ret = gpiochip_add(&wm8903->gpio_chip); if (ret != 0) dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); @@ -1906,10 +1908,13 @@ static void wm8903_free_gpio(struct snd_soc_codec *codec) static int wm8903_probe(struct snd_soc_codec *codec) { struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev); + struct wm8903_platform_data lpdata; struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); int ret, i; int trigger, irq_pol; u16 val; + const struct device_node *np; + u32 val32;
wm8903->codec = codec;
@@ -1932,6 +1937,31 @@ static int wm8903_probe(struct snd_soc_codec *codec)
wm8903_reset(codec);
+ if (!pdata && codec->dev->of_node) { + lpdata.irq_active_low = 0; + lpdata.micdet_cfg = 0; + lpdata.micdet_delay = 100; + lpdata.gpio_base = -1; + for (i = 0; i < 5; i++) + lpdata.gpio_cfg[i] = WM8903_GPIO_NO_CONFIG; + + np = codec->dev->of_node; + + if (of_find_property(np, "irq-active-low", NULL)) + lpdata.irq_active_low = 1; + + if (of_property_read_u32(np, "micdet-cfg", &val32) >= 0) + lpdata.micdet_cfg = val32; + + if (of_property_read_u32(np, "micdet-delay", &val32) >= 0) + lpdata.micdet_delay = val32; + + of_property_read_u32_array(np, "gpio-cfg", lpdata.gpio_cfg, + WM8903_NUM_GPIO); + + pdata = &lpdata; + } + /* Set up GPIOs and microphone detection */ if (pdata) { bool mic_gpio = false; @@ -2038,7 +2068,7 @@ static int wm8903_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, wm8903_snd_controls, ARRAY_SIZE(wm8903_snd_controls));
- wm8903_init_gpio(codec); + wm8903_init_gpio(codec, pdata);
return ret; } @@ -2101,6 +2131,17 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client) return 0; }
+#if defined(CONFIG_OF) +/* Match table for of_platform binding */ +static const struct of_device_id wm8903_of_match[] __devinitconst = { + { .compatible = "wlf,wm8903", }, + {}, +}; +MODULE_DEVICE_TABLE(of, wm8903_of_match); +#else +#define wm8903_of_match NULL +#endif + static const struct i2c_device_id wm8903_i2c_id[] = { { "wm8903", 0 }, { } @@ -2111,6 +2152,7 @@ static struct i2c_driver wm8903_i2c_driver = { .driver = { .name = "wm8903", .owner = THIS_MODULE, + .of_match_table = wm8903_of_match, }, .probe = wm8903_i2c_probe, .remove = __devexit_p(wm8903_i2c_remove),
On Tue, Nov 22, 2011 at 06:21:12PM -0700, Stephen Warren wrote:
- irq-active-low : Indicates whether the IRQ output should be active low
- (property present) or active high (property absent).
I think we ought to be coming up with a standard binding for this stuff rather than having every device defining it's own way of plugging the interrupt lines together - many devices have lots of flexibility with how their interrupt line signals for compatibility reasons.
- gpio-cfg : A list of GPIO pin mux register values. The list must be 5
- entries long. If absent, no configuration of these registers is
- performed.
What's a "GPIO pin mux"?
- /* 0x8000 = Not configured */
- gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
The 0x8000 isn't documented in the binding and this doesn't seem terribly idiomatic for device tree.
-static void wm8903_init_gpio(struct snd_soc_codec *codec) +static void wm8903_init_gpio(struct snd_soc_codec *codec,
struct wm8903_platform_data *pdata)
Why?
static int wm8903_probe(struct snd_soc_codec *codec) { struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
- struct wm8903_platform_data lpdata;
Why and what is "lpdata" supposed to mean?
- if (!pdata && codec->dev->of_node) {
lpdata.irq_active_low = 0;
lpdata.micdet_cfg = 0;
This should be set by default.
lpdata.micdet_delay = 100;
lpdata.gpio_base = -1;
This means that the defaults are in different different places if we have platform data and if we have device tree. We should restructure the code so that we only have defaults in one place.
if (of_property_read_u32(np, "micdet-cfg", &val32) >= 0)
lpdata.micdet_cfg = val32;
I'd rather have defaults as an else case I think.
+#if defined(CONFIG_OF)
ifdef.
This removes potentially machine-specific routing knowledge from the I2S driverinto the machine drivers, which is better equipped to know what the appropriate routing configuration is.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/tegra_i2s.c | 18 ------------------ sound/soc/tegra/tegra_wm8903.c | 13 +++++++++++++ sound/soc/tegra/trimslice.c | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 6728fab..33e62fc 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -42,7 +42,6 @@ #include <sound/pcm_params.h> #include <sound/soc.h>
-#include "tegra_das.h" #include "tegra_i2s.h"
#define DRV_NAME "tegra-i2s" @@ -363,23 +362,6 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) return -EINVAL; }
- /* - * FIXME: Until a codec driver exists for the tegra DAS, hard-code a - * 1:1 mapping between audio controllers and audio ports. - */ - ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1 + pdev->id, - TEGRA_DAS_DAP_SEL_DAC1 + pdev->id); - if (ret) { - dev_err(&pdev->dev, "Can't set up DAP connection\n"); - return ret; - } - ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1 + pdev->id, - TEGRA_DAS_DAC_SEL_DAP1 + pdev->id); - if (ret) { - dev_err(&pdev->dev, "Can't set up DAC connection\n"); - return ret; - } - i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL); if (!i2s) { dev_err(&pdev->dev, "Can't allocate tegra_i2s\n"); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index a81cf39..9b0ee15 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -249,6 +249,19 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) struct tegra_wm8903_platform_data *pdata = machine->pdata; int ret;
+ ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1, + TEGRA_DAS_DAP_SEL_DAC1); + if (ret) { + dev_err(card->dev, "Can't set up DAS DAP connection\n"); + return ret; + } + ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1, + TEGRA_DAS_DAC_SEL_DAP1); + if (ret) { + dev_err(card->dev, "Can't set up DAS DAC connection\n"); + return ret; + } + if (gpio_is_valid(pdata->gpio_spkr_en)) { ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); if (ret) { diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index b3a7efa..2699a6f 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -118,7 +118,22 @@ static const struct snd_soc_dapm_route trimslice_audio_map[] = { static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = codec->card; struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret; + + ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1, + TEGRA_DAS_DAP_SEL_DAC1); + if (ret) { + dev_err(card->dev, "Can't set up DAS DAP connection\n"); + return ret; + } + ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1, + TEGRA_DAS_DAC_SEL_DAP1); + if (ret) { + dev_err(card->dev, "Can't set up DAS DAC connection\n"); + return ret; + }
snd_soc_dapm_nc_pin(dapm, "LHPOUT"); snd_soc_dapm_nc_pin(dapm, "RHPOUT");
On Tue, Nov 22, 2011 at 06:21:13PM -0700, Stephen Warren wrote:
This removes potentially machine-specific routing knowledge from the I2S driverinto the machine drivers, which is better equipped to know what the appropriate routing configuration is.
Applied, thanks.
This saves some boiler-plate code.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/tegra_pcm.c | 13 +------------ 1 files changed, 1 insertions(+), 12 deletions(-)
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 436def1..90345ee 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -392,18 +392,7 @@ static struct platform_driver tegra_pcm_driver = { .probe = tegra_pcm_platform_probe, .remove = __devexit_p(tegra_pcm_platform_remove), }; - -static int __init snd_tegra_pcm_init(void) -{ - return platform_driver_register(&tegra_pcm_driver); -} -module_init(snd_tegra_pcm_init); - -static void __exit snd_tegra_pcm_exit(void) -{ - platform_driver_unregister(&tegra_pcm_driver); -} -module_exit(snd_tegra_pcm_exit); +module_platform_driver(tegra_pcm_driver);
MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra PCM ASoC driver");
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/tegra_das.c | 45 +++++++++--------------------------------- 1 files changed, 10 insertions(+), 35 deletions(-)
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c index 3b55a44..fa3a442 100644 --- a/sound/soc/tegra/tegra_das.c +++ b/sound/soc/tegra/tegra_das.c @@ -172,11 +172,11 @@ static int __devinit tegra_das_probe(struct platform_device *pdev) if (das) return -ENODEV;
- das = kzalloc(sizeof(struct tegra_das), GFP_KERNEL); + das = devm_kzalloc(&pdev->dev, sizeof(struct tegra_das), GFP_KERNEL); if (!das) { dev_err(&pdev->dev, "Can't allocate tegra_das\n"); ret = -ENOMEM; - goto exit; + goto err; } das->dev = &pdev->dev;
@@ -184,22 +184,22 @@ static int __devinit tegra_das_probe(struct platform_device *pdev) if (!res) { dev_err(&pdev->dev, "No memory resource\n"); ret = -ENODEV; - goto err_free; + goto err; }
- region = request_mem_region(res->start, resource_size(res), - pdev->name); + region = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name); if (!region) { dev_err(&pdev->dev, "Memory region already claimed\n"); ret = -EBUSY; - goto err_free; + goto err; }
- das->regs = ioremap(res->start, resource_size(res)); + das->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!das->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; - goto err_release; + goto err; }
tegra_das_debug_add(das); @@ -208,32 +208,18 @@ static int __devinit tegra_das_probe(struct platform_device *pdev)
return 0;
-err_release: - release_mem_region(res->start, resource_size(res)); -err_free: - kfree(das); +err: das = NULL; -exit: return ret; }
static int __devexit tegra_das_remove(struct platform_device *pdev) { - struct resource *res; - if (!das) return -ENODEV;
- platform_set_drvdata(pdev, NULL); - tegra_das_debug_remove(das);
- iounmap(das->regs); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - kfree(das); das = NULL;
return 0; @@ -246,18 +232,7 @@ static struct platform_driver tegra_das_driver = { .name = DRV_NAME, }, }; - -static int __init tegra_das_modinit(void) -{ - return platform_driver_register(&tegra_das_driver); -} -module_init(tegra_das_modinit); - -static void __exit tegra_das_modexit(void) -{ - platform_driver_unregister(&tegra_das_driver); -} -module_exit(tegra_das_modexit); +module_platform_driver(tegra_das_driver);
MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra DAS driver");
* Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Signed-off-by: Stephen Warren swarren@nvidia.com
sound/soc/tegra/tegra_das.c | 45 +++++++++--------------------------------- 1 files changed, 10 insertions(+), 35 deletions(-)
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c
[...]
@@ -208,32 +208,18 @@ static int __devinit tegra_das_probe(struct platform_device *pdev)
return 0;
-err_release:
- release_mem_region(res->start, resource_size(res));
-err_free:
- kfree(das);
+err: das = NULL; -exit: return ret; }
static int __devexit tegra_das_remove(struct platform_device *pdev) {
struct resource *res;
if (!das) return -ENODEV;
platform_set_drvdata(pdev, NULL);
[...]
Setting the driver data to NULL may still be a good idea.
Thierry
On Wed, Nov 23, 2011 at 07:58:08AM +0100, Thierry Reding wrote:
- Stephen Warren wrote:
- platform_set_drvdata(pdev, NULL);
Setting the driver data to NULL may still be a good idea.
It's always been a waste of time.
Thierry Reding wrote at Tuesday, November 22, 2011 11:58 PM:
- Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
...
static int __devexit tegra_das_remove(struct platform_device *pdev) {
struct resource *res;
if (!das) return -ENODEV;
platform_set_drvdata(pdev, NULL);
[...]
Setting the driver data to NULL may still be a good idea.
When Mark Brown reviewed the TrimSlice machine driver, he mentioned that clearing the drvdata was pointless; nothing should be using it when the device is not created.
As background, soon after that, I modified the tegra_wm8903.c machine driver along the same lines, but evidently didn't update tegra_das.c in a similar way, but would have if I'd been paying attention...
* Stephen Warren wrote:
Thierry Reding wrote at Tuesday, November 22, 2011 11:58 PM:
- Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
...
static int __devexit tegra_das_remove(struct platform_device *pdev) {
struct resource *res;
if (!das) return -ENODEV;
platform_set_drvdata(pdev, NULL);
[...]
Setting the driver data to NULL may still be a good idea.
When Mark Brown reviewed the TrimSlice machine driver, he mentioned that clearing the drvdata was pointless; nothing should be using it when the device is not created.
As background, soon after that, I modified the tegra_wm8903.c machine driver along the same lines, but evidently didn't update tegra_das.c in a similar way, but would have if I'd been paying attention...
Thinking about this some more I have to agree. The only one using the driver data would be the driver, which in turn shouldn't be doing anything with it after remove is called.
I was just commenting on it because I've seen it done in a lot of drivers and thought it was common (best) practice.
Thierry
On Tue, Nov 22, 2011 at 06:21:15PM -0700, Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Applied but this is two separate changes and should've been split.
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/tegra_i2s.c | 45 +++++++++--------------------------------- 1 files changed, 10 insertions(+), 35 deletions(-)
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 33e62fc..76014f0 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -362,11 +362,11 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) return -EINVAL; }
- i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL); + i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL); if (!i2s) { dev_err(&pdev->dev, "Can't allocate tegra_i2s\n"); ret = -ENOMEM; - goto exit; + goto err; } dev_set_drvdata(&pdev->dev, i2s);
@@ -374,7 +374,7 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) if (IS_ERR(i2s->clk_i2s)) { dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); ret = PTR_ERR(i2s->clk_i2s); - goto err_free; + goto err; }
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -391,19 +391,19 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) goto err_clk_put; }
- memregion = request_mem_region(mem->start, resource_size(mem), - DRV_NAME); + memregion = devm_request_mem_region(&pdev->dev, mem->start, + resource_size(mem), DRV_NAME); if (!memregion) { dev_err(&pdev->dev, "Memory region already claimed\n"); ret = -EBUSY; goto err_clk_put; }
- i2s->regs = ioremap(mem->start, resource_size(mem)); + i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); if (!i2s->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; - goto err_release; + goto err_clk_put; }
i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2; @@ -422,43 +422,29 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; - goto err_unmap; + goto err_clk_put; }
tegra_i2s_debug_add(i2s, pdev->id);
return 0;
-err_unmap: - iounmap(i2s->regs); -err_release: - release_mem_region(mem->start, resource_size(mem)); err_clk_put: clk_put(i2s->clk_i2s); -err_free: - kfree(i2s); -exit: +err: return ret; }
static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) { struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev); - struct resource *res;
snd_soc_unregister_dai(&pdev->dev);
tegra_i2s_debug_remove(i2s);
- iounmap(i2s->regs); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - clk_put(i2s->clk_i2s);
- kfree(i2s); - return 0; }
@@ -470,18 +456,7 @@ static struct platform_driver tegra_i2s_driver = { .probe = tegra_i2s_platform_probe, .remove = __devexit_p(tegra_i2s_platform_remove), }; - -static int __init snd_tegra_i2s_init(void) -{ - return platform_driver_register(&tegra_i2s_driver); -} -module_init(snd_tegra_i2s_init); - -static void __exit snd_tegra_i2s_exit(void) -{ - platform_driver_unregister(&tegra_i2s_driver); -} -module_exit(snd_tegra_i2s_exit); +module_platform_driver(tegra_i2s_driver);
MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra I2S ASoC driver");
* Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Signed-off-by: Stephen Warren swarren@nvidia.com
sound/soc/tegra/tegra_i2s.c | 45 +++++++++--------------------------------- 1 files changed, 10 insertions(+), 35 deletions(-)
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
[...]
@@ -422,43 +422,29 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM;
goto err_unmap;
goto err_clk_put;
}
tegra_i2s_debug_add(i2s, pdev->id);
return 0;
-err_unmap:
- iounmap(i2s->regs);
-err_release:
- release_mem_region(mem->start, resource_size(mem));
err_clk_put: clk_put(i2s->clk_i2s); -err_free:
- kfree(i2s);
-exit: +err: return ret; }
static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) { struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
struct resource *res;
snd_soc_unregister_dai(&pdev->dev);
tegra_i2s_debug_remove(i2s);
iounmap(i2s->regs);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
clk_put(i2s->clk_i2s);
kfree(i2s);
return 0;
}
[...]
Is this perhaps missing a dev_set_drvdata(&pdev->dev, NULL) as well?
Thierry
On Tue, Nov 22, 2011 at 06:21:16PM -0700, Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Applied but again this should be split into two separate patches.
When devices are instantiated from device-tree, pdev->id is not set to anything useful. Rework the driver so it doesn't depend on this value.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/tegra_i2s.c | 72 ++++++++++++++----------------------------- sound/soc/tegra/tegra_i2s.h | 1 + 2 files changed, 24 insertions(+), 49 deletions(-)
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 76014f0..3c0cbd2 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -98,13 +98,11 @@ static const struct file_operations tegra_i2s_debug_fops = { .release = single_release, };
-static void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id) +static void tegra_i2s_debug_add(struct tegra_i2s *i2s) { - char name[] = DRV_NAME ".0"; - - snprintf(name, sizeof(name), DRV_NAME".%1d", id); - i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root, - i2s, &tegra_i2s_debug_fops); + i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO, + snd_soc_debugfs_root, i2s, + &tegra_i2s_debug_fops); }
static void tegra_i2s_debug_remove(struct tegra_i2s *i2s) @@ -311,43 +309,22 @@ static struct snd_soc_dai_ops tegra_i2s_dai_ops = { .trigger = tegra_i2s_trigger, };
-static struct snd_soc_dai_driver tegra_i2s_dai[] = { - { - .name = DRV_NAME ".0", - .probe = tegra_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &tegra_i2s_dai_ops, - .symmetric_rates = 1, +static const struct snd_soc_dai_driver tegra_i2s_dai_template = { + .probe = tegra_i2s_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - { - .name = DRV_NAME ".1", - .probe = tegra_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &tegra_i2s_dai_ops, - .symmetric_rates = 1, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .ops = &tegra_i2s_dai_ops, + .symmetric_rates = 1, };
static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) @@ -356,12 +333,6 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) struct resource *mem, *memregion, *dmareq; int ret;
- if ((pdev->id < 0) || - (pdev->id >= ARRAY_SIZE(tegra_i2s_dai))) { - dev_err(&pdev->dev, "ID %d out of range\n", pdev->id); - return -EINVAL; - } - i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL); if (!i2s) { dev_err(&pdev->dev, "Can't allocate tegra_i2s\n"); @@ -370,6 +341,9 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, i2s);
+ i2s->dai = tegra_i2s_dai_template; + i2s->dai.name = pdev->name; + i2s->clk_i2s = clk_get(&pdev->dev, NULL); if (IS_ERR(i2s->clk_i2s)) { dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); @@ -418,14 +392,14 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
- ret = snd_soc_register_dai(&pdev->dev, &tegra_i2s_dai[pdev->id]); + ret = snd_soc_register_dai(&pdev->dev, &i2s->dai); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; goto err_clk_put; }
- tegra_i2s_debug_add(i2s, pdev->id); + tegra_i2s_debug_add(i2s);
return 0;
diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h index 2b38a09..15ce1e2 100644 --- a/sound/soc/tegra/tegra_i2s.h +++ b/sound/soc/tegra/tegra_i2s.h @@ -153,6 +153,7 @@ #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
struct tegra_i2s { + struct snd_soc_dai_driver dai; struct clk *clk_i2s; int clk_refs; struct tegra_pcm_dma_params capture_dma_data;
On Tue, Nov 22, 2011 at 06:21:17PM -0700, Stephen Warren wrote:
- i2s->dai = tegra_i2s_dai_template;
- i2s->dai.name = pdev->name;
This should really be part of the same commit as the arch/arm side change in order to avoid bisection breaks as from the point of view of non-DT systems it's moving the number into the name.
Mark Brown wrote at Wednesday, November 23, 2011 4:04 AM:
On Tue, Nov 22, 2011 at 06:21:17PM -0700, Stephen Warren wrote:
- i2s->dai = tegra_i2s_dai_template;
- i2s->dai.name = pdev->name;
This should really be part of the same commit as the arch/arm side change in order to avoid bisection breaks as from the point of view of non-DT systems it's moving the number into the name.
Sorry, I don't quite follow here; the original hard-coded dai structures already had the ID in the name, and hence exactly match the platform device names tegra-i2s.0 and tegra-i2s.1:
static struct snd_soc_dai_driver tegra_i2s_dai[] = { { .name = DRV_NAME ".0", ... }, { .name = DRV_NAME ".1",
Or were you referring the AUXDATA fix for tegra-i2s.1? That's not an issue since nothing uses the 2nd I2C controller on Tegra in mainline yet.
On Wed, Nov 23, 2011 at 09:54:21AM -0800, Stephen Warren wrote:
Mark Brown wrote at Wednesday, November 23, 2011 4:04 AM:
This should really be part of the same commit as the arch/arm side change in order to avoid bisection breaks as from the point of view of non-DT systems it's moving the number into the name.
Sorry, I don't quite follow here; the original hard-coded dai structures already had the ID in the name, and hence exactly match the platform device names tegra-i2s.0 and tegra-i2s.1:
If you're renaming the devices I'd expect the device to driver binding to break as the device name changes - actually looking at the code again I'm a bit depressed that the platform driver binding works at all with this as you've not renamed the driver but you have renamed the devices and they're still binding. I'd have expected the match to be on a (name, id) not on the result of rendering those down to a display name.
The whole bodge here just smells a bit to be honest, we ought to be able to match things up without jumping through this hoop.
Signed-off-by: Stephen Warren swarren@nvidia.com --- .../devicetree/bindings/sound/tegra20-das.txt | 12 ++++++++++++ sound/soc/tegra/tegra_das.c | 8 ++++++++ 2 files changed, 20 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tegra20-das.txt
diff --git a/Documentation/devicetree/bindings/sound/tegra20-das.txt b/Documentation/devicetree/bindings/sound/tegra20-das.txt new file mode 100644 index 0000000..6de3a7e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tegra20-das.txt @@ -0,0 +1,12 @@ +NVIDIA Tegra 20 DAS (Digital Audio Switch) controller + +Required properties: +- compatible : "nvidia,tegra20-das" +- reg : Should contain DAS registers location and length + +Example: + +das@70000c00 { + compatible = "nvidia,tegra20-das"; + reg = <0x70000c00 0x80>; +}; diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c index fa3a442..5b82b4e 100644 --- a/sound/soc/tegra/tegra_das.c +++ b/sound/soc/tegra/tegra_das.c @@ -225,11 +225,18 @@ static int __devexit tegra_das_remove(struct platform_device *pdev) return 0; }
+static const struct of_device_id tegra_das_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra20-das", }, + {}, +}; + static struct platform_driver tegra_das_driver = { .probe = tegra_das_probe, .remove = __devexit_p(tegra_das_remove), .driver = { .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tegra_das_of_match, }, }; module_platform_driver(tegra_das_driver); @@ -238,3 +245,4 @@ MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra DAS driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_das_of_match);
On Tue, Nov 22, 2011 at 06:21:18PM -0700, Stephen Warren wrote:
Signed-off-by: Stephen Warren swarren@nvidia.com
Applied, thanks - the binding seems entirely uncontroversial as there's just a compatible and register binding, if there are problems we can always revert or fix before 3.3.
BTW, you probably want to look at your CC list, it's rather large.
Signed-off-by: Stephen Warren swarren@nvidia.com --- .../devicetree/bindings/sound/tegra20-i2s.txt | 16 +++++++++++ sound/soc/tegra/tegra_i2s.c | 29 ++++++++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tegra20-i2s.txt
diff --git a/Documentation/devicetree/bindings/sound/tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/tegra20-i2s.txt new file mode 100644 index 0000000..d38abdc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tegra20-i2s.txt @@ -0,0 +1,16 @@ +NVIDIA Tegra 20 I2S controller + +Required properties: +- compatible : "nvidia,tegra20-i2s" +- reg : Should contain I2S registers location and length +- interrupts : Should contain I2S interrupt +- dma-channel : The Tegra DMA controller's channel ID for this I2S controller + +Example: + +i2s@70002800 { + compatible = "nvidia,tegra20-i2s"; + reg = <0x70002800 0x200>; + interrupts = < 45 >; + dma-channel = < 2 >; +}; diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 3c0cbd2..b4e19a5 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -36,6 +36,7 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/of.h> #include <mach/iomap.h> #include <sound/core.h> #include <sound/pcm.h> @@ -332,6 +333,7 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) struct tegra_i2s * i2s; struct resource *mem, *memregion, *dmareq; int ret; + u32 dma_ch;
i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL); if (!i2s) { @@ -360,9 +362,19 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmareq) { - dev_err(&pdev->dev, "No DMA resource\n"); - ret = -ENODEV; - goto err_clk_put; + /* + * FIXME: Perhaps there should be a standard binding for this + * that ends up creating the IORESOURCE_DMA resource for us. + */ + if (of_property_read_u32(pdev->dev.of_node, + "nvidia,dma-channels", + &dma_ch) < 0) { + dev_err(&pdev->dev, "No DMA resource\n"); + ret = -ENODEV; + goto err_clk_put; + } + } else { + dma_ch = dmareq->start; }
memregion = devm_request_mem_region(&pdev->dev, mem->start, @@ -383,12 +395,12 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2; i2s->capture_dma_data.wrap = 4; i2s->capture_dma_data.width = 32; - i2s->capture_dma_data.req_sel = dmareq->start; + i2s->capture_dma_data.req_sel = dma_ch;
i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1; i2s->playback_dma_data.wrap = 4; i2s->playback_dma_data.width = 32; - i2s->playback_dma_data.req_sel = dmareq->start; + i2s->playback_dma_data.req_sel = dma_ch;
i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
@@ -422,10 +434,16 @@ static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) return 0; }
+static const struct of_device_id tegra_i2s_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra20-i2s", }, + {}, +}; + static struct platform_driver tegra_i2s_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = tegra_i2s_of_match, }, .probe = tegra_i2s_platform_probe, .remove = __devexit_p(tegra_i2s_platform_remove), @@ -436,3 +454,4 @@ MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra I2S ASoC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_i2s_of_match);
* Stephen Warren wrote:
Signed-off-by: Stephen Warren swarren@nvidia.com
.../devicetree/bindings/sound/tegra20-i2s.txt | 16 +++++++++++ sound/soc/tegra/tegra_i2s.c | 29 ++++++++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tegra20-i2s.txt
diff --git a/Documentation/devicetree/bindings/sound/tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/tegra20-i2s.txt new file mode 100644 index 0000000..d38abdc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tegra20-i2s.txt @@ -0,0 +1,16 @@ +NVIDIA Tegra 20 I2S controller
+Required properties: +- compatible : "nvidia,tegra20-i2s" +- reg : Should contain I2S registers location and length +- interrupts : Should contain I2S interrupt +- dma-channel : The Tegra DMA controller's channel ID for this I2S controller
+Example:
+i2s@70002800 {
- compatible = "nvidia,tegra20-i2s";
- reg = <0x70002800 0x200>;
- interrupts = < 45 >;
- dma-channel = < 2 >;
+}; diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 3c0cbd2..b4e19a5 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -36,6 +36,7 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/of.h> #include <mach/iomap.h> #include <sound/core.h> #include <sound/pcm.h> @@ -332,6 +333,7 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) struct tegra_i2s * i2s; struct resource *mem, *memregion, *dmareq; int ret;
u32 dma_ch;
i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL); if (!i2s) {
@@ -360,9 +362,19 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmareq) {
dev_err(&pdev->dev, "No DMA resource\n");
ret = -ENODEV;
goto err_clk_put;
/*
* FIXME: Perhaps there should be a standard binding for this
* that ends up creating the IORESOURCE_DMA resource for us.
*/
if (of_property_read_u32(pdev->dev.of_node,
"nvidia,dma-channels",
The binding documentation says the property is called "nvidia,dma-channel" but you use "nvidia,dma-channel*s*" here.
&dma_ch) < 0) {
dev_err(&pdev->dev, "No DMA resource\n");
ret = -ENODEV;
goto err_clk_put;
}
} else {
dma_ch = dmareq->start;
}
memregion = devm_request_mem_region(&pdev->dev, mem->start,
@@ -383,12 +395,12 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2; i2s->capture_dma_data.wrap = 4; i2s->capture_dma_data.width = 32;
- i2s->capture_dma_data.req_sel = dmareq->start;
i2s->capture_dma_data.req_sel = dma_ch;
i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1; i2s->playback_dma_data.wrap = 4; i2s->playback_dma_data.width = 32;
- i2s->playback_dma_data.req_sel = dmareq->start;
i2s->playback_dma_data.req_sel = dma_ch;
i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
@@ -422,10 +434,16 @@ static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) return 0; }
+static const struct of_device_id tegra_i2s_of_match[] __devinitconst = {
- { .compatible = "nvidia,tegra20-i2s", },
- {},
+};
static struct platform_driver tegra_i2s_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE,
}, .probe = tegra_i2s_platform_probe, .remove = __devexit_p(tegra_i2s_platform_remove),.of_match_table = tegra_i2s_of_match,
@@ -436,3 +454,4 @@ MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra I2S ASoC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_i2s_of_match);
1.7.0.4
-- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Nov 23, 2011 at 08:04:49AM +0100, Thierry Reding wrote:
Always delete unneeded context from your mails so that people can actually find the content you've added and don't have to scroll through the entire patch.
* Mark Brown wrote:
On Wed, Nov 23, 2011 at 08:04:49AM +0100, Thierry Reding wrote:
Always delete unneeded context from your mails so that people can actually find the content you've added and don't have to scroll through the entire patch.
Understood.
Thierry
On Tue, Nov 22, 2011 at 06:21:19PM -0700, Stephen Warren wrote:
/*
* FIXME: Perhaps there should be a standard binding for this
* that ends up creating the IORESOURCE_DMA resource for us.
*/
if (of_property_read_u32(pdev->dev.of_node,
"nvidia,dma-channels",
&dma_ch) < 0) {
dev_err(&pdev->dev, "No DMA resource\n");
ret = -ENODEV;
goto err_clk_put;
}
I'll hold off on this patch for discussion of this FIXME.
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/tegra_wm8903.c | 26 +++++++------------------- 1 files changed, 7 insertions(+), 19 deletions(-)
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 9b0ee15..33feee8 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -390,17 +390,19 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) return -EINVAL; }
- machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL); + machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903), + GFP_KERNEL); if (!machine) { dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; }
machine->pdata = pdata;
ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); if (ret) - goto err_free_machine; + goto err;
card->dev = &pdev->dev; platform_set_drvdata(pdev, card); @@ -431,8 +433,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
err_fini_utils: tegra_asoc_utils_fini(&machine->util_data); -err_free_machine: - kfree(machine); +err: return ret; }
@@ -460,8 +461,6 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
tegra_asoc_utils_fini(&machine->util_data);
- kfree(machine); - return 0; }
@@ -474,18 +473,7 @@ static struct platform_driver tegra_wm8903_driver = { .probe = tegra_wm8903_driver_probe, .remove = __devexit_p(tegra_wm8903_driver_remove), }; - -static int __init tegra_wm8903_modinit(void) -{ - return platform_driver_register(&tegra_wm8903_driver); -} -module_init(tegra_wm8903_modinit); - -static void __exit tegra_wm8903_modexit(void) -{ - platform_driver_unregister(&tegra_wm8903_driver); -} -module_exit(tegra_wm8903_modexit); +module_platform_driver(tegra_wm8903_driver);
MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver");
* Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
module_platform_driver
Thierry
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Signed-off-by: Stephen Warren swarren@nvidia.com
sound/soc/tegra/tegra_wm8903.c | 26 +++++++------------------- 1 files changed, 7 insertions(+), 19 deletions(-)
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 9b0ee15..33feee8 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -390,17 +390,19 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) return -EINVAL; }
- machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL);
- machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903),
if (!machine) { dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n");GFP_KERNEL);
return -ENOMEM;
ret = -ENOMEM;
goto err;
}
machine->pdata = pdata;
ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); if (ret)
goto err_free_machine;
goto err;
card->dev = &pdev->dev; platform_set_drvdata(pdev, card);
@@ -431,8 +433,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
err_fini_utils: tegra_asoc_utils_fini(&machine->util_data); -err_free_machine:
- kfree(machine);
+err: return ret; }
@@ -460,8 +461,6 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
tegra_asoc_utils_fini(&machine->util_data);
- kfree(machine);
- return 0;
}
@@ -474,18 +473,7 @@ static struct platform_driver tegra_wm8903_driver = { .probe = tegra_wm8903_driver_probe, .remove = __devexit_p(tegra_wm8903_driver_remove), };
-static int __init tegra_wm8903_modinit(void) -{
- return platform_driver_register(&tegra_wm8903_driver);
-} -module_init(tegra_wm8903_modinit);
-static void __exit tegra_wm8903_modexit(void) -{
- platform_driver_unregister(&tegra_wm8903_driver);
-} -module_exit(tegra_wm8903_modexit); +module_platform_driver(tegra_wm8903_driver);
MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); -- 1.7.0.4
-- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, Nov 22, 2011 at 06:21:20PM -0700, Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Applied, thanks. Again, should be two changes.
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/trimslice.c | 26 +++++++------------------- 1 files changed, 7 insertions(+), 19 deletions(-)
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 2699a6f..d564b40 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -170,15 +170,17 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) struct tegra_trimslice *trimslice; int ret;
- trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL); + trimslice = devm_kzalloc(&pdev->dev, sizeof(struct tegra_trimslice), + GFP_KERNEL); if (!trimslice) { dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; }
ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); if (ret) - goto err_free_trimslice; + goto err;
card->dev = &pdev->dev; platform_set_drvdata(pdev, card); @@ -195,8 +197,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
err_fini_utils: tegra_asoc_utils_fini(&trimslice->util_data); -err_free_trimslice: - kfree(trimslice); +err: return ret; }
@@ -209,8 +210,6 @@ static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev)
tegra_asoc_utils_fini(&trimslice->util_data);
- kfree(trimslice); - return 0; }
@@ -222,18 +221,7 @@ static struct platform_driver tegra_snd_trimslice_driver = { .probe = tegra_snd_trimslice_probe, .remove = __devexit_p(tegra_snd_trimslice_remove), }; - -static int __init snd_tegra_trimslice_init(void) -{ - return platform_driver_register(&tegra_snd_trimslice_driver); -} -module_init(snd_tegra_trimslice_init); - -static void __exit snd_tegra_trimslice_exit(void) -{ - platform_driver_unregister(&tegra_snd_trimslice_driver); -} -module_exit(snd_tegra_trimslice_exit); +module_platform_driver(tegra_snd_trimslice_driver);
MODULE_AUTHOR("Mike Rapoport mike@compulab.co.il"); MODULE_DESCRIPTION("Trimslice machine ASoC driver");
* Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
Some here.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Signed-off-by: Stephen Warren swarren@nvidia.com
sound/soc/tegra/trimslice.c | 26 +++++++------------------- 1 files changed, 7 insertions(+), 19 deletions(-)
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 2699a6f..d564b40 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -170,15 +170,17 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) struct tegra_trimslice *trimslice; int ret;
- trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL);
- trimslice = devm_kzalloc(&pdev->dev, sizeof(struct tegra_trimslice),
if (!trimslice) { dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n");GFP_KERNEL);
return -ENOMEM;
ret = -ENOMEM;
goto err;
}
ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); if (ret)
goto err_free_trimslice;
goto err;
card->dev = &pdev->dev; platform_set_drvdata(pdev, card);
@@ -195,8 +197,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
err_fini_utils: tegra_asoc_utils_fini(&trimslice->util_data); -err_free_trimslice:
- kfree(trimslice);
+err: return ret; }
@@ -209,8 +210,6 @@ static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev)
tegra_asoc_utils_fini(&trimslice->util_data);
- kfree(trimslice);
- return 0;
}
@@ -222,18 +221,7 @@ static struct platform_driver tegra_snd_trimslice_driver = { .probe = tegra_snd_trimslice_probe, .remove = __devexit_p(tegra_snd_trimslice_remove), };
-static int __init snd_tegra_trimslice_init(void) -{
- return platform_driver_register(&tegra_snd_trimslice_driver);
-} -module_init(snd_tegra_trimslice_init);
-static void __exit snd_tegra_trimslice_exit(void) -{
- platform_driver_unregister(&tegra_snd_trimslice_driver);
-} -module_exit(snd_tegra_trimslice_exit); +module_platform_driver(tegra_snd_trimslice_driver);
MODULE_AUTHOR("Mike Rapoport mike@compulab.co.il"); MODULE_DESCRIPTION("Trimslice machine ASoC driver"); -- 1.7.0.4
-- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, Nov 22, 2011 at 06:21:21PM -0700, Stephen Warren wrote:
module_platform_drive saves some boiler-plate code.
The devm_ APIs remove the need to manually clean up allocations, thus removing some code.
Applied, thanks - again should be split.
Codecs often have a large number of external pins, and not all of these pins will be connected on all board designs. Some machine drivers therefore call snd_soc_dapm_nc_pin() for all the unused pins, in order to tell the ASoC core never to activate them.
However, the information needed to derive the set of unused pins may be present in card->dapm_routes. Hence, the ASoC core could automatically disable unconnected pins. This patch implements such a feature.
This feature is optional; it could cause problems on machines with incomplete dapm routes. To request the feature, set a card's auto_nc_codec_pins field to true.
This has been tested with soc/tegra/tegra_wm8903.c and soc/tegra/trimslice.c.
Signed-off-by: Stephen Warren swarren@nvidia.com --- include/sound/soc-dapm.h | 1 + include/sound/soc.h | 1 + sound/soc/soc-core.c | 4 ++ sound/soc/soc-dapm.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 17a4c17..0c159a7 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -380,6 +380,7 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); +void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
/* Mostly internal - should not normally be used */ void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason); diff --git a/include/sound/soc.h b/include/sound/soc.h index b21b304..3728533 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -815,6 +815,7 @@ struct snd_soc_card { int num_dapm_widgets; const struct snd_soc_dapm_route *dapm_routes; int num_dapm_routes; + bool auto_nc_codec_pins;
struct work_struct deferred_resume_work;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a5d3685..47e919b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1482,6 +1482,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
snd_soc_dapm_new_widgets(&card->dapm);
+ if (card->auto_nc_codec_pins) + list_for_each_entry(codec, &codec_list, list) + snd_soc_dapm_auto_nc_codec_pins(codec); + ret = snd_card_register(card->snd_card); if (ret < 0) { printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f42e8b9..1ecd1b4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2947,6 +2947,79 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
+static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, + struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p; + + list_for_each_entry(p, &card->paths, list) { + if ((p->source == w) || (p->sink == w)) { + dev_dbg(card->dev, + "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n", + p->source->name, p->source->id, p->source->dapm, + p->sink->name, p->sink->id, p->sink->dapm); + + /* Connected to something other than the codec */ + if (p->source->dapm != p->sink->dapm) + return true; + /* + * Loopback connection from codec external pin to + * codec external pin + */ + if (p->sink->id == snd_soc_dapm_input) { + switch (p->source->id) { + case snd_soc_dapm_output: + case snd_soc_dapm_micbias: + return true; + default: + break; + } + } + } + } + + return false; +} + +/** + * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins + * @codec: The codec whose pins should be processed + * + * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec + * which are unused. Pins are used if they are connected externally to the + * codec, whether that be to some other device, or a loop-back connection to + * the codec itself. + */ +void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec) +{ + struct snd_soc_card *card = codec->card; + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_widget *w; + + dev_dbg(card->dev, "Auto NC: DAPMs: card:%p codec:%p\n", + &card->dapm, &codec->dapm); + + list_for_each_entry(w, &card->widgets, list) { + if (w->dapm != dapm) + continue; + switch (w->id) { + case snd_soc_dapm_input: + case snd_soc_dapm_output: + case snd_soc_dapm_micbias: + dev_dbg(card->dev, "Auto NC: Checking widget %s\n", + w->name); + if (!snd_soc_dapm_widget_in_card_paths(card, w)) { + dev_dbg(card->dev, + "... Not in map; disabling\n"); + snd_soc_dapm_nc_pin(dapm, w->name); + } + break; + default: + break; + } + } +} + /** * snd_soc_dapm_free - free dapm resources * @dapm: DAPM context
On Tue, Nov 22, 2011 at 06:21:22PM -0700, Stephen Warren wrote:
Codecs often have a large number of external pins, and not all of these pins will be connected on all board designs. Some machine drivers therefore call snd_soc_dapm_nc_pin() for all the unused pins, in order to tell the ASoC core never to activate them.
This looks good from a code point of view but can you please rename the flag that needs to be set to something like "fully_routed" so that if we think of anything else we can do with a fully specified card routing map then the flag name doesn't look wrong.
Set card.auto_nc_codec_pins to true to enable the feature, and remove all the open-coded snd_soc_dapm_nc_pin() calls.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/tegra_wm8903.c | 22 +--------------------- 1 files changed, 1 insertions(+), 21 deletions(-)
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 33feee8..8791c69 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -331,27 +331,6 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
- /* FIXME: Calculate automatically based on DAPM routes? */ - if (!machine_is_harmony()) - snd_soc_dapm_nc_pin(dapm, "IN1L"); - if (!machine_is_seaboard() && !machine_is_aebl()) - snd_soc_dapm_nc_pin(dapm, "IN1R"); - snd_soc_dapm_nc_pin(dapm, "IN2L"); - if (!machine_is_kaen()) - snd_soc_dapm_nc_pin(dapm, "IN2R"); - snd_soc_dapm_nc_pin(dapm, "IN3L"); - snd_soc_dapm_nc_pin(dapm, "IN3R"); - - if (machine_is_aebl()) { - snd_soc_dapm_nc_pin(dapm, "LON"); - snd_soc_dapm_nc_pin(dapm, "RON"); - snd_soc_dapm_nc_pin(dapm, "ROP"); - snd_soc_dapm_nc_pin(dapm, "LOP"); - } else { - snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); - snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); - } - return 0; }
@@ -375,6 +354,7 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = { .num_controls = ARRAY_SIZE(tegra_wm8903_controls), .dapm_widgets = tegra_wm8903_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets), + .auto_nc_codec_pins = true, };
static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
Set card.auto_nc_codec_pins to true to enable the feature, and remove all the open-coded snd_soc_dapm_nc_pin() calls.
Signed-off-by: Stephen Warren swarren@nvidia.com --- sound/soc/tegra/trimslice.c | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index d564b40..7b07cb2 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -119,7 +119,6 @@ static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; - struct snd_soc_dapm_context *dapm = &codec->dapm; int ret;
ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1, @@ -135,10 +134,6 @@ static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd) return ret; }
- snd_soc_dapm_nc_pin(dapm, "LHPOUT"); - snd_soc_dapm_nc_pin(dapm, "RHPOUT"); - snd_soc_dapm_nc_pin(dapm, "MICIN"); - return 0; }
@@ -162,6 +157,7 @@ static struct snd_soc_card snd_soc_trimslice = { .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), .dapm_routes = trimslice_audio_map, .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), + .auto_nc_codec_pins = true, };
static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
From: John Bonesio bones@secretlab.ca
This driver is parameterized in two ways:
a) Platform data, which supplies a set of GPIOs used by the driver. These GPIOs can now be parsed out of device tree.
b) Machine-specific DAPM route arrays embedded into the ASoC machine driver itself. The driver picks the appropriate array to use using machine_is_*(). This array can now be parsed straight out of device tree, allowing the machine driver to be completely machine agnostic.
swarren applied the following modifications: * Moved all pdata and DT parsing into one place. * Added DAPM route parsing from DT. * Added tegra_pcm device registration. * Documented DT binding.
Signed-off-by: John Bonesio bones@secretlab.ca Signed-off-by: Grant Likely grant.likely@secretlab.ca Signed-off-by: Stephen Warren swarren@nvidia.com --- .../bindings/sound/tegra-audio-wm8903.txt | 63 +++++++++ sound/soc/tegra/tegra_wm8903.c | 133 ++++++++++++++++---- 2 files changed, 171 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt new file mode 100644 index 0000000..f22bdf1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt @@ -0,0 +1,63 @@ +NVIDIA Tegra audio complex + +Required properties: +- compatible : "nvidia,tegra-audio-wm8903" +- nvidia,routing : A list of the connections between audio components. Each + entry is a pair of strings, the first being the connection's sink, the + second being the connection's source pin. Valid names for sources and sinks + are the WM8903's pins, and the connectors on the board: + + WM8903 pins: + + * IN1L + * IN1R + * IN2L + * IN2R + * IN3L + * IN3R + * DMICDAT + * HPOUTL + * HPOUTR + * LINEOUTL + * LINEOUTR + * LOP + * LON + * ROP + * RON + * Mic Bias + + Board connectors: + + * Headphone Jack + * Int Spk + * Mic Jack + +Optional properties: +- nvidia,spkr-en-gpios : The GPIO that enables the speakers +- nvidia,hp-mute-gpios : The GPIO that mutes the headphones +- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in +- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone +- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone + +Example: + +sound { + compatible = "nvidia,tegra-audio-wm8903-seaboard", + "nvidia,tegra-audio-wm8903"; + + nvidia,spkr-en-gpios = <&codec 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ + + nvidia,routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Bias", "Mic Jack", + "IN1R", "Mic Bias"; +}; + diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 8791c69..b3abf32 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -34,6 +34,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/of_gpio.h>
#include <mach/tegra_wm8903_pdata.h>
@@ -59,8 +60,9 @@ #define GPIO_HP_DET BIT(4)
struct tegra_wm8903 { + struct tegra_wm8903_platform_data pdata; + struct platform_device *pcm_dev; struct tegra_asoc_utils_data util_data; - struct tegra_wm8903_platform_data *pdata; int gpio_requested; };
@@ -160,7 +162,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_wm8903_platform_data *pdata = &machine->pdata;
if (!(machine->gpio_requested & GPIO_SPKR_EN)) return 0; @@ -177,7 +179,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_wm8903_platform_data *pdata = &machine->pdata;
if (!(machine->gpio_requested & GPIO_HP_MUTE)) return 0; @@ -246,8 +248,10 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = codec->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; - int ret; + struct tegra_wm8903_platform_data *pdata; + struct device_node *np; + struct snd_soc_dapm_route *routes; + int ret, i;
ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1, TEGRA_DAS_DAP_SEL_DAC1); @@ -262,6 +266,83 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) return ret; }
+ pdata = &machine->pdata; + np = card->dev->of_node; + + if (card->dev->platform_data) { + *pdata = *(struct tegra_wm8903_platform_data *) + card->dev->platform_data; + } else if (np) { + /* + * This part must be in init() rather than probe() in order to + * guarantee that the WM8903 has been probed, and hence its + * GPIO controller registered, which is a pre-condition for + * of_get_named_gpio() to be able to map the phandles in the + * properties to the controller node. Given this, all + * pdata & OF handling is in init() for consistency. + */ + pdata->gpio_spkr_en = of_get_named_gpio(np, + "nvidia,spkr-en-gpios", 0); + pdata->gpio_hp_mute = of_get_named_gpio(np, + "nvidia,hp-mute-gpios", 0); + pdata->gpio_hp_det = of_get_named_gpio(np, + "nvidia,hp-det-gpios", 0); + pdata->gpio_int_mic_en = of_get_named_gpio(np, + "nvidia,int-mic-en-gpios", 0); + pdata->gpio_ext_mic_en = of_get_named_gpio(np, + "nvidia,ext-mic-en-gpios", 0); + } else { + dev_err(card->dev, "No platform data supplied\n"); + return -EINVAL; + } + + if (np) { + card->num_dapm_routes = + of_property_count_strings(np, "nvidia,routing"); + if (card->num_dapm_routes & 1) { + dev_err(card->dev, + "Property 'nvidia,routing's length is odd\n"); + return -EINVAL; + } + card->num_dapm_routes /= 2; + if (!card->num_dapm_routes) { + dev_err(card->dev, + "Property 'nvidia,routing' is zero length\n"); + return -EINVAL; + } + + routes = devm_kzalloc(card->dev, + card->num_dapm_routes * sizeof(*card->dapm_routes), + GFP_KERNEL); + if (!routes) { + dev_err(card->dev, + "Could not allocate DAPM route table\n"); + return -EINVAL; + } + card->dapm_routes = routes; + + for (i = 0; i < card->num_dapm_routes; i++) { + of_property_read_string_index(np, "nvidia,routing", + 2 * i, &routes[i].sink); + of_property_read_string_index(np, "nvidia,routing", + (2 * i) + 1, &routes[i].source); + } + } else { + if (machine_is_harmony()) { + card->dapm_routes = harmony_audio_map; + card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); + } else if (machine_is_seaboard()) { + card->dapm_routes = seaboard_audio_map; + card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); + } else if (machine_is_kaen()) { + card->dapm_routes = kaen_audio_map; + card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); + } else { + card->dapm_routes = aebl_audio_map; + card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); + } + } + if (gpio_is_valid(pdata->gpio_spkr_en)) { ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); if (ret) { @@ -361,11 +442,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_tegra_wm8903; struct tegra_wm8903 *machine; - struct tegra_wm8903_platform_data *pdata; int ret;
- pdata = pdev->dev.platform_data; - if (!pdata) { + if (!pdev->dev.platform_data && !pdev->dev.of_node) { dev_err(&pdev->dev, "No platform data supplied\n"); return -EINVAL; } @@ -378,30 +457,24 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) goto err; }
- machine->pdata = pdata; + if (pdev->dev.of_node) { + machine->pcm_dev = platform_device_register_simple( + "tegra-pcm-audio", -1, NULL, 0); + if (IS_ERR(machine->pcm_dev)) { + dev_err(&pdev->dev, "Can't instantiate ASoC DMA\n"); + ret = PTR_ERR(machine->pcm_dev); + goto err; + } + }
ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); if (ret) - goto err; + goto err_unregister;
card->dev = &pdev->dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine);
- if (machine_is_harmony()) { - card->dapm_routes = harmony_audio_map; - card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); - } else if (machine_is_seaboard()) { - card->dapm_routes = seaboard_audio_map; - card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); - } else if (machine_is_kaen()) { - card->dapm_routes = kaen_audio_map; - card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); - } else { - card->dapm_routes = aebl_audio_map; - card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); - } - ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", @@ -413,6 +486,8 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
err_fini_utils: tegra_asoc_utils_fini(&machine->util_data); +err_unregister: + platform_device_unregister(machine->pcm_dev); err: return ret; } @@ -421,7 +496,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_wm8903_platform_data *pdata = &machine->pdata;
if (machine->gpio_requested & GPIO_HP_DET) snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, @@ -440,15 +515,22 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) snd_soc_unregister_card(card);
tegra_asoc_utils_fini(&machine->util_data); + platform_device_unregister(machine->pcm_dev);
return 0; }
+static const struct of_device_id tegra_wm8903_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra-audio-wm8903", }, + {}, +}; + static struct platform_driver tegra_wm8903_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, + .of_match_table = tegra_wm8903_of_match, }, .probe = tegra_wm8903_driver_probe, .remove = __devexit_p(tegra_wm8903_driver_remove), @@ -459,3 +541,4 @@ MODULE_AUTHOR("Stephen Warren swarren@nvidia.com"); MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match);
* Stephen Warren wrote:
From: John Bonesio bones@secretlab.ca
This driver is parameterized in two ways:
a) Platform data, which supplies a set of GPIOs used by the driver. These GPIOs can now be parsed out of device tree.
b) Machine-specific DAPM route arrays embedded into the ASoC machine driver itself. The driver picks the appropriate array to use using machine_is_*(). This array can now be parsed straight out of device tree, allowing the machine driver to be completely machine agnostic.
swarren applied the following modifications:
- Moved all pdata and DT parsing into one place.
- Added DAPM route parsing from DT.
- Added tegra_pcm device registration.
- Documented DT binding.
Signed-off-by: John Bonesio bones@secretlab.ca Signed-off-by: Grant Likely grant.likely@secretlab.ca Signed-off-by: Stephen Warren swarren@nvidia.com
.../bindings/sound/tegra-audio-wm8903.txt | 63 +++++++++ sound/soc/tegra/tegra_wm8903.c | 133 ++++++++++++++++---- 2 files changed, 171 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt
[...]
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
[...]
@@ -262,6 +266,83 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) return ret; }
- pdata = &machine->pdata;
- np = card->dev->of_node;
- if (card->dev->platform_data) {
*pdata = *(struct tegra_wm8903_platform_data *)
card->dev->platform_data;
[...]
Minor nit: perhaps this should use memcpy() instead?
Thierry
On Tue, Nov 22, 2011 at 06:21:25PM -0700, Stephen Warren wrote:
This looks basically fine, a few comments and obviously it depends on the other patches in the series.
- nvidia,routing =
"Headphone Jack", "HPOUTR",
"Headphone Jack", "HPOUTL",
"Int Spk", "ROP",
"Int Spk", "RON",
"Int Spk", "LOP",
"Int Spk", "LON",
Hrm, I'm thinking we should generalise this for use by other systems - at least OMAP has a similar stuff in mainline and a lot of phone vendors who spin many devices from a platform design have broadly the same pattern of a core reference design with per board wiring differences that need to be represented in their code. We'll need to work out what to do about the board defined widgets, though.
We should also add a standard property or other mechanism for setting a display name for the card.
"Mic Bias", "Mic Jack",
"IN1R", "Mic Bias";
Before we merge this we should refactor the WM8903 mic bias to a supply widget, this stuff is both nasty and very Linux specific.
- pdata = &machine->pdata;
- np = card->dev->of_node;
- if (card->dev->platform_data) {
*pdata = *(struct tegra_wm8903_platform_data *)
card->dev->platform_data;
I'd go through a local variable or use memcpy() rather than having this long code.
- } else if (np) {
/*
* This part must be in init() rather than probe() in order to
* guarantee that the WM8903 has been probed, and hence its
* GPIO controller registered, which is a pre-condition for
* of_get_named_gpio() to be able to map the phandles in the
* properties to the controller node. Given this, all
* pdata & OF handling is in init() for consistency.
*/
I wonder how the probe retry stuff is getting on...
- if (np) {
card->num_dapm_routes =
of_property_count_strings(np, "nvidia,routing");
if (card->num_dapm_routes & 1) {
dev_err(card->dev,
"Property 'nvidia,routing's length is odd\n");
return -EINVAL;
I'd say "not even" for clarity here.
participants (4)
-
Mark Brown
-
Olof Johansson
-
Stephen Warren
-
Thierry Reding