summaryrefslogtreecommitdiffstats
path: root/sound/soc/omap/omap-abe-twl6040.c
diff options
context:
space:
mode:
authorPeter Ujfalusi2012-07-25 15:09:11 +0200
committerMark Brown2012-08-04 00:03:56 +0200
commit5ef75e710b4950439f953c4897e4a871c2f9dc8f (patch)
treedb66cba26297ae7906882e0ce889a4c88fe186b0 /sound/soc/omap/omap-abe-twl6040.c
parentASoC: ux500: Strengthen error checking after memory allocation (diff)
downloadkernel-qcow2-linux-5ef75e710b4950439f953c4897e4a871c2f9dc8f.tar.gz
kernel-qcow2-linux-5ef75e710b4950439f953c4897e4a871c2f9dc8f.tar.xz
kernel-qcow2-linux-5ef75e710b4950439f953c4897e4a871c2f9dc8f.zip
ASoC: omap-abe-twl6040: Add device tree support
When the board boots with device tree the driver will receive the name of the card, DAPM routing map, phandle for the audio components described in the dts file, mclk speed, and the possibility of detecting the jack detection. The card will be set up based on this information. Since the routing is provided via DT we can mark the card fully routed so core can take care of disconnecting the unused pins. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Reviwed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/omap/omap-abe-twl6040.c')
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c145
1 files changed, 115 insertions, 30 deletions
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 9d93793d3077..be525dfe9faa 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -25,6 +25,7 @@
#include <linux/mfd/twl6040.h>
#include <linux/platform_data/omap-abe-twl6040.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -43,6 +44,8 @@
struct abe_twl6040 {
int jack_detection; /* board can detect jack events */
int mclk_freq; /* MCLK frequency speed for twl6040 */
+
+ struct platform_device *dmic_codec_dev;
};
static int omap_abe_hw_params(struct snd_pcm_substream *substream,
@@ -185,17 +188,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
int hs_trim;
int ret = 0;
- /* Disable not connected paths if not used */
- twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
- twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
- twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
- twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
- twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
- twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
- twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
- twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
- twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
-
/*
* Configure McPDM offset cancellation based on the HSOTRIM value from
* twl6040.
@@ -216,6 +208,24 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
}
+ /*
+ * NULL pdata means we booted with DT. In this case the routing is
+ * provided and the card is fully routed, no need to mark pins.
+ */
+ if (!pdata)
+ return ret;
+
+ /* Disable not connected paths if not used */
+ twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
+ twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
+ twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
+ twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
+ twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
+ twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
+ twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
+ twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
+ twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
+
return ret;
}
@@ -270,52 +280,116 @@ static struct snd_soc_card omap_abe_card = {
static __devinit int omap_abe_probe(struct platform_device *pdev)
{
struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device_node *node = pdev->dev.of_node;
struct snd_soc_card *card = &omap_abe_card;
struct abe_twl6040 *priv;
int num_links = 0;
- int ret;
+ int ret = 0;
card->dev = &pdev->dev;
- if (!pdata) {
- dev_err(&pdev->dev, "Missing pdata\n");
- return -ENODEV;
- }
-
priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
- if (pdata->card_name) {
- card->name = pdata->card_name;
+ priv->dmic_codec_dev = ERR_PTR(-EINVAL);
+
+ if (node) {
+ struct device_node *dai_node;
+
+ if (snd_soc_of_parse_card_name(card, "ti,model")) {
+ dev_err(&pdev->dev, "Card name is not provided\n");
+ return -ENODEV;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card,
+ "ti,audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Error while parsing DAPM routing\n");
+ return ret;
+ }
+
+ dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
+ if (!dai_node) {
+ dev_err(&pdev->dev, "McPDM node is not provided\n");
+ return -EINVAL;
+ }
+ abe_twl6040_dai_links[0].cpu_dai_name = NULL;
+ abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+
+ dai_node = of_parse_phandle(node, "ti,dmic", 0);
+ if (dai_node) {
+ num_links = 2;
+ abe_twl6040_dai_links[1].cpu_dai_name = NULL;
+ abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+
+ priv->dmic_codec_dev = platform_device_register_simple(
+ "dmic-codec", -1, NULL, 0);
+ if (IS_ERR(priv->dmic_codec_dev)) {
+ dev_err(&pdev->dev,
+ "Can't instantiate dmic-codec\n");
+ return PTR_ERR(priv->dmic_codec_dev);
+ }
+ } else {
+ num_links = 1;
+ }
+
+ of_property_read_u32(node, "ti,jack-detection",
+ &priv->jack_detection);
+ of_property_read_u32(node, "ti,mclk-freq",
+ &priv->mclk_freq);
+ if (!priv->mclk_freq) {
+ dev_err(&pdev->dev, "MCLK frequency not provided\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+
+ omap_abe_card.fully_routed = 1;
+ } else if (pdata) {
+ if (pdata->card_name) {
+ card->name = pdata->card_name;
+ } else {
+ dev_err(&pdev->dev, "Card name is not provided\n");
+ return -ENODEV;
+ }
+
+ if (pdata->has_dmic)
+ num_links = 2;
+ else
+ num_links = 1;
+
+ priv->jack_detection = pdata->jack_detection;
+ priv->mclk_freq = pdata->mclk_freq;
} else {
- dev_err(&pdev->dev, "Card name is not provided\n");
+ dev_err(&pdev->dev, "Missing pdata\n");
return -ENODEV;
}
- priv->jack_detection = pdata->jack_detection;
- priv->mclk_freq = pdata->mclk_freq;
-
if (!priv->mclk_freq) {
dev_err(&pdev->dev, "MCLK frequency missing\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_unregister;
}
- if (pdata->has_dmic)
- num_links = 2;
- else
- num_links = 1;
-
card->dai_link = abe_twl6040_dai_links;
card->num_links = num_links;
snd_soc_card_set_drvdata(card, priv);
ret = snd_soc_register_card(card);
- if (ret)
+ if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
ret);
+ goto err_unregister;
+ }
+
+ return 0;
+
+err_unregister:
+ if (!IS_ERR(priv->dmic_codec_dev))
+ platform_device_unregister(priv->dmic_codec_dev);
return ret;
}
@@ -323,17 +397,28 @@ static __devinit int omap_abe_probe(struct platform_device *pdev)
static int __devexit omap_abe_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
snd_soc_unregister_card(card);
+ if (!IS_ERR(priv->dmic_codec_dev))
+ platform_device_unregister(priv->dmic_codec_dev);
+
return 0;
}
+static const struct of_device_id omap_abe_of_match[] = {
+ {.compatible = "ti,abe-twl6040", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, omap_abe_of_match);
+
static struct platform_driver omap_abe_driver = {
.driver = {
.name = "omap-abe-twl6040",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
+ .of_match_table = omap_abe_of_match,
},
.probe = omap_abe_probe,
.remove = __devexit_p(omap_abe_remove),