This patch adds device tree support to the Nokia N900 audio driver.
It also removes GPIO defines and gets them from platform data /
device tree, since some GPIO numbers may be different with DT boot.

The binding also changes a helper function in omap-mcbsp, which
is currently only used by the Nokia N900. This change is needed,
because DT instanced omap-mcbsp driver has no valid id assigned.

Last but not least the DT binding is documented.

Signed-off-by: Sebastian Reichel <s...@kernel.org>
---
 .../devicetree/bindings/sound/nokia,rx51.txt       |  27 ++++
 include/sound/rx51.h                               |  18 +++
 sound/soc/omap/omap-mcbsp.c                        |   5 +-
 sound/soc/omap/omap-mcbsp.h                        |   2 +-
 sound/soc/omap/rx51.c                              | 176 ++++++++++++++++-----
 5 files changed, 183 insertions(+), 45 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/nokia,rx51.txt
 create mode 100644 include/sound/rx51.h

diff --git a/Documentation/devicetree/bindings/sound/nokia,rx51.txt 
b/Documentation/devicetree/bindings/sound/nokia,rx51.txt
new file mode 100644
index 0000000..72f93d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nokia,rx51.txt
@@ -0,0 +1,27 @@
+* Nokia N900 audio setup
+
+Required properties:
+- compatible: Should contain "nokia,n900-audio"
+- nokia,cpu-dai: phandle for the McBSP node
+- nokia,audio-codec: phandles for the main TLV320AIC3X node and the
+                     auxiliary TLV320AIC3X node (in this order)
+- nokia,headphone-amplifier: phandle for the TPA6130A2 node
+- tvout-selection-gpios: GPIO for tvout selection
+- jack-detection-gpios: GPIO for jack detection
+- eci-switch-gpios: GPIO for ECI (Enhancement Control Interface) switch
+- speaker-amplifier-gpios: GPIO for speaker amplifier
+
+Example:
+
+sound {
+       compatible = "nokia,n900-audio";
+
+       nokia,cpu-dai = <&mcbsp2>;
+       nokia,audio-codec = <&tlv320aic3x>, <&tlv320aic3x_aux>;
+       nokia,headphone-amplifier = <&tpa6130a2>;
+
+       tvout-selection-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>; /* 40 */
+       jack-detection-gpios = <&gpio6 17 GPIO_ACTIVE_HIGH>; /* 177 */
+       eci-switch-gpios = <&gpio6 22 GPIO_ACTIVE_HIGH>; /* 182 */
+       speaker-amplifier-gpios = <&twl_gpio 7 GPIO_ACTIVE_HIGH>;
+};
diff --git a/include/sound/rx51.h b/include/sound/rx51.h
new file mode 100644
index 0000000..190d745
--- /dev/null
+++ b/include/sound/rx51.h
@@ -0,0 +1,18 @@
+/*
+ * Platform data for Nokia RX-51 SoC audio
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __RX51_AUDIO_H__
+#define __RX51_AUDIO_H__
+
+struct rx51_audio_pdata {
+       int tvout_selection_gpio;
+       int jack_detection_gpio;
+       int eci_sw_gpio;
+       int speaker_amp_gpio;
+};
+
+#endif
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 6c19bba..f88e31e 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -691,7 +691,7 @@ OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone 
Channel 1 Volume", \
 OMAP_MCBSP_ST_CONTROLS(2);
 OMAP_MCBSP_ST_CONTROLS(3);
 
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
 {
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
@@ -701,7 +701,7 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime 
*rtd)
                return 0;
        }
 
-       switch (mcbsp->id) {
+       switch (port_id) {
        case 2: /* McBSP 2 */
                return snd_soc_add_dai_controls(cpu_dai,
                                        omap_mcbsp2_st_controls,
@@ -711,6 +711,7 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime 
*rtd)
                                        omap_mcbsp3_st_controls,
                                        ARRAY_SIZE(omap_mcbsp3_st_controls));
        default:
+               dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
                break;
        }
 
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index ba8386a..2e3369c 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -39,6 +39,6 @@ enum omap_mcbsp_div {
        OMAP_MCBSP_CLKGDV,              /* Sample rate generator divider */
 };
 
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd);
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
 
 #endif
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 58f5e12..89deeb7 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -26,11 +26,13 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/of_gpio.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
+#include <sound/rx51.h>
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "../codecs/tpa6130a2.h"
 
