diff options
Diffstat (limited to 'firmware/target/coldfire/iriver/lcd-remote-iriver.c')
-rw-r--r-- | firmware/target/coldfire/iriver/lcd-remote-iriver.c | 610 |
1 files changed, 610 insertions, 0 deletions
diff --git a/firmware/target/coldfire/iriver/lcd-remote-iriver.c b/firmware/target/coldfire/iriver/lcd-remote-iriver.c new file mode 100644 index 0000000000..cdc5acacca --- /dev/null +++ b/firmware/target/coldfire/iriver/lcd-remote-iriver.c | |||
@@ -0,0 +1,610 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 by Richard S. La Charité III | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "config.h" | ||
21 | #include "system.h" | ||
22 | #include "kernel.h" | ||
23 | #include "lcd-remote.h" | ||
24 | |||
25 | /*** definitions ***/ | ||
26 | |||
27 | #define LCD_REMOTE_CNTL_ADC_NORMAL 0xa0 | ||
28 | #define LCD_REMOTE_CNTL_ADC_REVERSE 0xa1 | ||
29 | #define LCD_REMOTE_CNTL_SHL_NORMAL 0xc0 | ||
30 | #define LCD_REMOTE_CNTL_SHL_REVERSE 0xc8 | ||
31 | #define LCD_REMOTE_CNTL_DISPLAY_ON_OFF 0xae | ||
32 | #define LCD_REMOTE_CNTL_ENTIRE_ON_OFF 0xa4 | ||
33 | #define LCD_REMOTE_CNTL_REVERSE_ON_OFF 0xa6 | ||
34 | #define LCD_REMOTE_CNTL_NOP 0xe3 | ||
35 | #define LCD_REMOTE_CNTL_POWER_CONTROL 0x2b | ||
36 | #define LCD_REMOTE_CNTL_SELECT_REGULATOR 0x20 | ||
37 | #define LCD_REMOTE_CNTL_SELECT_BIAS 0xa2 | ||
38 | #define LCD_REMOTE_CNTL_SELECT_VOLTAGE 0x81 | ||
39 | #define LCD_REMOTE_CNTL_INIT_LINE 0x40 | ||
40 | #define LCD_REMOTE_CNTL_SET_PAGE_ADDRESS 0xB0 | ||
41 | |||
42 | #define LCD_REMOTE_CNTL_HIGHCOL 0x10 /* Upper column address */ | ||
43 | #define LCD_REMOTE_CNTL_LOWCOL 0x00 /* Lower column address */ | ||
44 | |||
45 | #define CS_LO and_l(~0x00000004, &GPIO1_OUT) | ||
46 | #define CS_HI or_l(0x00000004, &GPIO1_OUT) | ||
47 | #define CLK_LO and_l(~0x10000000, &GPIO_OUT) | ||
48 | #define CLK_HI or_l(0x10000000, &GPIO_OUT) | ||
49 | #define DATA_LO and_l(~0x00040000, &GPIO1_OUT) | ||
50 | #define DATA_HI or_l(0x00040000, &GPIO1_OUT) | ||
51 | #define RS_LO and_l(~0x00010000, &GPIO_OUT) | ||
52 | #define RS_HI or_l(0x00010000, &GPIO_OUT) | ||
53 | |||
54 | static int xoffset; /* needed for flip */ | ||
55 | |||
56 | /* timeout counter for deasserting /CS after access, <0 means not counting */ | ||
57 | static int cs_countdown IDATA_ATTR = 0; | ||
58 | #define CS_TIMEOUT (HZ/10) | ||
59 | |||
60 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
61 | /* If set to true, will prevent "ticking" to headphones. */ | ||
62 | static bool emireduce = false; | ||
63 | static int byte_delay = 0; | ||
64 | #endif | ||
65 | |||
66 | bool remote_initialized = false; | ||
67 | static int _remote_type = REMOTETYPE_UNPLUGGED; | ||
68 | |||
69 | /* cached settings values */ | ||
70 | static bool cached_invert = false; | ||
71 | static bool cached_flip = false; | ||
72 | static int cached_contrast = DEFAULT_REMOTE_CONTRAST_SETTING; | ||
73 | |||
74 | static void remote_tick(void); | ||
75 | |||
76 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
77 | static inline void _byte_delay(int delay) | ||
78 | { | ||
79 | asm ( | ||
80 | "move.l %[dly], %%d0 \n" | ||
81 | "ble.s 2f \n" | ||
82 | "1: \n" | ||
83 | "subq.l #1, %%d0 \n" | ||
84 | "bne.s 1b \n" | ||
85 | "2: \n" | ||
86 | : /* outputs */ | ||
87 | : /* inputs */ | ||
88 | [dly]"d"(delay) | ||
89 | : /* clobbers */ | ||
90 | "d0" | ||
91 | ); | ||
92 | } | ||
93 | #endif /* HAVE_REMOTE_LCD_TICKING */ | ||
94 | |||
95 | /* Standard low-level byte writer. Requires CLK low on entry */ | ||
96 | static inline void _write_byte(unsigned data) | ||
97 | { | ||
98 | asm volatile ( | ||
99 | "move.l (%[gpo1]), %%d0 \n" /* Get current state of data line */ | ||
100 | "and.l %[dbit], %%d0 \n" | ||
101 | "beq.s 1f \n" /* and set it as previous-state bit */ | ||
102 | "bset #8, %[data] \n" | ||
103 | "1: \n" | ||
104 | "move.l %[data], %%d0 \n" /* Compute the 'bit derivative', i.e. a value */ | ||
105 | "lsr.l #1, %%d0 \n" /* with 1's where the data changes from the */ | ||
106 | "eor.l %%d0, %[data] \n" /* previous state, and 0's where it doesn't */ | ||
107 | "swap %[data] \n" /* Shift data to upper byte */ | ||
108 | "lsl.l #8, %[data] \n" | ||
109 | |||
110 | "lsl.l #1,%[data] \n" /* Shift out MSB */ | ||
111 | "bcc.s 1f \n" | ||
112 | "eor.l %[dbit], (%[gpo1]) \n" /* 1: flip DATA */ | ||
113 | "1: \n" | ||
114 | "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK */ | ||
115 | "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK */ | ||
116 | |||
117 | "lsl.l #1,%[data] \n" /* ..unrolled.. */ | ||
118 | "bcc.s 1f \n" | ||
119 | "eor.l %[dbit], (%[gpo1]) \n" | ||
120 | "1: \n" | ||
121 | "eor.l %[cbit], (%[gpo0]) \n" | ||
122 | "eor.l %[cbit], (%[gpo0]) \n" | ||
123 | |||
124 | "lsl.l #1,%[data] \n" | ||
125 | "bcc.s 1f \n" | ||
126 | "eor.l %[dbit], (%[gpo1]) \n" | ||
127 | "1: \n" | ||
128 | "eor.l %[cbit], (%[gpo0]) \n" | ||
129 | "eor.l %[cbit], (%[gpo0]) \n" | ||
130 | |||
131 | "lsl.l #1,%[data] \n" | ||
132 | "bcc.s 1f \n" | ||
133 | "eor.l %[dbit], (%[gpo1]) \n" | ||
134 | "1: \n" | ||
135 | "eor.l %[cbit], (%[gpo0]) \n" | ||
136 | "eor.l %[cbit], (%[gpo0]) \n" | ||
137 | |||
138 | "lsl.l #1,%[data] \n" | ||
139 | "bcc.s 1f \n" | ||
140 | "eor.l %[dbit], (%[gpo1]) \n" | ||
141 | "1: \n" | ||
142 | "eor.l %[cbit], (%[gpo0]) \n" | ||
143 | "eor.l %[cbit], (%[gpo0]) \n" | ||
144 | |||
145 | "lsl.l #1,%[data] \n" | ||
146 | "bcc.s 1f \n" | ||
147 | "eor.l %[dbit], (%[gpo1]) \n" | ||
148 | "1: \n" | ||
149 | "eor.l %[cbit], (%[gpo0]) \n" | ||
150 | "eor.l %[cbit], (%[gpo0]) \n" | ||
151 | |||
152 | "lsl.l #1,%[data] \n" | ||
153 | "bcc.s 1f \n" | ||
154 | "eor.l %[dbit], (%[gpo1]) \n" | ||
155 | "1: \n" | ||
156 | "eor.l %[cbit], (%[gpo0]) \n" | ||
157 | "eor.l %[cbit], (%[gpo0]) \n" | ||
158 | |||
159 | "lsl.l #1,%[data] \n" | ||
160 | "bcc.s 1f \n" | ||
161 | "eor.l %[dbit], (%[gpo1]) \n" | ||
162 | "1: \n" | ||
163 | "eor.l %[cbit], (%[gpo0]) \n" | ||
164 | "eor.l %[cbit], (%[gpo0]) \n" | ||
165 | : /* outputs */ | ||
166 | [data]"+d"(data) | ||
167 | : /* inputs */ | ||
168 | [gpo0]"a"(&GPIO_OUT), | ||
169 | [cbit]"d"(0x10000000), | ||
170 | [gpo1]"a"(&GPIO1_OUT), | ||
171 | [dbit]"d"(0x00040000) | ||
172 | : /* clobbers */ | ||
173 | "d0" | ||
174 | ); | ||
175 | } | ||
176 | |||
177 | /* Fast low-level byte writer. Don't use with high CPU clock. | ||
178 | * Requires CLK low on entry */ | ||
179 | static inline void _write_fast(unsigned data) | ||
180 | { | ||
181 | asm volatile ( | ||
182 | "move.w %%sr,%%d3 \n" /* Get current interrupt level */ | ||
183 | "move.w #0x2700,%%sr \n" /* Disable interrupts */ | ||
184 | |||
185 | "move.l (%[gpo1]), %%d0 \n" /* Get current state of data port */ | ||
186 | "move.l %%d0, %%d1 \n" | ||
187 | "and.l %[dbit], %%d1 \n" /* Check current state of data line */ | ||
188 | "beq.s 1f \n" /* and set it as previous-state bit */ | ||
189 | "bset #8, %[data] \n" | ||
190 | "1: \n" | ||
191 | "move.l %[data], %%d1 \n" /* Compute the 'bit derivative', i.e. a value */ | ||
192 | "lsr.l #1, %%d1 \n" /* with 1's where the data changes from the */ | ||
193 | "eor.l %%d1, %[data] \n" /* previous state, and 0's where it doesn't */ | ||
194 | "swap %[data] \n" /* Shift data to upper byte */ | ||
195 | "lsl.l #8, %[data] \n" | ||
196 | |||
197 | "move.l (%[gpo0]), %%d1 \n" /* Get current state of clock port */ | ||
198 | "move.l %[cbit], %%d2 \n" /* Precalculate opposite state of clock line */ | ||
199 | "eor.l %%d1, %%d2 \n" | ||
200 | |||
201 | "lsl.l #1,%[data] \n" /* Shift out MSB */ | ||
202 | "bcc.s 1f \n" | ||
203 | "eor.l %[dbit], %%d0 \n" /* 1: flip data bit */ | ||
204 | "move.l %%d0, (%[gpo1]) \n" /* and output new DATA state */ | ||
205 | "1: \n" | ||
206 | "move.l %%d2, (%[gpo0]) \n" /* Set CLK */ | ||
207 | "move.l %%d1, (%[gpo0]) \n" /* Reset CLK */ | ||
208 | |||
209 | "lsl.l #1,%[data] \n" /* ..unrolled.. */ | ||
210 | "bcc.s 1f \n" | ||
211 | "eor.l %[dbit], %%d0 \n" | ||
212 | "move.l %%d0, (%[gpo1]) \n" | ||
213 | "1: \n" | ||
214 | "move.l %%d2, (%[gpo0]) \n" | ||
215 | "move.l %%d1, (%[gpo0]) \n" | ||
216 | |||
217 | "lsl.l #1,%[data] \n" | ||
218 | "bcc.s 1f \n" | ||
219 | "eor.l %[dbit], %%d0 \n" | ||
220 | "move.l %%d0, (%[gpo1]) \n" | ||
221 | "1: \n" | ||
222 | "move.l %%d2, (%[gpo0]) \n" | ||
223 | "move.l %%d1, (%[gpo0]) \n" | ||
224 | |||
225 | "lsl.l #1,%[data] \n" | ||
226 | "bcc.s 1f \n" | ||
227 | "eor.l %[dbit], %%d0 \n" | ||
228 | "move.l %%d0, (%[gpo1]) \n" | ||
229 | "1: \n" | ||
230 | "move.l %%d2, (%[gpo0]) \n" | ||
231 | "move.l %%d1, (%[gpo0]) \n" | ||
232 | |||
233 | "lsl.l #1,%[data] \n" | ||
234 | "bcc.s 1f \n" | ||
235 | "eor.l %[dbit], %%d0 \n" | ||
236 | "move.l %%d0, (%[gpo1]) \n" | ||
237 | "1: \n" | ||
238 | "move.l %%d2, (%[gpo0]) \n" | ||
239 | "move.l %%d1, (%[gpo0]) \n" | ||
240 | |||
241 | "lsl.l #1,%[data] \n" | ||
242 | "bcc.s 1f \n" | ||
243 | "eor.l %[dbit], %%d0 \n" | ||
244 | "move.l %%d0, (%[gpo1]) \n" | ||
245 | "1: \n" | ||
246 | "move.l %%d2, (%[gpo0]) \n" | ||
247 | "move.l %%d1, (%[gpo0]) \n" | ||
248 | |||
249 | "lsl.l #1,%[data] \n" | ||
250 | "bcc.s 1f \n" | ||
251 | "eor.l %[dbit], %%d0 \n" | ||
252 | "move.l %%d0, (%[gpo1]) \n" | ||
253 | "1: \n" | ||
254 | "move.l %%d2, (%[gpo0]) \n" | ||
255 | "move.l %%d1, (%[gpo0]) \n" | ||
256 | |||
257 | "lsl.l #1,%[data] \n" | ||
258 | "bcc.s 1f \n" | ||
259 | "eor.l %[dbit], %%d0 \n" | ||
260 | "move.l %%d0, (%[gpo1]) \n" | ||
261 | "1: \n" | ||
262 | "move.l %%d2, (%[gpo0]) \n" | ||
263 | "move.l %%d1, (%[gpo0]) \n" | ||
264 | |||
265 | "move.w %%d3, %%sr \n" /* Restore interrupt level */ | ||
266 | : /* outputs */ | ||
267 | [data]"+d"(data) | ||
268 | : /* inputs */ | ||
269 | [gpo0]"a"(&GPIO_OUT), | ||
270 | [cbit]"i"(0x10000000), | ||
271 | [gpo1]"a"(&GPIO1_OUT), | ||
272 | [dbit]"d"(0x00040000) | ||
273 | : /* clobbers */ | ||
274 | "d0", "d1", "d2", "d3" | ||
275 | ); | ||
276 | } | ||
277 | |||
278 | void lcd_remote_write_command(int cmd) | ||
279 | { | ||
280 | cs_countdown = 0; | ||
281 | RS_LO; | ||
282 | CS_LO; | ||
283 | |||
284 | _write_byte(cmd); | ||
285 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
286 | _byte_delay(byte_delay - 148); | ||
287 | #endif | ||
288 | |||
289 | cs_countdown = CS_TIMEOUT; | ||
290 | } | ||
291 | |||
292 | void lcd_remote_write_command_ex(int cmd, int data) | ||
293 | { | ||
294 | cs_countdown = 0; | ||
295 | RS_LO; | ||
296 | CS_LO; | ||
297 | |||
298 | _write_byte(cmd); | ||
299 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
300 | _byte_delay(byte_delay - 148); | ||
301 | #endif | ||
302 | _write_byte(data); | ||
303 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
304 | _byte_delay(byte_delay - 148); | ||
305 | #endif | ||
306 | |||
307 | cs_countdown = CS_TIMEOUT; | ||
308 | } | ||
309 | |||
310 | void lcd_remote_write_data(const unsigned char* p_bytes, int count) ICODE_ATTR; | ||
311 | void lcd_remote_write_data(const unsigned char* p_bytes, int count) | ||
312 | { | ||
313 | const unsigned char *p_end = p_bytes + count; | ||
314 | |||
315 | cs_countdown = 0; | ||
316 | RS_HI; | ||
317 | CS_LO; | ||
318 | |||
319 | /* This is safe as long as lcd_remote_write_data() isn't called from within | ||
320 | * an ISR. */ | ||
321 | if (cpu_frequency < 50000000) | ||
322 | { | ||
323 | while (p_bytes < p_end) | ||
324 | { | ||
325 | _write_fast(*p_bytes++); | ||
326 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
327 | _byte_delay(byte_delay - 87); | ||
328 | #endif | ||
329 | } | ||
330 | } | ||
331 | else | ||
332 | { | ||
333 | while (p_bytes < p_end) | ||
334 | { | ||
335 | _write_byte(*p_bytes++); | ||
336 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
337 | _byte_delay(byte_delay - 148); | ||
338 | #endif | ||
339 | } | ||
340 | } | ||
341 | |||
342 | cs_countdown = CS_TIMEOUT; | ||
343 | } | ||
344 | |||
345 | /*** hardware configuration ***/ | ||
346 | |||
347 | int lcd_remote_default_contrast(void) | ||
348 | { | ||
349 | return DEFAULT_REMOTE_CONTRAST_SETTING; | ||
350 | } | ||
351 | |||
352 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
353 | void lcd_remote_emireduce(bool state) | ||
354 | { | ||
355 | emireduce = state; | ||
356 | } | ||
357 | #endif | ||
358 | |||
359 | void lcd_remote_powersave(bool on) | ||
360 | { | ||
361 | if (remote_initialized) | ||
362 | { | ||
363 | lcd_remote_write_command(LCD_REMOTE_CNTL_DISPLAY_ON_OFF | (on ? 0 : 1)); | ||
364 | lcd_remote_write_command(LCD_REMOTE_CNTL_ENTIRE_ON_OFF | (on ? 1 : 0)); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | void lcd_remote_set_contrast(int val) | ||
369 | { | ||
370 | cached_contrast = val; | ||
371 | if (remote_initialized) | ||
372 | lcd_remote_write_command_ex(LCD_REMOTE_CNTL_SELECT_VOLTAGE, val); | ||
373 | } | ||
374 | |||
375 | void lcd_remote_set_invert_display(bool yesno) | ||
376 | { | ||
377 | cached_invert = yesno; | ||
378 | if (remote_initialized) | ||
379 | lcd_remote_write_command(LCD_REMOTE_CNTL_REVERSE_ON_OFF | (yesno?1:0)); | ||
380 | } | ||
381 | |||
382 | /* turn the display upside down (call lcd_remote_update() afterwards) */ | ||
383 | void lcd_remote_set_flip(bool yesno) | ||
384 | { | ||
385 | cached_flip = yesno; | ||
386 | if (yesno) | ||
387 | { | ||
388 | xoffset = 0; | ||
389 | if (remote_initialized) | ||
390 | { | ||
391 | lcd_remote_write_command(LCD_REMOTE_CNTL_ADC_NORMAL); | ||
392 | lcd_remote_write_command(LCD_REMOTE_CNTL_SHL_NORMAL); | ||
393 | } | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | xoffset = 132 - LCD_REMOTE_WIDTH; | ||
398 | if (remote_initialized) | ||
399 | { | ||
400 | lcd_remote_write_command(LCD_REMOTE_CNTL_ADC_REVERSE); | ||
401 | lcd_remote_write_command(LCD_REMOTE_CNTL_SHL_REVERSE); | ||
402 | } | ||
403 | } | ||
404 | } | ||
405 | |||
406 | bool remote_detect(void) | ||
407 | { | ||
408 | return (GPIO_READ & 0x40000000)?false:true; | ||
409 | } | ||
410 | |||
411 | int remote_type(void) | ||
412 | { | ||
413 | return _remote_type; | ||
414 | } | ||
415 | |||
416 | void lcd_remote_init_device(void) | ||
417 | { | ||
418 | #ifdef IRIVER_H300_SERIES | ||
419 | or_l(0x10010000, &GPIO_FUNCTION); /* GPIO16: RS | ||
420 | GPIO28: CLK */ | ||
421 | |||
422 | or_l(0x00040006, &GPIO1_FUNCTION); /* GPO33: Backlight | ||
423 | GPIO34: CS | ||
424 | GPIO50: Data */ | ||
425 | or_l(0x10010000, &GPIO_ENABLE); | ||
426 | or_l(0x00040006, &GPIO1_ENABLE); | ||
427 | #else | ||
428 | or_l(0x10010800, &GPIO_FUNCTION); /* GPIO11: Backlight | ||
429 | GPIO16: RS | ||
430 | GPIO28: CLK */ | ||
431 | |||
432 | or_l(0x00040004, &GPIO1_FUNCTION); /* GPIO34: CS | ||
433 | GPIO50: Data */ | ||
434 | or_l(0x10010800, &GPIO_ENABLE); | ||
435 | or_l(0x00040004, &GPIO1_ENABLE); | ||
436 | #endif | ||
437 | lcd_remote_clear_display(); | ||
438 | tick_add_task(remote_tick); | ||
439 | } | ||
440 | |||
441 | void lcd_remote_on(void) | ||
442 | { | ||
443 | CS_HI; | ||
444 | CLK_LO; | ||
445 | lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_BIAS | 0x0); | ||
446 | |||
447 | lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x5); | ||
448 | sleep(1); | ||
449 | lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x6); | ||
450 | sleep(1); | ||
451 | lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x7); | ||
452 | |||
453 | lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_REGULATOR | 0x4); // 0x4 Select regulator @ 5.0 (default); | ||
454 | |||
455 | sleep(1); | ||
456 | |||
457 | lcd_remote_write_command(LCD_REMOTE_CNTL_INIT_LINE | 0x0); // init line | ||
458 | lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | 0x0); // page address | ||
459 | lcd_remote_write_command_ex(0x10, 0x00); // Column MSB + LSB | ||
460 | |||
461 | lcd_remote_write_command(LCD_REMOTE_CNTL_DISPLAY_ON_OFF | 1); | ||
462 | |||
463 | remote_initialized = true; | ||
464 | |||
465 | lcd_remote_set_flip(cached_flip); | ||
466 | lcd_remote_set_contrast(cached_contrast); | ||
467 | lcd_remote_set_invert_display(cached_invert); | ||
468 | } | ||
469 | |||
470 | void lcd_remote_off(void) | ||
471 | { | ||
472 | remote_initialized = false; | ||
473 | CLK_LO; | ||
474 | CS_HI; | ||
475 | } | ||
476 | |||
477 | /* Monitor remote hotswap */ | ||
478 | static void remote_tick(void) | ||
479 | { | ||
480 | static bool last_status = false; | ||
481 | static int countdown = 0; | ||
482 | static int init_delay = 0; | ||
483 | bool current_status; | ||
484 | int val; | ||
485 | int level; | ||
486 | |||
487 | current_status = remote_detect(); | ||
488 | /* Only report when the status has changed */ | ||
489 | if (current_status != last_status) | ||
490 | { | ||
491 | last_status = current_status; | ||
492 | countdown = current_status ? 20*HZ : 1; | ||
493 | } | ||
494 | else | ||
495 | { | ||
496 | /* Count down until it gets negative */ | ||
497 | if (countdown >= 0) | ||
498 | countdown--; | ||
499 | |||
500 | if (current_status) | ||
501 | { | ||
502 | if (!(countdown % 8)) | ||
503 | { | ||
504 | /* Determine which type of remote it is */ | ||
505 | level = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
506 | val = adc_scan(ADC_REMOTEDETECT); | ||
507 | set_irq_level(level); | ||
508 | |||
509 | if (val < ADCVAL_H100_LCD_REMOTE_HOLD) | ||
510 | { | ||
511 | if (val < ADCVAL_H100_LCD_REMOTE) | ||
512 | if (val < ADCVAL_H300_LCD_REMOTE) | ||
513 | _remote_type = REMOTETYPE_H300_LCD; /* hold off */ | ||
514 | else | ||
515 | _remote_type = REMOTETYPE_H100_LCD; /* hold off */ | ||
516 | else | ||
517 | if (val < ADCVAL_H300_LCD_REMOTE_HOLD) | ||
518 | _remote_type = REMOTETYPE_H300_LCD; /* hold on */ | ||
519 | else | ||
520 | _remote_type = REMOTETYPE_H100_LCD; /* hold on */ | ||
521 | |||
522 | if (--init_delay <= 0) | ||
523 | { | ||
524 | queue_post(&remote_scroll_queue, REMOTE_INIT_LCD, 0); | ||
525 | init_delay = 6; | ||
526 | } | ||
527 | } | ||
528 | else | ||
529 | { | ||
530 | _remote_type = REMOTETYPE_H300_NONLCD; /* hold on or off */ | ||
531 | } | ||
532 | } | ||
533 | } | ||
534 | else | ||
535 | { | ||
536 | if (countdown == 0) | ||
537 | { | ||
538 | _remote_type = REMOTETYPE_UNPLUGGED; | ||
539 | |||
540 | queue_post(&remote_scroll_queue, REMOTE_DEINIT_LCD, 0); | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | |||
545 | /* handle chip select timeout */ | ||
546 | if (cs_countdown >= 0) | ||
547 | cs_countdown--; | ||
548 | if (cs_countdown == 0) | ||
549 | CS_HI; | ||
550 | } | ||
551 | |||
552 | /* Update the display. | ||
553 | This must be called after all other LCD functions that change the display. */ | ||
554 | void lcd_remote_update(void) ICODE_ATTR; | ||
555 | void lcd_remote_update(void) | ||
556 | { | ||
557 | int y; | ||
558 | |||
559 | if (!remote_initialized) | ||
560 | return; | ||
561 | |||
562 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
563 | /* Adjust byte delay for emi reduction. */ | ||
564 | byte_delay = emireduce ? cpu_frequency / 197600 + 28: 0; | ||
565 | #endif | ||
566 | |||
567 | /* Copy display bitmap to hardware */ | ||
568 | for (y = 0; y < LCD_REMOTE_FBHEIGHT; y++) | ||
569 | { | ||
570 | lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | y); | ||
571 | lcd_remote_write_command(LCD_REMOTE_CNTL_HIGHCOL | ((xoffset >> 4) & 0xf)); | ||
572 | lcd_remote_write_command(LCD_REMOTE_CNTL_LOWCOL | (xoffset & 0xf)); | ||
573 | lcd_remote_write_data(lcd_remote_framebuffer[y], LCD_REMOTE_WIDTH); | ||
574 | } | ||
575 | } | ||
576 | |||
577 | /* Update a fraction of the display. */ | ||
578 | void lcd_remote_update_rect(int, int, int, int) ICODE_ATTR; | ||
579 | void lcd_remote_update_rect(int x, int y, int width, int height) | ||
580 | { | ||
581 | int ymax; | ||
582 | |||
583 | if (!remote_initialized) | ||
584 | return; | ||
585 | |||
586 | /* The Y coordinates have to work on even 8 pixel rows */ | ||
587 | ymax = (y + height-1) >> 3; | ||
588 | y >>= 3; | ||
589 | |||
590 | if(x + width > LCD_REMOTE_WIDTH) | ||
591 | width = LCD_REMOTE_WIDTH - x; | ||
592 | if (width <= 0) | ||
593 | return; /* nothing left to do, 0 is harmful to lcd_write_data() */ | ||
594 | if(ymax >= LCD_REMOTE_FBHEIGHT) | ||
595 | ymax = LCD_REMOTE_FBHEIGHT-1; | ||
596 | |||
597 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
598 | /* Adjust byte delay for emi reduction */ | ||
599 | byte_delay = emireduce ? cpu_frequency / 197600 + 28: 0; | ||
600 | #endif | ||
601 | |||
602 | /* Copy specified rectange bitmap to hardware */ | ||
603 | for (; y <= ymax; y++) | ||
604 | { | ||
605 | lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | y); | ||
606 | lcd_remote_write_command(LCD_REMOTE_CNTL_HIGHCOL | (((x+xoffset) >> 4) & 0xf)); | ||
607 | lcd_remote_write_command(LCD_REMOTE_CNTL_LOWCOL | ((x+xoffset) & 0xf)); | ||
608 | lcd_remote_write_data(&lcd_remote_framebuffer[y][x], width); | ||
609 | } | ||
610 | } | ||