aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8940.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-07-10 18:12:01 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-08-03 11:59:16 -0400
commit8d50e447d19fec64adebeef55f2b60d695435412 (patch)
treeaac4234db113cf40abc4c7779ddecb76d7e0946b /sound/soc/codecs/wm8940.c
parentafa2f1066e7288a9e4f8e3fda277da245219dffc (diff)
ASoC: Factor out I/O for Wolfson 8 bit data 16 bit register CODECs
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8940.c')
-rw-r--r--sound/soc/codecs/wm8940.c143
1 files changed, 52 insertions, 91 deletions
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index b69210a77423..da97aae475a2 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -106,50 +106,6 @@ static u16 wm8940_reg_defaults[] = {
106 0x0000, /* Mono Mixer Control */ 106 0x0000, /* Mono Mixer Control */
107}; 107};
108 108
109static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec,
110 unsigned int reg)
111{
112 u16 *cache = codec->reg_cache;
113
114 if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
115 return -1;
116
117 return cache[reg];
118}
119
120static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec,
121 u16 reg, unsigned int value)
122{
123 u16 *cache = codec->reg_cache;
124
125 if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
126 return -1;
127
128 cache[reg] = value;
129
130 return 0;
131}
132
133static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg,
134 unsigned int value)
135{
136 int ret;
137 u8 data[3] = { reg,
138 (value & 0xff00) >> 8,
139 (value & 0x00ff)
140 };
141
142 wm8940_write_reg_cache(codec, reg, value);
143
144 ret = codec->hw_write(codec->control_data, data, 3);
145
146 if (ret < 0)
147 return ret;
148 else if (ret != 3)
149 return -EIO;
150 return 0;
151}
152
153static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; 109static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
154static const struct soc_enum wm8940_adc_companding_enum 110static const struct soc_enum wm8940_adc_companding_enum
155= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding); 111= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
@@ -348,14 +304,14 @@ error_ret:
348 return ret; 304 return ret;
349} 305}
350 306
351#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0); 307#define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
352 308
353static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, 309static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
354 unsigned int fmt) 310 unsigned int fmt)
355{ 311{
356 struct snd_soc_codec *codec = codec_dai->codec; 312 struct snd_soc_codec *codec = codec_dai->codec;
357 u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67; 313 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFE67;
358 u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe; 314 u16 clk = snd_soc_read(codec, WM8940_CLOCK) & 0x1fe;
359 315
360 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 316 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
361 case SND_SOC_DAIFMT_CBM_CFM: 317 case SND_SOC_DAIFMT_CBM_CFM:
@@ -366,7 +322,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
366 default: 322 default:
367 return -EINVAL; 323 return -EINVAL;
368 } 324 }
369 wm8940_write(codec, WM8940_CLOCK, clk); 325 snd_soc_write(codec, WM8940_CLOCK, clk);
370 326
371 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 327 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
372 case SND_SOC_DAIFMT_I2S: 328 case SND_SOC_DAIFMT_I2S:
@@ -399,7 +355,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
399 break; 355 break;
400 } 356 }
401 357
402 wm8940_write(codec, WM8940_IFACE, iface); 358 snd_soc_write(codec, WM8940_IFACE, iface);
403 359
404 return 0; 360 return 0;
405} 361}
@@ -411,9 +367,9 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
411 struct snd_soc_pcm_runtime *rtd = substream->private_data; 367 struct snd_soc_pcm_runtime *rtd = substream->private_data;
412 struct snd_soc_device *socdev = rtd->socdev; 368 struct snd_soc_device *socdev = rtd->socdev;
413 struct snd_soc_codec *codec = socdev->card->codec; 369 struct snd_soc_codec *codec = socdev->card->codec;
414 u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F; 370 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
415 u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1; 371 u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
416 u16 companding = wm8940_read_reg_cache(codec, 372 u16 companding = snd_soc_read(codec,
417 WM8940_COMPANDINGCTL) & 0xFFDF; 373 WM8940_COMPANDINGCTL) & 0xFFDF;
418 int ret; 374 int ret;
419 375
@@ -442,7 +398,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
442 case SNDRV_PCM_RATE_48000: 398 case SNDRV_PCM_RATE_48000:
443 break; 399 break;
444 } 400 }
445 ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl); 401 ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl);
446 if (ret) 402 if (ret)
447 goto error_ret; 403 goto error_ret;
448 404
@@ -462,10 +418,10 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
462 iface |= (3 << 5); 418 iface |= (3 << 5);
463 break; 419 break;
464 } 420 }
465 ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding); 421 ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding);
466 if (ret) 422 if (ret)
467 goto error_ret; 423 goto error_ret;
468 ret = wm8940_write(codec, WM8940_IFACE, iface); 424 ret = snd_soc_write(codec, WM8940_IFACE, iface);
469 425
470error_ret: 426error_ret:
471 return ret; 427 return ret;
@@ -474,19 +430,19 @@ error_ret:
474static int wm8940_mute(struct snd_soc_dai *dai, int mute) 430static int wm8940_mute(struct snd_soc_dai *dai, int mute)
475{ 431{
476 struct snd_soc_codec *codec = dai->codec; 432 struct snd_soc_codec *codec = dai->codec;
477 u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf; 433 u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf;
478 434
479 if (mute) 435 if (mute)
480 mute_reg |= 0x40; 436 mute_reg |= 0x40;
481 437
482 return wm8940_write(codec, WM8940_DAC, mute_reg); 438 return snd_soc_write(codec, WM8940_DAC, mute_reg);
483} 439}
484 440
485static int wm8940_set_bias_level(struct snd_soc_codec *codec, 441static int wm8940_set_bias_level(struct snd_soc_codec *codec,
486 enum snd_soc_bias_level level) 442 enum snd_soc_bias_level level)
487{ 443{
488 u16 val; 444 u16 val;
489 u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0; 445 u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;
490 int ret = 0; 446 int ret = 0;
491 447
492 switch (level) { 448 switch (level) {
@@ -494,26 +450,26 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
494 /* ensure bufioen and biasen */ 450 /* ensure bufioen and biasen */
495 pwr_reg |= (1 << 2) | (1 << 3); 451 pwr_reg |= (1 << 2) | (1 << 3);
496 /* Enable thermal shutdown */ 452 /* Enable thermal shutdown */
497 val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); 453 val = snd_soc_read(codec, WM8940_OUTPUTCTL);
498 ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2); 454 ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2);
499 if (ret) 455 if (ret)
500 break; 456 break;
501 /* set vmid to 75k */ 457 /* set vmid to 75k */
502 ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); 458 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
503 break; 459 break;
504 case SND_SOC_BIAS_PREPARE: 460 case SND_SOC_BIAS_PREPARE:
505 /* ensure bufioen and biasen */ 461 /* ensure bufioen and biasen */
506 pwr_reg |= (1 << 2) | (1 << 3); 462 pwr_reg |= (1 << 2) | (1 << 3);
507 ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); 463 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
508 break; 464 break;
509 case SND_SOC_BIAS_STANDBY: 465 case SND_SOC_BIAS_STANDBY:
510 /* ensure bufioen and biasen */ 466 /* ensure bufioen and biasen */
511 pwr_reg |= (1 << 2) | (1 << 3); 467 pwr_reg |= (1 << 2) | (1 << 3);
512 /* set vmid to 300k for standby */ 468 /* set vmid to 300k for standby */
513 ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2); 469 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2);
514 break; 470 break;
515 case SND_SOC_BIAS_OFF: 471 case SND_SOC_BIAS_OFF:
516 ret = wm8940_write(codec, WM8940_POWER1, pwr_reg); 472 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg);
517 break; 473 break;
518 } 474 }
519 475
@@ -587,36 +543,36 @@ static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai,
587 u16 reg; 543 u16 reg;
588 544
589 /* Turn off PLL */ 545 /* Turn off PLL */
590 reg = wm8940_read_reg_cache(codec, WM8940_POWER1); 546 reg = snd_soc_read(codec, WM8940_POWER1);
591 wm8940_write(codec, WM8940_POWER1, reg & 0x1df); 547 snd_soc_write(codec, WM8940_POWER1, reg & 0x1df);
592 548
593 if (freq_in == 0 || freq_out == 0) { 549 if (freq_in == 0 || freq_out == 0) {
594 /* Clock CODEC directly from MCLK */ 550 /* Clock CODEC directly from MCLK */
595 reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); 551 reg = snd_soc_read(codec, WM8940_CLOCK);
596 wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff); 552 snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff);
597 /* Pll power down */ 553 /* Pll power down */
598 wm8940_write(codec, WM8940_PLLN, (1 << 7)); 554 snd_soc_write(codec, WM8940_PLLN, (1 << 7));
599 return 0; 555 return 0;
600 } 556 }
601 557
602 /* Pll is followed by a frequency divide by 4 */ 558 /* Pll is followed by a frequency divide by 4 */
603 pll_factors(freq_out*4, freq_in); 559 pll_factors(freq_out*4, freq_in);
604 if (pll_div.k) 560 if (pll_div.k)
605 wm8940_write(codec, WM8940_PLLN, 561 snd_soc_write(codec, WM8940_PLLN,
606 (pll_div.pre_scale << 4) | pll_div.n | (1 << 6)); 562 (pll_div.pre_scale << 4) | pll_div.n | (1 << 6));
607 else /* No factional component */ 563 else /* No factional component */
608 wm8940_write(codec, WM8940_PLLN, 564 snd_soc_write(codec, WM8940_PLLN,
609 (pll_div.pre_scale << 4) | pll_div.n); 565 (pll_div.pre_scale << 4) | pll_div.n);
610 wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18); 566 snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18);
611 wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); 567 snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
612 wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); 568 snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff);
613 /* Enable the PLL */ 569 /* Enable the PLL */
614 reg = wm8940_read_reg_cache(codec, WM8940_POWER1); 570 reg = snd_soc_read(codec, WM8940_POWER1);
615 wm8940_write(codec, WM8940_POWER1, reg | 0x020); 571 snd_soc_write(codec, WM8940_POWER1, reg | 0x020);
616 572
617 /* Run CODEC from PLL instead of MCLK */ 573 /* Run CODEC from PLL instead of MCLK */
618 reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); 574 reg = snd_soc_read(codec, WM8940_CLOCK);
619 wm8940_write(codec, WM8940_CLOCK, reg | 0x100); 575 snd_soc_write(codec, WM8940_CLOCK, reg | 0x100);
620 576
621 return 0; 577 return 0;
622} 578}
@@ -648,16 +604,16 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
648 604
649 switch (div_id) { 605 switch (div_id) {
650 case WM8940_BCLKDIV: 606 case WM8940_BCLKDIV:
651 reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3; 607 reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFEF3;
652 ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2)); 608 ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2));
653 break; 609 break;
654 case WM8940_MCLKDIV: 610 case WM8940_MCLKDIV:
655 reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F; 611 reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F;
656 ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5)); 612 ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5));
657 break; 613 break;
658 case WM8940_OPCLKDIV: 614 case WM8940_OPCLKDIV:
659 reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF; 615 reg = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFCF;
660 ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4)); 616 ret = snd_soc_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
661 break; 617 break;
662 } 618 }
663 return ret; 619 return ret;
@@ -808,7 +764,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8940 = {
808}; 764};
809EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940); 765EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
810 766
811static int wm8940_register(struct wm8940_priv *wm8940) 767static int wm8940_register(struct wm8940_priv *wm8940,
768 enum snd_soc_control_type control)
812{ 769{
813 struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data; 770 struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
814 struct snd_soc_codec *codec = &wm8940->codec; 771 struct snd_soc_codec *codec = &wm8940->codec;
@@ -825,8 +782,6 @@ static int wm8940_register(struct wm8940_priv *wm8940)
825 codec->private_data = wm8940; 782 codec->private_data = wm8940;
826 codec->name = "WM8940"; 783 codec->name = "WM8940";
827 codec->owner = THIS_MODULE; 784 codec->owner = THIS_MODULE;
828 codec->read = wm8940_read_reg_cache;
829 codec->write = wm8940_write;
830 codec->bias_level = SND_SOC_BIAS_OFF; 785 codec->bias_level = SND_SOC_BIAS_OFF;
831 codec->set_bias_level = wm8940_set_bias_level; 786 codec->set_bias_level = wm8940_set_bias_level;
832 codec->dai = &wm8940_dai; 787 codec->dai = &wm8940_dai;
@@ -834,6 +789,12 @@ static int wm8940_register(struct wm8940_priv *wm8940)
834 codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults); 789 codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
835 codec->reg_cache = &wm8940->reg_cache; 790 codec->reg_cache = &wm8940->reg_cache;
836 791
792 ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
793 if (ret == 0) {
794 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
795 return ret;
796 }
797
837 memcpy(codec->reg_cache, wm8940_reg_defaults, 798 memcpy(codec->reg_cache, wm8940_reg_defaults,
838 sizeof(wm8940_reg_defaults)); 799 sizeof(wm8940_reg_defaults));
839 800
@@ -847,15 +808,15 @@ static int wm8940_register(struct wm8940_priv *wm8940)
847 808
848 wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 809 wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
849 810
850 ret = wm8940_write(codec, WM8940_POWER1, 0x180); 811 ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
851 if (ret < 0) 812 if (ret < 0)
852 return ret; 813 return ret;
853 814
854 if (!pdata) 815 if (!pdata)
855 dev_warn(codec->dev, "No platform data supplied\n"); 816 dev_warn(codec->dev, "No platform data supplied\n");
856 else { 817 else {
857 reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); 818 reg = snd_soc_read(codec, WM8940_OUTPUTCTL);
858 ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); 819 ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi);
859 if (ret < 0) 820 if (ret < 0)
860 return ret; 821 return ret;
861 } 822 }
@@ -904,7 +865,7 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,
904 codec->control_data = i2c; 865 codec->control_data = i2c;
905 codec->dev = &i2c->dev; 866 codec->dev = &i2c->dev;
906 867
907 return wm8940_register(wm8940); 868 return wm8940_register(wm8940, SND_SOC_I2C);
908} 869}
909 870
910static int __devexit wm8940_i2c_remove(struct i2c_client *client) 871static int __devexit wm8940_i2c_remove(struct i2c_client *client)