@@ -38,15 +40,6 @@
 
 #include "omap-mcbsp.h"
 
-#define RX51_TVOUT_SEL_GPIO            40
-#define RX51_JACK_DETECT_GPIO          177
-#define RX51_ECI_SW_GPIO               182
-/*
- * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
- * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
- */
-#define RX51_SPEAKER_AMP_TWL_GPIO      (192 + 7)
-
 enum {
        RX51_JACK_DISABLED,
        RX51_JACK_TVOUT,                /* tv-out with stereo output */
@@ -60,6 +53,8 @@ static int rx51_jack_func;
 
 static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
 {
+       struct snd_soc_card *card = dapm->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
        int hp = 0, hs = 0, tvout = 0;
 
        switch (rx51_jack_func) {
@@ -93,7 +88,7 @@ static void rx51_ext_control(struct snd_soc_dapm_context 
*dapm)
        else
                snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
 
-       gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout);
+       gpio_set_value(pdata->tvout_selection_gpio, tvout);
 
        snd_soc_dapm_sync_unlocked(dapm);
 
@@ -154,10 +149,12 @@ static int rx51_set_spk(struct snd_kcontrol *kcontrol,
 static int rx51_spk_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *k, int event)
 {
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
-       else
-               gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+
+       gpio_set_value_cansleep(pdata->speaker_amp_gpio,
+                               !!SND_SOC_DAPM_EVENT_ON(event));
 
        return 0;
 }
@@ -223,7 +220,6 @@ static struct snd_soc_jack rx51_av_jack;
 
 static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
        {
-               .gpio = RX51_JACK_DETECT_GPIO,
                .name = "avdet-gpio",
                .report = SND_JACK_HEADSET,
                .invert = 1,
@@ -290,6 +286,9 @@ static const struct snd_kcontrol_new aic34_rx51_controlsb[] 
= {
 static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_card *card = codec->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
@@ -301,8 +300,10 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
        /* Add RX-51 specific controls */
        err = snd_soc_add_card_controls(rtd->card, aic34_rx51_controls,
                                   ARRAY_SIZE(aic34_rx51_controls));
-       if (err < 0)
+       if (err < 0) {
+               dev_err(card->dev, "Failed to add RX-51 specific controls\n");
                return err;
+       }
 
        /* Add RX-51 specific widgets */
        snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
@@ -312,25 +313,39 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime 
*rtd)
        snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        err = tpa6130a2_add_controls(codec);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(card->dev, "Failed to add TPA6130A2 controls\n");
                return err;
+       }
        snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
 
-       err = omap_mcbsp_st_add_controls(rtd);
-       if (err < 0)
+       err = omap_mcbsp_st_add_controls(rtd, 2);
+       if (err < 0) {
+               dev_err(card->dev, "Failed to add MCBSP controls\n");
                return err;
+       }
 
        /* AV jack detection */
        err = snd_soc_jack_new(codec, "AV Jack",
                               SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
                               &rx51_av_jack);
-       if (err)
+       if (err) {
+               dev_err(card->dev, "Failed to add AV Jack\n");
                return err;
+
+       }
+
+       rx51_av_jack_gpios[0].gpio = pdata->jack_detection_gpio;
+
        err = snd_soc_jack_add_gpios(&rx51_av_jack,
-                                    ARRAY_SIZE(rx51_av_jack_gpios),
-                                    rx51_av_jack_gpios);
+                               ARRAY_SIZE(rx51_av_jack_gpios),
+                               rx51_av_jack_gpios);
+       if (err) {
+               dev_err(card->dev, "Failed to add GPIOs\n");
+               return err;
+       }
 
-       return err;
+       return 0;
 }
 
 static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm)
