aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2011-09-05 14:46:33 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-09-09 14:13:31 -0400
commit30ab1e78864ca5781de5b1fb501bed9df2c215f1 (patch)
treefa785b5c39bce0dcc9652e062f31c276e0f6b80e
parent4ae7335dae2d9378a594bdb0845c55f370516864 (diff)
ASoC: ad193x: Setup regmap read and write flag masks for SPI
Currently register read-back for the ad193x is broken, because it expects bit 0 of the upper byte to be set to indicate a read operation, while the regmap default for SPI is to use bit 7. This patch also addresses another oddity of the device. There are SPI and I2C versions of this codec. In both cases the registers are 8-bit wide and numbered from 0x0 to 0x10, but in the SPI case there is also a so called 'global address' which is prefixed in-front of the register address. The global address mimics I2C behaviour and includes a static device address the and the read/write flag. This basically extends the register address to an 16-bit value numbered from 0x800 to 0x810. These are the register numbers which are currently used by the driver. This works, because I2C will ignore the upper 8 bits of the register, but it is still a bit confusing, as there are no such register numbers in the I2C case. The approach taken by this patch is to number the registers from 0x00 to 0x10 and encode the global address for SPI mode into the read and write flag masks. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Liam Girdwood <lrg@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--sound/soc/codecs/ad193x.c65
-rw-r--r--sound/soc/codecs/ad193x.h34
2 files changed, 71 insertions, 28 deletions
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index eedb6f5e5823..f934670199a5 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -23,7 +23,7 @@
23 23
24/* codec private data */ 24/* codec private data */
25struct ad193x_priv { 25struct ad193x_priv {
26 enum snd_soc_control_type control_type; 26 struct regmap *regmap;
27 int sysclk; 27 int sysclk;
28}; 28};
29 29
@@ -349,10 +349,8 @@ static int ad193x_probe(struct snd_soc_codec *codec)
349 struct snd_soc_dapm_context *dapm = &codec->dapm; 349 struct snd_soc_dapm_context *dapm = &codec->dapm;
350 int ret; 350 int ret;
351 351
352 if (ad193x->control_type == SND_SOC_I2C) 352 codec->control_data = ad193x->regmap;
353 ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type); 353 ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
354 else
355 ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
356 if (ret < 0) { 354 if (ret < 0) {
357 dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); 355 dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
358 return ret; 356 return ret;
@@ -388,6 +386,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
388}; 386};
389 387
390#if defined(CONFIG_SPI_MASTER) 388#if defined(CONFIG_SPI_MASTER)
389
390static const struct regmap_config ad193x_spi_regmap_config = {
391 .val_bits = 8,
392 .reg_bits = 16,
393 .read_flag_mask = 0x09,
394 .write_flag_mask = 0x08,
395};
396
391static int __devinit ad193x_spi_probe(struct spi_device *spi) 397static int __devinit ad193x_spi_probe(struct spi_device *spi)
392{ 398{
393 struct ad193x_priv *ad193x; 399 struct ad193x_priv *ad193x;
@@ -397,20 +403,36 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
397 if (ad193x == NULL) 403 if (ad193x == NULL)
398 return -ENOMEM; 404 return -ENOMEM;
399 405
406 ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config);
407 if (IS_ERR(ad193x->regmap)) {
408 ret = PTR_ERR(ad193x->regmap);
409 goto err_free;
410 }
411
400 spi_set_drvdata(spi, ad193x); 412 spi_set_drvdata(spi, ad193x);
401 ad193x->control_type = SND_SOC_SPI;
402 413
403 ret = snd_soc_register_codec(&spi->dev, 414 ret = snd_soc_register_codec(&spi->dev,
404 &soc_codec_dev_ad193x, &ad193x_dai, 1); 415 &soc_codec_dev_ad193x, &ad193x_dai, 1);
405 if (ret < 0) 416 if (ret < 0)
406 kfree(ad193x); 417 goto err_regmap_exit;
418
419 return 0;
420
421err_regmap_exit:
422 regmap_exit(ad193x->regmap);
423err_free:
424 kfree(ad193x);
425
407 return ret; 426 return ret;
408} 427}
409 428
410static int __devexit ad193x_spi_remove(struct spi_device *spi) 429static int __devexit ad193x_spi_remove(struct spi_device *spi)
411{ 430{
431 struct ad193x_priv *ad193x = spi_get_drvdata(spi);
432
412 snd_soc_unregister_codec(&spi->dev); 433 snd_soc_unregister_codec(&spi->dev);
413 kfree(spi_get_drvdata(spi)); 434 regmap_exit(ad193x->regmap);
435 kfree(ad193x);
414 return 0; 436 return 0;
415} 437}
416 438
@@ -425,6 +447,12 @@ static struct spi_driver ad193x_spi_driver = {
425#endif 447#endif
426 448
427#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 449#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
450
451static const struct regmap_config ad193x_i2c_regmap_config = {
452 .val_bits = 8,
453 .reg_bits = 8,
454};
455
428static const struct i2c_device_id ad193x_id[] = { 456static const struct i2c_device_id ad193x_id[] = {
429 { "ad1936", 0 }, 457 { "ad1936", 0 },
430 { "ad1937", 0 }, 458 { "ad1937", 0 },
@@ -442,20 +470,35 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
442 if (ad193x == NULL) 470 if (ad193x == NULL)
443 return -ENOMEM; 471 return -ENOMEM;
444 472
473 ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config);
474 if (IS_ERR(ad193x->regmap)) {
475 ret = PTR_ERR(ad193x->regmap);
476 goto err_free;
477 }
478
445 i2c_set_clientdata(client, ad193x); 479 i2c_set_clientdata(client, ad193x);
446 ad193x->control_type = SND_SOC_I2C;
447 480
448 ret = snd_soc_register_codec(&client->dev, 481 ret = snd_soc_register_codec(&client->dev,
449 &soc_codec_dev_ad193x, &ad193x_dai, 1); 482 &soc_codec_dev_ad193x, &ad193x_dai, 1);
450 if (ret < 0) 483 if (ret < 0)
451 kfree(ad193x); 484 goto err_regmap_exit;
485
486 return 0;
487
488err_regmap_exit:
489 regmap_exit(ad193x->regmap);
490err_free:
491 kfree(ad193x);
452 return ret; 492 return ret;
453} 493}
454 494
455static int __devexit ad193x_i2c_remove(struct i2c_client *client) 495static int __devexit ad193x_i2c_remove(struct i2c_client *client)
456{ 496{
497 struct ad193x_priv *ad193x = i2c_get_clientdata(client);
498
457 snd_soc_unregister_codec(&client->dev); 499 snd_soc_unregister_codec(&client->dev);
458 kfree(i2c_get_clientdata(client)); 500 regmap_exit(ad193x->regmap);
501 kfree(ad193x);
459 return 0; 502 return 0;
460} 503}
461 504
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index cccc2e8e5fbd..536e5f2b136e 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -9,20 +9,20 @@
9#ifndef __AD193X_H__ 9#ifndef __AD193X_H__
10#define __AD193X_H__ 10#define __AD193X_H__
11 11
12#define AD193X_PLL_CLK_CTRL0 0x800 12#define AD193X_PLL_CLK_CTRL0 0x00
13#define AD193X_PLL_POWERDOWN 0x01 13#define AD193X_PLL_POWERDOWN 0x01
14#define AD193X_PLL_INPUT_MASK (~0x6) 14#define AD193X_PLL_INPUT_MASK (~0x6)
15#define AD193X_PLL_INPUT_256 (0 << 1) 15#define AD193X_PLL_INPUT_256 (0 << 1)
16#define AD193X_PLL_INPUT_384 (1 << 1) 16#define AD193X_PLL_INPUT_384 (1 << 1)
17#define AD193X_PLL_INPUT_512 (2 << 1) 17#define AD193X_PLL_INPUT_512 (2 << 1)
18#define AD193X_PLL_INPUT_768 (3 << 1) 18#define AD193X_PLL_INPUT_768 (3 << 1)
19#define AD193X_PLL_CLK_CTRL1 0x801 19#define AD193X_PLL_CLK_CTRL1 0x01
20#define AD193X_DAC_CTRL0 0x802 20#define AD193X_DAC_CTRL0 0x02
21#define AD193X_DAC_POWERDOWN 0x01 21#define AD193X_DAC_POWERDOWN 0x01
22#define AD193X_DAC_SERFMT_MASK 0xC0 22#define AD193X_DAC_SERFMT_MASK 0xC0
23#define AD193X_DAC_SERFMT_STEREO (0 << 6) 23#define AD193X_DAC_SERFMT_STEREO (0 << 6)
24#define AD193X_DAC_SERFMT_TDM (1 << 6) 24#define AD193X_DAC_SERFMT_TDM (1 << 6)
25#define AD193X_DAC_CTRL1 0x803 25#define AD193X_DAC_CTRL1 0x03
26#define AD193X_DAC_2_CHANNELS 0 26#define AD193X_DAC_2_CHANNELS 0
27#define AD193X_DAC_4_CHANNELS 1 27#define AD193X_DAC_4_CHANNELS 1
28#define AD193X_DAC_8_CHANNELS 2 28#define AD193X_DAC_8_CHANNELS 2
@@ -33,11 +33,11 @@
33#define AD193X_DAC_BCLK_MASTER (1 << 5) 33#define AD193X_DAC_BCLK_MASTER (1 << 5)
34#define AD193X_DAC_LEFT_HIGH (1 << 3) 34#define AD193X_DAC_LEFT_HIGH (1 << 3)
35#define AD193X_DAC_BCLK_INV (1 << 7) 35#define AD193X_DAC_BCLK_INV (1 << 7)
36#define AD193X_DAC_CTRL2 0x804 36#define AD193X_DAC_CTRL2 0x04
37#define AD193X_DAC_WORD_LEN_SHFT 3 37#define AD193X_DAC_WORD_LEN_SHFT 3
38#define AD193X_DAC_WORD_LEN_MASK 0x18 38#define AD193X_DAC_WORD_LEN_MASK 0x18
39#define AD193X_DAC_MASTER_MUTE 1 39#define AD193X_DAC_MASTER_MUTE 1
40#define AD193X_DAC_CHNL_MUTE 0x805 40#define AD193X_DAC_CHNL_MUTE 0x05
41#define AD193X_DACL1_MUTE 0 41#define AD193X_DACL1_MUTE 0
42#define AD193X_DACR1_MUTE 1 42#define AD193X_DACR1_MUTE 1
43#define AD193X_DACL2_MUTE 2 43#define AD193X_DACL2_MUTE 2
@@ -46,28 +46,28 @@
46#define AD193X_DACR3_MUTE 5 46#define AD193X_DACR3_MUTE 5
47#define AD193X_DACL4_MUTE 6 47#define AD193X_DACL4_MUTE 6
48#define AD193X_DACR4_MUTE 7 48#define AD193X_DACR4_MUTE 7
49#define AD193X_DAC_L1_VOL 0x806 49#define AD193X_DAC_L1_VOL 0x06
50#define AD193X_DAC_R1_VOL 0x807 50#define AD193X_DAC_R1_VOL 0x07
51#define AD193X_DAC_L2_VOL 0x808 51#define AD193X_DAC_L2_VOL 0x08
52#define AD193X_DAC_R2_VOL 0x809 52#define AD193X_DAC_R2_VOL 0x09
53#define AD193X_DAC_L3_VOL 0x80a 53#define AD193X_DAC_L3_VOL 0x0a
54#define AD193X_DAC_R3_VOL 0x80b 54#define AD193X_DAC_R3_VOL 0x0b
55#define AD193X_DAC_L4_VOL 0x80c 55#define AD193X_DAC_L4_VOL 0x0c
56#define AD193X_DAC_R4_VOL 0x80d 56#define AD193X_DAC_R4_VOL 0x0d
57#define AD193X_ADC_CTRL0 0x80e 57#define AD193X_ADC_CTRL0 0x0e
58#define AD193X_ADC_POWERDOWN 0x01 58#define AD193X_ADC_POWERDOWN 0x01
59#define AD193X_ADC_HIGHPASS_FILTER 1 59#define AD193X_ADC_HIGHPASS_FILTER 1
60#define AD193X_ADCL1_MUTE 2 60#define AD193X_ADCL1_MUTE 2
61#define AD193X_ADCR1_MUTE 3 61#define AD193X_ADCR1_MUTE 3
62#define AD193X_ADCL2_MUTE 4 62#define AD193X_ADCL2_MUTE 4
63#define AD193X_ADCR2_MUTE 5 63#define AD193X_ADCR2_MUTE 5
64#define AD193X_ADC_CTRL1 0x80f 64#define AD193X_ADC_CTRL1 0x0f
65#define AD193X_ADC_SERFMT_MASK 0x60 65#define AD193X_ADC_SERFMT_MASK 0x60
66#define AD193X_ADC_SERFMT_STEREO (0 << 5) 66#define AD193X_ADC_SERFMT_STEREO (0 << 5)
67#define AD193X_ADC_SERFMT_TDM (1 << 5) 67#define AD193X_ADC_SERFMT_TDM (1 << 5)
68#define AD193X_ADC_SERFMT_AUX (2 << 5) 68#define AD193X_ADC_SERFMT_AUX (2 << 5)
69#define AD193X_ADC_WORD_LEN_MASK 0x3 69#define AD193X_ADC_WORD_LEN_MASK 0x3
70#define AD193X_ADC_CTRL2 0x810 70#define AD193X_ADC_CTRL2 0x10
71#define AD193X_ADC_2_CHANNELS 0 71#define AD193X_ADC_2_CHANNELS 0
72#define AD193X_ADC_4_CHANNELS 1 72#define AD193X_ADC_4_CHANNELS 1
73#define AD193X_ADC_8_CHANNELS 2 73#define AD193X_ADC_8_CHANNELS 2