diff options
author | Liam Girdwood <lrg@slimlogic.co.uk> | 2010-03-17 16:15:21 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2010-08-12 09:00:00 -0400 |
commit | f0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch) | |
tree | f6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/codecs/wm8994.c | |
parent | bda7d2a862e6b788bca2d02d38a07966a9c92e48 (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.c | 230 |
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 | ||
39 | static struct snd_soc_codec *wm8994_codec; | ||
40 | struct snd_soc_codec_device soc_codec_dev_wm8994; | ||
41 | |||
42 | struct fll_config { | 39 | struct 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 */ |
72 | struct wm8994_priv { | 69 | struct 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 | |||
1906 | static void wm8994_set_drc(struct snd_soc_codec *codec, int drc) | 1903 | static 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 | ||
2883 | static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, | 2880 | static 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 | |||
2997 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; | 2994 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; |
2998 | 2995 | ||
2996 | static 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 | |||
2999 | static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | 3002 | static 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 | ||
3510 | struct snd_soc_dai wm8994_dai[] = { | 3513 | static 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 | }; |
3569 | EXPORT_SYMBOL_GPL(wm8994_dai); | ||
3570 | 3569 | ||
3571 | #ifdef CONFIG_PM | 3570 | #ifdef CONFIG_PM |
3572 | static int wm8994_suspend(struct platform_device *pdev, pm_message_t state) | 3571 | static 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 | ||
3593 | static int wm8994_resume(struct platform_device *pdev) | 3590 | static 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 | ||
3641 | static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) | 3636 | static 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 | ||
3708 | static void wm8994_handle_pdata(struct wm8994_priv *wm8994) | 3703 | static 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 | ||
3774 | static 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 | |||
3808 | static 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 | |||
3818 | struct 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 | }; | ||
3824 | EXPORT_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); | |||
3881 | static irqreturn_t wm8994_mic_irq(int irq, void *data) | 3824 | static 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 | ||
3916 | static int wm8994_codec_probe(struct platform_device *pdev) | 3859 | static 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 | ||
4100 | err_codec: | ||
4101 | snd_soc_unregister_codec(codec); | ||
4102 | err_irq: | 4007 | err_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 | ||
4112 | static int __devexit wm8994_codec_remove(struct platform_device *pdev) | 4017 | static 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 | ||
4032 | static 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 | |||
4042 | static 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 | |||
4048 | static int __devexit wm8994_remove(struct platform_device *pdev) | ||
4049 | { | ||
4050 | snd_soc_unregister_codec(&pdev->dev); | ||
4051 | return 0; | ||
4052 | } | ||
4053 | |||
4130 | static struct platform_driver wm8994_codec_driver = { | 4054 | static 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 | ||
4139 | static __init int wm8994_init(void) | 4063 | static __init int wm8994_init(void) |