diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-07-05 12:24:50 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-07-05 12:24:50 -0400 |
commit | 17a52fd60a0a0e617ed94aadb1b19751a8fa219e (patch) | |
tree | 2c2fd4526ae219ec9435a0a4b0fc281a5ca62b7c /sound/soc/codecs/wm8510.c | |
parent | 5420f30723122012c7bb868a55ff21c7d383b68e (diff) |
ASoC: Begin to factor out register cache I/O functions
A lot of CODECs share the same register data formats and therefore
replicate the code to manage access to and caching of the register
map. In order to reduce code duplication centralised versions of
this code will be introduced with drivers able to configure the use
of the common code by calling the new snd_soc_codec_set_cache_io()
API call during startup.
As an initial user the 7 bit address/9 bit data format used by many
Wolfson devices is supported for write only CODECs and the drivers
with straightforward register cache implementations are converted to
use it.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8510.c')
-rw-r--r-- | sound/soc/codecs/wm8510.c | 141 |
1 files changed, 49 insertions, 92 deletions
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index c8b8dba85890..7a169bff86f9 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -58,55 +58,7 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { | |||
58 | #define WM8510_POWER1_BIASEN 0x08 | 58 | #define WM8510_POWER1_BIASEN 0x08 |
59 | #define WM8510_POWER1_BUFIOEN 0x10 | 59 | #define WM8510_POWER1_BUFIOEN 0x10 |
60 | 60 | ||
61 | /* | 61 | #define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0) |
62 | * read wm8510 register cache | ||
63 | */ | ||
64 | static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, | ||
65 | unsigned int reg) | ||
66 | { | ||
67 | u16 *cache = codec->reg_cache; | ||
68 | if (reg == WM8510_RESET) | ||
69 | return 0; | ||
70 | if (reg >= WM8510_CACHEREGNUM) | ||
71 | return -1; | ||
72 | return cache[reg]; | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * write wm8510 register cache | ||
77 | */ | ||
78 | static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, | ||
79 | u16 reg, unsigned int value) | ||
80 | { | ||
81 | u16 *cache = codec->reg_cache; | ||
82 | if (reg >= WM8510_CACHEREGNUM) | ||
83 | return; | ||
84 | cache[reg] = value; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * write to the WM8510 register space | ||
89 | */ | ||
90 | static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, | ||
91 | unsigned int value) | ||
92 | { | ||
93 | u8 data[2]; | ||
94 | |||
95 | /* data is | ||
96 | * D15..D9 WM8510 register offset | ||
97 | * D8...D0 register data | ||
98 | */ | ||
99 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
100 | data[1] = value & 0x00ff; | ||
101 | |||
102 | wm8510_write_reg_cache(codec, reg, value); | ||
103 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
104 | return 0; | ||
105 | else | ||
106 | return -EIO; | ||
107 | } | ||
108 | |||
109 | #define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) | ||
110 | 62 | ||
111 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; | 63 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; |
112 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | 64 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; |
@@ -327,27 +279,27 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, | |||
327 | 279 | ||
328 | if (freq_in == 0 || freq_out == 0) { | 280 | if (freq_in == 0 || freq_out == 0) { |
329 | /* Clock CODEC directly from MCLK */ | 281 | /* Clock CODEC directly from MCLK */ |
330 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | 282 | reg = snd_soc_read(codec, WM8510_CLOCK); |
331 | wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); | 283 | snd_soc_write(codec, WM8510_CLOCK, reg & 0x0ff); |
332 | 284 | ||
333 | /* Turn off PLL */ | 285 | /* Turn off PLL */ |
334 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | 286 | reg = snd_soc_read(codec, WM8510_POWER1); |
335 | wm8510_write(codec, WM8510_POWER1, reg & 0x1df); | 287 | snd_soc_write(codec, WM8510_POWER1, reg & 0x1df); |
336 | return 0; | 288 | return 0; |
337 | } | 289 | } |
338 | 290 | ||
339 | pll_factors(freq_out*4, freq_in); | 291 | pll_factors(freq_out*4, freq_in); |
340 | 292 | ||
341 | wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); | 293 | snd_soc_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); |
342 | wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); | 294 | snd_soc_write(codec, WM8510_PLLK1, pll_div.k >> 18); |
343 | wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); | 295 | snd_soc_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); |
344 | wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); | 296 | snd_soc_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); |
345 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | 297 | reg = snd_soc_read(codec, WM8510_POWER1); |
346 | wm8510_write(codec, WM8510_POWER1, reg | 0x020); | 298 | snd_soc_write(codec, WM8510_POWER1, reg | 0x020); |
347 | 299 | ||
348 | /* Run CODEC from PLL instead of MCLK */ | 300 | /* Run CODEC from PLL instead of MCLK */ |
349 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | 301 | reg = snd_soc_read(codec, WM8510_CLOCK); |
350 | wm8510_write(codec, WM8510_CLOCK, reg | 0x100); | 302 | snd_soc_write(codec, WM8510_CLOCK, reg | 0x100); |
351 | 303 | ||
352 | return 0; | 304 | return 0; |
353 | } | 305 | } |
@@ -363,24 +315,24 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
363 | 315 | ||
364 | switch (div_id) { | 316 | switch (div_id) { |
365 | case WM8510_OPCLKDIV: | 317 | case WM8510_OPCLKDIV: |
366 | reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; | 318 | reg = snd_soc_read(codec, WM8510_GPIO) & 0x1cf; |
367 | wm8510_write(codec, WM8510_GPIO, reg | div); | 319 | snd_soc_write(codec, WM8510_GPIO, reg | div); |
368 | break; | 320 | break; |
369 | case WM8510_MCLKDIV: | 321 | case WM8510_MCLKDIV: |
370 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f; | 322 | reg = snd_soc_read(codec, WM8510_CLOCK) & 0x11f; |
371 | wm8510_write(codec, WM8510_CLOCK, reg | div); | 323 | snd_soc_write(codec, WM8510_CLOCK, reg | div); |
372 | break; | 324 | break; |
373 | case WM8510_ADCCLK: | 325 | case WM8510_ADCCLK: |
374 | reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; | 326 | reg = snd_soc_read(codec, WM8510_ADC) & 0x1f7; |
375 | wm8510_write(codec, WM8510_ADC, reg | div); | 327 | snd_soc_write(codec, WM8510_ADC, reg | div); |
376 | break; | 328 | break; |
377 | case WM8510_DACCLK: | 329 | case WM8510_DACCLK: |
378 | reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; | 330 | reg = snd_soc_read(codec, WM8510_DAC) & 0x1f7; |
379 | wm8510_write(codec, WM8510_DAC, reg | div); | 331 | snd_soc_write(codec, WM8510_DAC, reg | div); |
380 | break; | 332 | break; |
381 | case WM8510_BCLKDIV: | 333 | case WM8510_BCLKDIV: |
382 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; | 334 | reg = snd_soc_read(codec, WM8510_CLOCK) & 0x1e3; |
383 | wm8510_write(codec, WM8510_CLOCK, reg | div); | 335 | snd_soc_write(codec, WM8510_CLOCK, reg | div); |
384 | break; | 336 | break; |
385 | default: | 337 | default: |
386 | return -EINVAL; | 338 | return -EINVAL; |
@@ -394,7 +346,7 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
394 | { | 346 | { |
395 | struct snd_soc_codec *codec = codec_dai->codec; | 347 | struct snd_soc_codec *codec = codec_dai->codec; |
396 | u16 iface = 0; | 348 | u16 iface = 0; |
397 | u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; | 349 | u16 clk = snd_soc_read(codec, WM8510_CLOCK) & 0x1fe; |
398 | 350 | ||
399 | /* set master/slave audio interface */ | 351 | /* set master/slave audio interface */ |
400 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 352 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
@@ -441,8 +393,8 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
441 | return -EINVAL; | 393 | return -EINVAL; |
442 | } | 394 | } |
443 | 395 | ||
444 | wm8510_write(codec, WM8510_IFACE, iface); | 396 | snd_soc_write(codec, WM8510_IFACE, iface); |
445 | wm8510_write(codec, WM8510_CLOCK, clk); | 397 | snd_soc_write(codec, WM8510_CLOCK, clk); |
446 | return 0; | 398 | return 0; |
447 | } | 399 | } |
448 | 400 | ||
@@ -453,8 +405,8 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, | |||
453 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 405 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
454 | struct snd_soc_device *socdev = rtd->socdev; | 406 | struct snd_soc_device *socdev = rtd->socdev; |
455 | struct snd_soc_codec *codec = socdev->card->codec; | 407 | struct snd_soc_codec *codec = socdev->card->codec; |
456 | u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; | 408 | u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f; |
457 | u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; | 409 | u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1; |
458 | 410 | ||
459 | /* bit size */ | 411 | /* bit size */ |
460 | switch (params_format(params)) { | 412 | switch (params_format(params)) { |
@@ -493,20 +445,20 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, | |||
493 | break; | 445 | break; |
494 | } | 446 | } |
495 | 447 | ||
496 | wm8510_write(codec, WM8510_IFACE, iface); | 448 | snd_soc_write(codec, WM8510_IFACE, iface); |
497 | wm8510_write(codec, WM8510_ADD, adn); | 449 | snd_soc_write(codec, WM8510_ADD, adn); |
498 | return 0; | 450 | return 0; |
499 | } | 451 | } |
500 | 452 | ||
501 | static int wm8510_mute(struct snd_soc_dai *dai, int mute) | 453 | static int wm8510_mute(struct snd_soc_dai *dai, int mute) |
502 | { | 454 | { |
503 | struct snd_soc_codec *codec = dai->codec; | 455 | struct snd_soc_codec *codec = dai->codec; |
504 | u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; | 456 | u16 mute_reg = snd_soc_read(codec, WM8510_DAC) & 0xffbf; |
505 | 457 | ||
506 | if (mute) | 458 | if (mute) |
507 | wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); | 459 | snd_soc_write(codec, WM8510_DAC, mute_reg | 0x40); |
508 | else | 460 | else |
509 | wm8510_write(codec, WM8510_DAC, mute_reg); | 461 | snd_soc_write(codec, WM8510_DAC, mute_reg); |
510 | return 0; | 462 | return 0; |
511 | } | 463 | } |
512 | 464 | ||
@@ -514,13 +466,13 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute) | |||
514 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, | 466 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, |
515 | enum snd_soc_bias_level level) | 467 | enum snd_soc_bias_level level) |
516 | { | 468 | { |
517 | u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3; | 469 | u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3; |
518 | 470 | ||
519 | switch (level) { | 471 | switch (level) { |
520 | case SND_SOC_BIAS_ON: | 472 | case SND_SOC_BIAS_ON: |
521 | case SND_SOC_BIAS_PREPARE: | 473 | case SND_SOC_BIAS_PREPARE: |
522 | power1 |= 0x1; /* VMID 50k */ | 474 | power1 |= 0x1; /* VMID 50k */ |
523 | wm8510_write(codec, WM8510_POWER1, power1); | 475 | snd_soc_write(codec, WM8510_POWER1, power1); |
524 | break; | 476 | break; |
525 | 477 | ||
526 | case SND_SOC_BIAS_STANDBY: | 478 | case SND_SOC_BIAS_STANDBY: |
@@ -528,18 +480,18 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec, | |||
528 | 480 | ||
529 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 481 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
530 | /* Initial cap charge at VMID 5k */ | 482 | /* Initial cap charge at VMID 5k */ |
531 | wm8510_write(codec, WM8510_POWER1, power1 | 0x3); | 483 | snd_soc_write(codec, WM8510_POWER1, power1 | 0x3); |
532 | mdelay(100); | 484 | mdelay(100); |
533 | } | 485 | } |
534 | 486 | ||
535 | power1 |= 0x2; /* VMID 500k */ | 487 | power1 |= 0x2; /* VMID 500k */ |
536 | wm8510_write(codec, WM8510_POWER1, power1); | 488 | snd_soc_write(codec, WM8510_POWER1, power1); |
537 | break; | 489 | break; |
538 | 490 | ||
539 | case SND_SOC_BIAS_OFF: | 491 | case SND_SOC_BIAS_OFF: |
540 | wm8510_write(codec, WM8510_POWER1, 0); | 492 | snd_soc_write(codec, WM8510_POWER1, 0); |
541 | wm8510_write(codec, WM8510_POWER2, 0); | 493 | snd_soc_write(codec, WM8510_POWER2, 0); |
542 | wm8510_write(codec, WM8510_POWER3, 0); | 494 | snd_soc_write(codec, WM8510_POWER3, 0); |
543 | break; | 495 | break; |
544 | } | 496 | } |
545 | 497 | ||
@@ -619,8 +571,6 @@ static int wm8510_init(struct snd_soc_device *socdev) | |||
619 | 571 | ||
620 | codec->name = "WM8510"; | 572 | codec->name = "WM8510"; |
621 | codec->owner = THIS_MODULE; | 573 | codec->owner = THIS_MODULE; |
622 | codec->read = wm8510_read_reg_cache; | ||
623 | codec->write = wm8510_write; | ||
624 | codec->set_bias_level = wm8510_set_bias_level; | 574 | codec->set_bias_level = wm8510_set_bias_level; |
625 | codec->dai = &wm8510_dai; | 575 | codec->dai = &wm8510_dai; |
626 | codec->num_dai = 1; | 576 | codec->num_dai = 1; |
@@ -630,13 +580,20 @@ static int wm8510_init(struct snd_soc_device *socdev) | |||
630 | if (codec->reg_cache == NULL) | 580 | if (codec->reg_cache == NULL) |
631 | return -ENOMEM; | 581 | return -ENOMEM; |
632 | 582 | ||
583 | ret = snd_soc_codec_set_cache_io(codec, 7, 9); | ||
584 | if (ret < 0) { | ||
585 | printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", | ||
586 | ret); | ||
587 | goto err; | ||
588 | } | ||
589 | |||
633 | wm8510_reset(codec); | 590 | wm8510_reset(codec); |
634 | 591 | ||
635 | /* register pcms */ | 592 | /* register pcms */ |
636 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 593 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
637 | if (ret < 0) { | 594 | if (ret < 0) { |
638 | printk(KERN_ERR "wm8510: failed to create pcms\n"); | 595 | printk(KERN_ERR "wm8510: failed to create pcms\n"); |
639 | goto pcm_err; | 596 | goto err; |
640 | } | 597 | } |
641 | 598 | ||
642 | /* power on device */ | 599 | /* power on device */ |
@@ -655,7 +612,7 @@ static int wm8510_init(struct snd_soc_device *socdev) | |||
655 | card_err: | 612 | card_err: |
656 | snd_soc_free_pcms(socdev); | 613 | snd_soc_free_pcms(socdev); |
657 | snd_soc_dapm_free(socdev); | 614 | snd_soc_dapm_free(socdev); |
658 | pcm_err: | 615 | err: |
659 | kfree(codec->reg_cache); | 616 | kfree(codec->reg_cache); |
660 | return ret; | 617 | return ret; |
661 | } | 618 | } |