Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: sound/soc/codecs/twl4030.c

Issue 6577007: CHROMIUM: ASoC: Import entire upstream ASoC tree (Closed)
Patch Set: Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sound/soc/codecs/tpa6130a2.c ('k') | sound/soc/codecs/twl6040.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * ALSA SoC TWL4030 codec driver 2 * ALSA SoC TWL4030 codec driver
3 * 3 *
4 * Author: Steve Sakoman, <steve@sakoman.com> 4 * Author: Steve Sakoman, <steve@sakoman.com>
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation. 8 * version 2 as published by the Free Software Foundation.
9 * 9 *
10 * This program is distributed in the hope that it will be useful, but 10 * This program is distributed in the hope that it will be useful, but
(...skipping 14 matching lines...) Expand all
25 #include <linux/delay.h> 25 #include <linux/delay.h>
26 #include <linux/pm.h> 26 #include <linux/pm.h>
27 #include <linux/i2c.h> 27 #include <linux/i2c.h>
28 #include <linux/platform_device.h> 28 #include <linux/platform_device.h>
29 #include <linux/i2c/twl.h> 29 #include <linux/i2c/twl.h>
30 #include <linux/slab.h> 30 #include <linux/slab.h>
31 #include <sound/core.h> 31 #include <sound/core.h>
32 #include <sound/pcm.h> 32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h> 33 #include <sound/pcm_params.h>
34 #include <sound/soc.h> 34 #include <sound/soc.h>
35 #include <sound/soc-dapm.h>
36 #include <sound/initval.h> 35 #include <sound/initval.h>
37 #include <sound/tlv.h> 36 #include <sound/tlv.h>
38 37
39 /* Register descriptions are here */ 38 /* Register descriptions are here */
40 #include <linux/mfd/twl4030-codec.h> 39 #include <linux/mfd/twl4030-codec.h>
41 40
42 /* Shadow register used by the audio driver */ 41 /* Shadow register used by the audio driver */
43 #define TWL4030_REG_SW_SHADOW 0x4A 42 #define TWL4030_REG_SW_SHADOW 0x4A
44 #define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) 43 #define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
45 44
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 write_to_reg = 1; 225 write_to_reg = 1;
227 break; 226 break;
228 } 227 }
229 if (write_to_reg) 228 if (write_to_reg)
230 return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 229 return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
231 value, reg); 230 value, reg);
232 } 231 }
233 return 0; 232 return 0;
234 } 233 }
235 234
235 static inline void twl4030_wait_ms(int time)
236 {
237 if (time < 60) {
238 time *= 1000;
239 usleep_range(time, time + 500);
240 } else {
241 msleep(time);
242 }
243 }
244
236 static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) 245 static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
237 { 246 {
238 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 247 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
239 int mode; 248 int mode;
240 249
241 if (enable == twl4030->codec_powered) 250 if (enable == twl4030->codec_powered)
242 return; 251 return;
243 252
244 if (enable) 253 if (enable)
245 mode = twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER); 254 mode = twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER);
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 340
332 /* initiate offset cancellation */ 341 /* initiate offset cancellation */
333 twl4030_codec_enable(codec, 1); 342 twl4030_codec_enable(codec, 1);
334 343
335 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); 344 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
336 reg &= ~TWL4030_OFFSET_CNCL_SEL; 345 reg &= ~TWL4030_OFFSET_CNCL_SEL;
337 reg |= pdata->offset_cncl_path; 346 reg |= pdata->offset_cncl_path;
338 twl4030_write(codec, TWL4030_REG_ANAMICL, 347 twl4030_write(codec, TWL4030_REG_ANAMICL,
339 reg | TWL4030_CNCL_OFFSET_START); 348 reg | TWL4030_CNCL_OFFSET_START);
340 349
341 » /* wait for offset cancellation to complete */ 350 » /*
351 » * Wait for offset cancellation to complete.
352 » * Since this takes a while, do not slam the i2c.
353 » * Start polling the status after ~20ms.
354 » */
355 » msleep(20);
342 do { 356 do {
343 » » /* this takes a little while, so don't slam i2c */ 357 » » usleep_range(1000, 2000);
344 » » udelay(2000);
345 twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, 358 twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
346 TWL4030_REG_ANAMICL); 359 TWL4030_REG_ANAMICL);
347 } while ((i++ < 100) && 360 } while ((i++ < 100) &&
348 ((byte & TWL4030_CNCL_OFFSET_START) == 361 ((byte & TWL4030_CNCL_OFFSET_START) ==
349 TWL4030_CNCL_OFFSET_START)); 362 TWL4030_CNCL_OFFSET_START));
350 363
351 /* Make sure that the reg_cache has the same value as the HW */ 364 /* Make sure that the reg_cache has the same value as the HW */
352 twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); 365 twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
353 366
354 twl4030_codec_enable(codec, 0); 367 twl4030_codec_enable(codec, 0);
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
718 } 731 }
719 732
720 static void headset_ramp(struct snd_soc_codec *codec, int ramp) 733 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
721 { 734 {
722 struct twl4030_codec_audio_data *pdata = codec->dev->platform_data; 735 struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
723 unsigned char hs_gain, hs_pop; 736 unsigned char hs_gain, hs_pop;
724 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 737 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
725 /* Base values for ramp delay calculation: 2^19 - 2^26 */ 738 /* Base values for ramp delay calculation: 2^19 - 2^26 */
726 unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304, 739 unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
727 8388608, 16777216, 33554432, 67108864}; 740 8388608, 16777216, 33554432, 67108864};
741 unsigned int delay;
728 742
729 hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET); 743 hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
730 hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); 744 hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
745 delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
746 twl4030->sysclk) + 1;
731 747
732 /* Enable external mute control, this dramatically reduces 748 /* Enable external mute control, this dramatically reduces
733 * the pop-noise */ 749 * the pop-noise */
734 if (pdata && pdata->hs_extmute) { 750 if (pdata && pdata->hs_extmute) {
735 if (pdata->set_hs_extmute) { 751 if (pdata->set_hs_extmute) {
736 pdata->set_hs_extmute(1); 752 pdata->set_hs_extmute(1);
737 } else { 753 } else {
738 hs_pop |= TWL4030_EXTMUTE; 754 hs_pop |= TWL4030_EXTMUTE;
739 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); 755 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
740 } 756 }
741 } 757 }
742 758
743 if (ramp) { 759 if (ramp) {
744 /* Headset ramp-up according to the TRM */ 760 /* Headset ramp-up according to the TRM */
745 hs_pop |= TWL4030_VMID_EN; 761 hs_pop |= TWL4030_VMID_EN;
746 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); 762 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
747 /* Actually write to the register */ 763 /* Actually write to the register */
748 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 764 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
749 hs_gain, 765 hs_gain,
750 TWL4030_REG_HS_GAIN_SET); 766 TWL4030_REG_HS_GAIN_SET);
751 hs_pop |= TWL4030_RAMP_EN; 767 hs_pop |= TWL4030_RAMP_EN;
752 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); 768 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
753 /* Wait ramp delay time + 1, so the VMID can settle */ 769 /* Wait ramp delay time + 1, so the VMID can settle */
754 » » mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] / 770 » » twl4030_wait_ms(delay);
755 » » » twl4030->sysclk) + 1);
756 } else { 771 } else {
757 /* Headset ramp-down _not_ according to 772 /* Headset ramp-down _not_ according to
758 * the TRM, but in a way that it is working */ 773 * the TRM, but in a way that it is working */
759 hs_pop &= ~TWL4030_RAMP_EN; 774 hs_pop &= ~TWL4030_RAMP_EN;
760 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); 775 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
761 /* Wait ramp delay time + 1, so the VMID can settle */ 776 /* Wait ramp delay time + 1, so the VMID can settle */
762 » » mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] / 777 » » twl4030_wait_ms(delay);
763 » » » twl4030->sysclk) + 1);
764 /* Bypass the reg_cache to mute the headset */ 778 /* Bypass the reg_cache to mute the headset */
765 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 779 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
766 hs_gain & (~0x0f), 780 hs_gain & (~0x0f),
767 TWL4030_REG_HS_GAIN_SET); 781 TWL4030_REG_HS_GAIN_SET);
768 782
769 hs_pop &= ~TWL4030_VMID_EN; 783 hs_pop &= ~TWL4030_VMID_EN;
770 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); 784 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
771 } 785 }
772 786
773 /* Disable external mute */ 787 /* Disable external mute */
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 } 842 }
829 return 0; 843 return 0;
830 } 844 }
831 845
832 static int digimic_event(struct snd_soc_dapm_widget *w, 846 static int digimic_event(struct snd_soc_dapm_widget *w,
833 struct snd_kcontrol *kcontrol, int event) 847 struct snd_kcontrol *kcontrol, int event)
834 { 848 {
835 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); 849 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
836 850
837 if (twl4030->digimic_delay) 851 if (twl4030->digimic_delay)
838 » » mdelay(twl4030->digimic_delay); 852 » » twl4030_wait_ms(twl4030->digimic_delay);
839 return 0; 853 return 0;
840 } 854 }
841 855
842 /* 856 /*
843 * Some of the gain controls in TWL (mostly those which are associated with 857 * Some of the gain controls in TWL (mostly those which are associated with
844 * the outputs) are implemented in an interesting way: 858 * the outputs) are implemented in an interesting way:
845 * 0x0 : Power down (mute) 859 * 0x0 : Power down (mute)
846 * 0x1 : 6dB 860 * 0x1 : 6dB
847 * 0x2 : 0 dB 861 * 0x2 : 0 dB
848 * 0x3 : -6 dB 862 * 0x3 : -6 dB
(...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after
1614 {"Voice Digital Loopback", "Volume", "TX2 Capture Route"}, 1628 {"Voice Digital Loopback", "Volume", "TX2 Capture Route"},
1615 1629
1616 {"Digital R2 Playback Mixer", NULL, "Right Digital Loopback"}, 1630 {"Digital R2 Playback Mixer", NULL, "Right Digital Loopback"},
1617 {"Digital L2 Playback Mixer", NULL, "Left Digital Loopback"}, 1631 {"Digital L2 Playback Mixer", NULL, "Left Digital Loopback"},
1618 {"Digital Voice Playback Mixer", NULL, "Voice Digital Loopback"}, 1632 {"Digital Voice Playback Mixer", NULL, "Voice Digital Loopback"},
1619 1633
1620 }; 1634 };
1621 1635
1622 static int twl4030_add_widgets(struct snd_soc_codec *codec) 1636 static int twl4030_add_widgets(struct snd_soc_codec *codec)
1623 { 1637 {
1624 » snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets, 1638 » struct snd_soc_dapm_context *dapm = &codec->dapm;
1639
1640 » snd_soc_dapm_new_controls(dapm, twl4030_dapm_widgets,
1625 ARRAY_SIZE(twl4030_dapm_widgets)); 1641 ARRAY_SIZE(twl4030_dapm_widgets));
1626 1642 » snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
1627 » snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
1628 1643
1629 return 0; 1644 return 0;
1630 } 1645 }
1631 1646
1632 static int twl4030_set_bias_level(struct snd_soc_codec *codec, 1647 static int twl4030_set_bias_level(struct snd_soc_codec *codec,
1633 enum snd_soc_bias_level level) 1648 enum snd_soc_bias_level level)
1634 { 1649 {
1635 switch (level) { 1650 switch (level) {
1636 case SND_SOC_BIAS_ON: 1651 case SND_SOC_BIAS_ON:
1637 break; 1652 break;
1638 case SND_SOC_BIAS_PREPARE: 1653 case SND_SOC_BIAS_PREPARE:
1639 break; 1654 break;
1640 case SND_SOC_BIAS_STANDBY: 1655 case SND_SOC_BIAS_STANDBY:
1641 » » if (codec->bias_level == SND_SOC_BIAS_OFF) 1656 » » if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
1642 twl4030_codec_enable(codec, 1); 1657 twl4030_codec_enable(codec, 1);
1643 break; 1658 break;
1644 case SND_SOC_BIAS_OFF: 1659 case SND_SOC_BIAS_OFF:
1645 twl4030_codec_enable(codec, 0); 1660 twl4030_codec_enable(codec, 0);
1646 break; 1661 break;
1647 } 1662 }
1648 » codec->bias_level = level; 1663 » codec->dapm.bias_level = level;
1649 1664
1650 return 0; 1665 return 0;
1651 } 1666 }
1652 1667
1653 static void twl4030_constraints(struct twl4030_priv *twl4030, 1668 static void twl4030_constraints(struct twl4030_priv *twl4030,
1654 struct snd_pcm_substream *mst_substream) 1669 struct snd_pcm_substream *mst_substream)
1655 { 1670 {
1656 struct snd_pcm_substream *slv_substream; 1671 struct snd_pcm_substream *slv_substream;
1657 1672
1658 /* Pick the stream, which need to be constrained */ 1673 /* Pick the stream, which need to be constrained */
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1702 twl4030_write(codec, TWL4030_REG_OPTION, reg); 1717 twl4030_write(codec, TWL4030_REG_OPTION, reg);
1703 } 1718 }
1704 1719
1705 static int twl4030_startup(struct snd_pcm_substream *substream, 1720 static int twl4030_startup(struct snd_pcm_substream *substream,
1706 struct snd_soc_dai *dai) 1721 struct snd_soc_dai *dai)
1707 { 1722 {
1708 struct snd_soc_pcm_runtime *rtd = substream->private_data; 1723 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1709 struct snd_soc_codec *codec = rtd->codec; 1724 struct snd_soc_codec *codec = rtd->codec;
1710 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 1725 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
1711 1726
1727 snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
1712 if (twl4030->master_substream) { 1728 if (twl4030->master_substream) {
1713 twl4030->slave_substream = substream; 1729 twl4030->slave_substream = substream;
1714 /* The DAI has one configuration for playback and capture, so 1730 /* The DAI has one configuration for playback and capture, so
1715 * if the DAI has been already configured then constrain this 1731 * if the DAI has been already configured then constrain this
1716 * substream to match it. */ 1732 * substream to match it. */
1717 if (twl4030->configured) 1733 if (twl4030->configured)
1718 twl4030_constraints(twl4030, twl4030->master_substream); 1734 twl4030_constraints(twl4030, twl4030->master_substream);
1719 } else { 1735 } else {
1720 if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & 1736 if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) &
1721 TWL4030_OPTION_1)) { 1737 TWL4030_OPTION_1)) {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1826 } 1842 }
1827 1843
1828 /* sample size */ 1844 /* sample size */
1829 old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); 1845 old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
1830 format = old_format; 1846 format = old_format;
1831 format &= ~TWL4030_DATA_WIDTH; 1847 format &= ~TWL4030_DATA_WIDTH;
1832 switch (params_format(params)) { 1848 switch (params_format(params)) {
1833 case SNDRV_PCM_FORMAT_S16_LE: 1849 case SNDRV_PCM_FORMAT_S16_LE:
1834 format |= TWL4030_DATA_WIDTH_16S_16W; 1850 format |= TWL4030_DATA_WIDTH_16S_16W;
1835 break; 1851 break;
1836 » case SNDRV_PCM_FORMAT_S24_LE: 1852 » case SNDRV_PCM_FORMAT_S32_LE:
1837 format |= TWL4030_DATA_WIDTH_32S_24W; 1853 format |= TWL4030_DATA_WIDTH_32S_24W;
1838 break; 1854 break;
1839 default: 1855 default:
1840 printk(KERN_ERR "TWL4030 hw params: unknown format %d\n", 1856 printk(KERN_ERR "TWL4030 hw params: unknown format %d\n",
1841 params_format(params)); 1857 params_format(params));
1842 return -EINVAL; 1858 return -EINVAL;
1843 } 1859 }
1844 1860
1845 if (format != old_format || mode != old_mode) { 1861 if (format != old_format || mode != old_mode) {
1846 if (twl4030->codec_powered) { 1862 if (twl4030->codec_powered) {
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
2159 2175
2160 if (tristate) 2176 if (tristate)
2161 reg |= TWL4030_VIF_TRI_EN; 2177 reg |= TWL4030_VIF_TRI_EN;
2162 else 2178 else
2163 reg &= ~TWL4030_VIF_TRI_EN; 2179 reg &= ~TWL4030_VIF_TRI_EN;
2164 2180
2165 return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg); 2181 return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg);
2166 } 2182 }
2167 2183
2168 #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) 2184 #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
2169 #define TWL4030_FORMATS» (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) 2185 #define TWL4030_FORMATS» (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
2170 2186
2171 static struct snd_soc_dai_ops twl4030_dai_hifi_ops = { 2187 static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
2172 .startup = twl4030_startup, 2188 .startup = twl4030_startup,
2173 .shutdown = twl4030_shutdown, 2189 .shutdown = twl4030_shutdown,
2174 .hw_params = twl4030_hw_params, 2190 .hw_params = twl4030_hw_params,
2175 .set_sysclk = twl4030_set_dai_sysclk, 2191 .set_sysclk = twl4030_set_dai_sysclk,
2176 .set_fmt = twl4030_set_dai_fmt, 2192 .set_fmt = twl4030_set_dai_fmt,
2177 .set_tristate = twl4030_set_tristate, 2193 .set_tristate = twl4030_set_tristate,
2178 }; 2194 };
2179 2195
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
2238 struct twl4030_priv *twl4030; 2254 struct twl4030_priv *twl4030;
2239 2255
2240 twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL); 2256 twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
2241 if (twl4030 == NULL) { 2257 if (twl4030 == NULL) {
2242 printk("Can not allocate memroy\n"); 2258 printk("Can not allocate memroy\n");
2243 return -ENOMEM; 2259 return -ENOMEM;
2244 } 2260 }
2245 snd_soc_codec_set_drvdata(codec, twl4030); 2261 snd_soc_codec_set_drvdata(codec, twl4030);
2246 /* Set the defaults, and power up the codec */ 2262 /* Set the defaults, and power up the codec */
2247 twl4030->sysclk = twl4030_codec_get_mclk() / 1000; 2263 twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
2248 » codec->idle_bias_off = 1; 2264 » codec->dapm.idle_bias_off = 1;
2249 2265
2250 twl4030_init_chip(codec); 2266 twl4030_init_chip(codec);
2251 2267
2252 snd_soc_add_controls(codec, twl4030_snd_controls, 2268 snd_soc_add_controls(codec, twl4030_snd_controls,
2253 ARRAY_SIZE(twl4030_snd_controls)); 2269 ARRAY_SIZE(twl4030_snd_controls));
2254 twl4030_add_widgets(codec); 2270 twl4030_add_widgets(codec);
2255 return 0; 2271 return 0;
2256 } 2272 }
2257 2273
2258 static int twl4030_soc_remove(struct snd_soc_codec *codec) 2274 static int twl4030_soc_remove(struct snd_soc_codec *codec)
2259 { 2275 {
2276 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
2277
2260 /* Reset registers to their chip default before leaving */ 2278 /* Reset registers to their chip default before leaving */
2261 twl4030_reset_registers(codec); 2279 twl4030_reset_registers(codec);
2262 twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); 2280 twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
2281 kfree(twl4030);
2263 return 0; 2282 return 0;
2264 } 2283 }
2265 2284
2266 static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { 2285 static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
2267 .probe = twl4030_soc_probe, 2286 .probe = twl4030_soc_probe,
2268 .remove = twl4030_soc_remove, 2287 .remove = twl4030_soc_remove,
2269 .suspend = twl4030_soc_suspend, 2288 .suspend = twl4030_soc_suspend,
2270 .resume = twl4030_soc_resume, 2289 .resume = twl4030_soc_resume,
2271 .read = twl4030_read_reg_cache, 2290 .read = twl4030_read_reg_cache,
2272 .write = twl4030_write, 2291 .write = twl4030_write,
(...skipping 11 matching lines...) Expand all
2284 dev_err(&pdev->dev, "platform_data is missing\n"); 2303 dev_err(&pdev->dev, "platform_data is missing\n");
2285 return -EINVAL; 2304 return -EINVAL;
2286 } 2305 }
2287 2306
2288 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030, 2307 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
2289 twl4030_dai, ARRAY_SIZE(twl4030_dai)); 2308 twl4030_dai, ARRAY_SIZE(twl4030_dai));
2290 } 2309 }
2291 2310
2292 static int __devexit twl4030_codec_remove(struct platform_device *pdev) 2311 static int __devexit twl4030_codec_remove(struct platform_device *pdev)
2293 { 2312 {
2294 struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev);
2295
2296 snd_soc_unregister_codec(&pdev->dev); 2313 snd_soc_unregister_codec(&pdev->dev);
2297 kfree(twl4030);
2298 return 0; 2314 return 0;
2299 } 2315 }
2300 2316
2301 MODULE_ALIAS("platform:twl4030-codec"); 2317 MODULE_ALIAS("platform:twl4030-codec");
2302 2318
2303 static struct platform_driver twl4030_codec_driver = { 2319 static struct platform_driver twl4030_codec_driver = {
2304 .probe = twl4030_codec_probe, 2320 .probe = twl4030_codec_probe,
2305 .remove = __devexit_p(twl4030_codec_remove), 2321 .remove = __devexit_p(twl4030_codec_remove),
2306 .driver = { 2322 .driver = {
2307 .name = "twl4030-codec", 2323 .name = "twl4030-codec",
2308 .owner = THIS_MODULE, 2324 .owner = THIS_MODULE,
2309 }, 2325 },
2310 }; 2326 };
2311 2327
2312 static int __init twl4030_modinit(void) 2328 static int __init twl4030_modinit(void)
2313 { 2329 {
2314 return platform_driver_register(&twl4030_codec_driver); 2330 return platform_driver_register(&twl4030_codec_driver);
2315 } 2331 }
2316 module_init(twl4030_modinit); 2332 module_init(twl4030_modinit);
2317 2333
2318 static void __exit twl4030_exit(void) 2334 static void __exit twl4030_exit(void)
2319 { 2335 {
2320 platform_driver_unregister(&twl4030_codec_driver); 2336 platform_driver_unregister(&twl4030_codec_driver);
2321 } 2337 }
2322 module_exit(twl4030_exit); 2338 module_exit(twl4030_exit);
2323 2339
2324 MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); 2340 MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
2325 MODULE_AUTHOR("Steve Sakoman"); 2341 MODULE_AUTHOR("Steve Sakoman");
2326 MODULE_LICENSE("GPL"); 2342 MODULE_LICENSE("GPL");
OLDNEW
« no previous file with comments | « sound/soc/codecs/tpa6130a2.c ('k') | sound/soc/codecs/twl6040.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698