| OLD | NEW |
| 1 /* | 1 /* |
| 2 * ALSA SoC TLV320AIC3X codec driver | 2 * ALSA SoC TLV320AIC3X codec driver |
| 3 * | 3 * |
| 4 * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> | 4 * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
| 5 * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
| 6 * | 6 * |
| 7 * Based on sound/soc/codecs/wm8753.c by Liam Girdwood | 7 * Based on sound/soc/codecs/wm8753.c by Liam Girdwood |
| 8 * | 8 * |
| 9 * This program is free software; you can redistribute it and/or modify | 9 * This program is free software; you can redistribute it and/or modify |
| 10 * it under the terms of the GNU General Public License version 2 as | 10 * it under the terms of the GNU General Public License version 2 as |
| (...skipping 28 matching lines...) Expand all Loading... |
| 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/gpio.h> |
| 42 #include <linux/regulator/consumer.h> | 42 #include <linux/regulator/consumer.h> |
| 43 #include <linux/platform_device.h> | 43 #include <linux/platform_device.h> |
| 44 #include <linux/slab.h> | 44 #include <linux/slab.h> |
| 45 #include <sound/core.h> | 45 #include <sound/core.h> |
| 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> |
| 53 | 52 |
| 54 #include "tlv320aic3x.h" | 53 #include "tlv320aic3x.h" |
| 55 | 54 |
| 56 #define AIC3X_NUM_SUPPLIES 4 | 55 #define AIC3X_NUM_SUPPLIES 4 |
| 57 static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { | 56 static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { |
| 58 "IOVDD", /* I/O Voltage */ | 57 "IOVDD", /* I/O Voltage */ |
| 59 "DVDD", /* Digital Core Voltage */ | 58 "DVDD", /* Digital Core Voltage */ |
| 60 "AVDD", /* Analog DAC Voltage */ | 59 "AVDD", /* Analog DAC Voltage */ |
| 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 { |
| 67 struct notifier_block nb; | 68 struct notifier_block nb; |
| 68 struct aic3x_priv *aic3x; | 69 struct aic3x_priv *aic3x; |
| 69 }; | 70 }; |
| 70 | 71 |
| 71 /* codec private data */ | 72 /* codec private data */ |
| 72 struct aic3x_priv { | 73 struct aic3x_priv { |
| 73 struct snd_soc_codec *codec; | 74 struct snd_soc_codec *codec; |
| 74 struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; | 75 struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; |
| 75 struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; | 76 struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; |
| 76 enum snd_soc_control_type control_type; | 77 enum snd_soc_control_type control_type; |
| 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; |
| 83 #define AIC3X_MODEL_3X 0 | 85 #define AIC3X_MODEL_3X 0 |
| 84 #define AIC3X_MODEL_33 1 | 86 #define AIC3X_MODEL_33 1 |
| 85 #define AIC3X_MODEL_3007 2 | 87 #define AIC3X_MODEL_3007 2 |
| 86 u16 model; | 88 u16 model; |
| 87 }; | 89 }; |
| 88 | 90 |
| 89 /* | 91 /* |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 | 178 |
| 177 if (invert) | 179 if (invert) |
| 178 val = mask - val; | 180 val = mask - val; |
| 179 val_mask = mask << shift; | 181 val_mask = mask << shift; |
| 180 val = val << shift; | 182 val = val << shift; |
| 181 | 183 |
| 182 mutex_lock(&widget->codec->mutex); | 184 mutex_lock(&widget->codec->mutex); |
| 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 |
| 190 /* found, now check type */ | 192 /* found, now check type */ |
| 191 found = 1; | 193 found = 1; |
| 192 if (val) | 194 if (val) |
| 193 /* new connection */ | 195 /* new connection */ |
| 194 path->connect = invert ? 0 : 1; | 196 path->connect = invert ? 0 : 1; |
| 195 else | 197 else |
| 196 /* old connection must be powered down */ | 198 /* old connection must be powered down */ |
| 197 path->connect = invert ? 1 : 0; | 199 path->connect = invert ? 1 : 0; |
| 198 break; | 200 break; |
| 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); |
| 206 | 208 |
| 207 mutex_unlock(&widget->codec->mutex); | 209 mutex_unlock(&widget->codec->mutex); |
| 208 return ret; | 210 return ret; |
| 209 } | 211 } |
| 210 | 212 |
| 211 static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; | 213 static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; |
| 212 static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; | 214 static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; |
| (...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 /* Class-D outputs */ | 783 /* Class-D outputs */ |
| 782 {"Left Class-D Out", NULL, "Left Line Out"}, | 784 {"Left Class-D Out", NULL, "Left Line Out"}, |
| 783 {"Right Class-D Out", NULL, "Left Line Out"}, | 785 {"Right Class-D Out", NULL, "Left Line Out"}, |
| 784 {"SPOP", NULL, "Left Class-D Out"}, | 786 {"SPOP", NULL, "Left Class-D Out"}, |
| 785 {"SPOM", NULL, "Right Class-D Out"}, | 787 {"SPOM", NULL, "Right Class-D Out"}, |
| 786 }; | 788 }; |
| 787 | 789 |
| 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(interco
n_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; |
| 805 } | 809 } |
| 806 | 810 |
| 807 static int aic3x_hw_params(struct snd_pcm_substream *substream, | 811 static int aic3x_hw_params(struct snd_pcm_substream *substream, |
| 808 struct snd_pcm_hw_params *params, | 812 struct snd_pcm_hw_params *params, |
| 809 struct snd_soc_dai *dai) | 813 struct snd_soc_dai *dai) |
| 810 { | 814 { |
| 811 struct snd_soc_pcm_runtime *rtd = substream->private_data; | 815 struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1068 { | 1072 { |
| 1069 struct aic3x_disable_nb *disable_nb = | 1073 struct aic3x_disable_nb *disable_nb = |
| 1070 container_of(nb, struct aic3x_disable_nb, nb); | 1074 container_of(nb, struct aic3x_disable_nb, nb); |
| 1071 struct aic3x_priv *aic3x = disable_nb->aic3x; | 1075 struct aic3x_priv *aic3x = disable_nb->aic3x; |
| 1072 | 1076 |
| 1073 if (event & REGULATOR_EVENT_DISABLE) { | 1077 if (event & REGULATOR_EVENT_DISABLE) { |
| 1074 /* | 1078 /* |
| 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 } |
| 1082 | 1086 |
| 1083 return 0; | 1087 return 0; |
| 1084 } | 1088 } |
| 1085 | 1089 |
| 1086 static int aic3x_set_power(struct snd_soc_codec *codec, int power) | 1090 static int aic3x_set_power(struct snd_soc_codec *codec, int power) |
| 1087 { | 1091 { |
| 1088 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1092 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
| 1089 int i, ret; | 1093 int i, ret; |
| 1090 u8 *cache = codec->reg_cache; | 1094 u8 *cache = codec->reg_cache; |
| 1091 | 1095 |
| 1092 if (power) { | 1096 if (power) { |
| 1093 ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), | 1097 ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), |
| 1094 aic3x->supplies); | 1098 aic3x->supplies); |
| 1095 if (ret) | 1099 if (ret) |
| 1096 goto out; | 1100 goto out; |
| 1097 aic3x->power = 1; | 1101 aic3x->power = 1; |
| 1098 /* | 1102 /* |
| 1099 * Reset release and cache sync is necessary only if some | 1103 * Reset release and cache sync is necessary only if some |
| 1100 * supply was off or if there were cached writes | 1104 * supply was off or if there were cached writes |
| 1101 */ | 1105 */ |
| 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 } |
| 1109 | 1113 |
| 1110 /* Sync reg_cache with the hardware */ | 1114 /* Sync reg_cache with the hardware */ |
| 1111 codec->cache_only = 0; | 1115 codec->cache_only = 0; |
| 1112 for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) | 1116 for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) |
| 1113 snd_soc_write(codec, i, cache[i]); | 1117 snd_soc_write(codec, i, cache[i]); |
| 1114 if (aic3x->model == AIC3X_MODEL_3007) | 1118 if (aic3x->model == AIC3X_MODEL_3007) |
| 1115 aic3x_init_3007(codec); | 1119 aic3x_init_3007(codec); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1128 static int aic3x_set_bias_level(struct snd_soc_codec *codec, | 1132 static int aic3x_set_bias_level(struct snd_soc_codec *codec, |
| 1129 enum snd_soc_bias_level level) | 1133 enum snd_soc_bias_level level) |
| 1130 { | 1134 { |
| 1131 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1135 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
| 1132 u8 reg; | 1136 u8 reg; |
| 1133 | 1137 |
| 1134 switch (level) { | 1138 switch (level) { |
| 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); |
| 1142 snd_soc_write(codec, AIC3X_PLL_PROGA_REG, | 1146 snd_soc_write(codec, AIC3X_PLL_PROGA_REG, |
| 1143 reg | PLL_ENABLE); | 1147 reg | PLL_ENABLE); |
| 1144 } | 1148 } |
| 1145 break; | 1149 break; |
| 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); |
| 1153 snd_soc_write(codec, AIC3X_PLL_PROGA_REG, | 1157 snd_soc_write(codec, AIC3X_PLL_PROGA_REG, |
| 1154 reg & ~PLL_ENABLE); | 1158 reg & ~PLL_ENABLE); |
| 1155 } | 1159 } |
| 1156 break; | 1160 break; |
| 1157 case SND_SOC_BIAS_OFF: | 1161 case SND_SOC_BIAS_OFF: |
| 1158 if (aic3x->power) | 1162 if (aic3x->power) |
| 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 } |
| 1166 | 1170 |
| 1167 void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) | 1171 void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) |
| 1168 { | 1172 { |
| 1169 u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | 1173 u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; |
| 1170 u8 bit = gpio ? 3: 0; | 1174 u8 bit = gpio ? 3: 0; |
| 1171 u8 val = snd_soc_read(codec, reg) & ~(1 << bit); | 1175 u8 val = snd_soc_read(codec, reg) & ~(1 << bit); |
| 1172 snd_soc_write(codec, reg, val | (!!state << bit)); | 1176 snd_soc_write(codec, reg, val | (!!state << bit)); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1337 snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); | 1341 snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); |
| 1338 | 1342 |
| 1339 if (aic3x->model == AIC3X_MODEL_3007) { | 1343 if (aic3x->model == AIC3X_MODEL_3007) { |
| 1340 aic3x_init_3007(codec); | 1344 aic3x_init_3007(codec); |
| 1341 snd_soc_write(codec, CLASSD_CTRL, 0); | 1345 snd_soc_write(codec, CLASSD_CTRL, 0); |
| 1342 } | 1346 } |
| 1343 | 1347 |
| 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) { |
| 1358 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 1376 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 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; |
| 1366 gpio_direction_output(aic3x->gpio_reset, 0); | 1385 gpio_direction_output(aic3x->gpio_reset, 0); |
| 1367 } | 1386 } |
| 1368 | 1387 |
| 1369 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | 1388 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) |
| 1370 aic3x->supplies[i].supply = aic3x_supply_names[i]; | 1389 aic3x->supplies[i].supply = aic3x_supply_names[i]; |
| 1371 | 1390 |
| 1372 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), | 1391 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1398 snd_soc_write(codec, AIC3X_GPIO2_REG, | 1417 snd_soc_write(codec, AIC3X_GPIO2_REG, |
| 1399 (aic3x->setup->gpio_func[1] & 0xf) << 4); | 1418 (aic3x->setup->gpio_func[1] & 0xf) << 4); |
| 1400 } | 1419 } |
| 1401 | 1420 |
| 1402 snd_soc_add_controls(codec, aic3x_snd_controls, | 1421 snd_soc_add_controls(codec, aic3x_snd_controls, |
| 1403 ARRAY_SIZE(aic3x_snd_controls)); | 1422 ARRAY_SIZE(aic3x_snd_controls)); |
| 1404 if (aic3x->model == AIC3X_MODEL_3007) | 1423 if (aic3x->model == AIC3X_MODEL_3007) |
| 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 |
| 1411 err_notif: | 1431 err_notif: |
| 1412 while (i--) | 1432 while (i--) |
| 1413 regulator_unregister_notifier(aic3x->supplies[i].consumer, | 1433 regulator_unregister_notifier(aic3x->supplies[i].consumer, |
| 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 |
| 1424 static int aic3x_remove(struct snd_soc_codec *codec) | 1444 static int aic3x_remove(struct snd_soc_codec *codec) |
| 1425 { | 1445 { |
| 1426 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1446 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(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 } |
| 1434 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | 1456 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) |
| 1435 regulator_unregister_notifier(aic3x->supplies[i].consumer, | 1457 regulator_unregister_notifier(aic3x->supplies[i].consumer, |
| 1436 &aic3x->disable_nb[i].nb); | 1458 &aic3x->disable_nb[i].nb); |
| 1437 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | 1459 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); |
| 1438 | 1460 |
| 1439 return 0; | 1461 return 0; |
| 1440 } | 1462 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1516 /* machine i2c codec control layer */ | 1538 /* machine i2c codec control layer */ |
| 1517 static struct i2c_driver aic3x_i2c_driver = { | 1539 static struct i2c_driver aic3x_i2c_driver = { |
| 1518 .driver = { | 1540 .driver = { |
| 1519 .name = "tlv320aic3x-codec", | 1541 .name = "tlv320aic3x-codec", |
| 1520 .owner = THIS_MODULE, | 1542 .owner = THIS_MODULE, |
| 1521 }, | 1543 }, |
| 1522 .probe = aic3x_i2c_probe, | 1544 .probe = aic3x_i2c_probe, |
| 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) |
| 1544 { | 1551 { |
| 1545 int ret = 0; | 1552 int ret = 0; |
| 1546 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1553 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| 1547 ret = i2c_add_driver(&aic3x_i2c_driver); | 1554 ret = i2c_add_driver(&aic3x_i2c_driver); |
| 1548 if (ret != 0) { | 1555 if (ret != 0) { |
| 1549 printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n
", | 1556 printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n
", |
| 1550 ret); | 1557 ret); |
| 1551 } | 1558 } |
| 1552 #endif | 1559 #endif |
| 1553 return ret; | 1560 return ret; |
| 1554 } | 1561 } |
| 1555 module_init(aic3x_modinit); | 1562 module_init(aic3x_modinit); |
| 1556 | 1563 |
| 1557 static void __exit aic3x_exit(void) | 1564 static void __exit aic3x_exit(void) |
| 1558 { | 1565 { |
| 1559 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1566 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| 1560 i2c_del_driver(&aic3x_i2c_driver); | 1567 i2c_del_driver(&aic3x_i2c_driver); |
| 1561 #endif | 1568 #endif |
| 1562 } | 1569 } |
| 1563 module_exit(aic3x_exit); | 1570 module_exit(aic3x_exit); |
| 1564 | 1571 |
| 1565 MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); | 1572 MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); |
| 1566 MODULE_AUTHOR("Vladimir Barinov"); | 1573 MODULE_AUTHOR("Vladimir Barinov"); |
| 1567 MODULE_LICENSE("GPL"); | 1574 MODULE_LICENSE("GPL"); |
| OLD | NEW |