@@ -396,37 +411,107 @@ static struct snd_soc_card rx51_sound_card = {
 
 static int rx51_soc_probe(struct platform_device *pdev)
 {
+       struct rx51_audio_pdata *pdata = pdev->dev.platform_data;
+       struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &rx51_sound_card;
        int err;
 
        if (!machine_is_nokia_rx51() && 
!of_machine_is_compatible("nokia,omap3-n900"))
                return -ENODEV;
 
-       err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
+       card->dev = &pdev->dev;
+
+       if (np) {
+               struct device_node *dai_node;
+
+               pdata = devm_kzalloc(&pdev->dev,
+                               sizeof(struct rx51_audio_pdata), GFP_KERNEL);
+
+               if (pdata == NULL) {
+                       dev_err(card->dev, "failed to create private data\n");
+                       return -ENOMEM;
+               }
+
+               pdata->tvout_selection_gpio =
+                       of_get_named_gpio(np, "tvout-selection-gpios", 0);
+               pdata->jack_detection_gpio  =
+                       of_get_named_gpio(np, "jack-detection-gpios", 0);
+               pdata->eci_sw_gpio =
+                       of_get_named_gpio(np, "eci-switch-gpios", 0);
+               pdata->speaker_amp_gpio =
+                       of_get_named_gpio(np, "speaker-amplifier-gpios", 0);
+
+               dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "McBSP node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_dai[0].cpu_dai_name = NULL;
+               rx51_dai[0].cpu_of_node = dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,audio-codec", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "Codec node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_dai[0].codec_name = NULL;
+               rx51_dai[0].codec_of_node = dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,audio-codec", 1);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "Auxiliary Codec node is not 
provided\n");
+                       return -EINVAL;
+               }
+               rx51_aux_dev[0].codec_name = NULL;
+               rx51_aux_dev[0].codec_of_node = dai_node;
+               rx51_codec_conf[0].dev_name = NULL;
+               rx51_codec_conf[0].of_node = dai_node;
+
+               if (pdata->tvout_selection_gpio == -EPROBE_DEFER ||
+                   pdata->jack_detection_gpio == -EPROBE_DEFER ||
+                   pdata->eci_sw_gpio == -EPROBE_DEFER ||
+                   pdata->speaker_amp_gpio == -EPROBE_DEFER) {
+                       devm_kfree(card->dev, pdata);
+                       pdev->dev.platform_data = NULL;
+                       return -EPROBE_DEFER;
+               }
+
+               pdev->dev.platform_data = pdata;
+       } else if (!pdata) {
+               dev_err(card->dev, "platform data missing");
+               err = -ENODEV;
+               goto error;
+       }
+
+       err = devm_gpio_request_one(card->dev, pdata->tvout_selection_gpio,
                               GPIOF_DIR_OUT | GPIOF_INIT_LOW, "tvout_sel");
-       if (err)
-               goto err_gpio_tvout_sel;
-       err = gpio_request_one(RX51_ECI_SW_GPIO,
+       if (err) {
+               dev_err(card->dev, "could not setup tvout_sel\n");
+               goto error;
+       }
+       err = devm_gpio_request_one(card->dev, pdata->eci_sw_gpio,
                               GPIOF_DIR_OUT | GPIOF_INIT_HIGH, "eci_sw");
-       if (err)
-               goto err_gpio_eci_sw;
-
-       card->dev = &pdev->dev;
+       if (err) {
+               dev_err(card->dev, "could not setup eci_sw\n");
+               goto error;
+       }
+       err = devm_gpio_request_one(card->dev, pdata->speaker_amp_gpio,
+                              GPIOF_DIR_OUT | GPIOF_INIT_LOW, "speaker_en");
+       if (err) {
+               dev_err(card->dev, "could not setup speaker_en\n");
+               goto error;
+       }
 
+       snd_soc_card_set_drvdata(card, pdata);
        err = devm_snd_soc_register_card(card->dev, card);
        if (err) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err);
-               goto err_snd;
+               dev_err(card->dev, "snd_soc_register_card failed (%d)\n", err);
+               goto error;
        }
 
        return 0;
-err_snd:
+error:
        card->dev = NULL;
-       gpio_free(RX51_ECI_SW_GPIO);
-err_gpio_eci_sw:
-       gpio_free(RX51_TVOUT_SEL_GPIO);
-err_gpio_tvout_sel:
-
        return err;
 }
 
@@ -439,16 +524,23 @@ static int rx51_soc_remove(struct platform_device *pdev)
 
        card->dev = NULL;
 
-       gpio_free(RX51_ECI_SW_GPIO);
-       gpio_free(RX51_TVOUT_SEL_GPIO);
-
        return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id rx51_audio_of_match[] = {
+       { .compatible = "nokia,n900-audio", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rx51_audio_of_match);
+#endif
+
+
 static struct platform_driver rx51_soc_driver = {
        .driver = {
                .name = "rx51-audio",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(rx51_audio_of_match),
        },
        .probe = rx51_soc_probe,
        .remove = rx51_soc_remove,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to