diff options
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 231 |
1 files changed, 71 insertions, 160 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 7b618bbff884..898430f44f9d 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -36,7 +36,16 @@ | |||
36 | #include <sound/initval.h> | 36 | #include <sound/initval.h> |
37 | #include <sound/tlv.h> | 37 | #include <sound/tlv.h> |
38 | 38 | ||
39 | #include "twl4030.h" | 39 | /* Register descriptions are here */ |
40 | #include <linux/mfd/twl4030-codec.h> | ||
41 | |||
42 | /* Shadow register used by the audio driver */ | ||
43 | #define TWL4030_REG_SW_SHADOW 0x4A | ||
44 | #define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) | ||
45 | |||
46 | /* TWL4030_REG_SW_SHADOW (0x4A) Fields */ | ||
47 | #define TWL4030_HFL_EN 0x01 | ||
48 | #define TWL4030_HFR_EN 0x02 | ||
40 | 49 | ||
41 | /* | 50 | /* |
42 | * twl4030 register cache & default register settings | 51 | * twl4030 register cache & default register settings |
@@ -277,21 +286,19 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec) | |||
277 | 286 | ||
278 | } | 287 | } |
279 | 288 | ||
280 | static void twl4030_init_chip(struct platform_device *pdev) | 289 | static void twl4030_init_chip(struct snd_soc_codec *codec) |
281 | { | 290 | { |
282 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 291 | struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev); |
283 | struct twl4030_setup_data *setup = socdev->codec_data; | ||
284 | struct snd_soc_codec *codec = socdev->card->codec; | ||
285 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 292 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
286 | u8 reg, byte; | 293 | u8 reg, byte; |
287 | int i = 0; | 294 | int i = 0; |
288 | 295 | ||
289 | /* Check defaults, if instructed before anything else */ | 296 | /* Check defaults, if instructed before anything else */ |
290 | if (setup && setup->check_defaults) | 297 | if (pdata && pdata->check_defaults) |
291 | twl4030_check_defaults(codec); | 298 | twl4030_check_defaults(codec); |
292 | 299 | ||
293 | /* Reset registers, if no setup data or if instructed to do so */ | 300 | /* Reset registers, if no setup data or if instructed to do so */ |
294 | if (!setup || (setup && setup->reset_registers)) | 301 | if (!pdata || (pdata && pdata->reset_registers)) |
295 | twl4030_reset_registers(codec); | 302 | twl4030_reset_registers(codec); |
296 | 303 | ||
297 | /* Refresh APLL_CTL register from HW */ | 304 | /* Refresh APLL_CTL register from HW */ |
@@ -312,20 +319,14 @@ static void twl4030_init_chip(struct platform_device *pdev) | |||
312 | twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32); | 319 | twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32); |
313 | 320 | ||
314 | /* Machine dependent setup */ | 321 | /* Machine dependent setup */ |
315 | if (!setup) | 322 | if (!pdata) |
316 | return; | 323 | return; |
317 | 324 | ||
318 | twl4030->digimic_delay = setup->digimic_delay; | 325 | twl4030->digimic_delay = pdata->digimic_delay; |
319 | |||
320 | /* Configuration for headset ramp delay from setup data */ | ||
321 | if (setup->sysclk != twl4030->sysclk) | ||
322 | dev_warn(codec->dev, | ||
323 | "Mismatch in APLL mclk: %u (configured: %u)\n", | ||
324 | setup->sysclk, twl4030->sysclk); | ||
325 | 326 | ||
326 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); | 327 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); |
327 | reg &= ~TWL4030_RAMP_DELAY; | 328 | reg &= ~TWL4030_RAMP_DELAY; |
328 | reg |= (setup->ramp_delay_value << 2); | 329 | reg |= (pdata->ramp_delay_value << 2); |
329 | twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg); | 330 | twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg); |
330 | 331 | ||
331 | /* initiate offset cancellation */ | 332 | /* initiate offset cancellation */ |
@@ -333,7 +334,7 @@ static void twl4030_init_chip(struct platform_device *pdev) | |||
333 | 334 | ||
334 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | 335 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); |
335 | reg &= ~TWL4030_OFFSET_CNCL_SEL; | 336 | reg &= ~TWL4030_OFFSET_CNCL_SEL; |
336 | reg |= setup->offset_cncl_path; | 337 | reg |= pdata->offset_cncl_path; |
337 | twl4030_write(codec, TWL4030_REG_ANAMICL, | 338 | twl4030_write(codec, TWL4030_REG_ANAMICL, |
338 | reg | TWL4030_CNCL_OFFSET_START); | 339 | reg | TWL4030_CNCL_OFFSET_START); |
339 | 340 | ||
@@ -718,9 +719,7 @@ static int aif_event(struct snd_soc_dapm_widget *w, | |||
718 | 719 | ||
719 | static void headset_ramp(struct snd_soc_codec *codec, int ramp) | 720 | static void headset_ramp(struct snd_soc_codec *codec, int ramp) |
720 | { | 721 | { |
721 | struct snd_soc_device *socdev = codec->socdev; | 722 | struct twl4030_codec_audio_data *pdata = codec->dev->platform_data; |
722 | struct twl4030_setup_data *setup = socdev->codec_data; | ||
723 | |||
724 | unsigned char hs_gain, hs_pop; | 723 | unsigned char hs_gain, hs_pop; |
725 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 724 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
726 | /* Base values for ramp delay calculation: 2^19 - 2^26 */ | 725 | /* Base values for ramp delay calculation: 2^19 - 2^26 */ |
@@ -732,9 +731,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) | |||
732 | 731 | ||
733 | /* Enable external mute control, this dramatically reduces | 732 | /* Enable external mute control, this dramatically reduces |
734 | * the pop-noise */ | 733 | * the pop-noise */ |
735 | if (setup && setup->hs_extmute) { | 734 | if (pdata && pdata->hs_extmute) { |
736 | if (setup->set_hs_extmute) { | 735 | if (pdata->set_hs_extmute) { |
737 | setup->set_hs_extmute(1); | 736 | pdata->set_hs_extmute(1); |
738 | } else { | 737 | } else { |
739 | hs_pop |= TWL4030_EXTMUTE; | 738 | hs_pop |= TWL4030_EXTMUTE; |
740 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); | 739 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); |
@@ -772,9 +771,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) | |||
772 | } | 771 | } |
773 | 772 | ||
774 | /* Disable external mute */ | 773 | /* Disable external mute */ |
775 | if (setup && setup->hs_extmute) { | 774 | if (pdata && pdata->hs_extmute) { |
776 | if (setup->set_hs_extmute) { | 775 | if (pdata->set_hs_extmute) { |
777 | setup->set_hs_extmute(0); | 776 | pdata->set_hs_extmute(0); |
778 | } else { | 777 | } else { |
779 | hs_pop &= ~TWL4030_EXTMUTE; | 778 | hs_pop &= ~TWL4030_EXTMUTE; |
780 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); | 779 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); |
@@ -1707,8 +1706,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream, | |||
1707 | struct snd_soc_dai *dai) | 1706 | struct snd_soc_dai *dai) |
1708 | { | 1707 | { |
1709 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1708 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1710 | struct snd_soc_device *socdev = rtd->socdev; | 1709 | struct snd_soc_codec *codec = rtd->codec; |
1711 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1712 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 1710 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
1713 | 1711 | ||
1714 | if (twl4030->master_substream) { | 1712 | if (twl4030->master_substream) { |
@@ -1738,8 +1736,7 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream, | |||
1738 | struct snd_soc_dai *dai) | 1736 | struct snd_soc_dai *dai) |
1739 | { | 1737 | { |
1740 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1738 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1741 | struct snd_soc_device *socdev = rtd->socdev; | 1739 | struct snd_soc_codec *codec = rtd->codec; |
1742 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1743 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 1740 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
1744 | 1741 | ||
1745 | if (twl4030->master_substream == substream) | 1742 | if (twl4030->master_substream == substream) |
@@ -1764,8 +1761,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1764 | struct snd_soc_dai *dai) | 1761 | struct snd_soc_dai *dai) |
1765 | { | 1762 | { |
1766 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1763 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1767 | struct snd_soc_device *socdev = rtd->socdev; | 1764 | struct snd_soc_codec *codec = rtd->codec; |
1768 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1769 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 1765 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
1770 | u8 mode, old_mode, format, old_format; | 1766 | u8 mode, old_mode, format, old_format; |
1771 | 1767 | ||
@@ -1999,8 +1995,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream, | |||
1999 | struct snd_soc_dai *dai) | 1995 | struct snd_soc_dai *dai) |
2000 | { | 1996 | { |
2001 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1997 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
2002 | struct snd_soc_device *socdev = rtd->socdev; | 1998 | struct snd_soc_codec *codec = rtd->codec; |
2003 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2004 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 1999 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
2005 | u8 mode; | 2000 | u8 mode; |
2006 | 2001 | ||
@@ -2033,8 +2028,7 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream, | |||
2033 | struct snd_soc_dai *dai) | 2028 | struct snd_soc_dai *dai) |
2034 | { | 2029 | { |
2035 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 2030 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
2036 | struct snd_soc_device *socdev = rtd->socdev; | 2031 | struct snd_soc_codec *codec = rtd->codec; |
2037 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2038 | 2032 | ||
2039 | /* Enable voice digital filters */ | 2033 | /* Enable voice digital filters */ |
2040 | twl4030_voice_enable(codec, substream->stream, 0); | 2034 | twl4030_voice_enable(codec, substream->stream, 0); |
@@ -2044,8 +2038,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, | |||
2044 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 2038 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
2045 | { | 2039 | { |
2046 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 2040 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
2047 | struct snd_soc_device *socdev = rtd->socdev; | 2041 | struct snd_soc_codec *codec = rtd->codec; |
2048 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2049 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 2042 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
2050 | u8 old_mode, mode; | 2043 | u8 old_mode, mode; |
2051 | 2044 | ||
@@ -2175,7 +2168,7 @@ static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate) | |||
2175 | #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) | 2168 | #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) |
2176 | #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) | 2169 | #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) |
2177 | 2170 | ||
2178 | static struct snd_soc_dai_ops twl4030_dai_ops = { | 2171 | static struct snd_soc_dai_ops twl4030_dai_hifi_ops = { |
2179 | .startup = twl4030_startup, | 2172 | .startup = twl4030_startup, |
2180 | .shutdown = twl4030_shutdown, | 2173 | .shutdown = twl4030_shutdown, |
2181 | .hw_params = twl4030_hw_params, | 2174 | .hw_params = twl4030_hw_params, |
@@ -2193,9 +2186,9 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = { | |||
2193 | .set_tristate = twl4030_voice_set_tristate, | 2186 | .set_tristate = twl4030_voice_set_tristate, |
2194 | }; | 2187 | }; |
2195 | 2188 | ||
2196 | struct snd_soc_dai twl4030_dai[] = { | 2189 | static struct snd_soc_dai_driver twl4030_dai[] = { |
2197 | { | 2190 | { |
2198 | .name = "twl4030", | 2191 | .name = "twl4030-hifi", |
2199 | .playback = { | 2192 | .playback = { |
2200 | .stream_name = "HiFi Playback", | 2193 | .stream_name = "HiFi Playback", |
2201 | .channels_min = 2, | 2194 | .channels_min = 2, |
@@ -2208,10 +2201,10 @@ struct snd_soc_dai twl4030_dai[] = { | |||
2208 | .channels_max = 4, | 2201 | .channels_max = 4, |
2209 | .rates = TWL4030_RATES, | 2202 | .rates = TWL4030_RATES, |
2210 | .formats = TWL4030_FORMATS,}, | 2203 | .formats = TWL4030_FORMATS,}, |
2211 | .ops = &twl4030_dai_ops, | 2204 | .ops = &twl4030_dai_hifi_ops, |
2212 | }, | 2205 | }, |
2213 | { | 2206 | { |
2214 | .name = "twl4030 Voice", | 2207 | .name = "twl4030-voice", |
2215 | .playback = { | 2208 | .playback = { |
2216 | .stream_name = "Voice Playback", | 2209 | .stream_name = "Voice Playback", |
2217 | .channels_min = 1, | 2210 | .channels_min = 1, |
@@ -2227,164 +2220,90 @@ struct snd_soc_dai twl4030_dai[] = { | |||
2227 | .ops = &twl4030_dai_voice_ops, | 2220 | .ops = &twl4030_dai_voice_ops, |
2228 | }, | 2221 | }, |
2229 | }; | 2222 | }; |
2230 | EXPORT_SYMBOL_GPL(twl4030_dai); | ||
2231 | 2223 | ||
2232 | static int twl4030_soc_suspend(struct platform_device *pdev, pm_message_t state) | 2224 | static int twl4030_soc_suspend(struct snd_soc_codec *codec, pm_message_t state) |
2233 | { | 2225 | { |
2234 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
2235 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2236 | |||
2237 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2226 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); |
2238 | |||
2239 | return 0; | 2227 | return 0; |
2240 | } | 2228 | } |
2241 | 2229 | ||
2242 | static int twl4030_soc_resume(struct platform_device *pdev) | 2230 | static int twl4030_soc_resume(struct snd_soc_codec *codec) |
2243 | { | 2231 | { |
2244 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
2245 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2246 | |||
2247 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 2232 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
2248 | return 0; | 2233 | return 0; |
2249 | } | 2234 | } |
2250 | 2235 | ||
2251 | static struct snd_soc_codec *twl4030_codec; | 2236 | static int twl4030_soc_probe(struct snd_soc_codec *codec) |
2252 | |||
2253 | static int twl4030_soc_probe(struct platform_device *pdev) | ||
2254 | { | 2237 | { |
2255 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 2238 | struct twl4030_priv *twl4030; |
2256 | struct snd_soc_codec *codec; | ||
2257 | int ret; | ||
2258 | |||
2259 | BUG_ON(!twl4030_codec); | ||
2260 | |||
2261 | codec = twl4030_codec; | ||
2262 | socdev->card->codec = codec; | ||
2263 | |||
2264 | twl4030_init_chip(pdev); | ||
2265 | 2239 | ||
2266 | /* register pcms */ | 2240 | twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL); |
2267 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 2241 | if (twl4030 == NULL) { |
2268 | if (ret < 0) { | 2242 | printk("Can not allocate memroy\n"); |
2269 | dev_err(&pdev->dev, "failed to create pcms\n"); | 2243 | return -ENOMEM; |
2270 | return ret; | ||
2271 | } | 2244 | } |
2245 | snd_soc_codec_set_drvdata(codec, twl4030); | ||
2246 | /* Set the defaults, and power up the codec */ | ||
2247 | twl4030->sysclk = twl4030_codec_get_mclk() / 1000; | ||
2248 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
2249 | codec->idle_bias_off = 1; | ||
2250 | |||
2251 | twl4030_init_chip(codec); | ||
2272 | 2252 | ||
2273 | snd_soc_add_controls(codec, twl4030_snd_controls, | 2253 | snd_soc_add_controls(codec, twl4030_snd_controls, |
2274 | ARRAY_SIZE(twl4030_snd_controls)); | 2254 | ARRAY_SIZE(twl4030_snd_controls)); |
2275 | twl4030_add_widgets(codec); | 2255 | twl4030_add_widgets(codec); |
2276 | |||
2277 | return 0; | 2256 | return 0; |
2278 | } | 2257 | } |
2279 | 2258 | ||
2280 | static int twl4030_soc_remove(struct platform_device *pdev) | 2259 | static int twl4030_soc_remove(struct snd_soc_codec *codec) |
2281 | { | 2260 | { |
2282 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
2283 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2284 | |||
2285 | /* Reset registers to their chip default before leaving */ | ||
2286 | twl4030_reset_registers(codec); | ||
2287 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2261 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); |
2288 | snd_soc_free_pcms(socdev); | ||
2289 | snd_soc_dapm_free(socdev); | ||
2290 | |||
2291 | return 0; | 2262 | return 0; |
2292 | } | 2263 | } |
2293 | 2264 | ||
2265 | static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { | ||
2266 | .probe = twl4030_soc_probe, | ||
2267 | .remove = twl4030_soc_remove, | ||
2268 | .suspend = twl4030_soc_suspend, | ||
2269 | .resume = twl4030_soc_resume, | ||
2270 | .read = twl4030_read_reg_cache, | ||
2271 | .write = twl4030_write, | ||
2272 | .set_bias_level = twl4030_set_bias_level, | ||
2273 | .reg_cache_size = sizeof(twl4030_reg), | ||
2274 | .reg_word_size = sizeof(u8), | ||
2275 | .reg_cache_default = twl4030_reg, | ||
2276 | }; | ||
2277 | |||
2294 | static int __devinit twl4030_codec_probe(struct platform_device *pdev) | 2278 | static int __devinit twl4030_codec_probe(struct platform_device *pdev) |
2295 | { | 2279 | { |
2296 | struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data; | 2280 | struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data; |
2297 | struct snd_soc_codec *codec; | ||
2298 | struct twl4030_priv *twl4030; | ||
2299 | int ret; | ||
2300 | 2281 | ||
2301 | if (!pdata) { | 2282 | if (!pdata) { |
2302 | dev_err(&pdev->dev, "platform_data is missing\n"); | 2283 | dev_err(&pdev->dev, "platform_data is missing\n"); |
2303 | return -EINVAL; | 2284 | return -EINVAL; |
2304 | } | 2285 | } |
2305 | 2286 | ||
2306 | twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL); | 2287 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030, |
2307 | if (twl4030 == NULL) { | 2288 | twl4030_dai, ARRAY_SIZE(twl4030_dai)); |
2308 | dev_err(&pdev->dev, "Can not allocate memroy\n"); | ||
2309 | return -ENOMEM; | ||
2310 | } | ||
2311 | |||
2312 | codec = &twl4030->codec; | ||
2313 | snd_soc_codec_set_drvdata(codec, twl4030); | ||
2314 | codec->dev = &pdev->dev; | ||
2315 | twl4030_dai[0].dev = &pdev->dev; | ||
2316 | twl4030_dai[1].dev = &pdev->dev; | ||
2317 | |||
2318 | mutex_init(&codec->mutex); | ||
2319 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
2320 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
2321 | |||
2322 | codec->name = "twl4030"; | ||
2323 | codec->owner = THIS_MODULE; | ||
2324 | codec->read = twl4030_read_reg_cache; | ||
2325 | codec->write = twl4030_write; | ||
2326 | codec->set_bias_level = twl4030_set_bias_level; | ||
2327 | codec->idle_bias_off = 1; | ||
2328 | codec->dai = twl4030_dai; | ||
2329 | codec->num_dai = ARRAY_SIZE(twl4030_dai); | ||
2330 | codec->reg_cache_size = sizeof(twl4030_reg); | ||
2331 | codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), | ||
2332 | GFP_KERNEL); | ||
2333 | if (codec->reg_cache == NULL) { | ||
2334 | ret = -ENOMEM; | ||
2335 | goto error_cache; | ||
2336 | } | ||
2337 | |||
2338 | platform_set_drvdata(pdev, twl4030); | ||
2339 | twl4030_codec = codec; | ||
2340 | |||
2341 | /* Set the defaults, and power up the codec */ | ||
2342 | twl4030->sysclk = twl4030_codec_get_mclk() / 1000; | ||
2343 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
2344 | |||
2345 | ret = snd_soc_register_codec(codec); | ||
2346 | if (ret != 0) { | ||
2347 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
2348 | goto error_codec; | ||
2349 | } | ||
2350 | |||
2351 | ret = snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); | ||
2352 | if (ret != 0) { | ||
2353 | dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); | ||
2354 | snd_soc_unregister_codec(codec); | ||
2355 | goto error_codec; | ||
2356 | } | ||
2357 | |||
2358 | return 0; | ||
2359 | |||
2360 | error_codec: | ||
2361 | twl4030_codec_enable(codec, 0); | ||
2362 | kfree(codec->reg_cache); | ||
2363 | error_cache: | ||
2364 | kfree(twl4030); | ||
2365 | return ret; | ||
2366 | } | 2289 | } |
2367 | 2290 | ||
2368 | static int __devexit twl4030_codec_remove(struct platform_device *pdev) | 2291 | static int __devexit twl4030_codec_remove(struct platform_device *pdev) |
2369 | { | 2292 | { |
2370 | struct twl4030_priv *twl4030 = platform_get_drvdata(pdev); | 2293 | struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev); |
2371 | 2294 | ||
2372 | snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); | 2295 | snd_soc_unregister_codec(&pdev->dev); |
2373 | snd_soc_unregister_codec(&twl4030->codec); | ||
2374 | kfree(twl4030->codec.reg_cache); | ||
2375 | kfree(twl4030); | 2296 | kfree(twl4030); |
2376 | |||
2377 | twl4030_codec = NULL; | ||
2378 | return 0; | 2297 | return 0; |
2379 | } | 2298 | } |
2380 | 2299 | ||
2381 | MODULE_ALIAS("platform:twl4030_codec_audio"); | 2300 | MODULE_ALIAS("platform:twl4030-codec"); |
2382 | 2301 | ||
2383 | static struct platform_driver twl4030_codec_driver = { | 2302 | static struct platform_driver twl4030_codec_driver = { |
2384 | .probe = twl4030_codec_probe, | 2303 | .probe = twl4030_codec_probe, |
2385 | .remove = __devexit_p(twl4030_codec_remove), | 2304 | .remove = __devexit_p(twl4030_codec_remove), |
2386 | .driver = { | 2305 | .driver = { |
2387 | .name = "twl4030_codec_audio", | 2306 | .name = "twl4030-codec", |
2388 | .owner = THIS_MODULE, | 2307 | .owner = THIS_MODULE, |
2389 | }, | 2308 | }, |
2390 | }; | 2309 | }; |
@@ -2401,14 +2320,6 @@ static void __exit twl4030_exit(void) | |||
2401 | } | 2320 | } |
2402 | module_exit(twl4030_exit); | 2321 | module_exit(twl4030_exit); |
2403 | 2322 | ||
2404 | struct snd_soc_codec_device soc_codec_dev_twl4030 = { | ||
2405 | .probe = twl4030_soc_probe, | ||
2406 | .remove = twl4030_soc_remove, | ||
2407 | .suspend = twl4030_soc_suspend, | ||
2408 | .resume = twl4030_soc_resume, | ||
2409 | }; | ||
2410 | EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); | ||
2411 | |||
2412 | MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); | 2323 | MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); |
2413 | MODULE_AUTHOR("Steve Sakoman"); | 2324 | MODULE_AUTHOR("Steve Sakoman"); |
2414 | MODULE_LICENSE("GPL"); | 2325 | MODULE_LICENSE("GPL"); |