Skip to contentSkip to conversation

ARM: Tegra: Device Tree: i2c & wm8903

RFC New John Bonesio 5 participants 13 messages May 11, 2011 – Jun 3, 2011

Subsystems (9)
lore
Share & tools
lore
#0 lore raw

cover ARM: Tegra: Device Tree: i2c & wm8903

This is revision 2 of my previous patch series:
Tegra: Harmony: Device Tree first steps

The following patch series is a step in the direction of getting board specific devices initialized from a device tree.

This patch set adds intiailization of i2c and the wm8903. The i2c controller is in the SoC and is initialized statically, but the board specific information is pulled in from the device tree. The wm8903 is initialized using only the device tree when using the board-dt.c general Tegra board initialization file.

---

John Bonesio (3):
ARM: Tegra: Device Tree Support: Update how sdhci devices are initialized
ARM: Tegra: Device Tree Support: Add i2c devices
ARM:Tegra: Device Tree Support: Initialize from wm8903 the device tree

 arch/arm/boot/dts/tegra-harmony.dts |   37 ++++++++++++++
 arch/arm/boot/dts/tegra250.dtsi     |   37 ++++++++++++++
 arch/arm/mach-tegra/Makefile        |    1 
 arch/arm/mach-tegra/board-dt.c      |   94 ++++-------------------------------
 drivers/i2c/busses/i2c-tegra.c      |   16 ++++++
 sound/soc/codecs/wm8903.c           |   93 +++++++++++++++++++++++++++++++++--
 sound/soc/tegra/Kconfig             |    2 -
 sound/soc/tegra/harmony.c           |    8 +++
 8 files changed, 200 insertions(+), 88 deletions(-)
Signature · 1 line
- John
#1 lore raw

RFC 1/3 ARM: Tegra: Device Tree Support: Update how sdhci devices are initialized

This patch changes how sdhci devices are initialized so that a later patch can easily add support for i2c devies.

---

 arch/arm/mach-tegra/Makefile   |    1 
 arch/arm/mach-tegra/board-dt.c |   88 ++--------------------------------------
 2 files changed, 6 insertions(+), 83 deletions(-)
arch/arm/mach-tegra/Makefile +1 -0
index 842ec1a..54d2215 100644
@@ -31,6 +31,7 @@ obj-${CONFIG_MACH_SEABOARD}             += board-seaboard.o
 obj-${CONFIG_MACH_SEABOARD}             += board-seaboard-pinmux.o
 
 obj-${CONFIG_MACH_TEGRA_DT}             += board-dt.o
+obj-${CONFIG_MACH_TEGRA_DT}             += board-harmony-pinmux.o
 
 obj-${CONFIG_MACH_TRIMSLICE}            += board-trimslice.o
 obj-${CONFIG_MACH_TRIMSLICE}            += board-trimslice-pinmux.o
arch/arm/mach-tegra/board-dt.c +5 -83

104 lines not on this page · raw message

#2 lore raw

RFC 1/3 ARM: Tegra: Device Tree Support: Update how sdhci devices are initialized

John Bonesio wrote at Wednesday, May 11, 2011 5:27 PM:

arch/arm/mach-tegra/board-dt.c line 44

Quoted 8 lines

This patch changes how sdhci devices are initialized so that a later patch can easily add support for i2c devies.
...

arch/arm/mach-tegra/board-dt.c +2 -0
...
+#include <mach/sdhci.h>
...
+#include "gpio-names.h"

I don't think either of those headers are needed any more.

Otherwise, looks good.

Signature · 1 line
nvpublic
#3 lore raw

RFC 2/3 ARM: Tegra: Device Tree Support: Add i2c devices

In reply to John Bonesio

This patch initializes i2c controller devices in board-dt.c. The i2c controller is added to tegra250.dtsi so later on-board i2c devices can be found and initialized based on the device tree information.

Board specific i2c parameters are placed in tegra-harmony.dts.

---

 arch/arm/boot/dts/tegra-harmony.dts |   20 +++++++++++++++++++
 arch/arm/boot/dts/tegra250.dtsi     |   37 +++++++++++++++++++++++++++++++++++
 arch/arm/mach-tegra/board-dt.c      |    8 ++++++++
 drivers/i2c/busses/i2c-tegra.c      |   16 ++++++++++++++-
 4 files changed, 80 insertions(+), 1 deletions(-)
arch/arm/boot/dts/tegra-harmony.dts +20 -0
index 23592b2..af169aa 100644
@@ -16,6 +16,26 @@
 		reg = < 0x00000000 0x40000000 >;
 	};
 
