aboutsummaryrefslogtreecommitdiffstats
path: root/sound/aoa/codecs
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-07-10 07:44:39 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-10 16:24:19 -0400
commit6a4f57874538fc05b99bd3bf7106f3df9b23a4ab (patch)
tree9731131b78823ba2f28a57c6d4f860e8c42e237f /sound/aoa/codecs
parent14b42963f64b98ab61fa9723c03d71aa5ef4f862 (diff)
[PATCH] aoa: tas: fix initialisation/reset
This patch fixes the initialisation and reset of the tas codec. The tas will often reset if the i2s clocks go away so it needs to be completely re-initialised when clocks come back. Also, this patch adds some code for DRC that will be exploited later to add a DRC control again, fixing a regression over snd-powermac. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'sound/aoa/codecs')
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas.c126
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas.h8
2 files changed, 110 insertions, 24 deletions
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
index 27c1e2eea22b..23643b342cb0 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
@@ -75,19 +75,24 @@ MODULE_DESCRIPTION("tas codec driver for snd-aoa");
75#include "../aoa.h" 75#include "../aoa.h"
76#include "../soundbus/soundbus.h" 76#include "../soundbus/soundbus.h"
77 77
78
79#define PFX "snd-aoa-codec-tas: " 78#define PFX "snd-aoa-codec-tas: "
80 79
80
81struct tas { 81struct tas {
82 struct aoa_codec codec; 82 struct aoa_codec codec;
83 struct i2c_client i2c; 83 struct i2c_client i2c;
84 u32 muted_l:1, muted_r:1, 84 u32 mute_l:1, mute_r:1 ,
85 controls_created:1; 85 controls_created:1 ,
86 drc_enabled:1,
87 hw_enabled:1;
86 u8 cached_volume_l, cached_volume_r; 88 u8 cached_volume_l, cached_volume_r;
87 u8 mixer_l[3], mixer_r[3]; 89 u8 mixer_l[3], mixer_r[3];
88 u8 acr; 90 u8 acr;
91 int drc_range;
89}; 92};
90 93
94static int tas_reset_init(struct tas *tas);
95
91static struct tas *codec_to_tas(struct aoa_codec *codec) 96static struct tas *codec_to_tas(struct aoa_codec *codec)
92{ 97{
93 return container_of(codec, struct tas, codec); 98 return container_of(codec, struct tas, codec);
@@ -101,6 +106,28 @@ static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data)
101 return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data); 106 return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data);
102} 107}
103 108
109static void tas3004_set_drc(struct tas *tas)
110{
111 unsigned char val[6];
112
113 if (tas->drc_enabled)
114 val[0] = 0x50; /* 3:1 above threshold */
115 else
116 val[0] = 0x51; /* disabled */
117 val[1] = 0x02; /* 1:1 below threshold */
118 if (tas->drc_range > 0xef)
119 val[2] = 0xef;
120 else if (tas->drc_range < 0)
121 val[2] = 0x00;
122 else
123 val[2] = tas->drc_range;
124 val[3] = 0xb0;
125 val[4] = 0x60;
126 val[5] = 0xa0;
127
128 tas_write_reg(tas, TAS_REG_DRC, 6, val);
129}
130
104static void tas_set_volume(struct tas *tas) 131static void tas_set_volume(struct tas *tas)
105{ 132{
106 u8 block[6]; 133 u8 block[6];
@@ -113,8 +140,8 @@ static void tas_set_volume(struct tas *tas)
113 if (left > 177) left = 177; 140 if (left > 177) left = 177;
114 if (right > 177) right = 177; 141 if (right > 177) right = 177;
115 142
116 if (tas->muted_l) left = 0; 143 if (tas->mute_l) left = 0;
117 if (tas->muted_r) right = 0; 144 if (tas->mute_r) right = 0;
118 145
119 /* analysing the volume and mixer tables shows 146 /* analysing the volume and mixer tables shows
120 * that they are similar enough when we shift 147 * that they are similar enough when we shift
@@ -202,7 +229,8 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
202 229
203 tas->cached_volume_l = ucontrol->value.integer.value[0]; 230 tas->cached_volume_l = ucontrol->value.integer.value[0];
204 tas->cached_volume_r = ucontrol->value.integer.value[1]; 231 tas->cached_volume_r = ucontrol->value.integer.value[1];
205 tas_set_volume(tas); 232 if (tas->hw_enabled)
233 tas_set_volume(tas);
206 return 1; 234 return 1;
207} 235}
208 236
@@ -230,8 +258,8 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol,
230{ 258{
231 struct tas *tas = snd_kcontrol_chip(kcontrol); 259 struct tas *tas = snd_kcontrol_chip(kcontrol);
232 260
233 ucontrol->value.integer.value[0] = !tas->muted_l; 261 ucontrol->value.integer.value[0] = !tas->mute_l;
234 ucontrol->value.integer.value[1] = !tas->muted_r; 262 ucontrol->value.integer.value[1] = !tas->mute_r;
235 return 0; 263 return 0;
236} 264}
237 265
@@ -240,13 +268,14 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
240{ 268{
241 struct tas *tas = snd_kcontrol_chip(kcontrol); 269 struct tas *tas = snd_kcontrol_chip(kcontrol);
242 270
243 if (tas->muted_l == !ucontrol->value.integer.value[0] 271 if (tas->mute_l == !ucontrol->value.integer.value[0]
244 && tas->muted_r == !ucontrol->value.integer.value[1]) 272 && tas->mute_r == !ucontrol->value.integer.value[1])
245 return 0; 273 return 0;
246 274
247 tas->muted_l = !ucontrol->value.integer.value[0]; 275 tas->mute_l = !ucontrol->value.integer.value[0];
248 tas->muted_r = !ucontrol->value.integer.value[1]; 276 tas->mute_r = !ucontrol->value.integer.value[1];
249 tas_set_volume(tas); 277 if (tas->hw_enabled)
278 tas_set_volume(tas);
250 return 1; 279 return 1;
251} 280}
252 281
@@ -294,7 +323,8 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
294 tas->mixer_l[idx] = ucontrol->value.integer.value[0]; 323 tas->mixer_l[idx] = ucontrol->value.integer.value[0];
295 tas->mixer_r[idx] = ucontrol->value.integer.value[1]; 324 tas->mixer_r[idx] = ucontrol->value.integer.value[1];
296 325
297 tas_set_mixer(tas); 326 if (tas->hw_enabled)
327 tas_set_mixer(tas);
298 return 1; 328 return 1;
299} 329}
300 330
@@ -346,7 +376,8 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
346 tas->acr |= TAS_ACR_INPUT_B; 376 tas->acr |= TAS_ACR_INPUT_B;
347 if (oldacr == tas->acr) 377 if (oldacr == tas->acr)
348 return 0; 378 return 0;
349 tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); 379 if (tas->hw_enabled)
380 tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
350 return 1; 381 return 1;
351} 382}
352 383
@@ -399,26 +430,66 @@ static int tas_usable(struct codec_info_item *cii,
399static int tas_reset_init(struct tas *tas) 430static int tas_reset_init(struct tas *tas)
400{ 431{
401 u8 tmp; 432 u8 tmp;
433
434 tas->codec.gpio->methods->all_amps_off(tas->codec.gpio);
435 msleep(5);
402 tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0); 436 tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
403 msleep(1); 437 msleep(5);
404 tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1); 438 tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1);
405 msleep(1); 439 msleep(20);
406 tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0); 440 tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
407 msleep(1); 441 msleep(10);
408 442 tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
409 tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
410 tas->acr |= TAS_ACR_B_MONAUREAL | TAS_ACR_B_MON_SEL_RIGHT;
411 if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
412 return -ENODEV;
413 443
414 tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; 444 tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT;
415 if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) 445 if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp))
416 return -ENODEV; 446 return -ENODEV;
417 447
448 tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL |
449 TAS_ACR_B_MON_SEL_RIGHT;
450 if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
451 return -ENODEV;
452
418 tmp = 0; 453 tmp = 0;
419 if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) 454 if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp))
420 return -ENODEV; 455 return -ENODEV;
421 456
457 tas3004_set_drc(tas);
458
459 /* Set treble & bass to 0dB */
460 tmp = 114;
461 tas_write_reg(tas, TAS_REG_TREBLE, 1, &tmp);
462 tas_write_reg(tas, TAS_REG_BASS, 1, &tmp);
463
464 tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
465 if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
466 return -ENODEV;
467
468 return 0;
469}
470
471static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock)
472{
473 struct tas *tas = cii->codec_data;
474
475 switch(clock) {
476 case CLOCK_SWITCH_PREPARE_SLAVE:
477 /* Clocks are going away, mute mute mute */
478 tas->codec.gpio->methods->all_amps_off(tas->codec.gpio);
479 tas->hw_enabled = 0;
480 break;
481 case CLOCK_SWITCH_SLAVE:
482 /* Clocks are back, re-init the codec */
483 tas_reset_init(tas);
484 tas_set_volume(tas);
485 tas_set_mixer(tas);
486 tas->hw_enabled = 1;
487 tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
488 break;
489 default:
490 /* doesn't happen as of now */
491 return -EINVAL;
492 }
422 return 0; 493 return 0;
423} 494}
424 495
@@ -427,6 +498,7 @@ static int tas_reset_init(struct tas *tas)
427 * our i2c device is suspended, and then take note of that! */ 498 * our i2c device is suspended, and then take note of that! */
428static int tas_suspend(struct tas *tas) 499static int tas_suspend(struct tas *tas)
429{ 500{
501 tas->hw_enabled = 0;
430 tas->acr |= TAS_ACR_ANALOG_PDOWN; 502 tas->acr |= TAS_ACR_ANALOG_PDOWN;
431 tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); 503 tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
432 return 0; 504 return 0;
@@ -438,6 +510,7 @@ static int tas_resume(struct tas *tas)
438 tas_reset_init(tas); 510 tas_reset_init(tas);
439 tas_set_volume(tas); 511 tas_set_volume(tas);
440 tas_set_mixer(tas); 512 tas_set_mixer(tas);
513 tas->hw_enabled = 1;
441 return 0; 514 return 0;
442} 515}
443 516
@@ -463,6 +536,7 @@ static struct codec_info tas_codec_info = {
463 .bus_factor = 64, 536 .bus_factor = 64,
464 .owner = THIS_MODULE, 537 .owner = THIS_MODULE,
465 .usable = tas_usable, 538 .usable = tas_usable,
539 .switch_clock = tas_switch_clock,
466#ifdef CONFIG_PM 540#ifdef CONFIG_PM
467 .suspend = _tas_suspend, 541 .suspend = _tas_suspend,
468 .resume = _tas_resume, 542 .resume = _tas_resume,
@@ -483,6 +557,7 @@ static int tas_init_codec(struct aoa_codec *codec)
483 printk(KERN_ERR PFX "tas failed to initialise\n"); 557 printk(KERN_ERR PFX "tas failed to initialise\n");
484 return -ENXIO; 558 return -ENXIO;
485 } 559 }
560 tas->hw_enabled = 1;
486 561
487 if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, 562 if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
488 aoa_get_card(), 563 aoa_get_card(),
@@ -548,6 +623,7 @@ static int tas_create(struct i2c_adapter *adapter,
548 tas->i2c.driver = &tas_driver; 623 tas->i2c.driver = &tas_driver;
549 tas->i2c.adapter = adapter; 624 tas->i2c.adapter = adapter;
550 tas->i2c.addr = addr; 625 tas->i2c.addr = addr;
626 tas->drc_range = TAS3004_DRC_MAX;
551 strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE-1); 627 strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE-1);
552 628
553 if (i2c_attach_client(&tas->i2c)) { 629 if (i2c_attach_client(&tas->i2c)) {
@@ -564,7 +640,9 @@ static int tas_create(struct i2c_adapter *adapter,
564 if (aoa_codec_register(&tas->codec)) { 640 if (aoa_codec_register(&tas->codec)) {
565 goto detach; 641 goto detach;
566 } 642 }
567 printk(KERN_DEBUG "snd-aoa-codec-tas: created and attached tas instance\n"); 643 printk(KERN_DEBUG
644 "snd-aoa-codec-tas: tas found, addr 0x%02x on %s\n",
645 addr, node->full_name);
568 return 0; 646 return 0;
569 detach: 647 detach:
570 i2c_detach_client(&tas->i2c); 648 i2c_detach_client(&tas->i2c);
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.h b/sound/aoa/codecs/snd-aoa-codec-tas.h
index daf81f45d83a..ae177e3466e6 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.h
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.h
@@ -44,4 +44,12 @@
44#define TAS_REG_LEFT_BIQUAD6 0x10 44#define TAS_REG_LEFT_BIQUAD6 0x10
45#define TAS_REG_RIGHT_BIQUAD6 0x19 45#define TAS_REG_RIGHT_BIQUAD6 0x19
46 46
47#define TAS_REG_LEFT_LOUDNESS 0x21
48#define TAS_REG_RIGHT_LOUDNESS 0x22
49#define TAS_REG_LEFT_LOUDNESS_GAIN 0x23
50#define TAS_REG_RIGHT_LOUDNESS_GAIN 0x24
51
52#define TAS3001_DRC_MAX 0x5f
53#define TAS3004_DRC_MAX 0xef
54
47#endif /* __SND_AOA_CODECTASH */ 55#endif /* __SND_AOA_CODECTASH */