diff options
Diffstat (limited to 'sound/soc/omap/omap-abe-twl6040.c')
-rw-r--r-- | sound/soc/omap/omap-abe-twl6040.c | 145 |
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 @@ | |||
25 | #include <linux/mfd/twl6040.h> | 25 | #include <linux/mfd/twl6040.h> |
26 | #include <linux/platform_data/omap-abe-twl6040.h> | 26 | #include <linux/platform_data/omap-abe-twl6040.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/of.h> | ||
28 | 29 | ||
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
@@ -43,6 +44,8 @@ | |||
43 | struct abe_twl6040 { | 44 | struct abe_twl6040 { |
44 | int jack_detection; /* board can detect jack events */ | 45 | int jack_detection; /* board can detect jack events */ |
45 | int mclk_freq; /* MCLK frequency speed for twl6040 */ | 46 | int mclk_freq; /* MCLK frequency speed for twl6040 */ |
47 | |||
48 | struct platform_device *dmic_codec_dev; | ||
46 | }; | 49 | }; |
47 | 50 | ||
48 | static int omap_abe_hw_params(struct snd_pcm_substream *substream, | 51 | 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) | |||
185 | int hs_trim; | 188 | int hs_trim; |
186 | int ret = 0; | 189 | int ret = 0; |
187 | 190 | ||
188 | /* Disable not connected paths if not used */ | ||
189 | twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); | ||
190 | twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); | ||
191 | twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); | ||
192 | twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); | ||
193 | twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); | ||
194 | twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); | ||
195 | twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); | ||
196 | twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); | ||
197 | twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); | ||
198 | |||
199 | /* | 191 | /* |
200 | * Configure McPDM offset cancellation based on the HSOTRIM value from | 192 | * Configure McPDM offset cancellation based on the HSOTRIM value from |
201 | * twl6040. | 193 | * twl6040. |
@@ -216,6 +208,24 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) | |||
216 | twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); | 208 | twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); |
217 | } | 209 | } |
218 | 210 | ||
211 | /* | ||
212 | * NULL pdata means we booted with DT. In this case the routing is | ||
213 | * provided and the card is fully routed, no need to mark pins. | ||
214 | */ | ||
215 | if (!pdata) | ||
216 | return ret; | ||
217 | |||
218 | /* Disable not connected paths if not used */ | ||
219 | twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); | ||
220 | twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); | ||
221 | twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); | ||
222 | twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); | ||
223 | twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); | ||
224 | twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); | ||
225 | twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); | ||
226 | twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); | ||
227 | twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); | ||
228 | |||
219 | return ret; | 229 | return ret; |
220 | } | 230 | } |
221 | 231 | ||
@@ -270,52 +280,116 @@ static struct snd_soc_card omap_abe_card = { | |||
270 | static __devinit int omap_abe_probe(struct platform_device *pdev) | 280 | static __devinit int omap_abe_probe(struct platform_device *pdev) |
271 | { | 281 | { |
272 | struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); | 282 | struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); |
283 | struct device_node *node = pdev->dev.of_node; | ||
273 | struct snd_soc_card *card = &omap_abe_card; | 284 | struct snd_soc_card *card = &omap_abe_card; |
274 | struct abe_twl6040 *priv; | 285 | struct abe_twl6040 *priv; |
275 | int num_links = 0; | 286 | int num_links = 0; |
276 | int ret; | 287 | int ret = 0; |
277 | 288 | ||
278 | card->dev = &pdev->dev; | 289 | card->dev = &pdev->dev; |
279 | 290 | ||
280 | if (!pdata) { | ||
281 | dev_err(&pdev->dev, "Missing pdata\n"); | ||
282 | return -ENODEV; | ||
283 | } | ||
284 | |||
285 | priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); | 291 | priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); |
286 | if (priv == NULL) | 292 | if (priv == NULL) |
287 | return -ENOMEM; | 293 | return -ENOMEM; |
288 | 294 | ||
289 | if (pdata->card_name) { | 295 | priv->dmic_codec_dev = ERR_PTR(-EINVAL); |
290 | card->name = pdata->card_name; | 296 | |
297 | if (node) { | ||
298 | struct device_node *dai_node; | ||
299 | |||
300 | if (snd_soc_of_parse_card_name(card, "ti,model")) { | ||
301 | dev_err(&pdev->dev, "Card name is not provided\n"); | ||
302 | return -ENODEV; | ||
303 | } | ||
304 | |||
305 | ret = snd_soc_of_parse_audio_routing(card, | ||
306 | "ti,audio-routing"); | ||
307 | if (ret) { | ||
308 | dev_err(&pdev->dev, | ||
309 | "Error while parsing DAPM routing\n"); | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | dai_node = of_parse_phandle(node, "ti,mcpdm", 0); | ||
314 | if (!dai_node) { | ||
315 | dev_err(&pdev->dev, "McPDM node is not provided\n"); | ||
316 | return -EINVAL; | ||
317 | } | ||
318 | abe_twl6040_dai_links[0].cpu_dai_name = NULL; | ||
319 | abe_twl6040_dai_links[0].cpu_of_node = dai_node; | ||
320 | |||
321 | dai_node = of_parse_phandle(node, "ti,dmic", 0); | ||
322 | if (dai_node) { | ||
323 | num_links = 2; | ||
324 | abe_twl6040_dai_links[1].cpu_dai_name = NULL; | ||
325 | abe_twl6040_dai_links[1].cpu_of_node = dai_node; | ||
326 | |||
327 | priv->dmic_codec_dev = platform_device_register_simple( | ||
328 | "dmic-codec", -1, NULL, 0); | ||
329 | if (IS_ERR(priv->dmic_codec_dev)) { | ||
330 | dev_err(&pdev->dev, | ||
331 | "Can't instantiate dmic-codec\n"); | ||
332 | return PTR_ERR(priv->dmic_codec_dev); | ||
333 | } | ||
334 | } else { | ||
335 | num_links = 1; | ||
336 | } | ||
337 | |||
338 | of_property_read_u32(node, "ti,jack-detection", | ||
339 | &priv->jack_detection); | ||
340 | of_property_read_u32(node, "ti,mclk-freq", | ||
341 | &priv->mclk_freq); | ||
342 | if (!priv->mclk_freq) { | ||
343 | dev_err(&pdev->dev, "MCLK frequency not provided\n"); | ||
344 | ret = -EINVAL; | ||
345 | goto err_unregister; | ||
346 | } | ||
347 | |||
348 | omap_abe_card.fully_routed = 1; | ||
349 | } else if (pdata) { | ||
350 | if (pdata->card_name) { | ||
351 | card->name = pdata->card_name; | ||
352 | } else { | ||
353 | dev_err(&pdev->dev, "Card name is not provided\n"); | ||
354 | return -ENODEV; | ||
355 | } | ||
356 | |||
357 | if (pdata->has_dmic) | ||
358 | num_links = 2; | ||
359 | else | ||
360 | num_links = 1; | ||
361 | |||
362 | priv->jack_detection = pdata->jack_detection; | ||
363 | priv->mclk_freq = pdata->mclk_freq; | ||
291 | } else { | 364 | } else { |
292 | dev_err(&pdev->dev, "Card name is not provided\n"); | 365 | dev_err(&pdev->dev, "Missing pdata\n"); |
293 | return -ENODEV; | 366 | return -ENODEV; |
294 | } | 367 | } |
295 | 368 | ||
296 | priv->jack_detection = pdata->jack_detection; | ||
297 | priv->mclk_freq = pdata->mclk_freq; | ||
298 | |||
299 | 369 | ||
300 | if (!priv->mclk_freq) { | 370 | if (!priv->mclk_freq) { |
301 | dev_err(&pdev->dev, "MCLK frequency missing\n"); | 371 | dev_err(&pdev->dev, "MCLK frequency missing\n"); |
302 | return -ENODEV; | 372 | ret = -ENODEV; |
373 | goto err_unregister; | ||
303 | } | 374 | } |
304 | 375 | ||
305 | if (pdata->has_dmic) | ||
306 | num_links = 2; | ||
307 | else | ||
308 | num_links = 1; | ||
309 | |||
310 | card->dai_link = abe_twl6040_dai_links; | 376 | card->dai_link = abe_twl6040_dai_links; |
311 | card->num_links = num_links; | 377 | card->num_links = num_links; |
312 | 378 | ||
313 | snd_soc_card_set_drvdata(card, priv); | 379 | snd_soc_card_set_drvdata(card, priv); |
314 | 380 | ||
315 | ret = snd_soc_register_card(card); | 381 | ret = snd_soc_register_card(card); |
316 | if (ret) | 382 | if (ret) { |
317 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | 383 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", |
318 | ret); | 384 | ret); |
385 | goto err_unregister; | ||
386 | } | ||
387 | |||
388 | return 0; | ||
389 | |||
390 | err_unregister: | ||
391 | if (!IS_ERR(priv->dmic_codec_dev)) | ||
392 | platform_device_unregister(priv->dmic_codec_dev); | ||
319 | 393 | ||
320 | return ret; | 394 | return ret; |
321 | } | 395 | } |
@@ -323,17 +397,28 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) | |||
323 | static int __devexit omap_abe_remove(struct platform_device *pdev) | 397 | static int __devexit omap_abe_remove(struct platform_device *pdev) |
324 | { | 398 | { |
325 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 399 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
400 | struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); | ||
326 | 401 | ||
327 | snd_soc_unregister_card(card); | 402 | snd_soc_unregister_card(card); |
328 | 403 | ||
404 | if (!IS_ERR(priv->dmic_codec_dev)) | ||
405 | platform_device_unregister(priv->dmic_codec_dev); | ||
406 | |||
329 | return 0; | 407 | return 0; |
330 | } | 408 | } |
331 | 409 | ||
410 | static const struct of_device_id omap_abe_of_match[] = { | ||
411 | {.compatible = "ti,abe-twl6040", }, | ||
412 | { }, | ||
413 | }; | ||
414 | MODULE_DEVICE_TABLE(of, omap_abe_of_match); | ||
415 | |||
332 | static struct platform_driver omap_abe_driver = { | 416 | static struct platform_driver omap_abe_driver = { |
333 | .driver = { | 417 | .driver = { |
334 | .name = "omap-abe-twl6040", | 418 | .name = "omap-abe-twl6040", |
335 | .owner = THIS_MODULE, | 419 | .owner = THIS_MODULE, |
336 | .pm = &snd_soc_pm_ops, | 420 | .pm = &snd_soc_pm_ops, |
421 | .of_match_table = omap_abe_of_match, | ||
337 | }, | 422 | }, |
338 | .probe = omap_abe_probe, | 423 | .probe = omap_abe_probe, |
339 | .remove = __devexit_p(omap_abe_remove), | 424 | .remove = __devexit_p(omap_abe_remove), |