Fix build errors and warnings
[maemo-rb.git] / firmware / target / arm / olympus / mrobe-100 / lcd-remote-mr100.c
blob94f4249f9f4bb29367227c58992ce359daf2e25a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2009 Mark Arigo
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "cpu.h"
23 #include "kernel.h"
24 #include "thread.h"
25 #include "system.h"
26 #include "lcd-remote.h"
27 #include "lcd-remote-target.h"
28 #include "button.h"
29 #include "button-target.h"
31 /* Temporary defines until we sort out why the gui stuff doesn't like this size
32 (I believe the status bar isn't doing sanity checks and is writing outside
33 the frame buffer size). */
34 #define RC_WIDTH 79
35 #define RC_HEIGHT 16
37 #define RC_CONTRAST_MASK 0x000000ff
38 #define RC_SCREEN_ON 0x00000100
39 #define RC_BACKLIGHT_ON 0x00000200
41 #define RC_DEV_INIT 0x00001000
42 #define RC_DETECTED 0x00002000
43 #define RC_AWAKE 0x00004000
44 #define RC_POWER_OFF 0x00008000
46 #define RC_UPDATE_LCD 0x00010000
47 #define RC_UPDATE_CONTROLLER 0x00020000
48 #define RC_UPDATE_ICONS 0x00040000
49 #define RC_UPDATE_MASK (RC_UPDATE_LCD|RC_UPDATE_CONTROLLER|RC_UPDATE_ICONS)
51 #define RC_TX_ERROR 0x00100000
52 #define RC_RX_ERROR 0x00200000
53 #define RC_TIMEOUT_ERROR 0x00400000
54 #define RC_ERROR_MASK (RC_TX_ERROR|RC_RX_ERROR|RC_TIMEOUT_ERROR)
56 #define RC_FORCE_DETECT 0x80000000
58 #define RX_READY 0x01
59 #define TX_READY 0x20
61 #define POLL_TIMEOUT 50000
63 bool remote_initialized = false;
64 unsigned int rc_status = 0;
65 unsigned char rc_buf[5];
67 /* ================================================== */
68 /* Remote thread functions */
69 /* These functions are private to the remote thread */
70 /* ================================================== */
71 static struct semaphore rc_thread_wakeup;
72 static unsigned int remote_thread_id;
73 static int remote_stack[256/sizeof(int)];
74 static const char * const remote_thread_name = "remote";
76 static bool remote_wait_ready(int ready_mask)
78 unsigned long current;
79 unsigned long start = USEC_TIMER;
80 unsigned long timeout = start + POLL_TIMEOUT;
82 rc_status &= ~RC_TIMEOUT_ERROR;
84 if (start <= timeout)
88 if (SER1_LSR & ready_mask)
89 return true;
91 //~ sleep(1);
93 current = USEC_TIMER;
94 } while (current < timeout);
96 else
100 if (SER1_LSR & ready_mask)
101 return true;
103 //~ sleep(1);
105 current = USEC_TIMER - POLL_TIMEOUT;
106 } while (current < start);
109 rc_status |= RC_TIMEOUT_ERROR;
110 return false;
113 static bool remote_rx(void)
115 int i;
116 unsigned char chksum[2];
118 rc_status &= ~RC_RX_ERROR;
120 for (i = 0; i < 5; i++)
122 if (!remote_wait_ready(RX_READY))
124 rc_status |= RC_RX_ERROR;
125 return false;
128 rc_buf[i] = SER1_RBR;
131 /* check opcode */
132 if ((rc_buf[0] & 0xf0) != 0xf0)
134 rc_status |= RC_RX_ERROR;
135 return false;
138 /* verify the checksums */
139 chksum[0] = chksum[1] = 0;
140 for (i = 0; i < 3; i++)
142 chksum[0] ^= rc_buf[i];
143 chksum[1] += rc_buf[i];
146 if ((chksum[0] != rc_buf[3]) && (chksum[1] != rc_buf[4]))
148 rc_status |= RC_RX_ERROR;
149 return false;
152 /* reception error */
153 if ((rc_buf[0] & 0x1) || (rc_buf[0] & 0x2) || (rc_buf[0] & 0x4))
155 rc_status |= RC_RX_ERROR;
156 return false;
159 return true;
162 static bool remote_tx(unsigned char *data, int len)
164 int i;
165 unsigned char chksum[2];
167 rc_status &= ~RC_TX_ERROR;
169 chksum[0] = chksum[1] = 0;
171 for (i = 0; i < len; i++)
173 if (!remote_wait_ready(TX_READY))
175 rc_status |= RC_TX_ERROR;
176 return false;
179 SER1_THR = data[i];
180 chksum[0] ^= data[i];
181 chksum[1] += data[i];
184 for (i = 0; i < 2; i++)
186 if (!remote_wait_ready(TX_READY))
188 rc_status |= RC_TX_ERROR;
189 return false;
192 SER1_THR = chksum[i];
195 return remote_rx();
198 static void remote_dev_enable(bool enable)
200 if (enable)
202 outl(inl(0x70000018) | 0xaa000, 0x70000018);
203 DEV_INIT2 &= ~0x800;
205 GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_VAL, 0x80);
206 GPIO_SET_BITWISE(GPIOL_OUTPUT_EN, 0x80);
208 DEV_EN |= DEV_SER1;
210 SER1_RBR;
211 SER1_LCR = 0x80;
212 SER1_DLL = 0x50;
213 SER1_DLM = 0x00;
214 SER1_LCR = 0x03;
215 SER1_FCR = 0x07;
217 rc_status |= RC_DEV_INIT;
219 else
221 outl(inl(0x70000018) & ~0xaa000, 0x70000018);
222 DEV_INIT2 &= ~0x800;
224 GPIO_SET_BITWISE(GPIOL_OUTPUT_VAL, 0x80);
225 GPIO_SET_BITWISE(GPIOL_OUTPUT_EN, 0x80);
227 DEV_RS |= DEV_SER1;
228 nop;
229 DEV_RS &= ~DEV_SER1;
231 DEV_EN &= ~DEV_SER1;
233 rc_status &= ~RC_DEV_INIT;
237 static void remote_update_lcd(void)
239 int x, y, draw_now;
240 unsigned char data[RC_WIDTH + 7];
242 /* If the draw_now bit is set, the draw occurs directly on the LCD.
243 Otherwise, the data is stored in an off-screen buffer and displayed
244 the next time a draw operation is executed with this flag set. */
245 draw_now = 0;
247 for (y = 0; y < 2; y++)
249 data[0] = 0x51;
250 data[1] = draw_now << 7;
251 data[2] = RC_WIDTH; /* width */
252 data[3] = 0; /* x1 */
253 data[4] = y << 3; /* y1 */
254 data[5] = RC_WIDTH; /* x2 */
255 data[6] = (y + 1) << 3; /* y2 */
257 for (x = 0; x < RC_WIDTH; x++)
258 data[x + 7] = *FBREMOTEADDR(x,y);
260 remote_tx(data, RC_WIDTH + 7);
262 draw_now = 1;
266 static void remote_update_controller(void)
268 unsigned char data[3];
270 data[0] = 0x31;
271 data[1] = 0x00;
272 if (rc_status & RC_SCREEN_ON)
273 data[1] |= 0x80;
274 if (rc_status & RC_BACKLIGHT_ON)
275 data[1] |= 0x40;
276 data[2] = (unsigned char)(rc_status & RC_CONTRAST_MASK);
277 remote_tx(data, 3);
280 #if 0
281 static void remote_update_icons(unsigned char symbols)
283 unsigned char data[2];
285 if (!(rc_status & RC_AWAKE) && !(rc_status & RC_SCREEN_ON))
286 return;
288 data[0] = 0x41;
289 data[1] = symbols;
290 remote_tx(data, 2);
292 #endif
294 static bool remote_nop(void)
296 unsigned char val[2];
298 val[0] = 0x11;
299 val[1] = 0x30;
300 return remote_tx(val, 2);
303 static void remote_wake(void)
305 if (remote_nop())
307 rc_status |= RC_AWAKE;
308 return;
311 rc_status &= ~RC_AWAKE;
312 return;
315 static void remote_sleep(void)
317 unsigned char data[2];
319 if (rc_status & RC_AWAKE)
321 data[0] = 0x71;
322 data[1] = 0x30;
323 remote_tx(data, 2);
325 udelay(25000);
328 rc_status &= ~RC_AWAKE;
331 static void remote_off(void)
333 if (rc_status & RC_AWAKE)
334 remote_sleep();
336 if (rc_status & RC_DEV_INIT)
337 remote_dev_enable(false);
339 rc_status &= ~(RC_DETECTED | RC_ERROR_MASK | RC_UPDATE_MASK);
340 remote_initialized = false;
343 static void remote_on(void)
345 if (!(rc_status & RC_DEV_INIT))
346 remote_dev_enable(true);
348 remote_wake();
350 if (rc_status & RC_AWAKE)
352 rc_status |= RC_DETECTED;
353 remote_initialized = true;
355 rc_status |= (RC_UPDATE_MASK | RC_SCREEN_ON | RC_BACKLIGHT_ON);
356 //~ remote_update_icons(0xf0); /* show battery */
358 else
360 rc_status &= ~RC_DETECTED;
361 remote_initialized = false;
365 static void remote_thread(void)
367 int rc_thread_sleep_count = 10;
368 int rc_thread_wait_timeout = TIMEOUT_BLOCK;
370 while (1)
372 semaphore_wait(&rc_thread_wakeup, rc_thread_wait_timeout);
374 /* Error handling (most likely due to remote not present) */
375 if (rc_status & RC_ERROR_MASK)
377 if (--rc_thread_sleep_count == 0)
378 rc_status |= RC_POWER_OFF;
381 /* Power-off (thread sleeps) */
382 if (rc_status & RC_POWER_OFF)
384 remote_off();
386 rc_thread_sleep_count = 10;
387 rc_thread_wait_timeout = TIMEOUT_BLOCK;
389 continue;
392 /* Detection */
393 if (!(rc_status & RC_DETECTED))
395 rc_thread_wait_timeout = HZ;
397 if (headphones_inserted())
399 remote_on();
401 if (rc_status & RC_AWAKE)
403 rc_thread_sleep_count = 10;
404 rc_thread_wait_timeout = HZ/20; /* ~50ms for updates */
407 else
409 if (--rc_thread_sleep_count == 0)
410 rc_status &= ~RC_POWER_OFF;
413 continue;
416 /* Update the remote (one per wakeup cycle) */
417 if (headphones_inserted() && (rc_status & RC_AWAKE))
419 if (rc_status & RC_SCREEN_ON)
421 /* In order of importance */
422 if (rc_status & RC_UPDATE_CONTROLLER)
424 remote_update_controller();
425 rc_status &= ~RC_UPDATE_CONTROLLER;
427 else if (rc_status & RC_UPDATE_LCD)
429 remote_update_lcd();
430 rc_status &= ~RC_UPDATE_LCD;
432 else
434 remote_nop();
437 else
439 remote_nop();
445 /* ============================================= */
446 /* Public functions */
447 /* These should only set the update flags that */
448 /* will be executed in the remote thread. */
449 /* ============================================= */
450 bool lcd_remote_read_device(unsigned char *data)
452 if (!(rc_status & RC_AWAKE) || (rc_status & RC_ERROR_MASK))
453 return false;
455 /* Return the most recent data. While the remote is plugged,
456 this is updated ~50ms */
457 data[0] = rc_buf[0];
458 data[1] = rc_buf[1];
459 data[2] = rc_buf[2];
460 data[3] = rc_buf[3];
461 data[4] = rc_buf[4];
463 return true;
466 void lcd_remote_set_invert_display(bool yesno)
468 /* dummy function...need to introduce HAVE_LCD_REMOTE_INVERT */
469 (void)yesno;
472 /* turn the display upside down (call lcd_remote_update() afterwards) */
473 void lcd_remote_set_flip(bool yesno)
475 /* dummy function...need to introduce HAVE_LCD_REMOTE_FLIP */
476 (void)yesno;
479 int lcd_remote_default_contrast(void)
481 return DEFAULT_REMOTE_CONTRAST_SETTING;
484 void lcd_remote_set_contrast(int val)
486 rc_status = (rc_status & ~RC_CONTRAST_MASK) | (val & RC_CONTRAST_MASK);
487 rc_status |= RC_UPDATE_CONTROLLER;
490 void lcd_remote_off(void)
492 /* should only be used to power off at shutdown */
493 rc_status |= RC_POWER_OFF;
494 semaphore_release(&rc_thread_wakeup);
496 /* wait until the things are powered off */
497 while (rc_status & RC_DEV_INIT)
498 sleep(HZ/10);
501 void lcd_remote_on(void)
503 /* Only wake the remote thread if it's in the blocked state. */
504 struct thread_entry *rc_thread = thread_id_entry(remote_thread_id);
505 if (rc_thread->state == STATE_BLOCKED || (rc_status & RC_FORCE_DETECT))
507 rc_status &= ~RC_FORCE_DETECT;
508 rc_status &= ~RC_POWER_OFF;
509 semaphore_release(&rc_thread_wakeup);
513 bool remote_detect(void)
515 return (rc_status & RC_DETECTED);
518 void lcd_remote_init_device(void)
520 /* reset */
521 remote_dev_enable(false);
522 rc_status |= RC_FORCE_DETECT; /* force detection at startup */
524 /* unknown */
525 GPIO_SET_BITWISE(GPIOL_ENABLE, 0x80);
526 GPIO_CLEAR_BITWISE(GPIOL_OUTPUT_VAL, 0x80);
527 GPIO_SET_BITWISE(GPIOL_OUTPUT_EN, 0x80);
529 /* a thread is required to poll & update the remote */
530 semaphore_init(&rc_thread_wakeup, 1, 0);
531 remote_thread_id = create_thread(remote_thread, remote_stack,
532 sizeof(remote_stack), 0, remote_thread_name
533 IF_PRIO(, PRIORITY_SYSTEM)
534 IF_COP(, CPU));
537 /* Update the display.
538 This must be called after all other LCD functions that change the display. */
539 void lcd_remote_update(void)
541 rc_status |= RC_UPDATE_LCD;
544 /* Update a fraction of the display. */
545 void lcd_remote_update_rect(int x, int y, int width, int height)
547 (void)x;
548 (void)y;
549 (void)width;
550 (void)height;
552 rc_status |= RC_UPDATE_LCD;
555 void _remote_backlight_on(void)
557 rc_status |= RC_BACKLIGHT_ON;
558 rc_status |= RC_UPDATE_CONTROLLER;
561 void _remote_backlight_off(void)
563 rc_status &= ~RC_BACKLIGHT_ON;
564 rc_status |= RC_UPDATE_CONTROLLER;