+	i2c@7000c000 {
+		status = "ok";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000c400 {
+		status = "ok";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000c500 {
+		status = "ok";
+		clock-frequency = <400000>;
+	};
+
+	i2c@7000d000 {
+		status = "ok";
+		clock-frequency = <400000>;
+	};
+
 	serial@70006300 {
 		status = "ok";
 		clock-frequency = < 216000000 >;
arch/arm/boot/dts/tegra250.dtsi +37 -0
index f1801b8..0a056a2 100644
@@ -20,6 +20,43 @@
 		};
 	};
 
+
+	i2c@7000c000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "nvidia,tegra250-i2c";
+		reg = <0x7000C000 0x100>;
+		interrupts = < 70 >;
+		status = "disabled";
+	};
+
+	i2c@7000c400 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "nvidia,tegra250-i2c";
+		reg = <0x7000C400 0x100>;
+		interrupts = < 116 >;
+		status = "disabled";
+	};
+
+	i2c@7000c500 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "nvidia,tegra250-i2c";
+		reg = <0x7000C500 0x100>;
+		interrupts = < 124 >;
+		status = "disabled";
+	};
+
+	i2c@7000d000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "nvidia,tegra250-i2c";
+		reg = <0x7000D000 0x200>;
+		interrupts = < 85 >;
+		status = "disabled";
+	};
+
 	gpio: gpio@6000d000 {
 		compatible = "nvidia,tegra250-gpio";
 		reg = < 0x6000d000 0x1000 >;
arch/arm/mach-tegra/board-dt.c +8 -0
index 50ab328..c498e84 100644
@@ -28,6 +28,8 @@
 #include <linux/of_platform.h>
 #include <linux/pda_power.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -43,11 +45,17 @@
 #include "devices.h"
 #include "gpio-names.h"
 
+void harmony_pinmux_init(void);
+
 static struct platform_device *tegra250_devices[] __initdata = {
 	&tegra_sdhci_device1,
 	&tegra_sdhci_device2,
 	&tegra_sdhci_device3,
 	&tegra_sdhci_device4,
+	&tegra_i2c_device1,
+	&tegra_i2c_device2,
+	&tegra_i2c_device3,
+	&tegra_i2c_device4,
 };
 
 static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
drivers/i2c/busses/i2c-tegra.c +15 -1
index b4ab39b..1693c6a 100644
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/i2c-tegra.h>
+#include <linux/of_i2c.h>
 
 #include <asm/unaligned.h>
 
@@ -511,6 +512,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	struct resource *iomem;
 	struct clk *clk;
 	struct clk *i2c_clk;
+	const unsigned int *prop;
 	void *base;
 	int irq;
 	int ret = 0;
@@ -568,7 +570,16 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	i2c_dev->irq = irq;
 	i2c_dev->cont_id = pdev->id;
 	i2c_dev->dev = &pdev->dev;
-	i2c_dev->bus_clk_rate = pdata ? pdata->bus_clk_rate : 100000;
+
+	i2c_dev->bus_clk_rate = 100000; /* default clock rate */
+	if (i2c_dev->dev->of_node) {    /* if there is a device tree node ... */
+		prop = of_get_property(i2c_dev->dev->of_node,
+				"clock-frequency", NULL);
+		if (prop)
+			i2c_dev->bus_clk_rate = be32_to_cpup(prop);
+
+	} else if (pdata)
+		i2c_dev->bus_clk_rate = pdata->bus_clk_rate;
 
 	if (pdev->id == 3)
 		i2c_dev->is_dvc = 1;
@@ -598,6 +609,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	i2c_dev->adapter.algo = &tegra_i2c_algo;
 	i2c_dev->adapter.dev.parent = &pdev->dev;
 	i2c_dev->adapter.nr = pdev->id;
+	i2c_dev->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
 
 	ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
 	if (ret) {
@@ -605,6 +617,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 		goto err_free_irq;
 	}
 
+	of_i2c_register_devices(&i2c_dev->adapter);
+
 	return 0;
 err_free_irq:
 	free_irq(i2c_dev->irq, i2c_dev);
#4 lore raw

RFC 2/3 ARM: Tegra: Device Tree Support: Add i2c devices

John Bonesio wrote at Wednesday, May 11, 2011 5:27 PM:

arch/arm/mach-tegra/board-dt.c line 32

Quoted 8 lines

This patch initializes i2c controller devices in board-dt.c. The i2c controller is added to tegra250.dtsi so later on-board i2c devices can be found and initialized based on the device tree information.
...

arch/arm/mach-tegra/board-dt.c +2 -0
...
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>

I don't think those headers are needed now the platform data isn't set up here.

drivers/i2c/busses/i2c-tegra.c static int tegra_i2c_probe(struct platform_device *pdev) · line 612

Quoted 7 lines
drivers/i2c/busses/i2c-tegra.c +1 -0
...
@@ -598,6 +609,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	i2c_dev->adapter.algo = &tegra_i2c_algo;
 	i2c_dev->adapter.dev.parent = &pdev->dev;
 	i2c_dev->adapter.nr = pdev->id;
+	i2c_dev->adapter.dev.of_node = of_node_get(pdev->dev.of_node);

It seems like users of this of_node (i.e. the probe function) could just access pdev->dev.of_node directly (since pdev is already passed in) rather than storing a copy here. At least, sdhci-tegra.c works that way. Still, this isn't a big deal, I think.

drivers/i2c/busses/i2c-tegra.c static int tegra_i2c_probe(struct platform_device *pdev) · line 621

Quoted 6 lines
drivers/i2c/busses/i2c-tegra.c +2 -0
@@ -605,6 +617,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 		goto err_free_irq;
 	}
 
