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/wm8731.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/wm8731.c')
-rw-r--r-- | sound/soc/codecs/wm8731.c | 108 |
1 files changed, 29 insertions, 79 deletions
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index dfbc1bb375f4..4eb84ff691b3 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -50,60 +50,12 @@ static int wm8731_spi_write(struct spi_device *spi, const char *data, int len); | |||
50 | * There is no point in caching the reset register | 50 | * There is no point in caching the reset register |
51 | */ | 51 | */ |
52 | static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { | 52 | static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { |
53 | 0x0097, 0x0097, 0x0079, 0x0079, | 53 | 0x0097, 0x0097, 0x0079, 0x0079, |
54 | 0x000a, 0x0008, 0x009f, 0x000a, | 54 | 0x000a, 0x0008, 0x009f, 0x000a, |
55 | 0x0000, 0x0000 | 55 | 0x0000, 0x0000 |
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* | 58 | #define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0) |
59 | * read wm8731 register cache | ||
60 | */ | ||
61 | static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec, | ||
62 | unsigned int reg) | ||
63 | { | ||
64 | u16 *cache = codec->reg_cache; | ||
65 | if (reg == WM8731_RESET) | ||
66 | return 0; | ||
67 | if (reg >= WM8731_CACHEREGNUM) | ||
68 | return -1; | ||
69 | return cache[reg]; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * write wm8731 register cache | ||
74 | */ | ||
75 | static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec, | ||
76 | u16 reg, unsigned int value) | ||
77 | { | ||
78 | u16 *cache = codec->reg_cache; | ||
79 | if (reg >= WM8731_CACHEREGNUM) | ||
80 | return; | ||
81 | cache[reg] = value; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * write to the WM8731 register space | ||
86 | */ | ||
87 | static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg, | ||
88 | unsigned int value) | ||
89 | { | ||
90 | u8 data[2]; | ||
91 | |||
92 | /* data is | ||
93 | * D15..D9 WM8731 register offset | ||
94 | * D8...D0 register data | ||
95 | */ | ||
96 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
97 | data[1] = value & 0x00ff; | ||
98 | |||
99 | wm8731_write_reg_cache(codec, reg, value); | ||
100 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
101 | return 0; | ||
102 | else | ||
103 | return -EIO; | ||
104 | } | ||
105 | |||
106 | #define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0) | ||
107 | 59 | ||
108 | static const char *wm8731_input_select[] = {"Line In", "Mic"}; | 60 | static const char *wm8731_input_select[] = {"Line In", "Mic"}; |
109 | static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | 61 | static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; |
@@ -260,12 +212,12 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, | |||
260 | struct snd_soc_device *socdev = rtd->socdev; | 212 | struct snd_soc_device *socdev = rtd->socdev; |
261 | struct snd_soc_codec *codec = socdev->card->codec; | 213 | struct snd_soc_codec *codec = socdev->card->codec; |
262 | struct wm8731_priv *wm8731 = codec->private_data; | 214 | struct wm8731_priv *wm8731 = codec->private_data; |
263 | u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; | 215 | u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3; |
264 | int i = get_coeff(wm8731->sysclk, params_rate(params)); | 216 | int i = get_coeff(wm8731->sysclk, params_rate(params)); |
265 | u16 srate = (coeff_div[i].sr << 2) | | 217 | u16 srate = (coeff_div[i].sr << 2) | |
266 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | 218 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; |
267 | 219 | ||
268 | wm8731_write(codec, WM8731_SRATE, srate); | 220 | snd_soc_write(codec, WM8731_SRATE, srate); |
269 | 221 | ||
270 | /* bit size */ | 222 | /* bit size */ |
271 | switch (params_format(params)) { | 223 | switch (params_format(params)) { |
@@ -279,7 +231,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, | |||
279 | break; | 231 | break; |
280 | } | 232 | } |
281 | 233 | ||
282 | wm8731_write(codec, WM8731_IFACE, iface); | 234 | snd_soc_write(codec, WM8731_IFACE, iface); |
283 | return 0; | 235 | return 0; |
284 | } | 236 | } |
285 | 237 | ||
@@ -291,7 +243,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, | |||
291 | struct snd_soc_codec *codec = socdev->card->codec; | 243 | struct snd_soc_codec *codec = socdev->card->codec; |
292 | 244 | ||
293 | /* set active */ | 245 | /* set active */ |
294 | wm8731_write(codec, WM8731_ACTIVE, 0x0001); | 246 | snd_soc_write(codec, WM8731_ACTIVE, 0x0001); |
295 | 247 | ||
296 | return 0; | 248 | return 0; |
297 | } | 249 | } |
@@ -306,19 +258,19 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream, | |||
306 | /* deactivate */ | 258 | /* deactivate */ |
307 | if (!codec->active) { | 259 | if (!codec->active) { |
308 | udelay(50); | 260 | udelay(50); |
309 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 261 | snd_soc_write(codec, WM8731_ACTIVE, 0x0); |
310 | } | 262 | } |
311 | } | 263 | } |
312 | 264 | ||
313 | static int wm8731_mute(struct snd_soc_dai *dai, int mute) | 265 | static int wm8731_mute(struct snd_soc_dai *dai, int mute) |
314 | { | 266 | { |
315 | struct snd_soc_codec *codec = dai->codec; | 267 | struct snd_soc_codec *codec = dai->codec; |
316 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; | 268 | u16 mute_reg = snd_soc_read(codec, WM8731_APDIGI) & 0xfff7; |
317 | 269 | ||
318 | if (mute) | 270 | if (mute) |
319 | wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); | 271 | snd_soc_write(codec, WM8731_APDIGI, mute_reg | 0x8); |
320 | else | 272 | else |
321 | wm8731_write(codec, WM8731_APDIGI, mute_reg); | 273 | snd_soc_write(codec, WM8731_APDIGI, mute_reg); |
322 | return 0; | 274 | return 0; |
323 | } | 275 | } |
324 | 276 | ||
@@ -396,7 +348,7 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
396 | } | 348 | } |
397 | 349 | ||
398 | /* set iface */ | 350 | /* set iface */ |
399 | wm8731_write(codec, WM8731_IFACE, iface); | 351 | snd_soc_write(codec, WM8731_IFACE, iface); |
400 | return 0; | 352 | return 0; |
401 | } | 353 | } |
402 | 354 | ||
@@ -412,12 +364,12 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, | |||
412 | break; | 364 | break; |
413 | case SND_SOC_BIAS_STANDBY: | 365 | case SND_SOC_BIAS_STANDBY: |
414 | /* Clear PWROFF, gate CLKOUT, everything else as-is */ | 366 | /* Clear PWROFF, gate CLKOUT, everything else as-is */ |
415 | reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; | 367 | reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f; |
416 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); | 368 | snd_soc_write(codec, WM8731_PWR, reg | 0x0040); |
417 | break; | 369 | break; |
418 | case SND_SOC_BIAS_OFF: | 370 | case SND_SOC_BIAS_OFF: |
419 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 371 | snd_soc_write(codec, WM8731_ACTIVE, 0x0); |
420 | wm8731_write(codec, WM8731_PWR, 0xffff); | 372 | snd_soc_write(codec, WM8731_PWR, 0xffff); |
421 | break; | 373 | break; |
422 | } | 374 | } |
423 | codec->bias_level = level; | 375 | codec->bias_level = level; |
@@ -466,7 +418,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | |||
466 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 418 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
467 | struct snd_soc_codec *codec = socdev->card->codec; | 419 | struct snd_soc_codec *codec = socdev->card->codec; |
468 | 420 | ||
469 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 421 | snd_soc_write(codec, WM8731_ACTIVE, 0x0); |
470 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | 422 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
471 | return 0; | 423 | return 0; |
472 | } | 424 | } |
@@ -556,7 +508,6 @@ static int wm8731_register(struct wm8731_priv *wm8731) | |||
556 | { | 508 | { |
557 | int ret; | 509 | int ret; |
558 | struct snd_soc_codec *codec = &wm8731->codec; | 510 | struct snd_soc_codec *codec = &wm8731->codec; |
559 | u16 reg; | ||
560 | 511 | ||
561 | if (wm8731_codec) { | 512 | if (wm8731_codec) { |
562 | dev_err(codec->dev, "Another WM8731 is registered\n"); | 513 | dev_err(codec->dev, "Another WM8731 is registered\n"); |
@@ -571,8 +522,6 @@ static int wm8731_register(struct wm8731_priv *wm8731) | |||
571 | codec->private_data = wm8731; | 522 | codec->private_data = wm8731; |
572 | codec->name = "WM8731"; | 523 | codec->name = "WM8731"; |
573 | codec->owner = THIS_MODULE; | 524 | codec->owner = THIS_MODULE; |
574 | codec->read = wm8731_read_reg_cache; | ||
575 | codec->write = wm8731_write; | ||
576 | codec->bias_level = SND_SOC_BIAS_OFF; | 525 | codec->bias_level = SND_SOC_BIAS_OFF; |
577 | codec->set_bias_level = wm8731_set_bias_level; | 526 | codec->set_bias_level = wm8731_set_bias_level; |
578 | codec->dai = &wm8731_dai; | 527 | codec->dai = &wm8731_dai; |
@@ -582,6 +531,12 @@ static int wm8731_register(struct wm8731_priv *wm8731) | |||
582 | 531 | ||
583 | memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg)); | 532 | memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg)); |
584 | 533 | ||
534 | ret = snd_soc_codec_set_cache_io(codec, 7, 9); | ||
535 | if (ret < 0) { | ||
536 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
537 | goto err; | ||
538 | } | ||
539 | |||
585 | ret = wm8731_reset(codec); | 540 | ret = wm8731_reset(codec); |
586 | if (ret < 0) { | 541 | if (ret < 0) { |
587 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); | 542 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); |
@@ -593,18 +548,13 @@ static int wm8731_register(struct wm8731_priv *wm8731) | |||
593 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 548 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
594 | 549 | ||
595 | /* Latch the update bits */ | 550 | /* Latch the update bits */ |
596 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | 551 | snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0); |
597 | wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); | 552 | snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0); |
598 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); | 553 | snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0); |
599 | wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); | 554 | snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0); |
600 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); | ||
601 | wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); | ||
602 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | ||
603 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); | ||
604 | 555 | ||
605 | /* Disable bypass path by default */ | 556 | /* Disable bypass path by default */ |
606 | reg = wm8731_read_reg_cache(codec, WM8731_APANA); | 557 | snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0); |
607 | wm8731_write(codec, WM8731_APANA, reg & ~0x4); | ||
608 | 558 | ||
609 | wm8731_codec = codec; | 559 | wm8731_codec = codec; |
610 | 560 | ||