diff options
author | Liam Girdwood <lrg@slimlogic.co.uk> | 2010-08-23 07:58:01 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2010-08-23 07:58:01 -0400 |
commit | 97e15b1fcf79a60cb146d4123e7c72ac2736e258 (patch) | |
tree | 5923cd4d4f2e1945b66a7aab27acf684f8590c47 /sound/soc/codecs/tlv320aic3x.c | |
parent | a8165e0e6f0511d14132423b4bce2d285e890fc8 (diff) | |
parent | 38fec7272bc033b75a0eb8976c56c2024d371b7d (diff) |
Merge remote branch 'broonie-asoc/for-2.6.37' into for-2.6.37
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 80 |
1 files changed, 70 insertions, 10 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 0b80e242a66d..efae8b53fd64 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -12,11 +12,11 @@ | |||
12 | * | 12 | * |
13 | * Notes: | 13 | * Notes: |
14 | * The AIC3X is a driver for a low power stereo audio | 14 | * The AIC3X is a driver for a low power stereo audio |
15 | * codecs aic31, aic32, aic33. | 15 | * codecs aic31, aic32, aic33, aic3007. |
16 | * | 16 | * |
17 | * It supports full aic33 codec functionality. | 17 | * It supports full aic33 codec functionality. |
18 | * The compatibility with aic32, aic31 is as follows: | 18 | * The compatibility with aic32, aic31 and aic3007 is as follows: |
19 | * aic32 | aic31 | 19 | * aic32/aic3007 | aic31 |
20 | * --------------------------------------- | 20 | * --------------------------------------- |
21 | * MONO_LOUT -> N/A | MONO_LOUT -> N/A | 21 | * MONO_LOUT -> N/A | MONO_LOUT -> N/A |
22 | * | IN1L -> LINE1L | 22 | * | IN1L -> LINE1L |
@@ -70,6 +70,10 @@ struct aic3x_priv { | |||
70 | unsigned int sysclk; | 70 | unsigned int sysclk; |
71 | int master; | 71 | int master; |
72 | int gpio_reset; | 72 | int gpio_reset; |
73 | #define AIC3X_MODEL_3X 0 | ||
74 | #define AIC3X_MODEL_33 1 | ||
75 | #define AIC3X_MODEL_3007 2 | ||
76 | u16 model; | ||
73 | }; | 77 | }; |
74 | 78 | ||
75 | /* | 79 | /* |
@@ -361,6 +365,14 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
361 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | 365 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), |
362 | }; | 366 | }; |
363 | 367 | ||
368 | /* | ||
369 | * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps | ||
370 | */ | ||
371 | static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0); | ||
372 | |||
373 | static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = | ||
374 | SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv); | ||
375 | |||
364 | /* Left DAC Mux */ | 376 | /* Left DAC Mux */ |
365 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | 377 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = |
366 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); | 378 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); |
@@ -589,6 +601,15 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
589 | SND_SOC_DAPM_INPUT("LINE2R"), | 601 | SND_SOC_DAPM_INPUT("LINE2R"), |
590 | }; | 602 | }; |
591 | 603 | ||
604 | static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = { | ||
605 | /* Class-D outputs */ | ||
606 | SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0), | ||
607 | SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0), | ||
608 | |||
609 | SND_SOC_DAPM_OUTPUT("SPOP"), | ||
610 | SND_SOC_DAPM_OUTPUT("SPOM"), | ||
611 | }; | ||
612 | |||
592 | static const struct snd_soc_dapm_route intercon[] = { | 613 | static const struct snd_soc_dapm_route intercon[] = { |
593 | /* Left Output */ | 614 | /* Left Output */ |
594 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, | 615 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, |
@@ -759,14 +780,30 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
759 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, | 780 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, |
760 | }; | 781 | }; |
761 | 782 | ||
783 | static const struct snd_soc_dapm_route intercon_3007[] = { | ||
784 | /* Class-D outputs */ | ||
785 | {"Left Class-D Out", NULL, "Left Line Out"}, | ||
786 | {"Right Class-D Out", NULL, "Left Line Out"}, | ||
787 | {"SPOP", NULL, "Left Class-D Out"}, | ||
788 | {"SPOM", NULL, "Right Class-D Out"}, | ||
789 | }; | ||
790 | |||
762 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | 791 | static int aic3x_add_widgets(struct snd_soc_codec *codec) |
763 | { | 792 | { |
793 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
794 | |||
764 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, | 795 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
765 | ARRAY_SIZE(aic3x_dapm_widgets)); | 796 | ARRAY_SIZE(aic3x_dapm_widgets)); |
766 | 797 | ||
767 | /* set up audio path interconnects */ | 798 | /* set up audio path interconnects */ |
768 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | 799 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
769 | 800 | ||
801 | if (aic3x->model == AIC3X_MODEL_3007) { | ||
802 | snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets, | ||
803 | ARRAY_SIZE(aic3007_dapm_widgets)); | ||
804 | snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007)); | ||
805 | } | ||
806 | |||
770 | return 0; | 807 | return 0; |
771 | } | 808 | } |
772 | 809 | ||
@@ -1117,6 +1154,7 @@ static struct snd_soc_dai_driver aic3x_dai = { | |||
1117 | .rates = AIC3X_RATES, | 1154 | .rates = AIC3X_RATES, |
1118 | .formats = AIC3X_FORMATS,}, | 1155 | .formats = AIC3X_FORMATS,}, |
1119 | .ops = &aic3x_dai_ops, | 1156 | .ops = &aic3x_dai_ops, |
1157 | .symmetric_rates = 1, | ||
1120 | }; | 1158 | }; |
1121 | 1159 | ||
1122 | static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state) | 1160 | static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state) |
@@ -1150,6 +1188,7 @@ static int aic3x_resume(struct snd_soc_codec *codec) | |||
1150 | */ | 1188 | */ |
1151 | static int aic3x_init(struct snd_soc_codec *codec) | 1189 | static int aic3x_init(struct snd_soc_codec *codec) |
1152 | { | 1190 | { |
1191 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
1153 | int reg; | 1192 | int reg; |
1154 | 1193 | ||
1155 | aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); | 1194 | aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); |
@@ -1218,6 +1257,17 @@ static int aic3x_init(struct snd_soc_codec *codec) | |||
1218 | aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); | 1257 | aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); |
1219 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); | 1258 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); |
1220 | 1259 | ||
1260 | if (aic3x->model == AIC3X_MODEL_3007) { | ||
1261 | /* Class-D speaker driver init; datasheet p. 46 */ | ||
1262 | aic3x_write(codec, AIC3X_PAGE_SELECT, 0x0D); | ||
1263 | aic3x_write(codec, 0xD, 0x0D); | ||
1264 | aic3x_write(codec, 0x8, 0x5C); | ||
1265 | aic3x_write(codec, 0x8, 0x5D); | ||
1266 | aic3x_write(codec, 0x8, 0x5C); | ||
1267 | aic3x_write(codec, AIC3X_PAGE_SELECT, 0x00); | ||
1268 | aic3x_write(codec, CLASSD_CTRL, 0); | ||
1269 | } | ||
1270 | |||
1221 | /* off, with power on */ | 1271 | /* off, with power on */ |
1222 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1272 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1223 | 1273 | ||
@@ -1243,6 +1293,8 @@ static int aic3x_probe(struct snd_soc_codec *codec) | |||
1243 | 1293 | ||
1244 | snd_soc_add_controls(codec, aic3x_snd_controls, | 1294 | snd_soc_add_controls(codec, aic3x_snd_controls, |
1245 | ARRAY_SIZE(aic3x_snd_controls)); | 1295 | ARRAY_SIZE(aic3x_snd_controls)); |
1296 | if (aic3x->model == AIC3X_MODEL_3007) | ||
1297 | snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); | ||
1246 | 1298 | ||
1247 | aic3x_add_widgets(codec); | 1299 | aic3x_add_widgets(codec); |
1248 | 1300 | ||
@@ -1274,6 +1326,14 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = { | |||
1274 | * 0x18, 0x19, 0x1A, 0x1B | 1326 | * 0x18, 0x19, 0x1A, 0x1B |
1275 | */ | 1327 | */ |
1276 | 1328 | ||
1329 | static const struct i2c_device_id aic3x_i2c_id[] = { | ||
1330 | [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 }, | ||
1331 | [AIC3X_MODEL_33] = { "tlv320aic33", 0 }, | ||
1332 | [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 }, | ||
1333 | { } | ||
1334 | }; | ||
1335 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | ||
1336 | |||
1277 | /* | 1337 | /* |
1278 | * If the i2c layer weren't so broken, we could pass this kind of data | 1338 | * If the i2c layer weren't so broken, we could pass this kind of data |
1279 | * around | 1339 | * around |
@@ -1285,6 +1345,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
1285 | struct aic3x_setup_data *setup = pdata->setup; | 1345 | struct aic3x_setup_data *setup = pdata->setup; |
1286 | struct aic3x_priv *aic3x; | 1346 | struct aic3x_priv *aic3x; |
1287 | int ret, i; | 1347 | int ret, i; |
1348 | const struct i2c_device_id *tbl; | ||
1288 | 1349 | ||
1289 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | 1350 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); |
1290 | if (aic3x == NULL) { | 1351 | if (aic3x == NULL) { |
@@ -1305,6 +1366,12 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
1305 | gpio_direction_output(aic3x->gpio_reset, 0); | 1366 | gpio_direction_output(aic3x->gpio_reset, 0); |
1306 | } | 1367 | } |
1307 | 1368 | ||
1369 | for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) { | ||
1370 | if (!strcmp(tbl->name, id->name)) | ||
1371 | break; | ||
1372 | } | ||
1373 | aic3x->model = tbl - aic3x_i2c_id; | ||
1374 | |||
1308 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | 1375 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) |
1309 | aic3x->supplies[i].supply = aic3x_supply_names[i]; | 1376 | aic3x->supplies[i].supply = aic3x_supply_names[i]; |
1310 | 1377 | ||
@@ -1359,13 +1426,6 @@ static int aic3x_i2c_remove(struct i2c_client *client) | |||
1359 | return 0; | 1426 | return 0; |
1360 | } | 1427 | } |
1361 | 1428 | ||
1362 | static const struct i2c_device_id aic3x_i2c_id[] = { | ||
1363 | { "tlv320aic3x", 0 }, | ||
1364 | { "tlv320aic33", 0 }, | ||
1365 | { } | ||
1366 | }; | ||
1367 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | ||
1368 | |||
1369 | /* machine i2c codec control layer */ | 1429 | /* machine i2c codec control layer */ |
1370 | static struct i2c_driver aic3x_i2c_driver = { | 1430 | static struct i2c_driver aic3x_i2c_driver = { |
1371 | .driver = { | 1431 | .driver = { |