diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 71 |
1 files changed, 39 insertions, 32 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 77b8f9ae29be..3bedab26892f 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #include <sound/pcm.h> | 46 | #include <sound/pcm.h> |
47 | #include <sound/pcm_params.h> | 47 | #include <sound/pcm_params.h> |
48 | #include <sound/soc.h> | 48 | #include <sound/soc.h> |
49 | #include <sound/soc-dapm.h> | ||
50 | #include <sound/initval.h> | 49 | #include <sound/initval.h> |
51 | #include <sound/tlv.h> | 50 | #include <sound/tlv.h> |
52 | #include <sound/tlv320aic3x.h> | 51 | #include <sound/tlv320aic3x.h> |
@@ -61,6 +60,8 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { | |||
61 | "DRVDD", /* ADC Analog and Output Driver Voltage */ | 60 | "DRVDD", /* ADC Analog and Output Driver Voltage */ |
62 | }; | 61 | }; |
63 | 62 | ||
63 | static LIST_HEAD(reset_list); | ||
64 | |||
64 | struct aic3x_priv; | 65 | struct aic3x_priv; |
65 | 66 | ||
66 | struct aic3x_disable_nb { | 67 | struct aic3x_disable_nb { |
@@ -77,6 +78,7 @@ struct aic3x_priv { | |||
77 | struct aic3x_setup_data *setup; | 78 | struct aic3x_setup_data *setup; |
78 | void *control_data; | 79 | void *control_data; |
79 | unsigned int sysclk; | 80 | unsigned int sysclk; |
81 | struct list_head list; | ||
80 | int master; | 82 | int master; |
81 | int gpio_reset; | 83 | int gpio_reset; |
82 | int power; | 84 | int power; |
@@ -183,7 +185,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
183 | 185 | ||
184 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { | 186 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { |
185 | /* find dapm widget path assoc with kcontrol */ | 187 | /* find dapm widget path assoc with kcontrol */ |
186 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | 188 | list_for_each_entry(path, &widget->dapm->card->paths, list) { |
187 | if (path->kcontrol != kcontrol) | 189 | if (path->kcontrol != kcontrol) |
188 | continue; | 190 | continue; |
189 | 191 | ||
@@ -199,7 +201,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
199 | } | 201 | } |
200 | 202 | ||
201 | if (found) | 203 | if (found) |
202 | snd_soc_dapm_sync(widget->codec); | 204 | snd_soc_dapm_sync(widget->dapm); |
203 | } | 205 | } |
204 | 206 | ||
205 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | 207 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); |
@@ -788,17 +790,19 @@ static const struct snd_soc_dapm_route intercon_3007[] = { | |||
788 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | 790 | static int aic3x_add_widgets(struct snd_soc_codec *codec) |
789 | { | 791 | { |
790 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 792 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
793 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
791 | 794 | ||
792 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, | 795 | snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets, |
793 | ARRAY_SIZE(aic3x_dapm_widgets)); | 796 | ARRAY_SIZE(aic3x_dapm_widgets)); |
794 | 797 | ||
795 | /* set up audio path interconnects */ | 798 | /* set up audio path interconnects */ |
796 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | 799 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); |
797 | 800 | ||
798 | if (aic3x->model == AIC3X_MODEL_3007) { | 801 | if (aic3x->model == AIC3X_MODEL_3007) { |
799 | snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets, | 802 | snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets, |
800 | ARRAY_SIZE(aic3007_dapm_widgets)); | 803 | ARRAY_SIZE(aic3007_dapm_widgets)); |
801 | snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007)); | 804 | snd_soc_dapm_add_routes(dapm, intercon_3007, |
805 | ARRAY_SIZE(intercon_3007)); | ||
802 | } | 806 | } |
803 | 807 | ||
804 | return 0; | 808 | return 0; |
@@ -1075,7 +1079,7 @@ static int aic3x_regulator_event(struct notifier_block *nb, | |||
1075 | * Put codec to reset and require cache sync as at least one | 1079 | * Put codec to reset and require cache sync as at least one |
1076 | * of the supplies was disabled | 1080 | * of the supplies was disabled |
1077 | */ | 1081 | */ |
1078 | if (aic3x->gpio_reset >= 0) | 1082 | if (gpio_is_valid(aic3x->gpio_reset)) |
1079 | gpio_set_value(aic3x->gpio_reset, 0); | 1083 | gpio_set_value(aic3x->gpio_reset, 0); |
1080 | aic3x->codec->cache_sync = 1; | 1084 | aic3x->codec->cache_sync = 1; |
1081 | } | 1085 | } |
@@ -1102,7 +1106,7 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) | |||
1102 | if (!codec->cache_sync) | 1106 | if (!codec->cache_sync) |
1103 | goto out; | 1107 | goto out; |
1104 | 1108 | ||
1105 | if (aic3x->gpio_reset >= 0) { | 1109 | if (gpio_is_valid(aic3x->gpio_reset)) { |
1106 | udelay(1); | 1110 | udelay(1); |
1107 | gpio_set_value(aic3x->gpio_reset, 1); | 1111 | gpio_set_value(aic3x->gpio_reset, 1); |
1108 | } | 1112 | } |
@@ -1135,7 +1139,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1135 | case SND_SOC_BIAS_ON: | 1139 | case SND_SOC_BIAS_ON: |
1136 | break; | 1140 | break; |
1137 | case SND_SOC_BIAS_PREPARE: | 1141 | case SND_SOC_BIAS_PREPARE: |
1138 | if (codec->bias_level == SND_SOC_BIAS_STANDBY && | 1142 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY && |
1139 | aic3x->master) { | 1143 | aic3x->master) { |
1140 | /* enable pll */ | 1144 | /* enable pll */ |
1141 | reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); | 1145 | reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); |
@@ -1146,7 +1150,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1146 | case SND_SOC_BIAS_STANDBY: | 1150 | case SND_SOC_BIAS_STANDBY: |
1147 | if (!aic3x->power) | 1151 | if (!aic3x->power) |
1148 | aic3x_set_power(codec, 1); | 1152 | aic3x_set_power(codec, 1); |
1149 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && | 1153 | if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE && |
1150 | aic3x->master) { | 1154 | aic3x->master) { |
1151 | /* disable pll */ | 1155 | /* disable pll */ |
1152 | reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); | 1156 | reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); |
@@ -1159,7 +1163,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1159 | aic3x_set_power(codec, 0); | 1163 | aic3x_set_power(codec, 0); |
1160 | break; | 1164 | break; |
1161 | } | 1165 | } |
1162 | codec->bias_level = level; | 1166 | codec->dapm.bias_level = level; |
1163 | 1167 | ||
1164 | return 0; | 1168 | return 0; |
1165 | } | 1169 | } |
@@ -1344,14 +1348,28 @@ static int aic3x_init(struct snd_soc_codec *codec) | |||
1344 | return 0; | 1348 | return 0; |
1345 | } | 1349 | } |
1346 | 1350 | ||
1351 | static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x) | ||
1352 | { | ||
1353 | struct aic3x_priv *a; | ||
1354 | |||
1355 | list_for_each_entry(a, &reset_list, list) { | ||
1356 | if (gpio_is_valid(aic3x->gpio_reset) && | ||
1357 | aic3x->gpio_reset == a->gpio_reset) | ||
1358 | return true; | ||
1359 | } | ||
1360 | |||
1361 | return false; | ||
1362 | } | ||
1363 | |||
1347 | static int aic3x_probe(struct snd_soc_codec *codec) | 1364 | static int aic3x_probe(struct snd_soc_codec *codec) |
1348 | { | 1365 | { |
1349 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1366 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
1350 | int ret, i; | 1367 | int ret, i; |
1351 | 1368 | ||
1369 | INIT_LIST_HEAD(&aic3x->list); | ||
1352 | codec->control_data = aic3x->control_data; | 1370 | codec->control_data = aic3x->control_data; |
1353 | aic3x->codec = codec; | 1371 | aic3x->codec = codec; |
1354 | codec->idle_bias_off = 1; | 1372 | codec->dapm.idle_bias_off = 1; |
1355 | 1373 | ||
1356 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); | 1374 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); |
1357 | if (ret != 0) { | 1375 | if (ret != 0) { |
@@ -1359,7 +1377,8 @@ static int aic3x_probe(struct snd_soc_codec *codec) | |||
1359 | return ret; | 1377 | return ret; |
1360 | } | 1378 | } |
1361 | 1379 | ||
1362 | if (aic3x->gpio_reset >= 0) { | 1380 | if (gpio_is_valid(aic3x->gpio_reset) && |
1381 | !aic3x_is_shared_reset(aic3x)) { | ||
1363 | ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); | 1382 | ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); |
1364 | if (ret != 0) | 1383 | if (ret != 0) |
1365 | goto err_gpio; | 1384 | goto err_gpio; |
@@ -1405,6 +1424,7 @@ static int aic3x_probe(struct snd_soc_codec *codec) | |||
1405 | snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); | 1424 | snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); |
1406 | 1425 | ||
1407 | aic3x_add_widgets(codec); | 1426 | aic3x_add_widgets(codec); |
1427 | list_add(&aic3x->list, &reset_list); | ||
1408 | 1428 | ||
1409 | return 0; | 1429 | return 0; |
1410 | 1430 | ||
@@ -1414,10 +1434,10 @@ err_notif: | |||
1414 | &aic3x->disable_nb[i].nb); | 1434 | &aic3x->disable_nb[i].nb); |
1415 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | 1435 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); |
1416 | err_get: | 1436 | err_get: |
1417 | if (aic3x->gpio_reset >= 0) | 1437 | if (gpio_is_valid(aic3x->gpio_reset) && |
1438 | !aic3x_is_shared_reset(aic3x)) | ||
1418 | gpio_free(aic3x->gpio_reset); | 1439 | gpio_free(aic3x->gpio_reset); |
1419 | err_gpio: | 1440 | err_gpio: |
1420 | kfree(aic3x); | ||
1421 | return ret; | 1441 | return ret; |
1422 | } | 1442 | } |
1423 | 1443 | ||
@@ -1427,7 +1447,9 @@ static int aic3x_remove(struct snd_soc_codec *codec) | |||
1427 | int i; | 1447 | int i; |
1428 | 1448 | ||
1429 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1449 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1430 | if (aic3x->gpio_reset >= 0) { | 1450 | list_del(&aic3x->list); |
1451 | if (gpio_is_valid(aic3x->gpio_reset) && | ||
1452 | !aic3x_is_shared_reset(aic3x)) { | ||
1431 | gpio_set_value(aic3x->gpio_reset, 0); | 1453 | gpio_set_value(aic3x->gpio_reset, 0); |
1432 | gpio_free(aic3x->gpio_reset); | 1454 | gpio_free(aic3x->gpio_reset); |
1433 | } | 1455 | } |
@@ -1523,21 +1545,6 @@ static struct i2c_driver aic3x_i2c_driver = { | |||
1523 | .remove = aic3x_i2c_remove, | 1545 | .remove = aic3x_i2c_remove, |
1524 | .id_table = aic3x_i2c_id, | 1546 | .id_table = aic3x_i2c_id, |
1525 | }; | 1547 | }; |
1526 | |||
1527 | static inline void aic3x_i2c_init(void) | ||
1528 | { | ||
1529 | int ret; | ||
1530 | |||
1531 | ret = i2c_add_driver(&aic3x_i2c_driver); | ||
1532 | if (ret) | ||
1533 | printk(KERN_ERR "%s: error regsitering i2c driver, %d\n", | ||
1534 | __func__, ret); | ||
1535 | } | ||
1536 | |||
1537 | static inline void aic3x_i2c_exit(void) | ||
1538 | { | ||
1539 | i2c_del_driver(&aic3x_i2c_driver); | ||
1540 | } | ||
1541 | #endif | 1548 | #endif |
1542 | 1549 | ||
1543 | static int __init aic3x_modinit(void) | 1550 | static int __init aic3x_modinit(void) |