aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2008-04-30 10:20:52 -0400
committerJaroslav Kysela <perex@perex.cz>2008-05-19 07:19:14 -0400
commit54e7e6167d29a4a98207884b2fbd28b0b3fe91f6 (patch)
tree84ada6a443d563fbb3d0a58a18768aeefe24f33e
parent4f9c16ccfa26691dbb9a5d9e7d5098eb934ccdbe (diff)
[ALSA] soc - tlv320aic3x - add GPIO support
This patch adds support for AIC3x GPIO lines. They can be configured for many possible functions as well as be driven manually. I also introduced i2c read functionality since the GPIO state register has to be read from hardware every time and can not be served from cache. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--sound/soc/codecs/tlv320aic3x.c53
-rw-r--r--sound/soc/codecs/tlv320aic3x.h49
2 files changed, 101 insertions, 1 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 738b3b634d74..957996e0eba2 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -138,6 +138,20 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
138 return -EIO; 138 return -EIO;
139} 139}
140 140
141/*
142 * read from the aic3x register space
143 */
144static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
145 u8 *value)
146{
147 *value = reg & 0xff;
148 if (codec->hw_read(codec->control_data, value, 1) != 1)
149 return -EIO;
150
151 aic3x_write_reg_cache(codec, reg, *value);
152 return 0;
153}
154
141#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ 155#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
142{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 156{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
143 .info = snd_soc_info_volsw, \ 157 .info = snd_soc_info_volsw, \
@@ -911,6 +925,33 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
911 return 0; 925 return 0;
912} 926}
913 927
928void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state)
929{
930 u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
931 u8 bit = gpio ? 3: 0;
932 u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit);
933 aic3x_write(codec, reg, val | (!!state << bit));
934}
935EXPORT_SYMBOL_GPL(aic3x_set_gpio);
936
937int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio)
938{
939 u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
940 u8 val, bit = gpio ? 2: 1;
941
942 aic3x_read(codec, reg, &val);
943 return (val >> bit) & 1;
944}
945EXPORT_SYMBOL_GPL(aic3x_get_gpio);
946
947int aic3x_headset_detected(struct snd_soc_codec *codec)
948{
949 u8 val;
950 aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val);
951 return (val >> 2) & 1;
952}
953EXPORT_SYMBOL_GPL(aic3x_headset_detected);
954
914#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 955#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000
915#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ 956#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
916 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) 957 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -977,6 +1018,7 @@ static int aic3x_resume(struct platform_device *pdev)
977static int aic3x_init(struct snd_soc_device *socdev) 1018static int aic3x_init(struct snd_soc_device *socdev)
978{ 1019{
979 struct snd_soc_codec *codec = socdev->codec; 1020 struct snd_soc_codec *codec = socdev->codec;
1021 struct aic3x_setup_data *setup = socdev->codec_data;
980 int reg, ret = 0; 1022 int reg, ret = 0;
981 1023
982 codec->name = "aic3x"; 1024 codec->name = "aic3x";
@@ -1067,6 +1109,10 @@ static int aic3x_init(struct snd_soc_device *socdev)
1067 /* off, with power on */ 1109 /* off, with power on */
1068 aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot); 1110 aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
1069 1111
1112 /* setup GPIO functions */
1113 aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4);
1114 aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4);
1115
1070 aic3x_add_controls(codec); 1116 aic3x_add_controls(codec);
1071 aic3x_add_widgets(codec); 1117 aic3x_add_widgets(codec);
1072 ret = snd_soc_register_card(socdev); 1118 ret = snd_soc_register_card(socdev);
@@ -1174,6 +1220,12 @@ static struct i2c_client client_template = {
1174 .name = "AIC3X", 1220 .name = "AIC3X",
1175 .driver = &aic3x_i2c_driver, 1221 .driver = &aic3x_i2c_driver,
1176}; 1222};
1223
1224static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len)
1225{
1226 value[0] = i2c_smbus_read_byte_data(client, value[0]);
1227 return (len == 1);
1228}
1177#endif 1229#endif
1178 1230
1179static int aic3x_probe(struct platform_device *pdev) 1231static int aic3x_probe(struct platform_device *pdev)
@@ -1208,6 +1260,7 @@ static int aic3x_probe(struct platform_device *pdev)
1208 if (setup->i2c_address) { 1260 if (setup->i2c_address) {
1209 normal_i2c[0] = setup->i2c_address; 1261 normal_i2c[0] = setup->i2c_address;
1210 codec->hw_write = (hw_write_t) i2c_master_send; 1262 codec->hw_write = (hw_write_t) i2c_master_send;
1263 codec->hw_read = (hw_read_t) aic3x_i2c_read;
1211 ret = i2c_add_driver(&aic3x_i2c_driver); 1264 ret = i2c_add_driver(&aic3x_i2c_driver);
1212 if (ret != 0) 1265 if (ret != 0)
1213 printk(KERN_ERR "can't add i2c driver"); 1266 printk(KERN_ERR "can't add i2c driver");
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index d49d001e6e4c..c1dd1ac0ceac 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -108,8 +108,14 @@
108#define DACR1_2_RLOPM_VOL 92 108#define DACR1_2_RLOPM_VOL 92
109#define LLOPM_CTRL 86 109#define LLOPM_CTRL 86
110#define RLOPM_CTRL 93 110#define RLOPM_CTRL 93
111/* Clock generation control register */ 111/* GPIO/IRQ registers */
112#define AIC3X_STICKY_IRQ_FLAGS_REG 96
113#define AIC3X_RT_IRQ_FLAGS_REG 97
114#define AIC3X_GPIO1_REG 98
115#define AIC3X_GPIO2_REG 99
116#define AIC3X_GPIOA_REG 100
112#define AIC3X_GPIOB_REG 101 117#define AIC3X_GPIOB_REG 101
118/* Clock generation control register */
113#define AIC3X_CLKGEN_CTRL_REG 102 119#define AIC3X_CLKGEN_CTRL_REG 102
114 120
115/* Page select register bits */ 121/* Page select register bits */
@@ -175,8 +181,49 @@
175/* Default input volume */ 181/* Default input volume */
176#define DEFAULT_GAIN 0x20 182#define DEFAULT_GAIN 0x20
177 183
184/* GPIO API */
185enum {
186 AIC3X_GPIO1_FUNC_DISABLED = 0,
187 AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
188 AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
189 AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
190 AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
191 AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
192 AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
193 AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
194 AIC3X_GPIO1_FUNC_INPUT = 8,
195 AIC3X_GPIO1_FUNC_OUTPUT = 9,
196 AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
197 AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
198 AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
199 AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
200 AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
201 AIC3X_GPIO1_FUNC_ALL_IRQ = 16
202};
203
204enum {
205 AIC3X_GPIO2_FUNC_DISABLED = 0,
206 AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
207 AIC3X_GPIO2_FUNC_INPUT = 3,
208 AIC3X_GPIO2_FUNC_OUTPUT = 4,
209 AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
210 AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
211 AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
212 AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
213 AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
214 AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
215 AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
216 AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
217 AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
218};
219
220void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
221int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
222int aic3x_headset_detected(struct snd_soc_codec *codec);
223
178struct aic3x_setup_data { 224struct aic3x_setup_data {
179 unsigned short i2c_address; 225 unsigned short i2c_address;
226 unsigned int gpio_func[2];
180}; 227};
181 228
182extern struct snd_soc_codec_dai aic3x_dai; 229extern struct snd_soc_codec_dai aic3x_dai;