aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorMisael Lopez Cruz <misael.lopez@ti.com>2011-05-01 22:27:00 -0400
committerPeter Ujfalusi <peter.ujfalusi@ti.com>2011-07-04 12:35:06 -0400
commitfb34d3d5056a1f8439bbfa13d4519345814d4255 (patch)
treea0e1e1a2dd4415324a4e30f61c463252a217bd6c /sound/soc
parentf19b2823f82499c60ec15d5fe8783193d77e3043 (diff)
ASoC: twl6040: Convert into TWL6040 MFD child
Convert TWL6040 CODEC driver into a TWL6040 MFD child, it implies that MFD-level operations like register accesses, clock setting and power management are done through MFD APIs, not directly by CODEC driver anymore. To avoid conflicts with the other MFD child, vibrator registers are skipped in CODEC driver. Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/Kconfig1
-rw-r--r--sound/soc/codecs/twl6040.c425
-rw-r--r--sound/soc/codecs/twl6040.h118
-rw-r--r--sound/soc/omap/sdp4430.c2
4 files changed, 90 insertions, 456 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0002220bbc3b..922f59f9b82d 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -240,6 +240,7 @@ config SND_SOC_TWL4030
240 tristate 240 tristate
241 241
242config SND_SOC_TWL6040 242config SND_SOC_TWL6040
243 select TWL6040_CORE
243 tristate 244 tristate
244 245
245config SND_SOC_UDA134X 246config SND_SOC_UDA134X
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index ade6616bb790..a20e293b27b4 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -24,11 +24,10 @@
24#include <linux/init.h> 24#include <linux/init.h>
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>
28#include <linux/gpio.h>
29#include <linux/platform_device.h> 27#include <linux/platform_device.h>
30#include <linux/slab.h> 28#include <linux/slab.h>
31#include <linux/i2c/twl.h> 29#include <linux/i2c/twl.h>
30#include <linux/mfd/twl6040.h>
32 31
33#include <sound/core.h> 32#include <sound/core.h>
34#include <sound/pcm.h> 33#include <sound/pcm.h>
@@ -77,14 +76,12 @@ struct twl6040_jack_data {
77 76
78/* codec private data */ 77/* codec private data */
79struct twl6040_data { 78struct twl6040_data {
80 int audpwron;
81 int naudint;
82 int codec_powered; 79 int codec_powered;
83 int pll; 80 int pll;
84 int non_lp; 81 int non_lp;
82 unsigned int clk_in;
85 unsigned int sysclk; 83 unsigned int sysclk;
86 struct snd_pcm_hw_constraint_list *sysclk_constraints; 84 struct snd_pcm_hw_constraint_list *sysclk_constraints;
87 struct completion ready;
88 struct twl6040_jack_data hs_jack; 85 struct twl6040_jack_data hs_jack;
89 struct snd_soc_codec *codec; 86 struct snd_soc_codec *codec;
90 struct workqueue_struct *workqueue; 87 struct workqueue_struct *workqueue;
@@ -239,12 +236,13 @@ static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec,
239static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, 236static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
240 unsigned int reg) 237 unsigned int reg)
241{ 238{
239 struct twl6040 *twl6040 = codec->control_data;
242 u8 value; 240 u8 value;
243 241
244 if (reg >= TWL6040_CACHEREGNUM) 242 if (reg >= TWL6040_CACHEREGNUM)
245 return -EIO; 243 return -EIO;
246 244
247 twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &value, reg); 245 value = twl6040_reg_read(twl6040, reg);
248 twl6040_write_reg_cache(codec, reg, value); 246 twl6040_write_reg_cache(codec, reg, value);
249 247
250 return value; 248 return value;
@@ -256,11 +254,13 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
256static int twl6040_write(struct snd_soc_codec *codec, 254static int twl6040_write(struct snd_soc_codec *codec,
257 unsigned int reg, unsigned int value) 255 unsigned int reg, unsigned int value)
258{ 256{
257 struct twl6040 *twl6040 = codec->control_data;
258
259 if (reg >= TWL6040_CACHEREGNUM) 259 if (reg >= TWL6040_CACHEREGNUM)
260 return -EIO; 260 return -EIO;
261 261
262 twl6040_write_reg_cache(codec, reg, value); 262 twl6040_write_reg_cache(codec, reg, value);
263 return twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, value, reg); 263 return twl6040_reg_write(twl6040, reg, value);
264} 264}
265 265
266static void twl6040_init_vio_regs(struct snd_soc_codec *codec) 266static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
@@ -268,15 +268,21 @@ static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
268 u8 *cache = codec->reg_cache; 268 u8 *cache = codec->reg_cache;
269 int reg, i; 269 int reg, i;
270 270
271 /* allow registers to be accessed by i2c */
272 twl6040_write(codec, TWL6040_REG_ACCCTL, cache[TWL6040_REG_ACCCTL]);
273
274 for (i = 0; i < TWL6040_VIOREGNUM; i++) { 271 for (i = 0; i < TWL6040_VIOREGNUM; i++) {
275 reg = twl6040_vio_reg[i]; 272 reg = twl6040_vio_reg[i];
276 /* skip read-only registers (ASICID, ASICREV, STATUS) */ 273 /*
274 * skip read-only registers (ASICID, ASICREV, STATUS)
275 * and registers shared among MFD children
276 */
277 switch (reg) { 277 switch (reg) {
278 case TWL6040_REG_ASICID: 278 case TWL6040_REG_ASICID:
279 case TWL6040_REG_ASICREV: 279 case TWL6040_REG_ASICREV:
280 case TWL6040_REG_INTID:
281 case TWL6040_REG_INTMR:
282 case TWL6040_REG_NCPCTL:
283 case TWL6040_REG_LDOCTL:
284 case TWL6040_REG_GPOCTL:
285 case TWL6040_REG_ACCCTL:
280 case TWL6040_REG_STATUS: 286 case TWL6040_REG_STATUS:
281 continue; 287 continue;
282 default: 288 default:
@@ -293,6 +299,20 @@ static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
293 299
294 for (i = 0; i < TWL6040_VDDREGNUM; i++) { 300 for (i = 0; i < TWL6040_VDDREGNUM; i++) {
295 reg = twl6040_vdd_reg[i]; 301 reg = twl6040_vdd_reg[i];
302 /* skip vibra and PLL registers */
303 switch (reg) {
304 case TWL6040_REG_VIBCTLL:
305 case TWL6040_REG_VIBDATL:
306 case TWL6040_REG_VIBCTLR:
307 case TWL6040_REG_VIBDATR:
308 case TWL6040_REG_HPPLLCTL:
309 case TWL6040_REG_LPPLLCTL:
310 case TWL6040_REG_LPPLLDIV:
311 continue;
312 default:
313 break;
314 }
315
296 twl6040_write(codec, reg, cache[reg]); 316 twl6040_write(codec, reg, cache[reg]);
297 } 317 }
298} 318}
@@ -596,88 +616,6 @@ static int pga_event(struct snd_soc_dapm_widget *w,
596 return 0; 616 return 0;
597} 617}
598 618
599/* twl6040 codec manual power-up sequence */
600static void twl6040_power_up(struct snd_soc_codec *codec)
601{
602 u8 ncpctl, ldoctl, lppllctl, accctl;
603
604 ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
605 ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
606 lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
607 accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);
608
609 /* enable reference system */
610 ldoctl |= TWL6040_REFENA;
611 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
612 msleep(10);
613 /* enable internal oscillator */
614 ldoctl |= TWL6040_OSCENA;
615 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
616 udelay(10);
617 /* enable high-side ldo */
618 ldoctl |= TWL6040_HSLDOENA;
619 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
620 udelay(244);
621 /* enable negative charge pump */
622 ncpctl |= TWL6040_NCPENA | TWL6040_NCPOPEN;
623 twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
624 udelay(488);
625 /* enable low-side ldo */
626 ldoctl |= TWL6040_LSLDOENA;
627 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
628 udelay(244);
629 /* enable low-power pll */
630 lppllctl |= TWL6040_LPLLENA;
631 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
632 /* reset state machine */
633 accctl |= TWL6040_RESETSPLIT;
634 twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
635 mdelay(5);
636 accctl &= ~TWL6040_RESETSPLIT;
637 twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
638 /* disable internal oscillator */
639 ldoctl &= ~TWL6040_OSCENA;
640 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
641}
642
643/* twl6040 codec manual power-down sequence */
644static void twl6040_power_down(struct snd_soc_codec *codec)
645{
646 u8 ncpctl, ldoctl, lppllctl, accctl;
647
648 ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
649 ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
650 lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
651 accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);
652
653 /* enable internal oscillator */
654 ldoctl |= TWL6040_OSCENA;
655 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
656 udelay(10);
657 /* disable low-power pll */
658 lppllctl &= ~TWL6040_LPLLENA;
659 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
660 /* disable low-side ldo */
661 ldoctl &= ~TWL6040_LSLDOENA;
662 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
663 udelay(244);
664 /* disable negative charge pump */
665 ncpctl &= ~(TWL6040_NCPENA | TWL6040_NCPOPEN);
666 twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
667 udelay(488);
668 /* disable high-side ldo */
669 ldoctl &= ~TWL6040_HSLDOENA;
670 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
671 udelay(244);
672 /* disable internal oscillator */
673 ldoctl &= ~TWL6040_OSCENA;
674 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
675 /* disable reference system */
676 ldoctl &= ~TWL6040_REFENA;
677 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
678 msleep(10);
679}
680
681/* set headset dac and driver power mode */ 619/* set headset dac and driver power mode */
682static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) 620static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
683{ 621{
@@ -766,33 +704,19 @@ static void twl6040_accessory_work(struct work_struct *work)
766} 704}
767 705
768/* audio interrupt handler */ 706/* audio interrupt handler */
769static irqreturn_t twl6040_naudint_handler(int irq, void *data) 707static irqreturn_t twl6040_audio_handler(int irq, void *data)
770{ 708{
771 struct snd_soc_codec *codec = data; 709 struct snd_soc_codec *codec = data;
710 struct twl6040 *twl6040 = codec->control_data;
772 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 711 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
773 u8 intid; 712 u8 intid;
774 713
775 twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid, TWL6040_REG_INTID); 714 intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
776
777 if (intid & TWL6040_THINT)
778 dev_alert(codec->dev, "die temp over-limit detection\n");
779 715
780 if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT)) 716 if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT))
781 queue_delayed_work(priv->workqueue, &priv->delayed_work, 717 queue_delayed_work(priv->workqueue, &priv->delayed_work,
782 msecs_to_jiffies(200)); 718 msecs_to_jiffies(200));
783 719
784 if (intid & TWL6040_HOOKINT)
785 dev_info(codec->dev, "hook detection\n");
786
787 if (intid & TWL6040_HFINT)
788 dev_alert(codec->dev, "hf drivers over current detection\n");
789
790 if (intid & TWL6040_VIBINT)
791 dev_alert(codec->dev, "vib drivers over current detection\n");
792
793 if (intid & TWL6040_READYINT)
794 complete(&priv->ready);
795
796 return IRQ_HANDLED; 720 return IRQ_HANDLED;
797} 721}
798 722
@@ -1231,36 +1155,11 @@ static int twl6040_add_widgets(struct snd_soc_codec *codec)
1231 return 0; 1155 return 0;
1232} 1156}
1233 1157
1234static int twl6040_power_up_completion(struct snd_soc_codec *codec,
1235 int naudint)
1236{
1237 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1238 int time_left;
1239 u8 intid;
1240
1241 time_left = wait_for_completion_timeout(&priv->ready,
1242 msecs_to_jiffies(144));
1243
1244 if (!time_left) {
1245 twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid,
1246 TWL6040_REG_INTID);
1247 if (!(intid & TWL6040_READYINT)) {
1248 dev_err(codec->dev, "timeout waiting for READYINT\n");
1249 return -ETIMEDOUT;
1250 }
1251 }
1252
1253 priv->codec_powered = 1;
1254
1255 return 0;
1256}
1257
1258static int twl6040_set_bias_level(struct snd_soc_codec *codec, 1158static int twl6040_set_bias_level(struct snd_soc_codec *codec,
1259 enum snd_soc_bias_level level) 1159 enum snd_soc_bias_level level)
1260{ 1160{
1161 struct twl6040 *twl6040 = codec->control_data;
1261 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1162 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1262 int audpwron = priv->audpwron;
1263 int naudint = priv->naudint;
1264 int ret; 1163 int ret;
1265 1164
1266 switch (level) { 1165 switch (level) {
@@ -1272,62 +1171,30 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
1272 if (priv->codec_powered) 1171 if (priv->codec_powered)
1273 break; 1172 break;
1274 1173
1275 if (gpio_is_valid(audpwron)) { 1174 ret = twl6040_power(twl6040, 1);
1276 /* use AUDPWRON line */ 1175 if (ret)
1277 gpio_set_value(audpwron, 1); 1176 return ret;
1278
1279 /* wait for power-up completion */
1280 ret = twl6040_power_up_completion(codec, naudint);
1281 if (ret)
1282 return ret;
1283 1177
1284 /* sync registers updated during power-up sequence */ 1178 priv->codec_powered = 1;
1285 twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL);
1286 twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL);
1287 twl6040_read_reg_volatile(codec, TWL6040_REG_LPPLLCTL);
1288 } else {
1289 /* use manual power-up sequence */
1290 twl6040_power_up(codec);
1291 priv->codec_powered = 1;
1292 }
1293 1179
1294 /* initialize vdd/vss registers with reg_cache */ 1180 /* initialize vdd/vss registers with reg_cache */
1295 twl6040_init_vdd_regs(codec); 1181 twl6040_init_vdd_regs(codec);
1296 1182
1297 /* Set external boost GPO */ 1183 /* Set external boost GPO */
1298 twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02); 1184 twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
1299
1300 /* Set initial minimal gain values */
1301 twl6040_write(codec, TWL6040_REG_HSGAIN, 0xFF);
1302 twl6040_write(codec, TWL6040_REG_EARCTL, 0x1E);
1303 twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1D);
1304 twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1D);
1305 break; 1185 break;
1306 case SND_SOC_BIAS_OFF: 1186 case SND_SOC_BIAS_OFF:
1307 if (!priv->codec_powered) 1187 if (!priv->codec_powered)
1308 break; 1188 break;
1309 1189
1310 if (gpio_is_valid(audpwron)) { 1190 twl6040_power(twl6040, 0);
1311 /* use AUDPWRON line */
1312 gpio_set_value(audpwron, 0);
1313
1314 /* power-down sequence latency */
1315 udelay(500);
1316
1317 /* sync registers updated during power-down sequence */
1318 twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL);
1319 twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL);
1320 twl6040_write_reg_cache(codec, TWL6040_REG_LPPLLCTL,
1321 0x00);
1322 } else {
1323 /* use manual power-down sequence */
1324 twl6040_power_down(codec);
1325 }
1326
1327 priv->codec_powered = 0; 1191 priv->codec_powered = 0;
1328 break; 1192 break;
1329 } 1193 }
1330 1194
1195 /* get PLL and sysclk after power transition */
1196 priv->pll = twl6040_get_pll(twl6040);
1197 priv->sysclk = twl6040_get_sysclk(twl6040);
1331 codec->dapm.bias_level = level; 1198 codec->dapm.bias_level = level;
1332 1199
1333 return 0; 1200 return 0;
@@ -1374,39 +1241,40 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
1374{ 1241{
1375 struct snd_soc_pcm_runtime *rtd = substream->private_data; 1242 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1376 struct snd_soc_codec *codec = rtd->codec; 1243 struct snd_soc_codec *codec = rtd->codec;
1244 struct twl6040 *twl6040 = codec->control_data;
1377 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1245 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1378 u8 lppllctl; 1246 unsigned int sysclk;
1379 int rate; 1247 int rate, ret;
1380 1248
1381 /* nothing to do for high-perf pll, it supports only 48 kHz */ 1249 /* nothing to do for high-perf pll, it supports only 48 kHz */
1382 if (priv->pll == TWL6040_HPPLL_ID) 1250 if (priv->pll == TWL6040_HPPLL_ID)
1383 return 0; 1251 return 0;
1384 1252
1385 lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
1386
1387 rate = params_rate(params); 1253 rate = params_rate(params);
1388 switch (rate) { 1254 switch (rate) {
1389 case 11250: 1255 case 11250:
1390 case 22500: 1256 case 22500:
1391 case 44100: 1257 case 44100:
1392 case 88200: 1258 case 88200:
1393 lppllctl |= TWL6040_LPLLFIN; 1259 sysclk = 17640000;
1394 priv->sysclk = 17640000;
1395 break; 1260 break;
1396 case 8000: 1261 case 8000:
1397 case 16000: 1262 case 16000:
1398 case 32000: 1263 case 32000:
1399 case 48000: 1264 case 48000:
1400 case 96000: 1265 case 96000:
1401 lppllctl &= ~TWL6040_LPLLFIN; 1266 sysclk = 19200000;
1402 priv->sysclk = 19200000;
1403 break; 1267 break;
1404 default: 1268 default:
1405 dev_err(codec->dev, "unsupported rate %d\n", rate); 1269 dev_err(codec->dev, "unsupported rate %d\n", rate);
1406 return -EINVAL; 1270 return -EINVAL;
1407 } 1271 }
1408 1272
1409 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); 1273 ret = twl6040_set_pll(twl6040, TWL6040_LPPLL_ID, priv->clk_in, sysclk);
1274 if (ret)
1275 return ret;
1276
1277 priv->sysclk = twl6040_get_sysclk(twl6040);
1410 1278
1411 return 0; 1279 return 0;
1412} 1280}
@@ -1449,99 +1317,27 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
1449 int clk_id, unsigned int freq, int dir) 1317 int clk_id, unsigned int freq, int dir)
1450{ 1318{
1451 struct snd_soc_codec *codec = codec_dai->codec; 1319 struct snd_soc_codec *codec = codec_dai->codec;
1320 struct twl6040 *twl6040 = codec->control_data;
1452 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1321 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1453 u8 hppllctl, lppllctl; 1322 int ret = 0;
1454
1455 hppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_HPPLLCTL);
1456 lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
1457 1323
1458 switch (clk_id) { 1324 switch (clk_id) {
1459 case TWL6040_SYSCLK_SEL_LPPLL: 1325 case TWL6040_SYSCLK_SEL_LPPLL:
1460 switch (freq) { 1326 ret = twl6040_set_pll(twl6040, TWL6040_LPPLL_ID,
1461 case 32768: 1327 freq, priv->sysclk);
1462 /* headset dac and driver must be in low-power mode */ 1328 if (ret)
1463 headset_power_mode(codec, 0); 1329 return ret;
1464
1465 /* clk32k input requires low-power pll */
1466 lppllctl |= TWL6040_LPLLENA;
1467 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1468 mdelay(5);
1469 lppllctl &= ~TWL6040_HPLLSEL;
1470 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1471 hppllctl &= ~TWL6040_HPLLENA;
1472 twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
1473 break;
1474 default:
1475 dev_err(codec->dev, "unknown mclk freq %d\n", freq);
1476 return -EINVAL;
1477 }
1478
1479 /* lppll divider */
1480 switch (priv->sysclk) {
1481 case 17640000:
1482 lppllctl |= TWL6040_LPLLFIN;
1483 break;
1484 case 19200000:
1485 lppllctl &= ~TWL6040_LPLLFIN;
1486 break;
1487 default:
1488 /* sysclk not yet configured */
1489 lppllctl &= ~TWL6040_LPLLFIN;
1490 priv->sysclk = 19200000;
1491 break;
1492 }
1493
1494 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1495 1330
1496 priv->pll = TWL6040_LPPLL_ID; 1331 headset_power_mode(codec, 0);
1497 priv->sysclk_constraints = &lp_constraints; 1332 priv->sysclk_constraints = &lp_constraints;
1498 break; 1333 break;
1499 case TWL6040_SYSCLK_SEL_HPPLL: 1334 case TWL6040_SYSCLK_SEL_HPPLL:
1500 hppllctl &= ~TWL6040_MCLK_MSK; 1335 ret = twl6040_set_pll(twl6040, TWL6040_HPPLL_ID,
1501 1336 freq, priv->sysclk);
1502 switch (freq) { 1337 if (ret)
1503 case 12000000: 1338 return ret;
1504 /* mclk input, pll enabled */
1505 hppllctl |= TWL6040_MCLK_12000KHZ |
1506 TWL6040_HPLLSQRBP |
1507 TWL6040_HPLLENA;
1508 break;
1509 case 19200000:
1510 /* mclk input, pll disabled */
1511 hppllctl |= TWL6040_MCLK_19200KHZ |
1512 TWL6040_HPLLSQRENA |
1513 TWL6040_HPLLBP;
1514 break;
1515 case 26000000:
1516 /* mclk input, pll enabled */
1517 hppllctl |= TWL6040_MCLK_26000KHZ |
1518 TWL6040_HPLLSQRBP |
1519 TWL6040_HPLLENA;
1520 break;
1521 case 38400000:
1522 /* clk slicer, pll disabled */
1523 hppllctl |= TWL6040_MCLK_38400KHZ |
1524 TWL6040_HPLLSQRENA |
1525 TWL6040_HPLLBP;
1526 break;
1527 default:
1528 dev_err(codec->dev, "unknown mclk freq %d\n", freq);
1529 return -EINVAL;
1530 }
1531 1339
1532 /* headset dac and driver must be in high-performance mode */
1533 headset_power_mode(codec, 1); 1340 headset_power_mode(codec, 1);
1534
1535 twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
1536 udelay(500);
1537 lppllctl |= TWL6040_HPLLSEL;
1538 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1539 lppllctl &= ~TWL6040_LPLLENA;
1540 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1541
1542 /* high-performance pll can provide only 19.2 MHz */
1543 priv->pll = TWL6040_HPPLL_ID;
1544 priv->sysclk = 19200000;
1545 priv->sysclk_constraints = &hp_constraints; 1341 priv->sysclk_constraints = &hp_constraints;
1546 break; 1342 break;
1547 default: 1343 default:
@@ -1549,6 +1345,10 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
1549 return -EINVAL; 1345 return -EINVAL;
1550 } 1346 }
1551 1347
1348 priv->pll = twl6040_get_pll(twl6040);
1349 priv->clk_in = freq;
1350 priv->sysclk = twl6040_get_sysclk(twl6040);
1351
1552 return 0; 1352 return 0;
1553} 1353}
1554 1354
@@ -1600,11 +1400,8 @@ static int twl6040_resume(struct snd_soc_codec *codec)
1600 1400
1601static int twl6040_probe(struct snd_soc_codec *codec) 1401static int twl6040_probe(struct snd_soc_codec *codec)
1602{ 1402{
1603 struct twl4030_audio_data *twl_codec = codec->dev->platform_data;
1604 struct twl6040_data *priv; 1403 struct twl6040_data *priv;
1605 int audpwron, naudint;
1606 int ret = 0; 1404 int ret = 0;
1607 u8 icrev, intmr = TWL6040_ALLINT_MSK;
1608 1405
1609 priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL); 1406 priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
1610 if (priv == NULL) 1407 if (priv == NULL)
@@ -1612,23 +1409,9 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1612 snd_soc_codec_set_drvdata(codec, priv); 1409 snd_soc_codec_set_drvdata(codec, priv);
1613 1410
1614 priv->codec = codec; 1411 priv->codec = codec;
1412 codec->control_data = dev_get_drvdata(codec->dev->parent);
1615 1413
1616 twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &icrev, TWL6040_REG_ASICREV);
1617
1618 if (twl_codec && (icrev > 0))
1619 audpwron = twl_codec->audpwron_gpio;
1620 else
1621 audpwron = -EINVAL;
1622
1623 if (twl_codec)
1624 naudint = twl_codec->naudint_irq;
1625 else
1626 naudint = 0;
1627
1628 priv->audpwron = audpwron;
1629 priv->naudint = naudint;
1630 priv->workqueue = create_singlethread_workqueue("twl6040-codec"); 1414 priv->workqueue = create_singlethread_workqueue("twl6040-codec");
1631
1632 if (!priv->workqueue) { 1415 if (!priv->workqueue) {
1633 ret = -ENOMEM; 1416 ret = -ENOMEM;
1634 goto work_err; 1417 goto work_err;
@@ -1638,56 +1421,34 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1638 1421
1639 mutex_init(&priv->mutex); 1422 mutex_init(&priv->mutex);
1640 1423
1641 init_completion(&priv->ready);
1642 init_completion(&priv->headset.ramp_done); 1424 init_completion(&priv->headset.ramp_done);
1643 init_completion(&priv->handsfree.ramp_done); 1425 init_completion(&priv->handsfree.ramp_done);
1644 1426
1645 if (gpio_is_valid(audpwron)) {
1646 ret = gpio_request(audpwron, "audpwron");
1647 if (ret)
1648 goto gpio1_err;
1649
1650 ret = gpio_direction_output(audpwron, 0);
1651 if (ret)
1652 goto gpio2_err;
1653
1654 priv->codec_powered = 0;
1655
1656 /* enable only codec ready interrupt */
1657 intmr &= ~(TWL6040_READYMSK | TWL6040_PLUGMSK);
1658
1659 /* reset interrupt status to allow correct power up sequence */
1660 twl6040_read_reg_volatile(codec, TWL6040_REG_INTID);
1661 }
1662 twl6040_write(codec, TWL6040_REG_INTMR, intmr);
1663
1664 if (naudint) {
1665 /* audio interrupt */
1666 ret = request_threaded_irq(naudint, NULL,
1667 twl6040_naudint_handler,
1668 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
1669 "twl6040_codec", codec);
1670 if (ret)
1671 goto gpio2_err;
1672 }
1673
1674 /* init vio registers */
1675 twl6040_init_vio_regs(codec);
1676
1677 priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf"); 1427 priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf");
1678 if (priv->hf_workqueue == NULL) { 1428 if (priv->hf_workqueue == NULL) {
1679 ret = -ENOMEM; 1429 ret = -ENOMEM;
1680 goto irq_err; 1430 goto hfwq_err;
1681 } 1431 }
1682 priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs"); 1432 priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs");
1683 if (priv->hs_workqueue == NULL) { 1433 if (priv->hs_workqueue == NULL) {
1684 ret = -ENOMEM; 1434 ret = -ENOMEM;
1685 goto wq_err; 1435 goto hswq_err;
1686 } 1436 }
1687 1437
1688 INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work); 1438 INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work);
1689 INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work); 1439 INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work);
1690 1440
1441 ret = twl6040_request_irq(codec->control_data, TWL6040_IRQ_PLUG,
1442 twl6040_audio_handler, 0,
1443 "twl6040_irq_plug", codec);
1444 if (ret) {
1445 dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
1446 goto plugirq_err;
1447 }
1448
1449 /* init vio registers */
1450 twl6040_init_vio_regs(codec);
1451
1691 /* power on device */ 1452 /* power on device */
1692 ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1453 ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1693 if (ret) 1454 if (ret)
@@ -1700,16 +1461,12 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1700 return 0; 1461 return 0;
1701 1462
1702bias_err: 1463bias_err:
1464 twl6040_free_irq(codec->control_data, TWL6040_IRQ_PLUG, codec);
1465plugirq_err:
1703 destroy_workqueue(priv->hs_workqueue); 1466 destroy_workqueue(priv->hs_workqueue);
1704wq_err: 1467hswq_err:
1705 destroy_workqueue(priv->hf_workqueue); 1468 destroy_workqueue(priv->hf_workqueue);
1706irq_err: 1469hfwq_err:
1707 if (naudint)
1708 free_irq(naudint, codec);
1709gpio2_err:
1710 if (gpio_is_valid(audpwron))
1711 gpio_free(audpwron);
1712gpio1_err:
1713 destroy_workqueue(priv->workqueue); 1470 destroy_workqueue(priv->workqueue);
1714work_err: 1471work_err:
1715 kfree(priv); 1472 kfree(priv);
@@ -1719,17 +1476,9 @@ work_err:
1719static int twl6040_remove(struct snd_soc_codec *codec) 1476static int twl6040_remove(struct snd_soc_codec *codec)
1720{ 1477{
1721 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1478 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1722 int audpwron = priv->audpwron;
1723 int naudint = priv->naudint;
1724 1479
1725 twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); 1480 twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
1726 1481 twl6040_free_irq(codec->control_data, TWL6040_IRQ_PLUG, codec);
1727 if (gpio_is_valid(audpwron))
1728 gpio_free(audpwron);
1729
1730 if (naudint)
1731 free_irq(naudint, codec);
1732
1733 destroy_workqueue(priv->workqueue); 1482 destroy_workqueue(priv->workqueue);
1734 destroy_workqueue(priv->hf_workqueue); 1483 destroy_workqueue(priv->hf_workqueue);
1735 destroy_workqueue(priv->hs_workqueue); 1484 destroy_workqueue(priv->hs_workqueue);
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
index 23aeed0963e6..234bfad24e6f 100644
--- a/sound/soc/codecs/twl6040.h
+++ b/sound/soc/codecs/twl6040.h
@@ -22,124 +22,6 @@
22#ifndef __TWL6040_H__ 22#ifndef __TWL6040_H__
23#define __TWL6040_H__ 23#define __TWL6040_H__
24 24
25#define TWL6040_REG_ASICID 0x01
26#define TWL6040_REG_ASICREV 0x02
27#define TWL6040_REG_INTID 0x03
28#define TWL6040_REG_INTMR 0x04
29#define TWL6040_REG_NCPCTL 0x05
30#define TWL6040_REG_LDOCTL 0x06
31#define TWL6040_REG_HPPLLCTL 0x07
32#define TWL6040_REG_LPPLLCTL 0x08
33#define TWL6040_REG_LPPLLDIV 0x09
34#define TWL6040_REG_AMICBCTL 0x0A
35#define TWL6040_REG_DMICBCTL 0x0B
36#define TWL6040_REG_MICLCTL 0x0C
37#define TWL6040_REG_MICRCTL 0x0D
38#define TWL6040_REG_MICGAIN 0x0E
39#define TWL6040_REG_LINEGAIN 0x0F
40#define TWL6040_REG_HSLCTL 0x10
41#define TWL6040_REG_HSRCTL 0x11
42#define TWL6040_REG_HSGAIN 0x12
43#define TWL6040_REG_EARCTL 0x13
44#define TWL6040_REG_HFLCTL 0x14
45#define TWL6040_REG_HFLGAIN 0x15
46#define TWL6040_REG_HFRCTL 0x16
47#define TWL6040_REG_HFRGAIN 0x17
48#define TWL6040_REG_VIBCTLL 0x18
49#define TWL6040_REG_VIBDATL 0x19
50#define TWL6040_REG_VIBCTLR 0x1A
51#define TWL6040_REG_VIBDATR 0x1B
52#define TWL6040_REG_HKCTL1 0x1C
53#define TWL6040_REG_HKCTL2 0x1D
54#define TWL6040_REG_GPOCTL 0x1E
55#define TWL6040_REG_ALB 0x1F
56#define TWL6040_REG_DLB 0x20
57#define TWL6040_REG_TRIM1 0x28
58#define TWL6040_REG_TRIM2 0x29
59#define TWL6040_REG_TRIM3 0x2A
60#define TWL6040_REG_HSOTRIM 0x2B
61#define TWL6040_REG_HFOTRIM 0x2C
62#define TWL6040_REG_ACCCTL 0x2D
63#define TWL6040_REG_STATUS 0x2E
64
65#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
66
67#define TWL6040_VIOREGNUM 18
68#define TWL6040_VDDREGNUM 21
69
70/* INTID (0x03) fields */
71
72#define TWL6040_THINT 0x01
73#define TWL6040_PLUGINT 0x02
74#define TWL6040_UNPLUGINT 0x04
75#define TWL6040_HOOKINT 0x08
76#define TWL6040_HFINT 0x10
77#define TWL6040_VIBINT 0x20
78#define TWL6040_READYINT 0x40
79
80/* INTMR (0x04) fields */
81
82#define TWL6040_PLUGMSK 0x02
83#define TWL6040_READYMSK 0x40
84#define TWL6040_ALLINT_MSK 0x7B
85
86/* NCPCTL (0x05) fields */
87
88#define TWL6040_NCPENA 0x01
89#define TWL6040_NCPOPEN 0x40
90
91/* LDOCTL (0x06) fields */
92
93#define TWL6040_LSLDOENA 0x01
94#define TWL6040_HSLDOENA 0x04
95#define TWL6040_REFENA 0x40
96#define TWL6040_OSCENA 0x80
97
98/* HPPLLCTL (0x07) fields */
99
100#define TWL6040_HPLLENA 0x01
101#define TWL6040_HPLLRST 0x02
102#define TWL6040_HPLLBP 0x04
103#define TWL6040_HPLLSQRENA 0x08
104#define TWL6040_HPLLSQRBP 0x10
105#define TWL6040_MCLK_12000KHZ (0 << 5)
106#define TWL6040_MCLK_19200KHZ (1 << 5)
107#define TWL6040_MCLK_26000KHZ (2 << 5)
108#define TWL6040_MCLK_38400KHZ (3 << 5)
109#define TWL6040_MCLK_MSK 0x60
110
111/* LPPLLCTL (0x08) fields */
112
113#define TWL6040_LPLLENA 0x01
114#define TWL6040_LPLLRST 0x02
115#define TWL6040_LPLLSEL 0x04
116#define TWL6040_LPLLFIN 0x08
117#define TWL6040_HPLLSEL 0x10
118
119/* HSLCTL (0x10) fields */
120
121#define TWL6040_HSDACMODEL 0x02
122#define TWL6040_HSDRVMODEL 0x08
123
124/* HSRCTL (0x11) fields */
125
126#define TWL6040_HSDACMODER 0x02
127#define TWL6040_HSDRVMODER 0x08
128
129/* ACCCTL (0x2D) fields */
130
131#define TWL6040_RESETSPLIT 0x04
132
133#define TWL6040_SYSCLK_SEL_LPPLL 1
134#define TWL6040_SYSCLK_SEL_HPPLL 2
135
136#define TWL6040_HPPLL_ID 1
137#define TWL6040_LPPLL_ID 2
138
139/* STATUS (0x2E) fields */
140
141#define TWL6040_PLUGCOMP 0x02
142
143void twl6040_hs_jack_detect(struct snd_soc_codec *codec, 25void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
144 struct snd_soc_jack *jack, int report); 26 struct snd_soc_jack *jack, int report);
145 27
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index 189e03900637..5d67c25bca5e 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -21,6 +21,8 @@
21 21
22#include <linux/clk.h> 22#include <linux/clk.h>
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24#include <linux/mfd/twl6040.h>
25
24#include <sound/core.h> 26#include <sound/core.h>
25#include <sound/pcm.h> 27#include <sound/pcm.h>
26#include <sound/soc.h> 28#include <sound/soc.h>