+	of_i2c_register_devices(&i2c_dev->adapter);
+

I would have expected that to be performed inside the core I2C code, probably inside i2c_add_numbered_adapter? Still, it looks like the other I2C controllers don't already work that way, so this is probably more a suggestion for future cleanup than something to be addressed in this patch.

Signature · 1 line
nvpublic
#5 lore raw

RFC 2/3 ARM: Tegra: Device Tree Support: Add i2c devices

Quoted 12 lines · Stephen Warren

John Bonesio wrote at Wednesday, May 11, 2011 5:27 PM:

arch/arm/mach-tegra/board-dt.c line 32

Quoted 8 lines

This patch initializes i2c controller devices in board-dt.c. The i2c controller is added to tegra250.dtsi so later on-board i2c devices can be found and initialized based on the device tree information.
...

arch/arm/mach-tegra/board-dt.c +2 -0
...
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>

I don't think those headers are needed now the platform data isn't set up here.

Quoted 12 lines

drivers/i2c/busses/i2c-tegra.c static int tegra_i2c_probe(struct platform_device *pdev) · line 612

Quoted 7 lines
drivers/i2c/busses/i2c-tegra.c +1 -0
...
@@ -598,6 +609,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 ? ? ? i2c_dev->adapter.algo = &tegra_i2c_algo;
 ? ? ? i2c_dev->adapter.dev.parent = &pdev->dev;
 ? ? ? i2c_dev->adapter.nr = pdev->id;
+ ? ? i2c_dev->adapter.dev.of_node = of_node_get(pdev->dev.of_node);

It seems like users of this of_node (i.e. the probe function) could just access pdev->dev.of_node directly (since pdev is already passed in) rather than storing a copy here. At least, sdhci-tegra.c works that way. Still, this isn't a big deal, I think.

Actually, using of_node_get() here is the right thing since it increases the reference count on the of_node. However, the patch should also do an of_node_put() in the remove hook, or in the .probe error path.

Quoted 5 lines
Quoted 5 lines
drivers/i2c/busses/i2c-tegra.c +0 -0
@@ -605,6 +617,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 ? ? ? ? ? ? ? goto err_free_irq;
 ? ? ? }
 
Quoted 8 lines

drivers/i2c/busses/i2c-tegra.c static int tegra_i2c_probe(struct platform_device *pdev) · line 621

Quoted 2 lines
drivers/i2c/busses/i2c-tegra.c +2 -0
+ ? ? of_i2c_register_devices(&i2c_dev->adapter);
+

I would have expected that to be performed inside the core I2C code, probably inside i2c_add_numbered_adapter? Still, it looks like the other I2C controllers don't already work that way, so this is probably more a suggestion for future cleanup than something to be addressed in this patch.

This may move into core code in the future, but for the moment the drivers need to call it explicitly.

g.

#6 lore raw

RFC 2/3 ARM: Tegra: Device Tree Support: Add i2c devices

Grant Likely wrote at Wednesday, May 11, 2011 10:47 PM:

Quoted 17 lines · Stephen Warren
Quoted 15 lines

John Bonesio wrote at Wednesday, May 11, 2011 5:27 PM:

Review static int tegra_i2c_probe(struct platform_device *pdev) · line 612

Quoted 9 lines

This patch initializes i2c controller devices in board-dt.c. The i2c controller is added to tegra250.dtsi so later on-board i2c devices can be found and initialized based on the device tree information.
...

