diff options
| author | Takashi Iwai <tiwai@suse.de> | 2010-05-06 11:06:27 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2010-05-06 11:06:27 -0400 |
| commit | aeb29a82de7c80d4d0253b042f17eb1f725b08f1 (patch) | |
| tree | f15ba557a22b010cd790ead5a3c4a4a9872fe58f | |
| parent | 39b8eab7e7fe429d8d57f18c0ebdb7c25df55f5c (diff) | |
| parent | 2f005471e2e2f2c7fa5898153387d421f7d24ad6 (diff) | |
Merge branch 'for-2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc-2.6 into topic/asoc
| -rw-r--r-- | include/sound/tlv320aic3x.h | 17 | ||||
| -rw-r--r-- | include/sound/tpa6130a2-plat.h | 1 | ||||
| -rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 25 | ||||
| -rw-r--r-- | sound/soc/codecs/tlv320dac33.c | 223 | ||||
| -rw-r--r-- | sound/soc/codecs/tpa6130a2.c | 99 | ||||
| -rw-r--r-- | sound/soc/codecs/twl4030.c | 86 | ||||
| -rw-r--r-- | sound/soc/omap/Kconfig | 10 | ||||
| -rw-r--r-- | sound/soc/omap/Makefile | 2 | ||||
| -rw-r--r-- | sound/soc/omap/omap3pandora.c | 2 | ||||
| -rw-r--r-- | sound/soc/omap/rx51.c | 294 | ||||
| -rw-r--r-- | sound/soc/omap/zoom2.c | 3 |
11 files changed, 619 insertions, 143 deletions
diff --git a/include/sound/tlv320aic3x.h b/include/sound/tlv320aic3x.h new file mode 100644 index 000000000000..b1a5f34e5cfa --- /dev/null +++ b/include/sound/tlv320aic3x.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | /* | ||
| 2 | * Platform data for Texas Instruments TLV320AIC3x codec | ||
| 3 | * | ||
| 4 | * Author: Jarkko Nikula <jhnikula@gmail.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | #ifndef __TLV320AIC3x_H__ | ||
| 11 | #define __TLV320AIC3x_H__ | ||
| 12 | |||
| 13 | struct aic3x_pdata { | ||
| 14 | int gpio_reset; /* < 0 if not used */ | ||
| 15 | }; | ||
| 16 | |||
| 17 | #endif \ No newline at end of file | ||
diff --git a/include/sound/tpa6130a2-plat.h b/include/sound/tpa6130a2-plat.h index e29fde6b5cbe..426f62767dab 100644 --- a/include/sound/tpa6130a2-plat.h +++ b/include/sound/tpa6130a2-plat.h | |||
| @@ -31,6 +31,7 @@ enum tpa_model { | |||
| 31 | struct tpa6130a2_platform_data { | 31 | struct tpa6130a2_platform_data { |
| 32 | enum tpa_model id; | 32 | enum tpa_model id; |
| 33 | int power_gpio; | 33 | int power_gpio; |
| 34 | int limit_gain; | ||
| 34 | }; | 35 | }; |
| 35 | 36 | ||
| 36 | #endif | 37 | #endif |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 584bc1e67f76..d57372be7a96 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
| 39 | #include <linux/pm.h> | 39 | #include <linux/pm.h> |
| 40 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
| 41 | #include <linux/gpio.h> | ||
| 41 | #include <linux/regulator/consumer.h> | 42 | #include <linux/regulator/consumer.h> |
| 42 | #include <linux/platform_device.h> | 43 | #include <linux/platform_device.h> |
| 43 | #include <sound/core.h> | 44 | #include <sound/core.h> |
| @@ -47,6 +48,7 @@ | |||
| 47 | #include <sound/soc-dapm.h> | 48 | #include <sound/soc-dapm.h> |
| 48 | #include <sound/initval.h> | 49 | #include <sound/initval.h> |
| 49 | #include <sound/tlv.h> | 50 | #include <sound/tlv.h> |
| 51 | #include <sound/tlv320aic3x.h> | ||
| 50 | 52 | ||
| 51 | #include "tlv320aic3x.h" | 53 | #include "tlv320aic3x.h" |
| 52 | 54 | ||
| @@ -64,6 +66,7 @@ struct aic3x_priv { | |||
| 64 | struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; | 66 | struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; |
| 65 | unsigned int sysclk; | 67 | unsigned int sysclk; |
| 66 | int master; | 68 | int master; |
| 69 | int gpio_reset; | ||
| 67 | }; | 70 | }; |
| 68 | 71 | ||
| 69 | /* | 72 | /* |
| @@ -1278,6 +1281,10 @@ static int aic3x_unregister(struct aic3x_priv *aic3x) | |||
| 1278 | snd_soc_unregister_dai(&aic3x_dai); | 1281 | snd_soc_unregister_dai(&aic3x_dai); |
| 1279 | snd_soc_unregister_codec(&aic3x->codec); | 1282 | snd_soc_unregister_codec(&aic3x->codec); |
| 1280 | 1283 | ||
| 1284 | if (aic3x->gpio_reset >= 0) { | ||
| 1285 | gpio_set_value(aic3x->gpio_reset, 0); | ||
| 1286 | gpio_free(aic3x->gpio_reset); | ||
| 1287 | } | ||
| 1281 | regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | 1288 | regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); |
| 1282 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | 1289 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); |
| 1283 | 1290 | ||
| @@ -1302,6 +1309,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
| 1302 | { | 1309 | { |
| 1303 | struct snd_soc_codec *codec; | 1310 | struct snd_soc_codec *codec; |
| 1304 | struct aic3x_priv *aic3x; | 1311 | struct aic3x_priv *aic3x; |
| 1312 | struct aic3x_pdata *pdata = i2c->dev.platform_data; | ||
| 1305 | int ret, i; | 1313 | int ret, i; |
| 1306 | 1314 | ||
| 1307 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | 1315 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); |
| @@ -1318,6 +1326,15 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
| 1318 | 1326 | ||
| 1319 | i2c_set_clientdata(i2c, aic3x); | 1327 | i2c_set_clientdata(i2c, aic3x); |
| 1320 | 1328 | ||
| 1329 | aic3x->gpio_reset = -1; | ||
| 1330 | if (pdata && pdata->gpio_reset >= 0) { | ||
| 1331 | ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset"); | ||
| 1332 | if (ret != 0) | ||
| 1333 | goto err_gpio; | ||
| 1334 | aic3x->gpio_reset = pdata->gpio_reset; | ||
| 1335 | gpio_direction_output(aic3x->gpio_reset, 0); | ||
| 1336 | } | ||
| 1337 | |||
| 1321 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | 1338 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) |
| 1322 | aic3x->supplies[i].supply = aic3x_supply_names[i]; | 1339 | aic3x->supplies[i].supply = aic3x_supply_names[i]; |
| 1323 | 1340 | ||
| @@ -1335,11 +1352,19 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
| 1335 | goto err_enable; | 1352 | goto err_enable; |
| 1336 | } | 1353 | } |
| 1337 | 1354 | ||
| 1355 | if (aic3x->gpio_reset >= 0) { | ||
| 1356 | udelay(1); | ||
| 1357 | gpio_set_value(aic3x->gpio_reset, 1); | ||
| 1358 | } | ||
| 1359 | |||
| 1338 | return aic3x_register(codec); | 1360 | return aic3x_register(codec); |
| 1339 | 1361 | ||
| 1340 | err_enable: | 1362 | err_enable: |
| 1341 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | 1363 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); |
| 1342 | err_get: | 1364 | err_get: |
| 1365 | if (aic3x->gpio_reset >= 0) | ||
| 1366 | gpio_free(aic3x->gpio_reset); | ||
| 1367 | err_gpio: | ||
| 1343 | kfree(aic3x); | 1368 | kfree(aic3x); |
| 1344 | return ret; | 1369 | return ret; |
| 1345 | } | 1370 | } |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 3eddaec728c1..ad5e2636c944 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
| @@ -61,6 +61,8 @@ | |||
| 61 | #define US_TO_SAMPLES(rate, us) \ | 61 | #define US_TO_SAMPLES(rate, us) \ |
| 62 | (rate / (1000000 / us)) | 62 | (rate / (1000000 / us)) |
| 63 | 63 | ||
| 64 | static void dac33_calculate_times(struct snd_pcm_substream *substream); | ||
| 65 | static int dac33_prepare_chip(struct snd_pcm_substream *substream); | ||
| 64 | 66 | ||
| 65 | static struct snd_soc_codec *tlv320dac33_codec; | 67 | static struct snd_soc_codec *tlv320dac33_codec; |
| 66 | 68 | ||
| @@ -91,6 +93,7 @@ struct tlv320dac33_priv { | |||
| 91 | struct work_struct work; | 93 | struct work_struct work; |
| 92 | struct snd_soc_codec codec; | 94 | struct snd_soc_codec codec; |
| 93 | struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES]; | 95 | struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES]; |
| 96 | struct snd_pcm_substream *substream; | ||
| 94 | int power_gpio; | 97 | int power_gpio; |
| 95 | int chip_power; | 98 | int chip_power; |
| 96 | int irq; | 99 | int irq; |
| @@ -284,45 +287,47 @@ static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg, | |||
| 284 | return ret; | 287 | return ret; |
| 285 | } | 288 | } |
| 286 | 289 | ||
| 287 | static void dac33_restore_regs(struct snd_soc_codec *codec) | 290 | static void dac33_init_chip(struct snd_soc_codec *codec) |
| 288 | { | 291 | { |
| 289 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 292 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
| 290 | u8 *cache = codec->reg_cache; | ||
| 291 | u8 data[2]; | ||
| 292 | int i, ret; | ||
| 293 | 293 | ||
| 294 | if (!dac33->chip_power) | 294 | if (unlikely(!dac33->chip_power)) |
| 295 | return; | 295 | return; |
| 296 | 296 | ||
| 297 | for (i = DAC33_PWR_CTRL; i <= DAC33_INTP_CTRL_B; i++) { | 297 | /* 44-46: DAC Control Registers */ |
| 298 | data[0] = i; | 298 | /* A : DAC sample rate Fsref/1.5 */ |
| 299 | data[1] = cache[i]; | 299 | dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0)); |
| 300 | /* Skip the read only registers */ | 300 | /* B : DAC src=normal, not muted */ |
| 301 | if ((i >= DAC33_INT_OSC_STATUS && | 301 | dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT | |
| 302 | i <= DAC33_INT_OSC_FREQ_RAT_READ_B) || | 302 | DAC33_DACSRCL_LEFT); |
| 303 | (i >= DAC33_FIFO_WPTR_MSB && i <= DAC33_FIFO_IRQ_FLAG) || | 303 | /* C : (defaults) */ |
| 304 | i == DAC33_DAC_STATUS_FLAGS || | 304 | dac33_write(codec, DAC33_DAC_CTRL_C, 0x00); |
| 305 | i == DAC33_SRC_EST_REF_CLK_RATIO_A || | 305 | |
| 306 | i == DAC33_SRC_EST_REF_CLK_RATIO_B) | 306 | /* 73 : volume soft stepping control, |
| 307 | continue; | 307 | clock source = internal osc (?) */ |
| 308 | ret = codec->hw_write(codec->control_data, data, 2); | 308 | dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN); |
| 309 | if (ret != 2) | 309 | |
| 310 | dev_err(codec->dev, "Write failed (%d)\n", ret); | 310 | dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB); |
| 311 | } | 311 | |
| 312 | for (i = DAC33_LDAC_PWR_CTRL; i <= DAC33_LINEL_TO_LLO_VOL; i++) { | 312 | /* Restore only selected registers (gains mostly) */ |
| 313 | data[0] = i; | 313 | dac33_write(codec, DAC33_LDAC_DIG_VOL_CTRL, |
| 314 | data[1] = cache[i]; | 314 | dac33_read_reg_cache(codec, DAC33_LDAC_DIG_VOL_CTRL)); |
| 315 | ret = codec->hw_write(codec->control_data, data, 2); | 315 | dac33_write(codec, DAC33_RDAC_DIG_VOL_CTRL, |
| 316 | if (ret != 2) | 316 | dac33_read_reg_cache(codec, DAC33_RDAC_DIG_VOL_CTRL)); |
| 317 | dev_err(codec->dev, "Write failed (%d)\n", ret); | 317 | |
| 318 | } | 318 | dac33_write(codec, DAC33_LINEL_TO_LLO_VOL, |
| 319 | for (i = DAC33_LINER_TO_RLO_VOL; i <= DAC33_OSC_TRIM; i++) { | 319 | dac33_read_reg_cache(codec, DAC33_LINEL_TO_LLO_VOL)); |
| 320 | data[0] = i; | 320 | dac33_write(codec, DAC33_LINER_TO_RLO_VOL, |
| 321 | data[1] = cache[i]; | 321 | dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL)); |
| 322 | ret = codec->hw_write(codec->control_data, data, 2); | 322 | } |
| 323 | if (ret != 2) | 323 | |
| 324 | dev_err(codec->dev, "Write failed (%d)\n", ret); | 324 | static inline void dac33_read_id(struct snd_soc_codec *codec) |
| 325 | } | 325 | { |
| 326 | u8 reg; | ||
| 327 | |||
| 328 | dac33_read(codec, DAC33_DEVICE_ID_MSB, ®); | ||
| 329 | dac33_read(codec, DAC33_DEVICE_ID_LSB, ®); | ||
| 330 | dac33_read(codec, DAC33_DEVICE_REV_ID, ®); | ||
| 326 | } | 331 | } |
| 327 | 332 | ||
| 328 | static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) | 333 | static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) |
| @@ -341,9 +346,17 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) | |||
| 341 | static int dac33_hard_power(struct snd_soc_codec *codec, int power) | 346 | static int dac33_hard_power(struct snd_soc_codec *codec, int power) |
| 342 | { | 347 | { |
| 343 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 348 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
| 344 | int ret; | 349 | int ret = 0; |
| 345 | 350 | ||
| 346 | mutex_lock(&dac33->mutex); | 351 | mutex_lock(&dac33->mutex); |
| 352 | |||
| 353 | /* Safety check */ | ||
| 354 | if (unlikely(power == dac33->chip_power)) { | ||
| 355 | dev_warn(codec->dev, "Trying to set the same power state: %s\n", | ||
| 356 | power ? "ON" : "OFF"); | ||
| 357 | goto exit; | ||
| 358 | } | ||
| 359 | |||
| 347 | if (power) { | 360 | if (power) { |
| 348 | ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), | 361 | ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), |
| 349 | dac33->supplies); | 362 | dac33->supplies); |
| @@ -357,11 +370,6 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power) | |||
| 357 | gpio_set_value(dac33->power_gpio, 1); | 370 | gpio_set_value(dac33->power_gpio, 1); |
| 358 | 371 | ||
| 359 | dac33->chip_power = 1; | 372 | dac33->chip_power = 1; |
| 360 | |||
| 361 | /* Restore registers */ | ||
| 362 | dac33_restore_regs(codec); | ||
| 363 | |||
| 364 | dac33_soft_power(codec, 1); | ||
| 365 | } else { | 373 | } else { |
| 366 | dac33_soft_power(codec, 0); | 374 | dac33_soft_power(codec, 0); |
| 367 | if (dac33->power_gpio >= 0) | 375 | if (dac33->power_gpio >= 0) |
| @@ -383,6 +391,22 @@ exit: | |||
| 383 | return ret; | 391 | return ret; |
| 384 | } | 392 | } |
| 385 | 393 | ||
| 394 | static int playback_event(struct snd_soc_dapm_widget *w, | ||
| 395 | struct snd_kcontrol *kcontrol, int event) | ||
| 396 | { | ||
| 397 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec); | ||
| 398 | |||
| 399 | switch (event) { | ||
| 400 | case SND_SOC_DAPM_PRE_PMU: | ||
| 401 | if (likely(dac33->substream)) { | ||
| 402 | dac33_calculate_times(dac33->substream); | ||
| 403 | dac33_prepare_chip(dac33->substream); | ||
| 404 | } | ||
| 405 | break; | ||
| 406 | } | ||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 386 | static int dac33_get_nsample(struct snd_kcontrol *kcontrol, | 410 | static int dac33_get_nsample(struct snd_kcontrol *kcontrol, |
| 387 | struct snd_ctl_elem_value *ucontrol) | 411 | struct snd_ctl_elem_value *ucontrol) |
| 388 | { | 412 | { |
| @@ -512,6 +536,8 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = { | |||
| 512 | DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0), | 536 | DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0), |
| 513 | SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power", | 537 | SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power", |
| 514 | DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0), | 538 | DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0), |
| 539 | |||
| 540 | SND_SOC_DAPM_PRE("Prepare Playback", playback_event), | ||
| 515 | }; | 541 | }; |
| 516 | 542 | ||
| 517 | static const struct snd_soc_dapm_route audio_map[] = { | 543 | static const struct snd_soc_dapm_route audio_map[] = { |
| @@ -554,18 +580,18 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, | |||
| 554 | break; | 580 | break; |
| 555 | case SND_SOC_BIAS_STANDBY: | 581 | case SND_SOC_BIAS_STANDBY: |
| 556 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 582 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
| 583 | /* Coming from OFF, switch on the codec */ | ||
| 557 | ret = dac33_hard_power(codec, 1); | 584 | ret = dac33_hard_power(codec, 1); |
| 558 | if (ret != 0) | 585 | if (ret != 0) |
| 559 | return ret; | 586 | return ret; |
| 560 | } | ||
| 561 | 587 | ||
| 562 | dac33_soft_power(codec, 0); | 588 | dac33_init_chip(codec); |
| 589 | } | ||
| 563 | break; | 590 | break; |
| 564 | case SND_SOC_BIAS_OFF: | 591 | case SND_SOC_BIAS_OFF: |
| 565 | ret = dac33_hard_power(codec, 0); | 592 | ret = dac33_hard_power(codec, 0); |
| 566 | if (ret != 0) | 593 | if (ret != 0) |
| 567 | return ret; | 594 | return ret; |
| 568 | |||
| 569 | break; | 595 | break; |
| 570 | } | 596 | } |
| 571 | codec->bias_level = level; | 597 | codec->bias_level = level; |
| @@ -708,6 +734,31 @@ static void dac33_oscwait(struct snd_soc_codec *codec) | |||
| 708 | "internal oscillator calibration failed\n"); | 734 | "internal oscillator calibration failed\n"); |
| 709 | } | 735 | } |
| 710 | 736 | ||
| 737 | static int dac33_startup(struct snd_pcm_substream *substream, | ||
| 738 | struct snd_soc_dai *dai) | ||
| 739 | { | ||
| 740 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 741 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 742 | struct snd_soc_codec *codec = socdev->card->codec; | ||
| 743 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | ||
| 744 | |||
| 745 | /* Stream started, save the substream pointer */ | ||
| 746 | dac33->substream = substream; | ||
| 747 | |||
| 748 | return 0; | ||
| 749 | } | ||
| 750 | |||
| 751 | static void dac33_shutdown(struct snd_pcm_substream *substream, | ||
| 752 | struct snd_soc_dai *dai) | ||
| 753 | { | ||
| 754 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 755 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 756 | struct snd_soc_codec *codec = socdev->card->codec; | ||
| 757 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | ||
| 758 | |||
| 759 | dac33->substream = NULL; | ||
| 760 | } | ||
| 761 | |||
| 711 | static int dac33_hw_params(struct snd_pcm_substream *substream, | 762 | static int dac33_hw_params(struct snd_pcm_substream *substream, |
| 712 | struct snd_pcm_hw_params *params, | 763 | struct snd_pcm_hw_params *params, |
| 713 | struct snd_soc_dai *dai) | 764 | struct snd_soc_dai *dai) |
| @@ -791,6 +842,16 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) | |||
| 791 | } | 842 | } |
| 792 | 843 | ||
| 793 | mutex_lock(&dac33->mutex); | 844 | mutex_lock(&dac33->mutex); |
| 845 | |||
| 846 | if (!dac33->chip_power) { | ||
| 847 | /* | ||
| 848 | * Chip is not powered yet. | ||
| 849 | * Do the init in the dac33_set_bias_level later. | ||
| 850 | */ | ||
| 851 | mutex_unlock(&dac33->mutex); | ||
| 852 | return 0; | ||
| 853 | } | ||
| 854 | |||
| 794 | dac33_soft_power(codec, 0); | 855 | dac33_soft_power(codec, 0); |
| 795 | dac33_soft_power(codec, 1); | 856 | dac33_soft_power(codec, 1); |
| 796 | 857 | ||
| @@ -997,15 +1058,6 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) | |||
| 997 | 1058 | ||
| 998 | } | 1059 | } |
| 999 | 1060 | ||
| 1000 | static int dac33_pcm_prepare(struct snd_pcm_substream *substream, | ||
| 1001 | struct snd_soc_dai *dai) | ||
| 1002 | { | ||
| 1003 | dac33_calculate_times(substream); | ||
| 1004 | dac33_prepare_chip(substream); | ||
| 1005 | |||
| 1006 | return 0; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, | 1061 | static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, |
| 1010 | struct snd_soc_dai *dai) | 1062 | struct snd_soc_dai *dai) |
| 1011 | { | 1063 | { |
| @@ -1269,35 +1321,6 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
| 1269 | return 0; | 1321 | return 0; |
| 1270 | } | 1322 | } |
| 1271 | 1323 | ||
| 1272 | static void dac33_init_chip(struct snd_soc_codec *codec) | ||
| 1273 | { | ||
| 1274 | /* 44-46: DAC Control Registers */ | ||
| 1275 | /* A : DAC sample rate Fsref/1.5 */ | ||
| 1276 | dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0)); | ||
| 1277 | /* B : DAC src=normal, not muted */ | ||
| 1278 | dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT | | ||
| 1279 | DAC33_DACSRCL_LEFT); | ||
| 1280 | /* C : (defaults) */ | ||
| 1281 | dac33_write(codec, DAC33_DAC_CTRL_C, 0x00); | ||
| 1282 | |||
| 1283 | /* 64-65 : L&R DAC power control | ||
| 1284 | Line In -> OUT 1V/V Gain, DAC -> OUT 4V/V Gain*/ | ||
| 1285 | dac33_write(codec, DAC33_LDAC_PWR_CTRL, DAC33_LROUT_GAIN(2)); | ||
| 1286 | dac33_write(codec, DAC33_RDAC_PWR_CTRL, DAC33_LROUT_GAIN(2)); | ||
| 1287 | |||
| 1288 | /* 73 : volume soft stepping control, | ||
| 1289 | clock source = internal osc (?) */ | ||
| 1290 | dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN); | ||
| 1291 | |||
| 1292 | /* 66 : LOP/LOM Modes */ | ||
| 1293 | dac33_write(codec, DAC33_OUT_AMP_CM_CTRL, 0xff); | ||
| 1294 | |||
| 1295 | /* 68 : LOM inverted from LOP */ | ||
| 1296 | dac33_write(codec, DAC33_OUT_AMP_CTRL, (3<<2)); | ||
| 1297 | |||
| 1298 | dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB); | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | static int dac33_soc_probe(struct platform_device *pdev) | 1324 | static int dac33_soc_probe(struct platform_device *pdev) |
| 1302 | { | 1325 | { |
| 1303 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1326 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| @@ -1311,11 +1334,6 @@ static int dac33_soc_probe(struct platform_device *pdev) | |||
| 1311 | socdev->card->codec = codec; | 1334 | socdev->card->codec = codec; |
| 1312 | dac33 = snd_soc_codec_get_drvdata(codec); | 1335 | dac33 = snd_soc_codec_get_drvdata(codec); |
| 1313 | 1336 | ||
| 1314 | /* Power up the codec */ | ||
| 1315 | dac33_hard_power(codec, 1); | ||
| 1316 | /* Set default configuration */ | ||
| 1317 | dac33_init_chip(codec); | ||
| 1318 | |||
| 1319 | /* register pcms */ | 1337 | /* register pcms */ |
| 1320 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1338 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
| 1321 | if (ret < 0) { | 1339 | if (ret < 0) { |
| @@ -1332,12 +1350,6 @@ static int dac33_soc_probe(struct platform_device *pdev) | |||
| 1332 | 1350 | ||
| 1333 | dac33_add_widgets(codec); | 1351 | dac33_add_widgets(codec); |
| 1334 | 1352 | ||
| 1335 | /* power on device */ | ||
| 1336 | dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 1337 | |||
| 1338 | /* Bias level configuration has enabled regulator an extra time */ | ||
| 1339 | regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
| 1340 | |||
| 1341 | return 0; | 1353 | return 0; |
| 1342 | 1354 | ||
| 1343 | pcm_err: | 1355 | pcm_err: |
| @@ -1374,6 +1386,8 @@ static int dac33_soc_resume(struct platform_device *pdev) | |||
| 1374 | struct snd_soc_codec *codec = socdev->card->codec; | 1386 | struct snd_soc_codec *codec = socdev->card->codec; |
| 1375 | 1387 | ||
| 1376 | dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1388 | dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 1389 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) | ||
| 1390 | dac33_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | ||
| 1377 | dac33_set_bias_level(codec, codec->suspend_bias_level); | 1391 | dac33_set_bias_level(codec, codec->suspend_bias_level); |
| 1378 | 1392 | ||
| 1379 | return 0; | 1393 | return 0; |
| @@ -1392,8 +1406,9 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33); | |||
| 1392 | #define DAC33_FORMATS SNDRV_PCM_FMTBIT_S16_LE | 1406 | #define DAC33_FORMATS SNDRV_PCM_FMTBIT_S16_LE |
| 1393 | 1407 | ||
| 1394 | static struct snd_soc_dai_ops dac33_dai_ops = { | 1408 | static struct snd_soc_dai_ops dac33_dai_ops = { |
| 1409 | .startup = dac33_startup, | ||
| 1410 | .shutdown = dac33_shutdown, | ||
| 1395 | .hw_params = dac33_hw_params, | 1411 | .hw_params = dac33_hw_params, |
| 1396 | .prepare = dac33_pcm_prepare, | ||
| 1397 | .trigger = dac33_pcm_trigger, | 1412 | .trigger = dac33_pcm_trigger, |
| 1398 | .delay = dac33_dai_delay, | 1413 | .delay = dac33_dai_delay, |
| 1399 | .set_sysclk = dac33_set_dai_sysclk, | 1414 | .set_sysclk = dac33_set_dai_sysclk, |
| @@ -1447,6 +1462,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, | |||
| 1447 | codec->hw_write = (hw_write_t) i2c_master_send; | 1462 | codec->hw_write = (hw_write_t) i2c_master_send; |
| 1448 | codec->bias_level = SND_SOC_BIAS_OFF; | 1463 | codec->bias_level = SND_SOC_BIAS_OFF; |
| 1449 | codec->set_bias_level = dac33_set_bias_level; | 1464 | codec->set_bias_level = dac33_set_bias_level; |
| 1465 | codec->idle_bias_off = 1; | ||
| 1450 | codec->dai = &dac33_dai; | 1466 | codec->dai = &dac33_dai; |
| 1451 | codec->num_dai = 1; | 1467 | codec->num_dai = 1; |
| 1452 | codec->reg_cache_size = ARRAY_SIZE(dac33_reg); | 1468 | codec->reg_cache_size = ARRAY_SIZE(dac33_reg); |
| @@ -1487,8 +1503,6 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, | |||
| 1487 | goto error_gpio; | 1503 | goto error_gpio; |
| 1488 | } | 1504 | } |
| 1489 | gpio_direction_output(dac33->power_gpio, 0); | 1505 | gpio_direction_output(dac33->power_gpio, 0); |
| 1490 | } else { | ||
| 1491 | dac33->chip_power = 1; | ||
| 1492 | } | 1506 | } |
| 1493 | 1507 | ||
| 1494 | /* Check if the IRQ number is valid and request it */ | 1508 | /* Check if the IRQ number is valid and request it */ |
| @@ -1526,12 +1540,14 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, | |||
| 1526 | goto err_get; | 1540 | goto err_get; |
| 1527 | } | 1541 | } |
| 1528 | 1542 | ||
| 1529 | ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), | 1543 | /* Read the tlv320dac33 ID registers */ |
| 1530 | dac33->supplies); | 1544 | ret = dac33_hard_power(codec, 1); |
| 1531 | if (ret != 0) { | 1545 | if (ret != 0) { |
| 1532 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | 1546 | dev_err(codec->dev, "Failed to power up codec: %d\n", ret); |
| 1533 | goto err_enable; | 1547 | goto error_codec; |
| 1534 | } | 1548 | } |
| 1549 | dac33_read_id(codec); | ||
| 1550 | dac33_hard_power(codec, 0); | ||
| 1535 | 1551 | ||
| 1536 | ret = snd_soc_register_codec(codec); | 1552 | ret = snd_soc_register_codec(codec); |
| 1537 | if (ret != 0) { | 1553 | if (ret != 0) { |
| @@ -1546,14 +1562,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, | |||
| 1546 | goto error_codec; | 1562 | goto error_codec; |
| 1547 | } | 1563 | } |
| 1548 | 1564 | ||
| 1549 | /* Shut down the codec for now */ | ||
| 1550 | dac33_hard_power(codec, 0); | ||
| 1551 | |||
| 1552 | return ret; | 1565 | return ret; |
| 1553 | 1566 | ||
| 1554 | error_codec: | 1567 | error_codec: |
| 1555 | regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
| 1556 | err_enable: | ||
| 1557 | regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); | 1568 | regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); |
| 1558 | err_get: | 1569 | err_get: |
| 1559 | if (dac33->irq >= 0) { | 1570 | if (dac33->irq >= 0) { |
| @@ -1577,7 +1588,9 @@ static int __devexit dac33_i2c_remove(struct i2c_client *client) | |||
| 1577 | struct tlv320dac33_priv *dac33; | 1588 | struct tlv320dac33_priv *dac33; |
| 1578 | 1589 | ||
| 1579 | dac33 = i2c_get_clientdata(client); | 1590 | dac33 = i2c_get_clientdata(client); |
| 1580 | dac33_hard_power(&dac33->codec, 0); | 1591 | |
| 1592 | if (unlikely(dac33->chip_power)) | ||
| 1593 | dac33_hard_power(&dac33->codec, 0); | ||
| 1581 | 1594 | ||
| 1582 | if (dac33->power_gpio >= 0) | 1595 | if (dac33->power_gpio >= 0) |
| 1583 | gpio_free(dac33->power_gpio); | 1596 | gpio_free(dac33->power_gpio); |
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 958d49c969ac..31f67b527ca1 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c | |||
| @@ -46,6 +46,9 @@ static const char *tpa6140a2_supply_names[TPA6130A2_NUM_SUPPLIES] = { | |||
| 46 | "AVdd", | 46 | "AVdd", |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | #define TPA6130A2_GAIN_MAX 0x3f | ||
| 50 | #define TPA6140A2_GAIN_MAX 0x1f | ||
| 51 | |||
| 49 | /* This struct is used to save the context */ | 52 | /* This struct is used to save the context */ |
| 50 | struct tpa6130a2_data { | 53 | struct tpa6130a2_data { |
| 51 | struct mutex mutex; | 54 | struct mutex mutex; |
| @@ -53,6 +56,8 @@ struct tpa6130a2_data { | |||
| 53 | struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES]; | 56 | struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES]; |
| 54 | int power_gpio; | 57 | int power_gpio; |
| 55 | unsigned char power_state; | 58 | unsigned char power_state; |
| 59 | enum tpa_model id; | ||
| 60 | int gain_limit; | ||
| 56 | }; | 61 | }; |
| 57 | 62 | ||
| 58 | static int tpa6130a2_i2c_read(int reg) | 63 | static int tpa6130a2_i2c_read(int reg) |
| @@ -175,6 +180,40 @@ exit: | |||
| 175 | return ret; | 180 | return ret; |
| 176 | } | 181 | } |
| 177 | 182 | ||
| 183 | static int tpa6130a2_info_volsw(struct snd_kcontrol *kcontrol, | ||
| 184 | struct snd_ctl_elem_info *uinfo) | ||
| 185 | { | ||
| 186 | struct soc_mixer_control *mc = | ||
| 187 | (struct soc_mixer_control *)kcontrol->private_value; | ||
| 188 | struct tpa6130a2_data *data; | ||
| 189 | |||
| 190 | BUG_ON(tpa6130a2_client == NULL); | ||
| 191 | data = i2c_get_clientdata(tpa6130a2_client); | ||
| 192 | |||
| 193 | mutex_lock(&data->mutex); | ||
| 194 | switch (mc->reg) { | ||
| 195 | case TPA6130A2_REG_VOL_MUTE: | ||
| 196 | if (data->gain_limit != mc->max) | ||
| 197 | mc->max = data->gain_limit; | ||
| 198 | break; | ||
| 199 | default: | ||
| 200 | dev_err(&tpa6130a2_client->dev, | ||
| 201 | "Invalid register: 0x02%x\n", mc->reg); | ||
| 202 | goto out; | ||
| 203 | } | ||
| 204 | if (unlikely(mc->max == 1)) | ||
| 205 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
| 206 | else | ||
| 207 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 208 | |||
| 209 | uinfo->count = 1; | ||
| 210 | uinfo->value.integer.min = 0; | ||
| 211 | uinfo->value.integer.max = mc->max; | ||
| 212 | out: | ||
| 213 | mutex_unlock(&data->mutex); | ||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 178 | static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, | 217 | static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, |
| 179 | struct snd_ctl_elem_value *ucontrol) | 218 | struct snd_ctl_elem_value *ucontrol) |
| 180 | { | 219 | { |
| @@ -238,6 +277,15 @@ static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol, | |||
| 238 | return 1; | 277 | return 1; |
| 239 | } | 278 | } |
| 240 | 279 | ||
| 280 | #define SOC_SINGLE_EXT_TLV_TPA(xname, xreg, xshift, xmax, xinvert, tlv_array) \ | ||
| 281 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
| 282 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
| 283 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
| 284 | .tlv.p = (tlv_array), \ | ||
| 285 | .info = tpa6130a2_info_volsw, \ | ||
| 286 | .get = tpa6130a2_get_reg, .put = tpa6130a2_set_reg, \ | ||
| 287 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } | ||
| 288 | |||
| 241 | /* | 289 | /* |
| 242 | * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going | 290 | * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going |
| 243 | * down in gain. | 291 | * down in gain. |
| @@ -257,10 +305,22 @@ static const unsigned int tpa6130_tlv[] = { | |||
| 257 | }; | 305 | }; |
| 258 | 306 | ||
| 259 | static const struct snd_kcontrol_new tpa6130a2_controls[] = { | 307 | static const struct snd_kcontrol_new tpa6130a2_controls[] = { |
| 260 | SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume", | 308 | SOC_SINGLE_EXT_TLV_TPA("TPA6130A2 Headphone Playback Volume", |
| 261 | TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, | 309 | TPA6130A2_REG_VOL_MUTE, 0, TPA6130A2_GAIN_MAX, 0, |
| 262 | tpa6130a2_get_reg, tpa6130a2_set_reg, | 310 | tpa6130_tlv), |
| 263 | tpa6130_tlv), | 311 | }; |
| 312 | |||
| 313 | static const unsigned int tpa6140_tlv[] = { | ||
| 314 | TLV_DB_RANGE_HEAD(3), | ||
| 315 | 0, 8, TLV_DB_SCALE_ITEM(-5900, 400, 0), | ||
| 316 | 9, 16, TLV_DB_SCALE_ITEM(-2500, 200, 0), | ||
| 317 | 17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0), | ||
| 318 | }; | ||
| 319 | |||
| 320 | static const struct snd_kcontrol_new tpa6140a2_controls[] = { | ||
| 321 | SOC_SINGLE_EXT_TLV_TPA("TPA6140A2 Headphone Playback Volume", | ||
| 322 | TPA6130A2_REG_VOL_MUTE, 1, TPA6140A2_GAIN_MAX, 0, | ||
| 323 | tpa6140_tlv), | ||
| 264 | }; | 324 | }; |
| 265 | 325 | ||
| 266 | /* | 326 | /* |
| @@ -368,13 +428,22 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
| 368 | 428 | ||
| 369 | int tpa6130a2_add_controls(struct snd_soc_codec *codec) | 429 | int tpa6130a2_add_controls(struct snd_soc_codec *codec) |
| 370 | { | 430 | { |
| 431 | struct tpa6130a2_data *data; | ||
| 432 | |||
| 433 | BUG_ON(tpa6130a2_client == NULL); | ||
| 434 | data = i2c_get_clientdata(tpa6130a2_client); | ||
| 435 | |||
| 371 | snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets, | 436 | snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets, |
| 372 | ARRAY_SIZE(tpa6130a2_dapm_widgets)); | 437 | ARRAY_SIZE(tpa6130a2_dapm_widgets)); |
| 373 | 438 | ||
| 374 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 439 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 375 | 440 | ||
| 376 | return snd_soc_add_controls(codec, tpa6130a2_controls, | 441 | if (data->id == TPA6140A2) |
| 377 | ARRAY_SIZE(tpa6130a2_controls)); | 442 | return snd_soc_add_controls(codec, tpa6140a2_controls, |
| 443 | ARRAY_SIZE(tpa6140a2_controls)); | ||
| 444 | else | ||
| 445 | return snd_soc_add_controls(codec, tpa6130a2_controls, | ||
| 446 | ARRAY_SIZE(tpa6130a2_controls)); | ||
| 378 | 447 | ||
| 379 | } | 448 | } |
| 380 | EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); | 449 | EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); |
| @@ -407,6 +476,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, | |||
| 407 | 476 | ||
| 408 | pdata = client->dev.platform_data; | 477 | pdata = client->dev.platform_data; |
| 409 | data->power_gpio = pdata->power_gpio; | 478 | data->power_gpio = pdata->power_gpio; |
| 479 | data->id = pdata->id; | ||
| 410 | 480 | ||
| 411 | mutex_init(&data->mutex); | 481 | mutex_init(&data->mutex); |
| 412 | 482 | ||
| @@ -425,20 +495,35 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, | |||
| 425 | gpio_direction_output(data->power_gpio, 0); | 495 | gpio_direction_output(data->power_gpio, 0); |
| 426 | } | 496 | } |
| 427 | 497 | ||
| 428 | switch (pdata->id) { | 498 | switch (data->id) { |
| 429 | case TPA6130A2: | 499 | case TPA6130A2: |
| 430 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) | 500 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) |
| 431 | data->supplies[i].supply = tpa6130a2_supply_names[i]; | 501 | data->supplies[i].supply = tpa6130a2_supply_names[i]; |
| 502 | if (pdata->limit_gain > 0 && | ||
| 503 | pdata->limit_gain < TPA6130A2_GAIN_MAX) | ||
| 504 | data->gain_limit = pdata->limit_gain; | ||
| 505 | else | ||
| 506 | data->gain_limit = TPA6130A2_GAIN_MAX; | ||
| 432 | break; | 507 | break; |
| 433 | case TPA6140A2: | 508 | case TPA6140A2: |
| 434 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) | 509 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) |
| 435 | data->supplies[i].supply = tpa6140a2_supply_names[i];; | 510 | data->supplies[i].supply = tpa6140a2_supply_names[i];; |
| 511 | if (pdata->limit_gain > 0 && | ||
| 512 | pdata->limit_gain < TPA6140A2_GAIN_MAX) | ||
| 513 | data->gain_limit = pdata->limit_gain; | ||
| 514 | else | ||
| 515 | data->gain_limit = TPA6140A2_GAIN_MAX; | ||
| 436 | break; | 516 | break; |
| 437 | default: | 517 | default: |
| 438 | dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n", | 518 | dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n", |
| 439 | pdata->id); | 519 | pdata->id); |
| 440 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) | 520 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) |
| 441 | data->supplies[i].supply = tpa6130a2_supply_names[i]; | 521 | data->supplies[i].supply = tpa6130a2_supply_names[i]; |
| 522 | if (pdata->limit_gain > 0 && | ||
| 523 | pdata->limit_gain < TPA6130A2_GAIN_MAX) | ||
| 524 | data->gain_limit = pdata->limit_gain; | ||
| 525 | else | ||
| 526 | data->gain_limit = TPA6130A2_GAIN_MAX; | ||
| 442 | } | 527 | } |
| 443 | 528 | ||
| 444 | ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), | 529 | ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 2e025a3a2618..b717a03dfacf 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
| @@ -123,6 +123,8 @@ struct twl4030_priv { | |||
| 123 | struct snd_soc_codec codec; | 123 | struct snd_soc_codec codec; |
| 124 | 124 | ||
| 125 | unsigned int codec_powered; | 125 | unsigned int codec_powered; |
| 126 | |||
| 127 | /* reference counts of AIF/APLL users */ | ||
| 126 | unsigned int apll_enabled; | 128 | unsigned int apll_enabled; |
| 127 | 129 | ||
| 128 | struct snd_pcm_substream *master_substream; | 130 | struct snd_pcm_substream *master_substream; |
| @@ -259,22 +261,22 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) | |||
| 259 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) | 261 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) |
| 260 | { | 262 | { |
| 261 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 263 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
| 262 | int status; | 264 | int status = -1; |
| 263 | |||
| 264 | if (enable == twl4030->apll_enabled) | ||
| 265 | return; | ||
| 266 | 265 | ||
| 267 | if (enable) | 266 | if (enable) { |
| 268 | /* Enable PLL */ | 267 | twl4030->apll_enabled++; |
| 269 | status = twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL); | 268 | if (twl4030->apll_enabled == 1) |
| 270 | else | 269 | status = twl4030_codec_enable_resource( |
| 271 | /* Disable PLL */ | 270 | TWL4030_CODEC_RES_APLL); |
| 272 | status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL); | 271 | } else { |
| 272 | twl4030->apll_enabled--; | ||
| 273 | if (!twl4030->apll_enabled) | ||
| 274 | status = twl4030_codec_disable_resource( | ||
| 275 | TWL4030_CODEC_RES_APLL); | ||
| 276 | } | ||
| 273 | 277 | ||
| 274 | if (status >= 0) | 278 | if (status >= 0) |
| 275 | twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); | 279 | twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); |
| 276 | |||
| 277 | twl4030->apll_enabled = enable; | ||
| 278 | } | 280 | } |
| 279 | 281 | ||
| 280 | static void twl4030_power_up(struct snd_soc_codec *codec) | 282 | static void twl4030_power_up(struct snd_soc_codec *codec) |
| @@ -672,6 +674,31 @@ static int apll_event(struct snd_soc_dapm_widget *w, | |||
| 672 | return 0; | 674 | return 0; |
| 673 | } | 675 | } |
| 674 | 676 | ||
| 677 | static int aif_event(struct snd_soc_dapm_widget *w, | ||
| 678 | struct snd_kcontrol *kcontrol, int event) | ||
| 679 | { | ||
| 680 | u8 audio_if; | ||
| 681 | |||
| 682 | audio_if = twl4030_read_reg_cache(w->codec, TWL4030_REG_AUDIO_IF); | ||
| 683 | switch (event) { | ||
| 684 | case SND_SOC_DAPM_PRE_PMU: | ||
| 685 | /* Enable AIF */ | ||
| 686 | /* enable the PLL before we use it to clock the DAI */ | ||
| 687 | twl4030_apll_enable(w->codec, 1); | ||
| 688 | |||
| 689 | twl4030_write(w->codec, TWL4030_REG_AUDIO_IF, | ||
| 690 | audio_if | TWL4030_AIF_EN); | ||
| 691 | break; | ||
| 692 | case SND_SOC_DAPM_POST_PMD: | ||
| 693 | /* disable the DAI before we stop it's source PLL */ | ||
| 694 | twl4030_write(w->codec, TWL4030_REG_AUDIO_IF, | ||
| 695 | audio_if & ~TWL4030_AIF_EN); | ||
| 696 | twl4030_apll_enable(w->codec, 0); | ||
| 697 | break; | ||
| 698 | } | ||
| 699 | return 0; | ||
| 700 | } | ||
| 701 | |||
| 675 | static void headset_ramp(struct snd_soc_codec *codec, int ramp) | 702 | static void headset_ramp(struct snd_soc_codec *codec, int ramp) |
| 676 | { | 703 | { |
| 677 | struct snd_soc_device *socdev = codec->socdev; | 704 | struct snd_soc_device *socdev = codec->socdev; |
| @@ -1167,8 +1194,6 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
| 1167 | SND_SOC_DAPM_INPUT("DIGIMIC1"), | 1194 | SND_SOC_DAPM_INPUT("DIGIMIC1"), |
| 1168 | 1195 | ||
| 1169 | /* Outputs */ | 1196 | /* Outputs */ |
| 1170 | SND_SOC_DAPM_OUTPUT("OUTL"), | ||
| 1171 | SND_SOC_DAPM_OUTPUT("OUTR"), | ||
| 1172 | SND_SOC_DAPM_OUTPUT("EARPIECE"), | 1197 | SND_SOC_DAPM_OUTPUT("EARPIECE"), |
| 1173 | SND_SOC_DAPM_OUTPUT("PREDRIVEL"), | 1198 | SND_SOC_DAPM_OUTPUT("PREDRIVEL"), |
| 1174 | SND_SOC_DAPM_OUTPUT("PREDRIVER"), | 1199 | SND_SOC_DAPM_OUTPUT("PREDRIVER"), |
| @@ -1180,6 +1205,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
| 1180 | SND_SOC_DAPM_OUTPUT("HFR"), | 1205 | SND_SOC_DAPM_OUTPUT("HFR"), |
| 1181 | SND_SOC_DAPM_OUTPUT("VIBRA"), | 1206 | SND_SOC_DAPM_OUTPUT("VIBRA"), |
| 1182 | 1207 | ||
| 1208 | /* AIF and APLL clocks for running DAIs (including loopback) */ | ||
| 1209 | SND_SOC_DAPM_OUTPUT("Virtual HiFi OUT"), | ||
| 1210 | SND_SOC_DAPM_INPUT("Virtual HiFi IN"), | ||
| 1211 | SND_SOC_DAPM_OUTPUT("Virtual Voice OUT"), | ||
| 1212 | |||
| 1183 | /* DACs */ | 1213 | /* DACs */ |
| 1184 | SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback", | 1214 | SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback", |
| 1185 | SND_SOC_NOPM, 0, 0), | 1215 | SND_SOC_NOPM, 0, 0), |
| @@ -1243,7 +1273,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
| 1243 | SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event, | 1273 | SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event, |
| 1244 | SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), | 1274 | SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), |
| 1245 | 1275 | ||
| 1246 | SND_SOC_DAPM_SUPPLY("AIF Enable", TWL4030_REG_AUDIO_IF, 0, 0, NULL, 0), | 1276 | SND_SOC_DAPM_SUPPLY("AIF Enable", SND_SOC_NOPM, 0, 0, aif_event, |
| 1277 | SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), | ||
| 1247 | 1278 | ||
| 1248 | /* Output MIXER controls */ | 1279 | /* Output MIXER controls */ |
| 1249 | /* Earpiece */ | 1280 | /* Earpiece */ |
| @@ -1373,10 +1404,6 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
| 1373 | {"Digital Voice Playback Mixer", NULL, "DAC Voice"}, | 1404 | {"Digital Voice Playback Mixer", NULL, "DAC Voice"}, |
| 1374 | 1405 | ||
| 1375 | /* Supply for the digital part (APLL) */ | 1406 | /* Supply for the digital part (APLL) */ |
| 1376 | {"Digital R1 Playback Mixer", NULL, "APLL Enable"}, | ||
| 1377 | {"Digital L1 Playback Mixer", NULL, "APLL Enable"}, | ||
| 1378 | {"Digital R2 Playback Mixer", NULL, "APLL Enable"}, | ||
| 1379 | {"Digital L2 Playback Mixer", NULL, "APLL Enable"}, | ||
| 1380 | {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, | 1407 | {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, |
| 1381 | 1408 | ||
| 1382 | {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, | 1409 | {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, |
| @@ -1450,8 +1477,14 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
| 1450 | {"Vibra Mux", "AudioR2", "DAC Right2"}, | 1477 | {"Vibra Mux", "AudioR2", "DAC Right2"}, |
| 1451 | 1478 | ||
| 1452 | /* outputs */ | 1479 | /* outputs */ |
| 1453 | {"OUTL", NULL, "Analog L2 Playback Mixer"}, | 1480 | /* Must be always connected (for AIF and APLL) */ |
| 1454 | {"OUTR", NULL, "Analog R2 Playback Mixer"}, | 1481 | {"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"}, |
| 1482 | {"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"}, | ||
| 1483 | {"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"}, | ||
| 1484 | {"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"}, | ||
| 1485 | /* Must be always connected (for APLL) */ | ||
| 1486 | {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"}, | ||
| 1487 | /* Physical outputs */ | ||
| 1455 | {"EARPIECE", NULL, "Earpiece PGA"}, | 1488 | {"EARPIECE", NULL, "Earpiece PGA"}, |
| 1456 | {"PREDRIVEL", NULL, "PredriveL PGA"}, | 1489 | {"PREDRIVEL", NULL, "PredriveL PGA"}, |
| 1457 | {"PREDRIVER", NULL, "PredriveR PGA"}, | 1490 | {"PREDRIVER", NULL, "PredriveR PGA"}, |
| @@ -1465,6 +1498,12 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
| 1465 | {"VIBRA", NULL, "Vibra Route"}, | 1498 | {"VIBRA", NULL, "Vibra Route"}, |
| 1466 | 1499 | ||
| 1467 | /* Capture path */ | 1500 | /* Capture path */ |
| 1501 | /* Must be always connected (for AIF and APLL) */ | ||
| 1502 | {"ADC Virtual Left1", NULL, "Virtual HiFi IN"}, | ||
| 1503 | {"ADC Virtual Right1", NULL, "Virtual HiFi IN"}, | ||
| 1504 | {"ADC Virtual Left2", NULL, "Virtual HiFi IN"}, | ||
| 1505 | {"ADC Virtual Right2", NULL, "Virtual HiFi IN"}, | ||
| 1506 | /* Physical inputs */ | ||
| 1468 | {"Analog Left", "Main Mic Capture Switch", "MAINMIC"}, | 1507 | {"Analog Left", "Main Mic Capture Switch", "MAINMIC"}, |
| 1469 | {"Analog Left", "Headset Mic Capture Switch", "HSMIC"}, | 1508 | {"Analog Left", "Headset Mic Capture Switch", "HSMIC"}, |
| 1470 | {"Analog Left", "AUXL Capture Switch", "AUXL"}, | 1509 | {"Analog Left", "AUXL Capture Switch", "AUXL"}, |
| @@ -1497,11 +1536,6 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
| 1497 | {"ADC Virtual Left2", NULL, "TX2 Capture Route"}, | 1536 | {"ADC Virtual Left2", NULL, "TX2 Capture Route"}, |
| 1498 | {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, | 1537 | {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, |
| 1499 | 1538 | ||
| 1500 | {"ADC Virtual Left1", NULL, "APLL Enable"}, | ||
| 1501 | {"ADC Virtual Right1", NULL, "APLL Enable"}, | ||
| 1502 | {"ADC Virtual Left2", NULL, "APLL Enable"}, | ||
| 1503 | {"ADC Virtual Right2", NULL, "APLL Enable"}, | ||
| 1504 | |||
| 1505 | {"ADC Virtual Left1", NULL, "AIF Enable"}, | 1539 | {"ADC Virtual Left1", NULL, "AIF Enable"}, |
| 1506 | {"ADC Virtual Right1", NULL, "AIF Enable"}, | 1540 | {"ADC Virtual Right1", NULL, "AIF Enable"}, |
| 1507 | {"ADC Virtual Left2", NULL, "AIF Enable"}, | 1541 | {"ADC Virtual Left2", NULL, "AIF Enable"}, |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index f11963c21873..83be4a76d2bb 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
| @@ -18,6 +18,16 @@ config SND_OMAP_SOC_N810 | |||
| 18 | help | 18 | help |
| 19 | Say Y if you want to add support for SoC audio on Nokia N810. | 19 | Say Y if you want to add support for SoC audio on Nokia N810. |
| 20 | 20 | ||
| 21 | config SND_OMAP_SOC_RX51 | ||
| 22 | tristate "SoC Audio support for Nokia RX-51" | ||
| 23 | depends on SND_OMAP_SOC && MACH_NOKIA_RX51 | ||
| 24 | select OMAP_MCBSP | ||
| 25 | select SND_OMAP_SOC_MCBSP | ||
| 26 | select SND_SOC_TLV320AIC3X | ||
| 27 | help | ||
| 28 | Say Y if you want to add support for SoC audio on Nokia RX-51 | ||
| 29 | hardware. This is also known as Nokia N900 product. | ||
| 30 | |||
| 21 | config SND_OMAP_SOC_AMS_DELTA | 31 | config SND_OMAP_SOC_AMS_DELTA |
| 22 | tristate "SoC Audio support for Amstrad E3 (Delta) videophone" | 32 | tristate "SoC Audio support for Amstrad E3 (Delta) videophone" |
| 23 | depends on SND_OMAP_SOC && MACH_AMS_DELTA | 33 | depends on SND_OMAP_SOC && MACH_AMS_DELTA |
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 0bc00ca14b37..3a75755f25e4 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
| @@ -9,6 +9,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o | |||
| 9 | 9 | ||
| 10 | # OMAP Machine Support | 10 | # OMAP Machine Support |
| 11 | snd-soc-n810-objs := n810.o | 11 | snd-soc-n810-objs := n810.o |
| 12 | snd-soc-rx51-objs := rx51.o | ||
| 12 | snd-soc-ams-delta-objs := ams-delta.o | 13 | snd-soc-ams-delta-objs := ams-delta.o |
| 13 | snd-soc-osk5912-objs := osk5912.o | 14 | snd-soc-osk5912-objs := osk5912.o |
| 14 | snd-soc-overo-objs := overo.o | 15 | snd-soc-overo-objs := overo.o |
| @@ -22,6 +23,7 @@ snd-soc-zoom2-objs := zoom2.o | |||
| 22 | snd-soc-igep0020-objs := igep0020.o | 23 | snd-soc-igep0020-objs := igep0020.o |
| 23 | 24 | ||
| 24 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 25 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
| 26 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o | ||
| 25 | obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o | 27 | obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o |
| 26 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o | 28 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o |
| 27 | obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o | 29 | obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o |
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index de10f76baded..87ce842fa2e8 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c | |||
| @@ -188,8 +188,6 @@ static int omap3pandora_out_init(struct snd_soc_codec *codec) | |||
| 188 | int ret; | 188 | int ret; |
| 189 | 189 | ||
| 190 | /* All TWL4030 output pins are floating */ | 190 | /* All TWL4030 output pins are floating */ |
| 191 | snd_soc_dapm_nc_pin(codec, "OUTL"); | ||
| 192 | snd_soc_dapm_nc_pin(codec, "OUTR"); | ||
| 193 | snd_soc_dapm_nc_pin(codec, "EARPIECE"); | 191 | snd_soc_dapm_nc_pin(codec, "EARPIECE"); |
| 194 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"); | 192 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"); |
| 195 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"); | 193 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"); |
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c new file mode 100644 index 000000000000..47d831ef2dbb --- /dev/null +++ b/sound/soc/omap/rx51.c | |||
| @@ -0,0 +1,294 @@ | |||
| 1 | /* | ||
| 2 | * rx51.c -- SoC audio for Nokia RX-51 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 - 2009 Nokia Corporation | ||
| 5 | * | ||
| 6 | * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com> | ||
| 7 | * Eduardo Valentin <eduardo.valentin@nokia.com> | ||
| 8 | * Jarkko Nikula <jhnikula@gmail.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU General Public License | ||
| 12 | * version 2 as published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 22 | * 02110-1301 USA | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/gpio.h> | ||
| 28 | #include <linux/platform_device.h> | ||
| 29 | #include <sound/core.h> | ||
| 30 | #include <sound/pcm.h> | ||
| 31 | #include <sound/soc.h> | ||
| 32 | #include <sound/soc-dapm.h> | ||
| 33 | |||
| 34 | #include <asm/mach-types.h> | ||
| 35 | |||
| 36 | #include "omap-mcbsp.h" | ||
| 37 | #include "omap-pcm.h" | ||
| 38 | #include "../codecs/tlv320aic3x.h" | ||
| 39 | |||
| 40 | /* | ||
| 41 | * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This | ||
| 42 | * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c | ||
| 43 | */ | ||
| 44 | #define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7) | ||
| 45 | |||
| 46 | static int rx51_spk_func; | ||
| 47 | static int rx51_dmic_func; | ||
| 48 | |||
| 49 | static void rx51_ext_control(struct snd_soc_codec *codec) | ||
| 50 | { | ||
| 51 | if (rx51_spk_func) | ||
| 52 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
| 53 | else | ||
| 54 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); | ||
| 55 | if (rx51_dmic_func) | ||
| 56 | snd_soc_dapm_enable_pin(codec, "DMic"); | ||
| 57 | else | ||
| 58 | snd_soc_dapm_disable_pin(codec, "DMic"); | ||
| 59 | |||
| 60 | snd_soc_dapm_sync(codec); | ||
| 61 | } | ||
| 62 | |||
| 63 | static int rx51_startup(struct snd_pcm_substream *substream) | ||
| 64 | { | ||
| 65 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 66 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 67 | struct snd_soc_codec *codec = rtd->socdev->card->codec; | ||
| 68 | |||
| 69 | snd_pcm_hw_constraint_minmax(runtime, | ||
| 70 | SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); | ||
| 71 | rx51_ext_control(codec); | ||
| 72 | |||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | |||
| 76 | static int rx51_hw_params(struct snd_pcm_substream *substream, | ||
| 77 | struct snd_pcm_hw_params *params) | ||
| 78 | { | ||
| 79 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 80 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
| 81 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
| 82 | int err; | ||
| 83 | |||
| 84 | /* Set codec DAI configuration */ | ||
| 85 | err = snd_soc_dai_set_fmt(codec_dai, | ||
| 86 | SND_SOC_DAIFMT_DSP_A | | ||
| 87 | SND_SOC_DAIFMT_IB_NF | | ||
| 88 | SND_SOC_DAIFMT_CBM_CFM); | ||
| 89 | if (err < 0) | ||
| 90 | return err; | ||
| 91 | |||
| 92 | /* Set cpu DAI configuration */ | ||
| 93 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
| 94 | SND_SOC_DAIFMT_DSP_A | | ||
| 95 | SND_SOC_DAIFMT_IB_NF | | ||
| 96 | SND_SOC_DAIFMT_CBM_CFM); | ||
| 97 | if (err < 0) | ||
| 98 | return err; | ||
| 99 | |||
| 100 | /* Set the codec system clock for DAC and ADC */ | ||
| 101 | return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000, | ||
| 102 | SND_SOC_CLOCK_IN); | ||
| 103 | } | ||
| 104 | |||
| 105 | static struct snd_soc_ops rx51_ops = { | ||
| 106 | .startup = rx51_startup, | ||
| 107 | .hw_params = rx51_hw_params, | ||
| 108 | }; | ||
| 109 | |||
| 110 | static int rx51_get_spk(struct snd_kcontrol *kcontrol, | ||
| 111 | struct snd_ctl_elem_value *ucontrol) | ||
| 112 | { | ||
| 113 | ucontrol->value.integer.value[0] = rx51_spk_func; | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | static int rx51_set_spk(struct snd_kcontrol *kcontrol, | ||
| 119 | struct snd_ctl_elem_value *ucontrol) | ||
| 120 | { | ||
| 121 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 122 | |||
| 123 | if (rx51_spk_func == ucontrol->value.integer.value[0]) | ||
| 124 | return 0; | ||
| 125 | |||
| 126 | rx51_spk_func = ucontrol->value.integer.value[0]; | ||
| 127 | rx51_ext_control(codec); | ||
| 128 | |||
| 129 | return 1; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int rx51_spk_event(struct snd_soc_dapm_widget *w, | ||
| 133 | struct snd_kcontrol *k, int event) | ||
| 134 | { | ||
| 135 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
| 136 | gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 1); | ||
| 137 | else | ||
| 138 | gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 0); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int rx51_get_input(struct snd_kcontrol *kcontrol, | ||
| 144 | struct snd_ctl_elem_value *ucontrol) | ||
| 145 | { | ||
| 146 | ucontrol->value.integer.value[0] = rx51_dmic_func; | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static int rx51_set_input(struct snd_kcontrol *kcontrol, | ||
| 152 | struct snd_ctl_elem_value *ucontrol) | ||
| 153 | { | ||
| 154 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 155 | |||
| 156 | if (rx51_dmic_func == ucontrol->value.integer.value[0]) | ||
| 157 | return 0; | ||
| 158 | |||
| 159 | rx51_dmic_func = ucontrol->value.integer.value[0]; | ||
| 160 | rx51_ext_control(codec); | ||
| 161 | |||
| 162 | return 1; | ||
| 163 | } | ||
| 164 | |||
| 165 | static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { | ||
| 166 | SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), | ||
| 167 | SND_SOC_DAPM_MIC("DMic", NULL), | ||
| 168 | }; | ||
| 169 | |||
| 170 | static const struct snd_soc_dapm_route audio_map[] = { | ||
| 171 | {"Ext Spk", NULL, "HPLOUT"}, | ||
| 172 | {"Ext Spk", NULL, "HPROUT"}, | ||
| 173 | |||
| 174 | {"DMic Rate 64", NULL, "Mic Bias 2V"}, | ||
| 175 | {"Mic Bias 2V", NULL, "DMic"}, | ||
| 176 | }; | ||
| 177 | |||
| 178 | static const char *spk_function[] = {"Off", "On"}; | ||
| 179 | static const char *input_function[] = {"ADC", "Digital Mic"}; | ||
| 180 | |||
| 181 | static const struct soc_enum rx51_enum[] = { | ||
| 182 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), | ||
| 183 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), | ||
| 184 | }; | ||
| 185 | |||
| 186 | static const struct snd_kcontrol_new aic34_rx51_controls[] = { | ||
| 187 | SOC_ENUM_EXT("Speaker Function", rx51_enum[0], | ||
| 188 | rx51_get_spk, rx51_set_spk), | ||
| 189 | SOC_ENUM_EXT("Input Select", rx51_enum[1], | ||
| 190 | rx51_get_input, rx51_set_input), | ||
| 191 | }; | ||
| 192 | |||
| 193 | static int rx51_aic34_init(struct snd_soc_codec *codec) | ||
| 194 | { | ||
| 195 | int err; | ||
| 196 | |||
| 197 | /* Set up NC codec pins */ | ||
| 198 | snd_soc_dapm_nc_pin(codec, "MIC3L"); | ||
| 199 | snd_soc_dapm_nc_pin(codec, "MIC3R"); | ||
| 200 | snd_soc_dapm_nc_pin(codec, "LINE1R"); | ||
| 201 | |||
| 202 | /* Add RX-51 specific controls */ | ||
| 203 | err = snd_soc_add_controls(codec, aic34_rx51_controls, | ||
| 204 | ARRAY_SIZE(aic34_rx51_controls)); | ||
| 205 | if (err < 0) | ||
| 206 | return err; | ||
| 207 | |||
| 208 | /* Add RX-51 specific widgets */ | ||
| 209 | snd_soc_dapm_new_controls(codec, aic34_dapm_widgets, | ||
| 210 | ARRAY_SIZE(aic34_dapm_widgets)); | ||
| 211 | |||
| 212 | /* Set up RX-51 specific audio path audio_map */ | ||
| 213 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
| 214 | |||
| 215 | snd_soc_dapm_sync(codec); | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | /* Digital audio interface glue - connects codec <--> CPU */ | ||
| 221 | static struct snd_soc_dai_link rx51_dai[] = { | ||
| 222 | { | ||
| 223 | .name = "TLV320AIC34", | ||
| 224 | .stream_name = "AIC34", | ||
| 225 | .cpu_dai = &omap_mcbsp_dai[0], | ||
| 226 | .codec_dai = &aic3x_dai, | ||
| 227 | .init = rx51_aic34_init, | ||
| 228 | .ops = &rx51_ops, | ||
| 229 | }, | ||
| 230 | }; | ||
| 231 | |||
| 232 | /* Audio private data */ | ||
| 233 | static struct aic3x_setup_data rx51_aic34_setup = { | ||
| 234 | .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, | ||
| 235 | .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, | ||
| 236 | }; | ||
| 237 | |||
| 238 | /* Audio card */ | ||
| 239 | static struct snd_soc_card rx51_sound_card = { | ||
| 240 | .name = "RX-51", | ||
| 241 | .dai_link = rx51_dai, | ||
| 242 | .num_links = ARRAY_SIZE(rx51_dai), | ||
| 243 | .platform = &omap_soc_platform, | ||
| 244 | }; | ||
| 245 | |||
| 246 | /* Audio subsystem */ | ||
| 247 | static struct snd_soc_device rx51_snd_devdata = { | ||
| 248 | .card = &rx51_sound_card, | ||
| 249 | .codec_dev = &soc_codec_dev_aic3x, | ||
| 250 | .codec_data = &rx51_aic34_setup, | ||
| 251 | }; | ||
| 252 | |||
| 253 | static struct platform_device *rx51_snd_device; | ||
| 254 | |||
| 255 | static int __init rx51_soc_init(void) | ||
| 256 | { | ||
| 257 | int err; | ||
| 258 | |||
| 259 | if (!machine_is_nokia_rx51()) | ||
| 260 | return -ENODEV; | ||
| 261 | |||
| 262 | rx51_snd_device = platform_device_alloc("soc-audio", -1); | ||
| 263 | if (!rx51_snd_device) { | ||
| 264 | err = -ENOMEM; | ||
| 265 | goto err1; | ||
| 266 | } | ||
| 267 | |||
| 268 | platform_set_drvdata(rx51_snd_device, &rx51_snd_devdata); | ||
| 269 | rx51_snd_devdata.dev = &rx51_snd_device->dev; | ||
| 270 | *(unsigned int *)rx51_dai[0].cpu_dai->private_data = 1; /* McBSP2 */ | ||
| 271 | |||
| 272 | err = platform_device_add(rx51_snd_device); | ||
| 273 | if (err) | ||
| 274 | goto err2; | ||
| 275 | |||
| 276 | return 0; | ||
| 277 | err2: | ||
| 278 | platform_device_put(rx51_snd_device); | ||
| 279 | err1: | ||
| 280 | |||
| 281 | return err; | ||
| 282 | } | ||
| 283 | |||
| 284 | static void __exit rx51_soc_exit(void) | ||
| 285 | { | ||
| 286 | platform_device_unregister(rx51_snd_device); | ||
| 287 | } | ||
| 288 | |||
| 289 | module_init(rx51_soc_init); | ||
| 290 | module_exit(rx51_soc_exit); | ||
| 291 | |||
| 292 | MODULE_AUTHOR("Nokia Corporation"); | ||
| 293 | MODULE_DESCRIPTION("ALSA SoC Nokia RX-51"); | ||
| 294 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index f90a2ac888cf..50a94ee76ecc 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c | |||
| @@ -181,9 +181,6 @@ static int zoom2_twl4030_init(struct snd_soc_codec *codec) | |||
| 181 | snd_soc_dapm_nc_pin(codec, "CARKITMIC"); | 181 | snd_soc_dapm_nc_pin(codec, "CARKITMIC"); |
| 182 | snd_soc_dapm_nc_pin(codec, "DIGIMIC0"); | 182 | snd_soc_dapm_nc_pin(codec, "DIGIMIC0"); |
| 183 | snd_soc_dapm_nc_pin(codec, "DIGIMIC1"); | 183 | snd_soc_dapm_nc_pin(codec, "DIGIMIC1"); |
| 184 | |||
| 185 | snd_soc_dapm_nc_pin(codec, "OUTL"); | ||
| 186 | snd_soc_dapm_nc_pin(codec, "OUTR"); | ||
| 187 | snd_soc_dapm_nc_pin(codec, "EARPIECE"); | 184 | snd_soc_dapm_nc_pin(codec, "EARPIECE"); |
| 188 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"); | 185 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"); |
| 189 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"); | 186 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"); |
