diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-07-09 05:27:12 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-12-12 17:59:15 -0500 |
commit | 7dde0c032869ea92206398ad5c538d01931e3947 (patch) | |
tree | cc85223cd5c247a1ef6cdc41aaf55d25a4293508 | |
parent | 374b105797c3d4f29c685f3be535c35f5689b30e (diff) |
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>
-rw-r--r-- | arch/arm/mach-sa1100/assabet.c | 135 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/include/mach/assabet.h | 6 |
2 files changed, 137 insertions, 4 deletions
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index c9808c684152..6a15354d43b8 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c | |||
@@ -75,11 +75,142 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val) | |||
75 | 75 | ||
76 | EXPORT_SYMBOL(ASSABET_BCR_frob); | 76 | EXPORT_SYMBOL(ASSABET_BCR_frob); |
77 | 77 | ||
78 | /* | ||
79 | * The codec reset goes to three devices, so we need to release | ||
80 | * the rest when any one of these requests it. However, that | ||
81 | * causes the ADV7171 to consume around 100mA - more than half | ||
82 | * the LCD-blanked power. | ||
83 | * | ||
84 | * With the ADV7171, LCD and backlight enabled, we go over | ||
85 | * budget on the MAX846 Li-Ion charger, and if no Li-Ion battery | ||
86 | * is connected, the Assabet crashes. | ||
87 | */ | ||
88 | #define RST_UCB1X00 (1 << 0) | ||
89 | #define RST_UDA1341 (1 << 1) | ||
90 | #define RST_ADV7171 (1 << 2) | ||
91 | |||
92 | #define SDA GPIO_GPIO(15) | ||
93 | #define SCK GPIO_GPIO(18) | ||
94 | #define MOD GPIO_GPIO(17) | ||
95 | |||
96 | static void adv7171_start(void) | ||
97 | { | ||
98 | GPSR = SCK; | ||
99 | udelay(1); | ||
100 | GPSR = SDA; | ||
101 | udelay(2); | ||
102 | GPCR = SDA; | ||
103 | } | ||
104 | |||
105 | static void adv7171_stop(void) | ||
106 | { | ||
107 | GPSR = SCK; | ||
108 | udelay(2); | ||
109 | GPSR = SDA; | ||
110 | udelay(1); | ||
111 | } | ||
112 | |||
113 | static void adv7171_send(unsigned byte) | ||
114 | { | ||
115 | unsigned i; | ||
116 | |||
117 | for (i = 0; i < 8; i++, byte <<= 1) { | ||
118 | GPCR = SCK; | ||
119 | udelay(1); | ||
120 | if (byte & 0x80) | ||
121 | GPSR = SDA; | ||
122 | else | ||
123 | GPCR = SDA; | ||
124 | udelay(1); | ||
125 | GPSR = SCK; | ||
126 | udelay(1); | ||
127 | } | ||
128 | GPCR = SCK; | ||
129 | udelay(1); | ||
130 | GPSR = SDA; | ||
131 | udelay(1); | ||
132 | GPDR &= ~SDA; | ||
133 | GPSR = SCK; | ||
134 | udelay(1); | ||
135 | if (GPLR & SDA) | ||
136 | printk(KERN_WARNING "No ACK from ADV7171\n"); | ||
137 | udelay(1); | ||
138 | GPCR = SCK | SDA; | ||
139 | udelay(1); | ||
140 | GPDR |= SDA; | ||
141 | udelay(1); | ||
142 | } | ||
143 | |||
144 | static void adv7171_write(unsigned reg, unsigned val) | ||
145 | { | ||
146 | unsigned gpdr = GPDR; | ||
147 | unsigned gplr = GPLR; | ||
148 | |||
149 | ASSABET_BCR = BCR_value | ASSABET_BCR_AUDIO_ON; | ||
150 | udelay(100); | ||
151 | |||
152 | GPCR = SDA | SCK | MOD; /* clear L3 mode to ensure UDA1341 doesn't respond */ | ||
153 | GPDR = (GPDR | SCK | MOD) & ~SDA; | ||
154 | udelay(10); | ||
155 | if (!(GPLR & SDA)) | ||
156 | printk(KERN_WARNING "Something dragging SDA down?\n"); | ||
157 | GPDR |= SDA; | ||
158 | |||
159 | adv7171_start(); | ||
160 | adv7171_send(0x54); | ||
161 | adv7171_send(reg); | ||
162 | adv7171_send(val); | ||
163 | adv7171_stop(); | ||
164 | |||
165 | /* Restore GPIO state for L3 bus */ | ||
166 | GPSR = gplr & (SDA | SCK | MOD); | ||
167 | GPCR = (~gplr) & (SDA | SCK | MOD); | ||
168 | GPDR = gpdr; | ||
169 | } | ||
170 | |||
171 | static void adv7171_sleep(void) | ||
172 | { | ||
173 | /* Put the ADV7171 into sleep mode */ | ||
174 | adv7171_write(0x04, 0x40); | ||
175 | } | ||
176 | |||
177 | static unsigned codec_nreset; | ||
178 | |||
179 | static void assabet_codec_reset(unsigned mask, int set) | ||
180 | { | ||
181 | unsigned long flags; | ||
182 | bool old; | ||
183 | |||
184 | local_irq_save(flags); | ||
185 | old = !codec_nreset; | ||
186 | if (set) | ||
187 | codec_nreset &= ~mask; | ||
188 | else | ||
189 | codec_nreset |= mask; | ||
190 | |||
191 | if (old != !codec_nreset) { | ||
192 | if (codec_nreset) { | ||
193 | ASSABET_BCR_set(ASSABET_BCR_NCODEC_RST); | ||
194 | adv7171_sleep(); | ||
195 | } else { | ||
196 | ASSABET_BCR_clear(ASSABET_BCR_NCODEC_RST); | ||
197 | } | ||
198 | } | ||
199 | local_irq_restore(flags); | ||
200 | } | ||
201 | |||
78 | static void assabet_ucb1x00_reset(enum ucb1x00_reset state) | 202 | static void assabet_ucb1x00_reset(enum ucb1x00_reset state) |
79 | { | 203 | { |
80 | if (state == UCB_RST_PROBE) | 204 | int set = state == UCB_RST_REMOVE || state == UCB_RST_SUSPEND || |
81 | ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); | 205 | state == UCB_RST_PROBE_FAIL; |
206 | assabet_codec_reset(RST_UCB1X00, set); | ||
207 | } | ||
208 | |||
209 | void assabet_uda1341_reset(int set) | ||
210 | { | ||
211 | assabet_codec_reset(RST_UDA1341, set); | ||
82 | } | 212 | } |
213 | EXPORT_SYMBOL(assabet_uda1341_reset); | ||
83 | 214 | ||
84 | 215 | ||
85 | /* | 216 | /* |
diff --git a/arch/arm/mach-sa1100/include/mach/assabet.h b/arch/arm/mach-sa1100/include/mach/assabet.h index 307391488c22..c23fcdb047a5 100644 --- a/arch/arm/mach-sa1100/include/mach/assabet.h +++ b/arch/arm/mach-sa1100/include/mach/assabet.h | |||
@@ -39,8 +39,8 @@ extern unsigned long SCR_value; | |||
39 | 39 | ||
40 | #define ASSABET_BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */ | 40 | #define ASSABET_BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */ |
41 | #define ASSABET_BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */ | 41 | #define ASSABET_BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */ |
42 | #define ASSABET_BCR_GFX_RST (1<<1) /* Graphics Accelerator Reset (0 = hold reset) */ | 42 | #define ASSABET_BCR_NGFX_RST (1<<1) /* Graphics Accelerator Reset (0 = hold reset) */ |
43 | #define ASSABET_BCR_CODEC_RST (1<<2) /* 0 = Holds UCB1300, ADI7171, and UDA1341 in reset */ | 43 | #define ASSABET_BCR_NCODEC_RST (1<<2) /* 0 = Holds UCB1300, ADI7171, and UDA1341 in reset */ |
44 | #define ASSABET_BCR_IRDA_FSEL (1<<3) /* IRDA Frequency select (0 = SIR, 1 = MIR/ FIR) */ | 44 | #define ASSABET_BCR_IRDA_FSEL (1<<3) /* IRDA Frequency select (0 = SIR, 1 = MIR/ FIR) */ |
45 | #define ASSABET_BCR_IRDA_MD0 (1<<4) /* Range/Power select */ | 45 | #define ASSABET_BCR_IRDA_MD0 (1<<4) /* Range/Power select */ |
46 | #define ASSABET_BCR_IRDA_MD1 (1<<5) /* Range/Power select */ | 46 | #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); | |||
69 | #define ASSABET_BCR_frob(x,y) do { } while (0) | 69 | #define ASSABET_BCR_frob(x,y) do { } while (0) |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | extern void assabet_uda1341_reset(int set); | ||
73 | |||
72 | #define ASSABET_BCR_set(x) ASSABET_BCR_frob((x), (x)) | 74 | #define ASSABET_BCR_set(x) ASSABET_BCR_frob((x), (x)) |
73 | #define ASSABET_BCR_clear(x) ASSABET_BCR_frob((x), 0) | 75 | #define ASSABET_BCR_clear(x) ASSABET_BCR_frob((x), 0) |
74 | 76 | ||