diff options
author | Barry Song <21cnbao@gmail.com> | 2010-01-26 22:46:18 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-01-27 05:43:09 -0500 |
commit | 994dc4245d3f50329da4ead453a5dfcfbc716a0d (patch) | |
tree | 1523d8129ccf168d953c44e500a01e5f13cb8dbf | |
parent | 63b62ab0d52c736b3274b294df962e0a4b7aae79 (diff) |
ASoC: ad1938: use soc-cache framework for codec registers access
Signed-off-by: Barry Song <Barry.Song@analog.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/ad1938.c | 164 | ||||
-rw-r--r-- | sound/soc/soc-cache.c | 108 |
2 files changed, 144 insertions, 128 deletions
diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 47d9ac0ec9d9..c233810d463d 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c | |||
@@ -46,6 +46,11 @@ struct ad1938_priv { | |||
46 | u8 reg_cache[AD1938_NUM_REGS]; | 46 | u8 reg_cache[AD1938_NUM_REGS]; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | /* ad1938 register cache & default register settings */ | ||
50 | static const u8 ad1938_reg[AD1938_NUM_REGS] = { | ||
51 | 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, | ||
52 | }; | ||
53 | |||
49 | static struct snd_soc_codec *ad1938_codec; | 54 | static struct snd_soc_codec *ad1938_codec; |
50 | struct snd_soc_codec_device soc_codec_dev_ad1938; | 55 | struct snd_soc_codec_device soc_codec_dev_ad1938; |
51 | static int ad1938_register(struct ad1938_priv *ad1938); | 56 | static int ad1938_register(struct ad1938_priv *ad1938); |
@@ -129,10 +134,10 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute) | |||
129 | struct snd_soc_codec *codec = dai->codec; | 134 | struct snd_soc_codec *codec = dai->codec; |
130 | int reg; | 135 | int reg; |
131 | 136 | ||
132 | reg = codec->read(codec, AD1938_DAC_CTRL2); | 137 | reg = snd_soc_read(codec, AD1938_DAC_CTRL2); |
133 | reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & | 138 | reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & |
134 | (~AD1938_DAC_MASTER_MUTE); | 139 | (~AD1938_DAC_MASTER_MUTE); |
135 | codec->write(codec, AD1938_DAC_CTRL2, reg); | 140 | snd_soc_write(codec, AD1938_DAC_CTRL2, reg); |
136 | 141 | ||
137 | return 0; | 142 | return 0; |
138 | } | 143 | } |
@@ -141,8 +146,8 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
141 | unsigned int rx_mask, int slots, int width) | 146 | unsigned int rx_mask, int slots, int width) |
142 | { | 147 | { |
143 | struct snd_soc_codec *codec = dai->codec; | 148 | struct snd_soc_codec *codec = dai->codec; |
144 | int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); | 149 | int dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1); |
145 | int adc_reg = codec->read(codec, AD1938_ADC_CTRL2); | 150 | int adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2); |
146 | 151 | ||
147 | dac_reg &= ~AD1938_DAC_CHAN_MASK; | 152 | dac_reg &= ~AD1938_DAC_CHAN_MASK; |
148 | adc_reg &= ~AD1938_ADC_CHAN_MASK; | 153 | adc_reg &= ~AD1938_ADC_CHAN_MASK; |
@@ -168,8 +173,8 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
168 | return -EINVAL; | 173 | return -EINVAL; |
169 | } | 174 | } |
170 | 175 | ||
171 | codec->write(codec, AD1938_DAC_CTRL1, dac_reg); | 176 | snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg); |
172 | codec->write(codec, AD1938_ADC_CTRL2, adc_reg); | 177 | snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg); |
173 | 178 | ||
174 | return 0; | 179 | return 0; |
175 | } | 180 | } |
@@ -180,8 +185,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
180 | struct snd_soc_codec *codec = codec_dai->codec; | 185 | struct snd_soc_codec *codec = codec_dai->codec; |
181 | int adc_reg, dac_reg; | 186 | int adc_reg, dac_reg; |
182 | 187 | ||
183 | adc_reg = codec->read(codec, AD1938_ADC_CTRL2); | 188 | adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2); |
184 | dac_reg = codec->read(codec, AD1938_DAC_CTRL1); | 189 | dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1); |
185 | 190 | ||
186 | /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S | 191 | /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S |
187 | * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) | 192 | * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) |
@@ -258,8 +263,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
258 | return -EINVAL; | 263 | return -EINVAL; |
259 | } | 264 | } |
260 | 265 | ||
261 | codec->write(codec, AD1938_ADC_CTRL2, adc_reg); | 266 | snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg); |
262 | codec->write(codec, AD1938_DAC_CTRL1, dac_reg); | 267 | snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg); |
263 | 268 | ||
264 | return 0; | 269 | return 0; |
265 | } | 270 | } |
@@ -288,116 +293,13 @@ static int ad1938_hw_params(struct snd_pcm_substream *substream, | |||
288 | break; | 293 | break; |
289 | } | 294 | } |
290 | 295 | ||
291 | reg = codec->read(codec, AD1938_DAC_CTRL2); | 296 | reg = snd_soc_read(codec, AD1938_DAC_CTRL2); |
292 | reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len; | 297 | reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len; |
293 | codec->write(codec, AD1938_DAC_CTRL2, reg); | 298 | snd_soc_write(codec, AD1938_DAC_CTRL2, reg); |
294 | 299 | ||
295 | reg = codec->read(codec, AD1938_ADC_CTRL1); | 300 | reg = snd_soc_read(codec, AD1938_ADC_CTRL1); |
296 | reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len; | 301 | reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len; |
297 | codec->write(codec, AD1938_ADC_CTRL1, reg); | 302 | snd_soc_write(codec, AD1938_ADC_CTRL1, reg); |
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * interface to read/write ad1938 register | ||
304 | */ | ||
305 | |||
306 | #define AD1938_SPI_ADDR 0x4 | ||
307 | #define AD1938_SPI_READ 0x1 | ||
308 | #define AD1938_SPI_BUFLEN 3 | ||
309 | |||
310 | /* | ||
311 | * write to the ad1938 register space | ||
312 | */ | ||
313 | |||
314 | static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg, | ||
315 | unsigned int value) | ||
316 | { | ||
317 | u8 *reg_cache = codec->reg_cache; | ||
318 | int ret = 0; | ||
319 | |||
320 | if (value != reg_cache[reg]) { | ||
321 | uint8_t buf[AD1938_SPI_BUFLEN]; | ||
322 | struct spi_transfer t = { | ||
323 | .tx_buf = buf, | ||
324 | .len = AD1938_SPI_BUFLEN, | ||
325 | }; | ||
326 | struct spi_message m; | ||
327 | |||
328 | buf[0] = AD1938_SPI_ADDR << 1; | ||
329 | buf[1] = reg; | ||
330 | buf[2] = value; | ||
331 | spi_message_init(&m); | ||
332 | spi_message_add_tail(&t, &m); | ||
333 | ret = spi_sync(codec->control_data, &m); | ||
334 | if (ret == 0) | ||
335 | reg_cache[reg] = value; | ||
336 | } | ||
337 | |||
338 | return ret; | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * read from the ad1938 register space cache | ||
343 | */ | ||
344 | |||
345 | static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec, | ||
346 | unsigned int reg) | ||
347 | { | ||
348 | u8 *reg_cache = codec->reg_cache; | ||
349 | |||
350 | if (reg >= codec->reg_cache_size) | ||
351 | return -EINVAL; | ||
352 | |||
353 | return reg_cache[reg]; | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * read from the ad1938 register space | ||
358 | */ | ||
359 | |||
360 | static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, | ||
361 | unsigned int reg) | ||
362 | { | ||
363 | char w_buf[AD1938_SPI_BUFLEN]; | ||
364 | char r_buf[AD1938_SPI_BUFLEN]; | ||
365 | int ret; | ||
366 | |||
367 | struct spi_transfer t = { | ||
368 | .tx_buf = w_buf, | ||
369 | .rx_buf = r_buf, | ||
370 | .len = AD1938_SPI_BUFLEN, | ||
371 | }; | ||
372 | struct spi_message m; | ||
373 | |||
374 | w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ; | ||
375 | w_buf[1] = reg; | ||
376 | w_buf[2] = 0; | ||
377 | |||
378 | spi_message_init(&m); | ||
379 | spi_message_add_tail(&t, &m); | ||
380 | ret = spi_sync(codec->control_data, &m); | ||
381 | if (ret == 0) | ||
382 | return r_buf[2]; | ||
383 | else | ||
384 | return -EIO; | ||
385 | } | ||
386 | |||
387 | static int ad1938_fill_cache(struct snd_soc_codec *codec) | ||
388 | { | ||
389 | int i; | ||
390 | u8 *reg_cache = codec->reg_cache; | ||
391 | struct spi_device *spi = codec->control_data; | ||
392 | |||
393 | for (i = 0; i < codec->reg_cache_size; i++) { | ||
394 | int ret = ad1938_read_reg(codec, i); | ||
395 | if (ret == -EIO) { | ||
396 | dev_err(&spi->dev, "AD1938 SPI read failure\n"); | ||
397 | return ret; | ||
398 | } | ||
399 | reg_cache[i] = ret; | ||
400 | } | ||
401 | 303 | ||
402 | return 0; | 304 | return 0; |
403 | } | 305 | } |
@@ -487,31 +389,37 @@ static int ad1938_register(struct ad1938_priv *ad1938) | |||
487 | codec->owner = THIS_MODULE; | 389 | codec->owner = THIS_MODULE; |
488 | codec->dai = &ad1938_dai; | 390 | codec->dai = &ad1938_dai; |
489 | codec->num_dai = 1; | 391 | codec->num_dai = 1; |
490 | codec->write = ad1938_write_reg; | ||
491 | codec->read = ad1938_read_reg_cache; | ||
492 | INIT_LIST_HEAD(&codec->dapm_widgets); | 392 | INIT_LIST_HEAD(&codec->dapm_widgets); |
493 | INIT_LIST_HEAD(&codec->dapm_paths); | 393 | INIT_LIST_HEAD(&codec->dapm_paths); |
494 | 394 | ||
495 | ad1938_dai.dev = codec->dev; | 395 | ad1938_dai.dev = codec->dev; |
496 | ad1938_codec = codec; | 396 | ad1938_codec = codec; |
497 | 397 | ||
398 | memcpy(codec->reg_cache, ad1938_reg, AD1938_NUM_REGS); | ||
399 | |||
400 | ret = snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_SPI); | ||
401 | if (ret < 0) { | ||
402 | dev_err(codec->dev, "failed to set cache I/O: %d\n", | ||
403 | ret); | ||
404 | kfree(ad1938); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
498 | /* default setting for ad1938 */ | 408 | /* default setting for ad1938 */ |
499 | 409 | ||
500 | /* unmute dac channels */ | 410 | /* unmute dac channels */ |
501 | codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); | 411 | snd_soc_write(codec, AD1938_DAC_CHNL_MUTE, 0x0); |
502 | /* de-emphasis: 48kHz, powedown dac */ | 412 | /* de-emphasis: 48kHz, powedown dac */ |
503 | codec->write(codec, AD1938_DAC_CTRL2, 0x1A); | 413 | snd_soc_write(codec, AD1938_DAC_CTRL2, 0x1A); |
504 | /* powerdown dac, dac in tdm mode */ | 414 | /* powerdown dac, dac in tdm mode */ |
505 | codec->write(codec, AD1938_DAC_CTRL0, 0x41); | 415 | snd_soc_write(codec, AD1938_DAC_CTRL0, 0x41); |
506 | /* high-pass filter enable */ | 416 | /* high-pass filter enable */ |
507 | codec->write(codec, AD1938_ADC_CTRL0, 0x3); | 417 | snd_soc_write(codec, AD1938_ADC_CTRL0, 0x3); |
508 | /* sata delay=1, adc aux mode */ | 418 | /* sata delay=1, adc aux mode */ |
509 | codec->write(codec, AD1938_ADC_CTRL1, 0x43); | 419 | snd_soc_write(codec, AD1938_ADC_CTRL1, 0x43); |
510 | /* pll input: mclki/xi */ | 420 | /* pll input: mclki/xi */ |
511 | codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); | 421 | snd_soc_write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); |
512 | codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04); | 422 | snd_soc_write(codec, AD1938_PLL_CLK_CTRL1, 0x04); |
513 | |||
514 | ad1938_fill_cache(codec); | ||
515 | 423 | ||
516 | ret = snd_soc_register_codec(codec); | 424 | ret = snd_soc_register_codec(codec); |
517 | if (ret != 0) { | 425 | if (ret != 0) { |
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index cde7b63de113..097e33510a7a 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -233,6 +233,108 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, | |||
233 | #define snd_soc_8_16_read_i2c NULL | 233 | #define snd_soc_8_16_read_i2c NULL |
234 | #endif | 234 | #endif |
235 | 235 | ||
236 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
237 | static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, | ||
238 | unsigned int r) | ||
239 | { | ||
240 | struct i2c_msg xfer[2]; | ||
241 | u16 reg = r; | ||
242 | u8 data; | ||
243 | int ret; | ||
244 | struct i2c_client *client = codec->control_data; | ||
245 | |||
246 | /* Write register */ | ||
247 | xfer[0].addr = client->addr; | ||
248 | xfer[0].flags = 0; | ||
249 | xfer[0].len = 2; | ||
250 | xfer[0].buf = (u8 *)® | ||
251 | |||
252 | /* Read data */ | ||
253 | xfer[1].addr = client->addr; | ||
254 | xfer[1].flags = I2C_M_RD; | ||
255 | xfer[1].len = 1; | ||
256 | xfer[1].buf = &data; | ||
257 | |||
258 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
259 | if (ret != 2) { | ||
260 | dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | return data; | ||
265 | } | ||
266 | #else | ||
267 | #define snd_soc_16_8_read_i2c NULL | ||
268 | #endif | ||
269 | |||
270 | static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | ||
271 | unsigned int reg) | ||
272 | { | ||
273 | u16 *cache = codec->reg_cache; | ||
274 | |||
275 | reg &= 0xff; | ||
276 | if (reg >= codec->reg_cache_size) | ||
277 | return -1; | ||
278 | return cache[reg]; | ||
279 | } | ||
280 | |||
281 | static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | ||
282 | unsigned int value) | ||
283 | { | ||
284 | u16 *cache = codec->reg_cache; | ||
285 | u8 data[3]; | ||
286 | int ret; | ||
287 | |||
288 | BUG_ON(codec->volatile_register); | ||
289 | |||
290 | data[0] = (reg >> 8) & 0xff; | ||
291 | data[1] = reg & 0xff; | ||
292 | data[2] = value; | ||
293 | |||
294 | reg &= 0xff; | ||
295 | if (reg < codec->reg_cache_size) | ||
296 | cache[reg] = value; | ||
297 | ret = codec->hw_write(codec->control_data, data, 3); | ||
298 | if (ret == 3) | ||
299 | return 0; | ||
300 | if (ret < 0) | ||
301 | return ret; | ||
302 | else | ||
303 | return -EIO; | ||
304 | } | ||
305 | |||
306 | #if defined(CONFIG_SPI_MASTER) | ||
307 | static int snd_soc_16_8_spi_write(void *control_data, const char *data, | ||
308 | int len) | ||
309 | { | ||
310 | struct spi_device *spi = control_data; | ||
311 | struct spi_transfer t; | ||
312 | struct spi_message m; | ||
313 | u8 msg[3]; | ||
314 | |||
315 | if (len <= 0) | ||
316 | return 0; | ||
317 | |||
318 | msg[0] = data[0]; | ||
319 | msg[1] = data[1]; | ||
320 | msg[2] = data[2]; | ||
321 | |||
322 | spi_message_init(&m); | ||
323 | memset(&t, 0, (sizeof t)); | ||
324 | |||
325 | t.tx_buf = &msg[0]; | ||
326 | t.len = len; | ||
327 | |||
328 | spi_message_add_tail(&t, &m); | ||
329 | spi_sync(spi, &m); | ||
330 | |||
331 | return len; | ||
332 | } | ||
333 | #else | ||
334 | #define snd_soc_16_8_spi_write NULL | ||
335 | #endif | ||
336 | |||
337 | |||
236 | static struct { | 338 | static struct { |
237 | int addr_bits; | 339 | int addr_bits; |
238 | int data_bits; | 340 | int data_bits; |
@@ -260,6 +362,12 @@ static struct { | |||
260 | .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, | 362 | .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, |
261 | .i2c_read = snd_soc_8_16_read_i2c, | 363 | .i2c_read = snd_soc_8_16_read_i2c, |
262 | }, | 364 | }, |
365 | { | ||
366 | .addr_bits = 16, .data_bits = 8, | ||
367 | .write = snd_soc_16_8_write, .read = snd_soc_16_8_read, | ||
368 | .i2c_read = snd_soc_16_8_read_i2c, | ||
369 | .spi_write = snd_soc_16_8_spi_write, | ||
370 | }, | ||
263 | }; | 371 | }; |
264 | 372 | ||
265 | /** | 373 | /** |