ARM: sa11x0: assabet: better reset handling
The codec reset pin is connected to several peripherals. When the reset is released, unfortunately the ADV7171 powers itself up rather than remaining in power-down mode. As we don't have a driver for this device, we end up needlessly consuming an additional 330mW. Not only that but we should have a way to arbitrate the reset signal. This patch provides that facility: we program the ADV7171 to sleep mode whenever the reset is released, and we release the reset when any one of the three peripherals requests the reset to be released. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Родитель
374b105797
Коммит
7dde0c0328
|
@ -75,12 +75,143 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
|
||||||
|
|
||||||
EXPORT_SYMBOL(ASSABET_BCR_frob);
|
EXPORT_SYMBOL(ASSABET_BCR_frob);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The codec reset goes to three devices, so we need to release
|
||||||
|
* the rest when any one of these requests it. However, that
|
||||||
|
* causes the ADV7171 to consume around 100mA - more than half
|
||||||
|
* the LCD-blanked power.
|
||||||
|
*
|
||||||
|
* With the ADV7171, LCD and backlight enabled, we go over
|
||||||
|
* budget on the MAX846 Li-Ion charger, and if no Li-Ion battery
|
||||||
|
* is connected, the Assabet crashes.
|
||||||
|
*/
|
||||||
|
#define RST_UCB1X00 (1 << 0)
|
||||||
|
#define RST_UDA1341 (1 << 1)
|
||||||
|
#define RST_ADV7171 (1 << 2)
|
||||||
|
|
||||||
|
#define SDA GPIO_GPIO(15)
|
||||||
|
#define SCK GPIO_GPIO(18)
|
||||||
|
#define MOD GPIO_GPIO(17)
|
||||||
|
|
||||||
|
static void adv7171_start(void)
|
||||||
|
{
|
||||||
|
GPSR = SCK;
|
||||||
|
udelay(1);
|
||||||
|
GPSR = SDA;
|
||||||
|
udelay(2);
|
||||||
|
GPCR = SDA;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adv7171_stop(void)
|
||||||
|
{
|
||||||
|
GPSR = SCK;
|
||||||
|
udelay(2);
|
||||||
|
GPSR = SDA;
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adv7171_send(unsigned byte)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++, byte <<= 1) {
|
||||||
|
GPCR = SCK;
|
||||||
|
udelay(1);
|
||||||
|
if (byte & 0x80)
|
||||||
|
GPSR = SDA;
|
||||||
|
else
|
||||||
|
GPCR = SDA;
|
||||||
|
udelay(1);
|
||||||
|
GPSR = SCK;
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
GPCR = SCK;
|
||||||
|
udelay(1);
|
||||||
|
GPSR = SDA;
|
||||||
|
udelay(1);
|
||||||
|
GPDR &= ~SDA;
|
||||||
|
GPSR = SCK;
|
||||||
|
udelay(1);
|
||||||
|
if (GPLR & SDA)
|
||||||
|
printk(KERN_WARNING "No ACK from ADV7171\n");
|
||||||
|
udelay(1);
|
||||||
|
GPCR = SCK | SDA;
|
||||||
|
udelay(1);
|
||||||
|
GPDR |= SDA;
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adv7171_write(unsigned reg, unsigned val)
|
||||||
|
{
|
||||||
|
unsigned gpdr = GPDR;
|
||||||
|
unsigned gplr = GPLR;
|
||||||
|
|
||||||
|
ASSABET_BCR = BCR_value | ASSABET_BCR_AUDIO_ON;
|
||||||
|
udelay(100);
|
||||||
|
|
||||||
|
GPCR = SDA | SCK | MOD; /* clear L3 mode to ensure UDA1341 doesn't respond */
|
||||||
|
GPDR = (GPDR | SCK | MOD) & ~SDA;
|
||||||
|
udelay(10);
|
||||||
|
if (!(GPLR & SDA))
|
||||||
|
printk(KERN_WARNING "Something dragging SDA down?\n");
|
||||||
|
GPDR |= SDA;
|
||||||
|
|
||||||
|
adv7171_start();
|
||||||
|
adv7171_send(0x54);
|
||||||
|
adv7171_send(reg);
|
||||||
|
adv7171_send(val);
|
||||||
|
adv7171_stop();
|
||||||
|
|
||||||
|
/* Restore GPIO state for L3 bus */
|
||||||
|
GPSR = gplr & (SDA | SCK | MOD);
|
||||||
|
GPCR = (~gplr) & (SDA | SCK | MOD);
|
||||||
|
GPDR = gpdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adv7171_sleep(void)
|
||||||
|
{
|
||||||
|
/* Put the ADV7171 into sleep mode */
|
||||||
|
adv7171_write(0x04, 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned codec_nreset;
|
||||||
|
|
||||||
|
static void assabet_codec_reset(unsigned mask, int set)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
bool old;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
old = !codec_nreset;
|
||||||
|
if (set)
|
||||||
|
codec_nreset &= ~mask;
|
||||||
|
else
|
||||||
|
codec_nreset |= mask;
|
||||||
|
|
||||||
|
if (old != !codec_nreset) {
|
||||||
|
if (codec_nreset) {
|
||||||
|
ASSABET_BCR_set(ASSABET_BCR_NCODEC_RST);
|
||||||
|
adv7171_sleep();
|
||||||
|
} else {
|
||||||
|
ASSABET_BCR_clear(ASSABET_BCR_NCODEC_RST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local_irq_restore(flags);
|
||||||
|
}
|
||||||
|
|
||||||
static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
|
static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
|
||||||
{
|
{
|
||||||
if (state == UCB_RST_PROBE)
|
int set = state == UCB_RST_REMOVE || state == UCB_RST_SUSPEND ||
|
||||||
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
|
state == UCB_RST_PROBE_FAIL;
|
||||||
|
assabet_codec_reset(RST_UCB1X00, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assabet_uda1341_reset(int set)
|
||||||
|
{
|
||||||
|
assabet_codec_reset(RST_UDA1341, set);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(assabet_uda1341_reset);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assabet flash support code.
|
* Assabet flash support code.
|
||||||
|
|
|
@ -39,8 +39,8 @@ extern unsigned long SCR_value;
|
||||||
|
|
||||||
#define ASSABET_BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */
|
#define ASSABET_BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */
|
||||||
#define ASSABET_BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */
|
#define ASSABET_BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */
|
||||||
#define ASSABET_BCR_GFX_RST (1<<1) /* Graphics Accelerator Reset (0 = hold reset) */
|
#define ASSABET_BCR_NGFX_RST (1<<1) /* Graphics Accelerator Reset (0 = hold reset) */
|
||||||
#define ASSABET_BCR_CODEC_RST (1<<2) /* 0 = Holds UCB1300, ADI7171, and UDA1341 in reset */
|
#define ASSABET_BCR_NCODEC_RST (1<<2) /* 0 = Holds UCB1300, ADI7171, and UDA1341 in reset */
|
||||||
#define ASSABET_BCR_IRDA_FSEL (1<<3) /* IRDA Frequency select (0 = SIR, 1 = MIR/ FIR) */
|
#define ASSABET_BCR_IRDA_FSEL (1<<3) /* IRDA Frequency select (0 = SIR, 1 = MIR/ FIR) */
|
||||||
#define ASSABET_BCR_IRDA_MD0 (1<<4) /* Range/Power select */
|
#define ASSABET_BCR_IRDA_MD0 (1<<4) /* Range/Power select */
|
||||||
#define ASSABET_BCR_IRDA_MD1 (1<<5) /* Range/Power select */
|
#define ASSABET_BCR_IRDA_MD1 (1<<5) /* Range/Power select */
|
||||||
|
@ -69,6 +69,8 @@ extern void ASSABET_BCR_frob(unsigned int mask, unsigned int set);
|
||||||
#define ASSABET_BCR_frob(x,y) do { } while (0)
|
#define ASSABET_BCR_frob(x,y) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern void assabet_uda1341_reset(int set);
|
||||||
|
|
||||||
#define ASSABET_BCR_set(x) ASSABET_BCR_frob((x), (x))
|
#define ASSABET_BCR_set(x) ASSABET_BCR_frob((x), (x))
|
||||||
#define ASSABET_BCR_clear(x) ASSABET_BCR_frob((x), 0)
|
#define ASSABET_BCR_clear(x) ASSABET_BCR_frob((x), 0)
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче