aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8994.c
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-03-17 16:15:21 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:00 -0400
commitf0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch)
treef6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/codecs/wm8994.c
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
ASoC: multi-component - ASoC Multi-Component Support
This patch extends the ASoC API to allow sound cards to have more than one CODEC and more than one platform DMA controller. This is achieved by dividing some current ASoC structures that contain both driver data and device data into structures that only either contain device data or driver data. i.e. struct snd_soc_codec ---> struct snd_soc_codec (device data) +-> struct snd_soc_codec_driver (driver data) struct snd_soc_platform ---> struct snd_soc_platform (device data) +-> struct snd_soc_platform_driver (driver data) struct snd_soc_dai ---> struct snd_soc_dai (device data) +-> struct snd_soc_dai_driver (driver data) struct snd_soc_device ---> deleted This now allows ASoC to be more tightly aligned with the Linux driver model and also means that every ASoC codec, platform and (platform) DAI is a kernel device. ASoC component private data is now stored as device private data. The ASoC sound card struct snd_soc_card has also been updated to store lists of it's components rather than a pointer to a codec and platform. The PCM runtime struct soc_pcm_runtime now has pointers to all its components. This patch adds DAPM support for ASoC multi-component and removes struct snd_soc_socdev from DAPM core. All DAPM calls are now made on a card, codec or runtime PCM level basis rather than using snd_soc_socdev. Other notable multi-component changes:- * Stream operations now de-reference less structures. * close_delayed work() now runs on a DAI basis rather than looping all DAIs in a card. * PM suspend()/resume() operations can now handle N CODECs and Platforms per sound card. * Added soc_bind_dai_link() to bind the component devices to the sound card. * Added soc_dai_link_probe() and soc_dai_link_remove() to probe and remove DAI link components. * sysfs entries can now be registered per component per card. * snd_soc_new_pcms() functionailty rolled into dai_link_probe(). * snd_soc_register_codec() now does all the codec list and mutex init. This patch changes the probe() and remove() of the CODEC drivers as follows:- o Make CODEC driver a platform driver o Moved all struct snd_soc_codec list, mutex, etc initialiasation to core. o Removed all static codec pointers (drivers now support > 1 codec dev) o snd_soc_register_pcms() now done by core. o snd_soc_register_dai() folded into snd_soc_register_codec(). CS4270 portions: Acked-by: Timur Tabi <timur@freescale.com> Some TLV320aic23 and Cirrus platform fixes. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> TI CODEC and OMAP fixes Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Samsung platform and misc fixes :- Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Seungwhan Youn <sw.youn@samsung.com> MPC8610 and PPC fixes. Signed-off-by: Timur Tabi <timur@freescale.com> i.MX fixes and some core fixes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> J4740 platform fixes:- Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> CC: Tony Lindgren <tony@atomide.com> CC: Nicolas Ferre <nicolas.ferre@atmel.com> CC: Kevin Hilman <khilman@deeprootsystems.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Atsushi Nemoto <anemo@mba.ocn.ne.jp> CC: Kuninori Morimoto <morimoto.kuninori@renesas.com> CC: Daniel Gloeckner <dg@emlix.com> CC: Manuel Lauss <mano@roarinelk.homelinux.net> CC: Mike Frysinger <vapier.adi@gmail.com> CC: Arnaud Patard <apatard@mandriva.com> CC: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r--sound/soc/codecs/wm8994.c230
1 files changed, 77 insertions, 153 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index a87046a96f2a..7823f92413f3 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -36,9 +36,6 @@
36#include "wm8994.h" 36#include "wm8994.h"
37#include "wm_hubs.h" 37#include "wm_hubs.h"
38 38
39static struct snd_soc_codec *wm8994_codec;
40struct snd_soc_codec_device soc_codec_dev_wm8994;
41
42struct fll_config { 39struct fll_config {
43 int src; 40 int src;
44 int in; 41 int in;
@@ -71,7 +68,9 @@ struct wm8994_micdet {
71/* codec private data */ 68/* codec private data */
72struct wm8994_priv { 69struct wm8994_priv {
73 struct wm_hubs_data hubs; 70 struct wm_hubs_data hubs;
74 struct snd_soc_codec codec; 71 enum snd_soc_control_type control_type;
72 void *control_data;
73 struct snd_soc_codec *codec;
75 u16 reg_cache[WM8994_REG_CACHE_SIZE + 1]; 74 u16 reg_cache[WM8994_REG_CACHE_SIZE + 1];
76 int sysclk[2]; 75 int sysclk[2];
77 int sysclk_rate[2]; 76 int sysclk_rate[2];
@@ -1901,8 +1900,6 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
1901 return snd_soc_put_volsw(kcontrol, ucontrol); 1900 return snd_soc_put_volsw(kcontrol, ucontrol);
1902} 1901}
1903 1902
1904
1905
1906static void wm8994_set_drc(struct snd_soc_codec *codec, int drc) 1903static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
1907{ 1904{
1908 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 1905 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1941,7 +1938,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
1941 struct snd_ctl_elem_value *ucontrol) 1938 struct snd_ctl_elem_value *ucontrol)
1942{ 1939{
1943 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 1940 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1944 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 1941 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
1945 struct wm8994_pdata *pdata = wm8994->pdata; 1942 struct wm8994_pdata *pdata = wm8994->pdata;
1946 int drc = wm8994_get_drc(kcontrol->id.name); 1943 int drc = wm8994_get_drc(kcontrol->id.name);
1947 int value = ucontrol->value.integer.value[0]; 1944 int value = ucontrol->value.integer.value[0];
@@ -2044,7 +2041,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
2044 struct snd_ctl_elem_value *ucontrol) 2041 struct snd_ctl_elem_value *ucontrol)
2045{ 2042{
2046 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 2043 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2047 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 2044 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
2048 struct wm8994_pdata *pdata = wm8994->pdata; 2045 struct wm8994_pdata *pdata = wm8994->pdata;
2049 int block = wm8994_get_retune_mobile_block(kcontrol->id.name); 2046 int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
2050 int value = ucontrol->value.integer.value[0]; 2047 int value = ucontrol->value.integer.value[0];
@@ -2066,7 +2063,7 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
2066 struct snd_ctl_elem_value *ucontrol) 2063 struct snd_ctl_elem_value *ucontrol)
2067{ 2064{
2068 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 2065 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2069 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 2066 struct wm8994_priv *wm8994 =snd_soc_codec_get_drvdata(codec);
2070 int block = wm8994_get_retune_mobile_block(kcontrol->id.name); 2067 int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
2071 2068
2072 ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block]; 2069 ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
@@ -2880,10 +2877,9 @@ static int wm8994_get_fll_config(struct fll_div *fll,
2880 return 0; 2877 return 0;
2881} 2878}
2882 2879
2883static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, 2880static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
2884 unsigned int freq_in, unsigned int freq_out) 2881 unsigned int freq_in, unsigned int freq_out)
2885{ 2882{
2886 struct snd_soc_codec *codec = dai->codec;
2887 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 2883 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
2888 int reg_offset, ret; 2884 int reg_offset, ret;
2889 struct fll_div fll; 2885 struct fll_div fll;
@@ -2994,8 +2990,15 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
2994 return 0; 2990 return 0;
2995} 2991}
2996 2992
2993
2997static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; 2994static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
2998 2995
2996static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
2997 unsigned int freq_in, unsigned int freq_out)
2998{
2999 return _wm8994_set_fll(dai->codec, id, src, freq_in, freq_out);
3000}
3001
2999static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, 3002static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
3000 int clk_id, unsigned int freq, int dir) 3003 int clk_id, unsigned int freq, int dir)
3001{ 3004{
@@ -3507,10 +3510,9 @@ static struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
3507 .set_tristate = wm8994_set_tristate, 3510 .set_tristate = wm8994_set_tristate,
3508}; 3511};
3509 3512
3510struct snd_soc_dai wm8994_dai[] = { 3513static struct snd_soc_dai_driver wm8994_dai[] = {
3511 { 3514 {
3512 .name = "WM8994 AIF1", 3515 .name = "wm8994-aif1",
3513 .id = 1,
3514 .playback = { 3516 .playback = {
3515 .stream_name = "AIF1 Playback", 3517 .stream_name = "AIF1 Playback",
3516 .channels_min = 2, 3518 .channels_min = 2,
@@ -3528,8 +3530,7 @@ struct snd_soc_dai wm8994_dai[] = {
3528 .ops = &wm8994_aif1_dai_ops, 3530 .ops = &wm8994_aif1_dai_ops,
3529 }, 3531 },
3530 { 3532 {
3531 .name = "WM8994 AIF2", 3533 .name = "wm8994-aif2",
3532 .id = 2,
3533 .playback = { 3534 .playback = {
3534 .stream_name = "AIF2 Playback", 3535 .stream_name = "AIF2 Playback",
3535 .channels_min = 2, 3536 .channels_min = 2,
@@ -3547,8 +3548,7 @@ struct snd_soc_dai wm8994_dai[] = {
3547 .ops = &wm8994_aif2_dai_ops, 3548 .ops = &wm8994_aif2_dai_ops,
3548 }, 3549 },
3549 { 3550 {
3550 .name = "WM8994 AIF3", 3551 .name = "wm8994-aif3",
3551 .id = 3,
3552 .playback = { 3552 .playback = {
3553 .stream_name = "AIF3 Playback", 3553 .stream_name = "AIF3 Playback",
3554 .channels_min = 2, 3554 .channels_min = 2,
@@ -3566,20 +3566,17 @@ struct snd_soc_dai wm8994_dai[] = {
3566 .ops = &wm8994_aif3_dai_ops, 3566 .ops = &wm8994_aif3_dai_ops,
3567 } 3567 }
3568}; 3568};
3569EXPORT_SYMBOL_GPL(wm8994_dai);
3570 3569
3571#ifdef CONFIG_PM 3570#ifdef CONFIG_PM
3572static int wm8994_suspend(struct platform_device *pdev, pm_message_t state) 3571static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
3573{ 3572{
3574 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
3575 struct snd_soc_codec *codec = socdev->card->codec;
3576 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 3573 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
3577 int i, ret; 3574 int i, ret;
3578 3575
3579 for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { 3576 for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
3580 memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], 3577 memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
3581 sizeof(struct fll_config)); 3578 sizeof(struct fll_config));
3582 ret = wm8994_set_fll(&codec->dai[0], i + 1, 0, 0, 0); 3579 ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
3583 if (ret < 0) 3580 if (ret < 0)
3584 dev_warn(codec->dev, "Failed to stop FLL%d: %d\n", 3581 dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
3585 i + 1, ret); 3582 i + 1, ret);
@@ -3590,10 +3587,8 @@ static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
3590 return 0; 3587 return 0;
3591} 3588}
3592 3589
3593static int wm8994_resume(struct platform_device *pdev) 3590static int wm8994_resume(struct snd_soc_codec *codec)
3594{ 3591{
3595 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
3596 struct snd_soc_codec *codec = socdev->card->codec;
3597 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 3592 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
3598 u16 *reg_cache = codec->reg_cache; 3593 u16 *reg_cache = codec->reg_cache;
3599 int i, ret; 3594 int i, ret;
@@ -3622,7 +3617,7 @@ static int wm8994_resume(struct platform_device *pdev)
3622 if (!wm8994->fll_suspend[i].out) 3617 if (!wm8994->fll_suspend[i].out)
3623 continue; 3618 continue;
3624 3619
3625 ret = wm8994_set_fll(&codec->dai[0], i + 1, 3620 ret = _wm8994_set_fll(codec, i + 1,
3626 wm8994->fll_suspend[i].src, 3621 wm8994->fll_suspend[i].src,
3627 wm8994->fll_suspend[i].in, 3622 wm8994->fll_suspend[i].in,
3628 wm8994->fll_suspend[i].out); 3623 wm8994->fll_suspend[i].out);
@@ -3640,7 +3635,7 @@ static int wm8994_resume(struct platform_device *pdev)
3640 3635
3641static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) 3636static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
3642{ 3637{
3643 struct snd_soc_codec *codec = &wm8994->codec; 3638 struct snd_soc_codec *codec = wm8994->codec;
3644 struct wm8994_pdata *pdata = wm8994->pdata; 3639 struct wm8994_pdata *pdata = wm8994->pdata;
3645 struct snd_kcontrol_new controls[] = { 3640 struct snd_kcontrol_new controls[] = {
3646 SOC_ENUM_EXT("AIF1.1 EQ Mode", 3641 SOC_ENUM_EXT("AIF1.1 EQ Mode",
@@ -3698,16 +3693,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
3698 wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; 3693 wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
3699 wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; 3694 wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
3700 3695
3701 ret = snd_soc_add_controls(&wm8994->codec, controls, 3696 ret = snd_soc_add_controls(wm8994->codec, controls,
3702 ARRAY_SIZE(controls)); 3697 ARRAY_SIZE(controls));
3703 if (ret != 0) 3698 if (ret != 0)
3704 dev_err(wm8994->codec.dev, 3699 dev_err(wm8994->codec->dev,
3705 "Failed to add ReTune Mobile controls: %d\n", ret); 3700 "Failed to add ReTune Mobile controls: %d\n", ret);
3706} 3701}
3707 3702
3708static void wm8994_handle_pdata(struct wm8994_priv *wm8994) 3703static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
3709{ 3704{
3710 struct snd_soc_codec *codec = &wm8994->codec; 3705 struct snd_soc_codec *codec = wm8994->codec;
3711 struct wm8994_pdata *pdata = wm8994->pdata; 3706 struct wm8994_pdata *pdata = wm8994->pdata;
3712 int ret, i; 3707 int ret, i;
3713 3708
@@ -3739,7 +3734,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
3739 wm8994->drc_texts = kmalloc(sizeof(char *) 3734 wm8994->drc_texts = kmalloc(sizeof(char *)
3740 * pdata->num_drc_cfgs, GFP_KERNEL); 3735 * pdata->num_drc_cfgs, GFP_KERNEL);
3741 if (!wm8994->drc_texts) { 3736 if (!wm8994->drc_texts) {
3742 dev_err(wm8994->codec.dev, 3737 dev_err(wm8994->codec->dev,
3743 "Failed to allocate %d DRC config texts\n", 3738 "Failed to allocate %d DRC config texts\n",
3744 pdata->num_drc_cfgs); 3739 pdata->num_drc_cfgs);
3745 return; 3740 return;
@@ -3751,10 +3746,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
3751 wm8994->drc_enum.max = pdata->num_drc_cfgs; 3746 wm8994->drc_enum.max = pdata->num_drc_cfgs;
3752 wm8994->drc_enum.texts = wm8994->drc_texts; 3747 wm8994->drc_enum.texts = wm8994->drc_texts;
3753 3748
3754 ret = snd_soc_add_controls(&wm8994->codec, controls, 3749 ret = snd_soc_add_controls(wm8994->codec, controls,
3755 ARRAY_SIZE(controls)); 3750 ARRAY_SIZE(controls));
3756 if (ret != 0) 3751 if (ret != 0)
3757 dev_err(wm8994->codec.dev, 3752 dev_err(wm8994->codec->dev,
3758 "Failed to add DRC mode controls: %d\n", ret); 3753 "Failed to add DRC mode controls: %d\n", ret);
3759 3754
3760 for (i = 0; i < WM8994_NUM_DRC; i++) 3755 for (i = 0; i < WM8994_NUM_DRC; i++)
@@ -3767,62 +3762,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
3767 if (pdata->num_retune_mobile_cfgs) 3762 if (pdata->num_retune_mobile_cfgs)
3768 wm8994_handle_retune_mobile_pdata(wm8994); 3763 wm8994_handle_retune_mobile_pdata(wm8994);
3769 else 3764 else
3770 snd_soc_add_controls(&wm8994->codec, wm8994_eq_controls, 3765 snd_soc_add_controls(wm8994->codec, wm8994_eq_controls,
3771 ARRAY_SIZE(wm8994_eq_controls)); 3766 ARRAY_SIZE(wm8994_eq_controls));
3772} 3767}
3773 3768
3774static int wm8994_probe(struct platform_device *pdev)
3775{
3776 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
3777 struct snd_soc_codec *codec;
3778 int ret = 0;
3779
3780 if (wm8994_codec == NULL) {
3781 dev_err(&pdev->dev, "Codec device not registered\n");
3782 return -ENODEV;
3783 }
3784
3785 socdev->card->codec = wm8994_codec;
3786 codec = wm8994_codec;
3787
3788 /* register pcms */
3789 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
3790 if (ret < 0) {
3791 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
3792 return ret;
3793 }
3794
3795 wm8994_handle_pdata(snd_soc_codec_get_drvdata(codec));
3796
3797 wm_hubs_add_analogue_controls(codec);
3798 snd_soc_add_controls(codec, wm8994_snd_controls,
3799 ARRAY_SIZE(wm8994_snd_controls));
3800 snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
3801 ARRAY_SIZE(wm8994_dapm_widgets));
3802 wm_hubs_add_analogue_routes(codec, 0, 0);
3803 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
3804
3805 return 0;
3806}
3807
3808static int wm8994_remove(struct platform_device *pdev)
3809{
3810 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
3811
3812 snd_soc_free_pcms(socdev);
3813 snd_soc_dapm_free(socdev);
3814
3815 return 0;
3816}
3817
3818struct snd_soc_codec_device soc_codec_dev_wm8994 = {
3819 .probe = wm8994_probe,
3820 .remove = wm8994_remove,
3821 .suspend = wm8994_suspend,
3822 .resume = wm8994_resume,
3823};
3824EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
3825
3826/** 3769/**
3827 * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ 3770 * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
3828 * 3771 *
@@ -3881,7 +3824,7 @@ EXPORT_SYMBOL_GPL(wm8994_mic_detect);
3881static irqreturn_t wm8994_mic_irq(int irq, void *data) 3824static irqreturn_t wm8994_mic_irq(int irq, void *data)
3882{ 3825{
3883 struct wm8994_priv *priv = data; 3826 struct wm8994_priv *priv = data;
3884 struct snd_soc_codec *codec = &priv->codec; 3827 struct snd_soc_codec *codec = priv->codec;
3885 int reg; 3828 int reg;
3886 int report; 3829 int report;
3887 3830
@@ -3913,47 +3856,20 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
3913 return IRQ_HANDLED; 3856 return IRQ_HANDLED;
3914} 3857}
3915 3858
3916static int wm8994_codec_probe(struct platform_device *pdev) 3859static int wm8994_codec_probe(struct snd_soc_codec *codec)
3917{ 3860{
3918 int ret;
3919 struct wm8994_priv *wm8994; 3861 struct wm8994_priv *wm8994;
3920 struct snd_soc_codec *codec; 3862 int ret, i, rev;
3921 int i;
3922 u16 rev;
3923 3863
3924 if (wm8994_codec) { 3864 codec->control_data = dev_get_drvdata(codec->dev->parent);
3925 dev_err(&pdev->dev, "Another WM8994 is registered\n");
3926 return -EINVAL;
3927 }
3928 3865
3929 wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL); 3866 wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL);
3930 if (!wm8994) { 3867 if (wm8994 == NULL)
3931 dev_err(&pdev->dev, "Failed to allocate private data\n");
3932 return -ENOMEM; 3868 return -ENOMEM;
3933 }
3934
3935 codec = &wm8994->codec;
3936
3937 mutex_init(&codec->mutex);
3938 INIT_LIST_HEAD(&codec->dapm_widgets);
3939 INIT_LIST_HEAD(&codec->dapm_paths);
3940
3941 snd_soc_codec_set_drvdata(codec, wm8994); 3869 snd_soc_codec_set_drvdata(codec, wm8994);
3942 codec->control_data = dev_get_drvdata(pdev->dev.parent); 3870
3943 codec->name = "WM8994"; 3871 wm8994->pdata = dev_get_platdata(codec->dev->parent);
3944 codec->owner = THIS_MODULE; 3872 wm8994->codec = codec;
3945 codec->read = wm8994_read;
3946 codec->write = wm8994_write;
3947 codec->readable_register = wm8994_readable;
3948 codec->bias_level = SND_SOC_BIAS_OFF;
3949 codec->set_bias_level = wm8994_set_bias_level;
3950 codec->dai = &wm8994_dai[0];
3951 codec->num_dai = 3;
3952 codec->reg_cache_size = WM8994_MAX_REGISTER;
3953 codec->reg_cache = &wm8994->reg_cache;
3954 codec->dev = &pdev->dev;
3955
3956 wm8994->pdata = pdev->dev.parent->platform_data;
3957 3873
3958 /* Fill the cache with physical values we inherited; don't reset */ 3874 /* Fill the cache with physical values we inherited; don't reset */
3959 ret = wm8994_bulk_read(codec->control_data, 0, 3875 ret = wm8994_bulk_read(codec->control_data, 0,
@@ -3989,25 +3905,25 @@ static int wm8994_codec_probe(struct platform_device *pdev)
3989 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET, 3905 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
3990 wm8994_mic_irq, "Mic 1 detect", wm8994); 3906 wm8994_mic_irq, "Mic 1 detect", wm8994);
3991 if (ret != 0) 3907 if (ret != 0)
3992 dev_warn(&pdev->dev, 3908 dev_warn(codec->dev,
3993 "Failed to request Mic1 detect IRQ: %d\n", ret); 3909 "Failed to request Mic1 detect IRQ: %d\n", ret);
3994 3910
3995 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, 3911 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
3996 wm8994_mic_irq, "Mic 1 short", wm8994); 3912 wm8994_mic_irq, "Mic 1 short", wm8994);
3997 if (ret != 0) 3913 if (ret != 0)
3998 dev_warn(&pdev->dev, 3914 dev_warn(codec->dev,
3999 "Failed to request Mic1 short IRQ: %d\n", ret); 3915 "Failed to request Mic1 short IRQ: %d\n", ret);
4000 3916
4001 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET, 3917 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
4002 wm8994_mic_irq, "Mic 2 detect", wm8994); 3918 wm8994_mic_irq, "Mic 2 detect", wm8994);
4003 if (ret != 0) 3919 if (ret != 0)
4004 dev_warn(&pdev->dev, 3920 dev_warn(codec->dev,
4005 "Failed to request Mic2 detect IRQ: %d\n", ret); 3921 "Failed to request Mic2 detect IRQ: %d\n", ret);
4006 3922
4007 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, 3923 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
4008 wm8994_mic_irq, "Mic 2 short", wm8994); 3924 wm8994_mic_irq, "Mic 2 short", wm8994);
4009 if (ret != 0) 3925 if (ret != 0)
4010 dev_warn(&pdev->dev, 3926 dev_warn(codec->dev,
4011 "Failed to request Mic2 short IRQ: %d\n", ret); 3927 "Failed to request Mic2 short IRQ: %d\n", ret);
4012 3928
4013 /* Remember if AIFnLRCLK is configured as a GPIO. This should be 3929 /* Remember if AIFnLRCLK is configured as a GPIO. This should be
@@ -4038,13 +3954,8 @@ static int wm8994_codec_probe(struct platform_device *pdev)
4038 wm8994->lrclk_shared[1] = 0; 3954 wm8994->lrclk_shared[1] = 0;
4039 } 3955 }
4040 3956
4041 for (i = 0; i < ARRAY_SIZE(wm8994_dai); i++)
4042 wm8994_dai[i].dev = codec->dev;
4043
4044 wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 3957 wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
4045 3958
4046 wm8994_codec = codec;
4047
4048 /* Latch volume updates (right only; we always do left then right). */ 3959 /* Latch volume updates (right only; we always do left then right). */
4049 snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, 3960 snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME,
4050 WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); 3961 WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU);
@@ -4081,24 +3992,18 @@ static int wm8994_codec_probe(struct platform_device *pdev)
4081 3992
4082 wm8994_update_class_w(codec); 3993 wm8994_update_class_w(codec);
4083 3994
4084 ret = snd_soc_register_codec(codec); 3995 wm8994_handle_pdata(wm8994);
4085 if (ret != 0) {
4086 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
4087 goto err_irq;
4088 }
4089
4090 ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
4091 if (ret != 0) {
4092 dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
4093 goto err_codec;
4094 }
4095 3996
4096 platform_set_drvdata(pdev, wm8994); 3997 wm_hubs_add_analogue_controls(codec);
3998 snd_soc_add_controls(codec, wm8994_snd_controls,
3999 ARRAY_SIZE(wm8994_snd_controls));
4000 snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
4001 ARRAY_SIZE(wm8994_dapm_widgets));
4002 wm_hubs_add_analogue_routes(codec, 0, 0);
4003 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
4097 4004
4098 return 0; 4005 return 0;
4099 4006
4100err_codec:
4101 snd_soc_unregister_codec(codec);
4102err_irq: 4007err_irq:
4103 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994); 4008 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
4104 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994); 4009 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
@@ -4109,31 +4014,50 @@ err:
4109 return ret; 4014 return ret;
4110} 4015}
4111 4016
4112static int __devexit wm8994_codec_remove(struct platform_device *pdev) 4017static int wm8994_codec_remove(struct snd_soc_codec *codec)
4113{ 4018{
4114 struct wm8994_priv *wm8994 = platform_get_drvdata(pdev); 4019 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
4115 struct snd_soc_codec *codec = &wm8994->codec;
4116 4020
4117 wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); 4021 wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
4118 snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); 4022
4119 snd_soc_unregister_codec(&wm8994->codec);
4120 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994); 4023 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
4121 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994); 4024 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
4122 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); 4025 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
4123 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994); 4026 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
4124 kfree(wm8994); 4027 kfree(wm8994);
4125 wm8994_codec = NULL;
4126 4028
4127 return 0; 4029 return 0;
4128} 4030}
4129 4031
4032static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
4033 .probe = wm8994_codec_probe,
4034 .remove = wm8994_codec_remove,
4035 .suspend = wm8994_suspend,
4036 .resume = wm8994_resume,
4037 .read = wm8994_read,
4038 .write = wm8994_write,
4039 .set_bias_level = wm8994_set_bias_level,
4040};
4041
4042static int __devinit wm8994_probe(struct platform_device *pdev)
4043{
4044 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
4045 wm8994_dai, ARRAY_SIZE(wm8994_dai));
4046}
4047
4048static int __devexit wm8994_remove(struct platform_device *pdev)
4049{
4050 snd_soc_unregister_codec(&pdev->dev);
4051 return 0;
4052}
4053
4130static struct platform_driver wm8994_codec_driver = { 4054static struct platform_driver wm8994_codec_driver = {
4131 .driver = { 4055 .driver = {
4132 .name = "wm8994-codec", 4056 .name = "wm8994-codec",
4133 .owner = THIS_MODULE, 4057 .owner = THIS_MODULE,
4134 }, 4058 },
4135 .probe = wm8994_codec_probe, 4059 .probe = wm8994_probe,
4136 .remove = __devexit_p(wm8994_codec_remove), 4060 .remove = __devexit_p(wm8994_remove),
4137}; 4061};
4138 4062
4139static __init int wm8994_init(void) 4063static __init int wm8994_init(void)