(quoted diff) +1 -0
@@ -598,6 +609,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 ? ? ? i2c_dev->adapter.algo = &tegra_i2c_algo;
 ? ? ? i2c_dev->adapter.dev.parent = &pdev->dev;
 ? ? ? i2c_dev->adapter.nr = pdev->id;
+ ? ? i2c_dev->adapter.dev.of_node = of_node_get(pdev->dev.of_node);

It seems like users of this of_node (i.e. the probe function) could just access pdev->dev.of_node directly (since pdev is already passed in) rather than storing a copy here. At least, sdhci-tegra.c works that way. Still, this isn't a big deal, I think.

Quoted 4 lines

Actually, using of_node_get() here is the right thing since it increases the reference count on the of_node. However, the patch should also do an of_node_put() in the remove hook, or in the .probe error path.

Ah OK, I was missing that the later all of of_i2c_register_devices() uses i2c_dev->adapter.dev.of_node; I was thinking that it'd just use i2c_dev->adapter.dev.parent->of_node directly, in which case we wouldn't need to copy the pointer, nor increment the refcount.

So, I agree this is OK.

Signature · 1 line
nvpublic
#7 lore raw

RFC 3/3 ARM:Tegra: Device Tree Support: Initialize from wm8903 the device tree

In reply to John Bonesio

This patch makes it so the wm8903 is initialized from it's device tree node.

---

 arch/arm/boot/dts/tegra-harmony.dts |   17 ++++++
 sound/soc/codecs/wm8903.c           |   93 +++++++++++++++++++++++++++++++++--
 sound/soc/tegra/Kconfig             |    2 -
 sound/soc/tegra/harmony.c           |    8 +++
 4 files changed, 115 insertions(+), 5 deletions(-)
arch/arm/boot/dts/tegra-harmony.dts +17 -0
index af169aa..05521a5 100644
@@ -19,6 +19,23 @@
 	i2c@7000c000 {
 		status = "ok";
 		clock-frequency = <400000>;
+
+		codec: wm8903@1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupts = < 347 >;
+			irq-active-low = <0>;
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			gpio-base = < 224 >;
+			gpio-num-cfg = < 5 >;
+			/* #define WM8903_GPIO_NO_CONFIG 0x8000 */
+			gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
+		};
 	};
 
 	i2c@7000c400 {
sound/soc/codecs/wm8903.c +89 -4

121 lines not on this page · raw message

sound/soc/tegra/Kconfig +1 -1
index 66b504f..6dc89bc 100644
@@ -16,7 +16,7 @@ config SND_TEGRA_SOC_I2S
 
 config SND_TEGRA_SOC_HARMONY
 	tristate "SoC Audio support for Tegra Harmony reference board"
-	depends on SND_TEGRA_SOC && MACH_HARMONY && I2C
+	depends on SND_TEGRA_SOC && (MACH_HARMONY || MACH_TEGRA_DT) && I2C
 	default m
 	select SND_TEGRA_SOC_I2S
 	select SND_SOC_WM8903
sound/soc/tegra/harmony.c +8 -0
index 556a571..f225087 100644
@@ -292,12 +292,20 @@ static __devinit int tegra_snd_harmony_probe(struct platform_device *pdev)
 	struct snd_soc_card *card = &snd_soc_harmony;
 	struct tegra_harmony *harmony;
 	struct harmony_audio_platform_data *pdata;
+	const char *sprop;
 	int ret;
 
+#ifdef CONFIG_OF
+	if ((!of_machine_is_compatible("nvidia,harmony")) && (!machine_is_harmony())) {
+		dev_err(&pdev->dev, "Not running on Tegra Harmony!\n");
+		return -ENODEV;
+	}
+#else
 	if (!machine_is_harmony()) {
 		dev_err(&pdev->dev, "Not running on Tegra Harmony!\n");
 		return -ENODEV;
 	}
+#endif
 
 	pdata = pdev->dev.platform_data;
 	if (!pdata) {
#8 lore raw

RFC 3/3 ARM:Tegra: Device Tree Support: Initialize from wm8903 the device tree

John Bonesio wrote at Wednesday, May 11, 2011 5:27 PM:

Quoted 10 lines

This patch makes it so the wm8903 is initialized from it's device tree node.

arch/arm/boot/dts/tegra-harmony.dts +0 -0
index af169aa..05521a5 100644
@@ -19,6 +19,23 @@
 	i2c at 7000c000 {

arch/arm/boot/dts/tegra-harmony.dts line 29

Quoted 10 lines
arch/arm/boot/dts/tegra-harmony.dts +8 -0
 		status = "ok";
 		clock-frequency = <400000>;
+
+		codec: wm8903 at 1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupts = < 347 >;
+			irq-active-low = <0>;
+			micdet-cfg = <0>;
+			micdet-delay = <100>;

Nit: Maybe group all the WM8903-specific fields together, rather than spacing them out and interleaving the gpio-controller/gpio-cells in the middle of them?

arch/arm/boot/dts/tegra-harmony.dts line 35

Quoted 6 lines
arch/arm/boot/dts/tegra-harmony.dts +6 -0
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			gpio-base = < 224 >;
+			gpio-num-cfg = < 5 >;

I don't think gpio-num-cfg is required; the codec always exports 5 GPIOs.

Quoted 15 lines
arch/arm/boot/dts/tegra-harmony.dts +3 -0
+			/* #define WM8903_GPIO_NO_CONFIG 0x8000 */
+			gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
+		};
 	};
 
 	i2c at 7000c400 {
sound/soc/codecs/wm8903.c +0 -1
index f52b623..2347201 100644
@@ -1865,10 +1865,14 @@ static void wm8903_init_gpio(struct snd_soc_codec *codec)
 	wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
 	wm8903->gpio_chip.dev = codec->dev;
 
-	if (pdata && pdata->gpio_base)

sound/soc/codecs/wm8903.c static void wm8903_init_gpio(struct snd_soc_codec *codec) · line 1875

Quoted 10 lines
sound/soc/codecs/wm8903.c +7 -2
+	wm8903->gpio_chip.base = -1;
+	if (pdata && pdata->gpio_base) {
 		wm8903->gpio_chip.base = pdata->gpio_base;
-	else
-		wm8903->gpio_chip.base = -1;
+	} else if (codec->dev->of_node) {
+		prop = of_get_property(codec->dev->of_node, "gpio-base", NULL);
+		if (prop)
+			wm8903->gpio_chip.base = be32_to_cpup(prop);
+	}

The above checks for pdata first, then falls back to of_node. However, The previous i2c-tegra.c patch checks of_node first then falls back to pdata. It seems like the ordering should be consistent (although changing the I2C patch might be best, since I imagine checking pdata first would lead to least compatibility issues)

sound/soc/codecs/wm8903.c static int wm8903_probe(struct snd_soc_codec · line 1982

Quoted 11 lines
sound/soc/codecs/wm8903.c +6 -0
@@ -1964,10 +1973,76 @@ static int wm8903_probe(struct snd_soc_codec
 *codec)
 		WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
 
 		wm8903->mic_delay = pdata->micdet_delay;
+	} else if (codec->dev->of_node) {
+		bool mic_gpio = false;
+
+		prop = of_get_property(codec->dev->of_node, "gpio-num-cfg", NULL);
+		if (prop)
+			num_gpios = be32_to_cpup(prop);

Again, I'd just hard-code num_gpios==WM8903_NUM_GPIO in the loop below, instead of making it configurable, since the HW is fixed.

Quoted 41 lines
sound/soc/codecs/wm8903.c +41 -0
+		prop = of_get_property(codec->dev->of_node, "gpio-cfg", NULL);
+		if (num_gpios && prop) {
+			for (i = 0; i < num_gpios; i++) {
+				gpio_cfg = be32_to_cpu(prop[i]);
+
+				if (gpio_cfg == WM8903_GPIO_NO_CONFIG)
+					continue;
+
+				snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i,
+					      gpio_cfg & 0xffff);
+
+				val = (gpio_cfg & WM8903_GP1_FN_MASK)
+					>> WM8903_GP1_FN_SHIFT;
+
+				switch (val) {
+				case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
+				case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
+					mic_gpio = true;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+
+		prop = of_get_property(codec->dev->of_node, "interrupts", NULL);
+		if (prop)
+			wm8903->irq = be32_to_cpup(prop);
+
+		prop = of_get_property(codec->dev->of_node, "micdet-cfg", NULL);
+		if (prop)
+			micdet_cfg = be32_to_cpup(prop);
+
+		snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0, micdet_cfg);
+
+		if (micdet_cfg)
+			snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
+					    WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+
+		/* If microphone detection is enabled in device tree but
+		 * detected via IRQ then interrupts can be lost before

sound/soc/codecs/wm8903.c static int wm8903_probe(struct snd_soc_codec *codec) · line 2033

Quoted 10 lines
sound/soc/codecs/wm8903.c +10 -0
+		 * the machine driver has set up microphone detection
+		 * IRQs as the IRQs are clear on read.  The detection
+		 * will be enabled when the machine driver configures.
+		 */
+		WARN_ON(!mic_gpio && (micdet_cfg & WM8903_MICDET_ENA));
+
+		prop = of_get_property(codec->dev->of_node, "micdet-delay", NULL);
+		if (prop)
+			wm8903->mic_delay = be32_to_cpup(prop);
+

The above chunk duplicates a lot of code in the pdata and of_node paths.

Instead, perhaps it'd be better to do something more like:

if (!pdata && of_node) {
pdata = kalloc()
read of_node, convert & write to pdata
}

if (pdata) {
    // existing code to handle pdata
}

That way, the code to handle the pdata is re-used and not duplicated.

Quoted 5 lines
sound/soc/tegra/harmony.c +2 -0
...
+#ifdef CONFIG_OF
+	if ((!of_machine_is_compatible("nvidia,harmony")) &&

(!machine_is_harmony())) {

sound/soc/tegra/harmony.c static __devinit int tegra_snd_harmony_probe(struct platform_device *pdev) · line 308

Quoted 9 lines
sound/soc/tegra/harmony.c +5 -0
+		dev_err(&pdev->dev, "Not running on Tegra Harmony!\n");
+		return -ENODEV;
+	}
+#else
 	if (!machine_is_harmony()) {
 		dev_err(&pdev->dev, "Not running on Tegra Harmony!\n");
 		return -ENODEV;
 	}
+#endif

Is that backwards-compatible if CONFIG_OF is enabled, but a devicetree wasn't provided, but instead the old-style Harmony machine ID was used? I note that the board-harmony.c machine description doesn't include a DT_MACHINE_START listing that compatible value; only board-dt.c does this, and that has a different ARM machine ID.

Signature · 1 line
nvpublic
#9 lore raw

RFC 3/3 ARM:Tegra: Device Tree Support: Initialize from wm8903 the device tree

In reply to John Bonesio
Quoted 7 lines · John Bonesio

This patch makes it so the wm8903 is initialized from it's device tree node.

---

 arch/arm/boot/dts/tegra-harmony.dts |   17 ++++++
 sound/soc/codecs/wm8903.c           |   93 +++++++++++++++++++++++++++++++++--

This needs to be sent separately to the relevant mailing lists and maintainers. You can't go making substantial changes to drivers without even telling the maintainers about it - this will apply to any device tree work you're doing. In this case one of the maintainers happens to be me, but even so.

arch/arm/boot/dts/tegra-harmony.dts line 29

Quoted 4 lines
arch/arm/boot/dts/tegra-harmony.dts +4 -0
+			interrupts = < 347 >;
+			irq-active-low = <0>;
+			micdet-cfg = <0>;
+			micdet-delay = <100>;

Some of this looks like chip default, why is it being configured?

arch/arm/boot/dts/tegra-harmony.dts line 32

Quoted 2 lines
arch/arm/boot/dts/tegra-harmony.dts +2 -0
+                       gpio-controller;
+                       #gpio-cells = <2>;

The fact that this device is a GPIO controller is a physical property of the device, we shouldn't need to be putting it into the device tree.

arch/arm/boot/dts/tegra-harmony.dts line 35

Quoted 1 line
arch/arm/boot/dts/tegra-harmony.dts +1 -0
+			gpio-num-cfg = < 5 >;

Similarly here, the device has a fixed number of GPIOs.

arch/arm/boot/dts/tegra-harmony.dts line 37

Quoted 2 lines
arch/arm/boot/dts/tegra-harmony.dts +2 -0
+			/* #define WM8903_GPIO_NO_CONFIG 0x8000 */
+			gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;

This doesn't seem great for usability. I'd suggest key/value pairs rather than an array.

sound/soc/codecs/wm8903.c static void wm8903_init_gpio(struct snd_soc_codec *codec) · line 1875

Quoted 11 lines
sound/soc/codecs/wm8903.c +7 -3
-	if (pdata && pdata->gpio_base)
+	wm8903->gpio_chip.base = -1;
+	if (pdata && pdata->gpio_base) {
 		wm8903->gpio_chip.base = pdata->gpio_base;
-	else
-		wm8903->gpio_chip.base = -1;
+	} else if (codec->dev->of_node) {
+		prop = of_get_property(codec->dev->of_node, "gpio-base", NULL);
+		if (prop)
+			wm8903->gpio_chip.base = be32_to_cpup(prop);
+	}

We have to do manual endianness conversions to read from the device tree? Oh, well.

sound/soc/codecs/wm8903.c static int wm8903_probe(struct snd_soc_codec *codec) · line 2011

Quoted 5 lines
sound/soc/codecs/wm8903.c +5 -0
+
+		prop = of_get_property(codec->dev->of_node, "interrupts", NULL);
+		if (prop)
+			wm8903->irq = be32_to_cpup(prop);
+

We have a standard way of passing the IRQ number to I2C devices, surely we should make sure that works at the bus level rather than having to replicate this code everywhere?

Quoted 8 lines
sound/soc/codecs/wm8903.c +8 -0
+		prop = of_get_property(codec->dev->of_node, "micdet-cfg", NULL);
+		if (prop)
+			micdet_cfg = be32_to_cpup(prop);
+
+		snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0, micdet_cfg);
+
+		if (micdet_cfg)
+			snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,

sound/soc/codecs/wm8903.c static int wm8903_probe(struct snd_soc_codec *codec) · line 2029

Quoted 10 lines
sound/soc/codecs/wm8903.c +10 -0
+					    WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+		
+		/* If microphone detection is enabled in device tree but
+		 * detected via IRQ then interrupts can be lost before
+		 * the machine driver has set up microphone detection
+		 * IRQs as the IRQs are clear on read.  The detection
+		 * will be enabled when the machine driver configures.
+		 */
+		WARN_ON(!mic_gpio && (micdet_cfg & WM8903_MICDET_ENA));
+

There's an awful lot of cut'n'paste code for the parsing code from the platform data code.

sound/soc/tegra/Kconfig config SND_TEGRA_SOC_I2S · line 19

Quoted 4 lines

config SND_TEGRA_SOC_HARMONY

sound/soc/tegra/Kconfig +1 -1
 	tristate "SoC Audio support for Tegra Harmony reference board"
-	depends on SND_TEGRA_SOC && MACH_HARMONY && I2C
+	depends on SND_TEGRA_SOC && (MACH_HARMONY || MACH_TEGRA_DT) && I2C

You've not added anything to the device tree to register the platform device for the machine and I rather fear this won't apply to current code. You should develop against -next.

#10 lore raw

RFC 3/3 ARM:Tegra: Device Tree Support: Initialize from wm8903 the device tree

Quoted 13 lines · Mark Brown
Quoted 11 lines · John Bonesio

- ? ? if (pdata && pdata->gpio_base)
+ ? ? wm8903->gpio_chip.base = -1;
+ ? ? if (pdata && pdata->gpio_base) {
? ? ? ? ? ? ? wm8903->gpio_chip.base = pdata->gpio_base;
- ? ? else
- ? ? ? ? ? ? wm8903->gpio_chip.base = -1;
+ ? ? } else if (codec->dev->of_node) {
+ ? ? ? ? ? ? prop = of_get_property(codec->dev->of_node, "gpio-base", NULL);
+ ? ? ? ? ? ? if (prop)
+ ? ? ? ? ? ? ? ? ? ? wm8903->gpio_chip.base = be32_to_cpup(prop);
+ ? ? }

Quoted 2 lines

We have to do manual endianness conversions to read from the device tree? ?Oh, well.

Yeah, it's not great. I'd really like to have a set of helper functions that locate and decode the data for the most common types of properties, but I've not sat down to focus on it and I've not seen a pattern I'm happy with yet. It does need to be solved though. The issue is I want something that handles fetching the property, error checking and decoding, all in a consistent way so that it actually reduces the amount of parsing code required.

Perhaps something like:

/* Not sure about this; in this case the return value is an error code so that bad properties can be detected */
int dt_decode_cell(struct *property, int index, u32 *out_val); int dt_decode_string(struct *property, int index, char **out_val); int dt_decode_number(struct *property, int start, int len, unsigned long long *out_val);

and perhaps a set of companion functions:
int dt_get_prop_cell(struct *device_node, char *propname, int index, u32 *out_val);
int dt_get_prop_string(struct *device_node, char *propname, int index, char **out_val);
int dt_get_prop_number(struct *device_node, char *propname, int start, int len, unsigned long long *out_val);

The first set would be used when the property pointer has already be obtained, and multiple datum need to be extracted. The second would be most useful when only one value will be extracted from a property. I'm not totally happy with returning the value via a passed in pointer though. Thoughts?

g.

#11 lore raw

RFC 3/3 ARM:Tegra: Device Tree Support: Initialize from wm8903 the device tree

Quoted 4 lines · Grant Likely

Yeah, it's not great. I'd really like to have a set of helper functions that locate and decode the data for the most common types of properties, but I've not sat down to focus on it and I've not seen a pattern I'm happy with yet. It does need to be solved though. The

Yes, looking at the examples you've got below it looks like you've got a similar set of issues to the ones that I've been running into trying to factor the register map access code out of ASoC.

Quoted 17 lines

Perhaps something like:

/* Not sure about this; in this case the return value is an error code so that bad properties can be detected */
int dt_decode_cell(struct *property, int index, u32 *out_val); int dt_decode_string(struct *property, int index, char **out_val); int dt_decode_number(struct *property, int start, int len, unsigned long long *out_val);

and perhaps a set of companion functions:
int dt_get_prop_cell(struct *device_node, char *propname, int index, u32 *out_val);
int dt_get_prop_string(struct *device_node, char *propname, int index, char **out_val);
int dt_get_prop_number(struct *device_node, char *propname, int start, int len, unsigned long long *out_val);

Quoted 5 lines

The first set would be used when the property pointer has already be obtained, and multiple datum need to be extracted. The second would be most useful when only one value will be extracted from a property. I'm not totally happy with returning the value via a passed in pointer though. Thoughts?

Yes, I think this sort of format with the error out of band from the number is best if a little ugly, and especially the second set is definitely going to cut down the amount of boiler plate code. It's a little painful having to pass a pointer to the result but otherwise the error handling gets a bit rubbish, especially for the numbers where there really isn't a sensible invalid value.

#12 lore raw

RFC 3/3 ARM:Tegra: Device Tree Support: Initialize from wm8903 the device tree

In reply to Mark Brown
Quoted 53 lines · Mark Brown
Quoted 7 lines · John Bonesio

This patch makes it so the wm8903 is initialized from it's device tree node.

---

?arch/arm/boot/dts/tegra-harmony.dts | ? 17 ++++++ ?sound/soc/codecs/wm8903.c ? ? ? ? ? | ? 93 +++++++++++++++++++++++++++++++++--

This needs to be sent separately to the relevant mailing lists and maintainers. ?You can't go making substantial changes to drivers without even telling the maintainers about it - this will apply to any device tree work you're doing. ?In this case one of the maintainers happens to be me, but even so.

Quoted 4 lines

+ ? ? ? ? ? ? ? ? ? ? interrupts = < 347 >;
+ ? ? ? ? ? ? ? ? ? ? irq-active-low = <0>;
+ ? ? ? ? ? ? ? ? ? ? micdet-cfg = <0>;
+ ? ? ? ? ? ? ? ? ? ? micdet-delay = <100>;

Some of this looks like chip default, why is it being configured?

Quoted 2 lines

+ ? ? ? ? ? ? ? ? ? ? ? gpio-controller;
+ ? ? ? ? ? ? ? ? ? ? ? #gpio-cells = <2>;

The fact that this device is a GPIO controller is a physical property of the device, we shouldn't need to be putting it into the device tree.

Quoted 1 line

+ ? ? ? ? ? ? ? ? ? ? gpio-num-cfg = < 5 >;

Similarly here, the device has a fixed number of GPIOs.

Quoted 2 lines

+ ? ? ? ? ? ? ? ? ? ? /* #define WM8903_GPIO_NO_CONFIG 0x8000 */
+ ? ? ? ? ? ? ? ? ? ? gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;

This doesn't seem great for usability. ?I'd suggest key/value pairs rather than an array.

Quoted 11 lines

- ? ? if (pdata && pdata->gpio_base)
+ ? ? wm8903->gpio_chip.base = -1;
+ ? ? if (pdata && pdata->gpio_base) {
? ? ? ? ? ? ? wm8903->gpio_chip.base = pdata->gpio_base;
- ? ? else
- ? ? ? ? ? ? wm8903->gpio_chip.base = -1;
+ ? ? } else if (codec->dev->of_node) {
+ ? ? ? ? ? ? prop = of_get_property(codec->dev->of_node, "gpio-base", NULL);
+ ? ? ? ? ? ? if (prop)
+ ? ? ? ? ? ? ? ? ? ? wm8903->gpio_chip.base = be32_to_cpup(prop);
+ ? ? }

We have to do manual endianness conversions to read from the device tree? ?Oh, well.

Quoted 9 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+
+ ? ? ? ? ? ? prop = of_get_property(codec->dev->of_node, "interrupts", NULL);
+ ? ? ? ? ? ? if (prop)
+ ? ? ? ? ? ? ? ? ? ? wm8903->irq = be32_to_cpup(prop);
+

We have a standard way of passing the IRQ number to I2C devices, surely we should make sure that works at the bus level rather than having to replicate this code everywhere?

Yes actually there is. The code in drivers/of/of_i2c.c already correctly populates the i2c_client irq from the device tree. This hunk can be completely removed.

g.