blob: e8fc8b97ea9e863c660986200ee15999ba736eb7 [file] [log] [blame]
Mark Arigoe66ddd72008-01-09 07:24:43 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Mark Arigo
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * 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.
Mark Arigoe66ddd72008-01-09 07:24:43 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdlib.h>
23#include "config.h"
24#include "cpu.h"
25#include "system.h"
26#include "button.h"
27#include "kernel.h"
28#include "backlight.h"
29#include "backlight-target.h"
30#include "system.h"
31
Mark Arigod8290752008-02-24 04:12:16 +000032#define LOGF_ENABLE
33#include "logf.h"
34
Robert Kuklad6c23b42008-03-05 21:52:45 +000035static int int_btn = BUTTON_NONE;
36
37#ifndef BOOTLOADER
Mark Arigod8290752008-02-24 04:12:16 +000038/* Driver for the Synaptics Touchpad based on the "Synaptics Modular Embedded
39 Protocol: 3-Wire Interface Specification" documentation */
40
41#define ACK (GPIOD_INPUT_VAL & 0x1)
42#define ACK_HI GPIOD_OUTPUT_VAL |= 0x1
43#define ACK_LO GPIOD_OUTPUT_VAL &= ~0x1
44
45#define CLK ((GPIOD_INPUT_VAL & 0x2) >> 1)
46#define CLK_HI GPIOD_OUTPUT_VAL |= 0x2
47#define CLK_LO GPIOD_OUTPUT_VAL &= ~0x2
48
49#define DATA ((GPIOD_INPUT_VAL & 0x4) >> 2)
50#define DATA_HI GPIOD_OUTPUT_EN |= 0x4; GPIOD_OUTPUT_VAL |= 0x4
51#define DATA_LO GPIOD_OUTPUT_EN |= 0x4; GPIOD_OUTPUT_VAL &= ~0x4
52
53#define LO 0
54#define HI 1
55
56#define STATUS_READY 1
57#define READ_RETRY 8
58#define READ_ERROR -1
59
60#define HELLO_HEADER 0x19
61#define HELLO_ID 0x1
62#define BUTTONS_HEADER 0x1a
63#define BUTTONS_ID 0x9
64#define ABSOLUTE_HEADER 0x0b
65
Dominik Wenger7135f2d2008-06-27 20:19:27 +000066#define MEP_READ 0x1
67#define MEP_WRITE 0x3
68
Mark Arigod8290752008-02-24 04:12:16 +000069static int syn_status = 0;
Mark Arigod8290752008-02-24 04:12:16 +000070
71static int syn_wait_clk_change(unsigned int val)
72{
73 int i;
74
75 for (i = 0; i < 10000; i++)
76 {
77 if (CLK == val)
78 return 1;
79 }
80
81 return 0;
82}
83
84static inline int syn_get_data(void)
85{
86 GPIOD_OUTPUT_EN &= ~0x4;
87 return DATA;
88}
89
90static void syn_wait_guest_flush(void)
91{
92 /* Flush receiving (flushee) state:
93 handshake until DATA goes high during P3 stage */
94 if (CLK == LO)
95 {
96 ACK_HI; /* P1 -> P2 */
97 syn_wait_clk_change(HI); /* P2 -> P3 */
98 }
99
100 while (syn_get_data() == LO)
101 {
102 ACK_HI; /* P3 -> P0 */
103 syn_wait_clk_change(LO); /* P0 -> P1 */
104 ACK_LO; /* P1 -> P2 */
105 syn_wait_clk_change(HI); /* P2 -> P3 */
106 }
107
108 /* Continue handshaking until back to P0 */
109 ACK_HI; /* P3 -> P0 */
110}
111
112static void syn_flush(void)
113{
114 int i;
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000115#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000116 logf("syn_flush...");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000117#endif
Mark Arigod8290752008-02-24 04:12:16 +0000118 /* Flusher holds DATA low for at least 36 handshake cycles */
119 DATA_LO;
120
121 for (i = 0; i < 36; i++)
122 {
123 syn_wait_clk_change(LO); /* P0 -> P1 */
124 ACK_LO; /* P1 -> P2 */
125 syn_wait_clk_change(HI); /* P2 -> P3 */
126 ACK_HI; /* P3 -> P0 */
127 }
128
129 /* Raise DATA in P1 stage */
130 syn_wait_clk_change(LO); /* P0 -> P1 */
131 DATA_HI;
132
133 /* After a flush, the flushing device enters a flush-receiving (flushee)
134 state */
135 syn_wait_guest_flush();
136}
137
138static int syn_send_data(int *data, int len)
139{
140 int i, bit;
141 int parity = 0;
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000142#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000143 logf("syn_send_data...");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000144#endif
Mark Arigod8290752008-02-24 04:12:16 +0000145 /* 1. Lower DATA line to issue a request-to-send to guest */
146 DATA_LO;
147
148 /* 2. Wait for guest to lower CLK */
149 syn_wait_clk_change(LO);
150
151 /* 3. Lower ACK (with DATA still low) */
152 ACK_LO;
153
154 /* 4. Wait for guest to raise CLK */
155 syn_wait_clk_change(HI);
156
157 /* 5. Send data */
158 for (i = 0; i < len; i++)
159 {
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000160#if defined(LOGF_ENABLE)
161 logf(" sending byte: %d", data[i]);
162#endif
Mark Arigod8290752008-02-24 04:12:16 +0000163 bit = 0;
164 while (bit < 8)
165 {
166 /* 5a. Drive data low if bit is 0, or high if bit is 1 */
167 if (data[i] & (1 << bit))
168 {
169 DATA_HI;
170 parity++;
171 }
172 else
173 {
174 DATA_LO;
175 }
176 bit++;
177
178 /* 5b. Invert ACK to indicate that the data bit is ready */
179 ACK_HI;
180
181 /* 5c. Wait for guest to invert CLK */
182 syn_wait_clk_change(LO);
183
184 /* Repeat for next bit */
185 if (data[i] & (1 << bit))
186 {
187 DATA_HI;
188 parity++;
189 }
190 else
191 {
192 DATA_LO;
193 }
194 bit++;
195
196 ACK_LO;
197
198 syn_wait_clk_change(HI);
199 }
200 }
201
202 /* 7. Transmission termination sequence: */
203 /* 7a. Host may put parity bit on DATA. Hosts that do not generate
204 parity should set DATA high. Parity is 1 if there's an odd
205 number of '1' bits, or 0 if there's an even number of '1' bits. */
206 parity = parity % 2;
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000207#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000208 logf(" send parity = %d", parity);
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000209#endif
Mark Arigod8290752008-02-24 04:12:16 +0000210 if (parity)
211 {
212 DATA_HI;
213 }
214 else
215 {
216 DATA_LO;
217 }
218
219 /* 7b. Raise ACK to indicate that the optional parity bit is ready */
220 ACK_HI;
221
222 /* 7c. Guest lowers CLK */
223 syn_wait_clk_change(LO);
224
225 /* 7d. Pull DATA high (if parity bit was 0) */
226 DATA_HI;
227
228 /* 7e. Lower ACK to indicate that the stop bit is ready */
229 ACK_LO;
230
231 /* 7f. Guest raises CLK */
232 syn_wait_clk_change(HI);
233
234 /* 7g. If DATA is low, guest is flushing this transfer. Host should
235 enter the flushee state. */
236 if (syn_get_data() == LO)
237 {
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000238#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000239 logf(" module flushing");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000240#endif
Mark Arigod8290752008-02-24 04:12:16 +0000241 syn_wait_guest_flush();
242 return -1;
243 }
244
245 /* 7h. Host raises ACK and the link enters the idle state */
246 ACK_HI;
247
248 return len;
249}
250
251static int syn_read_data(int *data, int data_len)
252{
253 int i, len, bit, parity, tmp;
254 int *data_ptr;
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000255#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000256 logf("syn_read_data...");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000257#endif
Mark Arigod8290752008-02-24 04:12:16 +0000258 /* 1. Guest drives CLK low */
259 if (CLK != LO)
260 return 0;
261
262 /* 1a. If the host is willing to receive a packet it lowers ACK */
263 ACK_LO;
264
265 /* 2. Guest may issue a request-to-send by lowering DATA. If the
266 guest decides not to transmit a packet, it may abort the
267 transmission by not lowering DATA. */
268
269 /* 3. The guest raises CLK */
270 syn_wait_clk_change(HI);
271
272 /* 4. If the guest is still driving DATA low, the transfer is commited
273 to occur. Otherwise, the transfer is aborted. In either case,
274 the host raises ACK. */
275 if (syn_get_data() == HI)
276 {
277 logf(" read abort");
278
279 ACK_HI;
280 return READ_ERROR;
281 }
282 else
283 {
284 ACK_HI;
285 }
286
287 /* 5. Read the incoming data packet */
288 i = 0;
289 len = 0;
290 parity = 0;
291 while (i <= len)
292 {
293 bit = 0;
294
295 if (i < data_len)
296 data_ptr = &data[i];
297 else
298 data_ptr = &tmp;
299
300 *data_ptr = 0;
301 while (bit < 8)
302 {
303 /* 5b. Guset inverts CLK to indicate that data is ready */
304 syn_wait_clk_change(LO);
305
306 /* 5d. Read the data bit from DATA */
307 if (syn_get_data() == HI)
308 {
309 *data_ptr |= (1 << bit);
310 parity++;
311 }
312 bit++;
313
314 /* 5e. Invert ACK to indicate that data has been read */
315 ACK_LO;
316
317 /* Repeat for next bit */
318 syn_wait_clk_change(HI);
319
320 if (syn_get_data() == HI)
321 {
322 *data_ptr |= (1 << bit);
323 parity++;
324 }
325 bit++;
326
327 ACK_HI;
328 }
329
330 /* First byte is the packet header */
331 if (i == 0)
332 {
333 /* Format control (bit 3) should be 1 */
334 if (*data_ptr & 0x8)
335 {
336 /* Packet length is bits 0:2 */
337 len = *data_ptr & 0x7;
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000338#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000339 logf(" packet length = %d", len);
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000340#endif
Mark Arigod8290752008-02-24 04:12:16 +0000341 }
342 else
343 {
344 logf(" invalid format ctrl bit");
345 return READ_ERROR;
346 }
347 }
348
349 i++;
350 }
351
352 /* 7. Transmission termination cycle */
353 /* 7a. The guest generates a parity bit on DATA */
354 /* 7b. The host waits for guest to lower CLK */
355 syn_wait_clk_change(LO);
356
357 /* 7c. The host verifies the parity bit is correct */
358 parity = parity % 2;
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000359#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000360 logf(" parity check: %d / %d", syn_get_data(), parity);
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000361#endif
Mark Arigod8290752008-02-24 04:12:16 +0000362 /* TODO: parity error handling */
363
364 /* 7d. The host lowers ACK */
365 ACK_LO;
366
367 /* 7e. The host waits for the guest to raise CLK indicating
368 that the stop bit is ready */
369 syn_wait_clk_change(HI);
370
371 /* 7f. The host reads DATA and verifies that it is 1 */
372 if (syn_get_data() == LO)
373 {
374 logf(" framing error");
375
376 ACK_HI;
377 return READ_ERROR;
378 }
379
380 ACK_HI;
381
382 return len;
383}
384
385static int syn_read_device(int *data, int len)
386{
387 int i;
388 int ret = READ_ERROR;
389
390 for (i = 0; i < READ_RETRY; i++)
391 {
392 if (syn_wait_clk_change(LO))
393 {
394 /* module is sending data */
395 ret = syn_read_data(data, len);
396 if (ret != READ_ERROR)
397 return ret;
398
399 syn_flush();
400 }
401 else
402 {
403 /* module is idle */
404 return 0;
405 }
406 }
407
408 return ret;
409}
410
411static int syn_reset(void)
412{
413 int val, id;
414 int data[2];
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000415#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000416 logf("syn_reset...");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000417#endif
Mark Arigod8290752008-02-24 04:12:16 +0000418 /* reset module 0 */
419 val = (0 << 4) | (1 << 3) | 0;
420 syn_send_data(&val, 1);
421
422 val = syn_read_device(data, 2);
423 if (val == 1)
424 {
425 val = data[0] & 0xff; /* packet header */
426 id = (data[1] >> 4) & 0xf; /* packet id */
427 if ((val == HELLO_HEADER) && (id == HELLO_ID))
428 {
429 logf(" module 0 reset");
430 return 1;
431 }
432 }
433
434 logf(" reset failed");
435 return 0;
436}
437
438#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
439static void syn_info(void)
440{
441 int i, val;
442 int data[8];
443
444 logf("syn_info...");
445
446 /* module base info */
447 logf("module base info:");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000448 data[0] = MEP_READ;
Mark Arigod8290752008-02-24 04:12:16 +0000449 data[1] = 0x80;
450 syn_send_data(data, 2);
451 val = syn_read_device(data, 8);
452 if (val > 0)
453 {
454 for (i = 0; i < 8; i++)
455 logf(" data[%d] = 0x%02x", i, data[i]);
456 }
457
458 /* module product info */
459 logf("module product info:");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000460 data[0] = MEP_READ;
Mark Arigod8290752008-02-24 04:12:16 +0000461 data[1] = 0x81;
462 syn_send_data(data, 2);
463 val = syn_read_device(data, 8);
464 if (val > 0)
465 {
466 for (i = 0; i < 8; i++)
467 logf(" data[%d] = 0x%02x", i, data[i]);
468 }
469
470 /* module serialization */
471 logf("module serialization:");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000472 data[0] = MEP_READ;
Mark Arigod8290752008-02-24 04:12:16 +0000473 data[1] = 0x82;
474 syn_send_data(data, 2);
475 val = syn_read_device(data, 8);
476 if (val > 0)
477 {
478 for (i = 0; i < 8; i++)
479 logf(" data[%d] = 0x%02x", i, data[i]);
480 }
481
482 /* 1-D sensor info */
483 logf("1-d sensor info:");
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000484 data[0] = MEP_READ;
Mark Arigod8290752008-02-24 04:12:16 +0000485 data[1] = 0x80 + 0x20;
486 syn_send_data(data, 2);
487 val = syn_read_device(data, 8);
488 if (val > 0)
489 {
490 for (i = 0; i < 8; i++)
491 logf(" data[%d] = 0x%02x", i, data[i]);
492 }
493}
494#endif
495
Mark Arigoe66ddd72008-01-09 07:24:43 +0000496void button_init_device(void)
497{
Mark Arigoe66ddd72008-01-09 07:24:43 +0000498 /* enable touchpad leds */
Mark Arigod8290752008-02-24 04:12:16 +0000499 GPIOA_ENABLE |= BUTTONLIGHT_ALL;
Mark Arigoe66ddd72008-01-09 07:24:43 +0000500 GPIOA_OUTPUT_EN |= BUTTONLIGHT_ALL;
Mark Arigod8290752008-02-24 04:12:16 +0000501
502 /* enable touchpad */
503 GPO32_ENABLE |= 0x40000000;
504 GPO32_VAL &= ~0x40000000;
505
506 /* enable ACK, CLK, DATA lines */
507 GPIOD_ENABLE |= (0x1 | 0x2 | 0x4);
508
509 GPIOD_OUTPUT_EN |= 0x1; /* ACK */
510 GPIOD_OUTPUT_VAL |= 0x1; /* high */
511
512 GPIOD_OUTPUT_EN &= ~0x2; /* CLK */
513
514 GPIOD_OUTPUT_EN |= 0x4; /* DATA */
515 GPIOD_OUTPUT_VAL |= 0x4; /* high */
516
517 syn_flush();
518
519 if (syn_reset())
520 {
521#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
522 syn_info();
523#endif
524
525 syn_status = STATUS_READY;
526
527 /* enable interrupts */
528 GPIOD_INT_LEV &= ~0x2;
529 GPIOD_INT_CLR |= 0x2;
530 GPIOD_INT_EN |= 0x2;
531
532 CPU_INT_EN |= HI_MASK;
533 CPU_HI_INT_EN |= GPIO0_MASK;
534 }
535}
536
537/*
538 * Button interrupt handler
539 */
540void button_int(void)
541{
542 int data[4];
543 int val, id;
544
545 int_btn = BUTTON_NONE;
546
547 if (syn_status == STATUS_READY)
548 {
549 /* disable interrupt while we read the touchpad */
550 GPIOD_INT_EN &= ~0x2;
551
552 val = syn_read_device(data, 4);
553 if (val > 0)
554 {
555 val = data[0] & 0xff; /* packet header */
556 id = (data[1] >> 4) & 0xf; /* packet id */
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000557#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000558 logf("button_read_device...");
559 logf(" data[0] = 0x%08x", data[0]);
560 logf(" data[1] = 0x%08x", data[1]);
561 logf(" data[2] = 0x%08x", data[2]);
562 logf(" data[3] = 0x%08x", data[3]);
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000563#endif
Mark Arigod8290752008-02-24 04:12:16 +0000564 if ((val == BUTTONS_HEADER) && (id == BUTTONS_ID))
565 {
566 /* Buttons packet - touched one of the 5 "buttons" */
567 if (data[1] & 0x1)
568 int_btn |= BUTTON_PLAY;
569 if (data[1] & 0x2)
570 int_btn |= BUTTON_MENU;
571 if (data[1] & 0x4)
572 int_btn |= BUTTON_LEFT;
573 if (data[1] & 0x8)
574 int_btn |= BUTTON_DISPLAY;
575 if (data[2] & 0x1)
576 int_btn |= BUTTON_RIGHT;
577
578 /* An Absolute packet should follow which we ignore */
579 val = syn_read_device(data, 4);
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000580#if defined(LOGF_ENABLE)
Mark Arigod8290752008-02-24 04:12:16 +0000581 logf(" int_btn = 0x%04x", int_btn);
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000582#endif
Mark Arigod8290752008-02-24 04:12:16 +0000583 }
584 else if (val == ABSOLUTE_HEADER)
585 {
586 /* Absolute packet - the finger is on the vertical strip.
587 Position ranges from 1-4095, with 1 at the bottom. */
588 val = ((data[1] >> 4) << 8) | data[2]; /* position */
Dominik Wenger7135f2d2008-06-27 20:19:27 +0000589#if defined(LOGF_ENABLE)
590 logf(" pos %d", val);
591 logf(" z %d", data[3]);
592 logf(" finger %d", data[1] & 0x1);
593 logf(" gesture %d", data[1] & 0x2);
594 logf(" RelPosVld %d", data[1] & 0x4);
595#endif
596 if(data[1] & 0x1) /* if finger on touch strip */
597 {
598 if ((val > 0) && (val <= 1365))
599 int_btn |= BUTTON_DOWN;
600 else if ((val > 1365) && (val <= 2730))
601 int_btn |= BUTTON_SELECT;
602 else if ((val > 2730) && (val <= 4095))
603 int_btn |= BUTTON_UP;
604 }
Mark Arigod8290752008-02-24 04:12:16 +0000605 }
606 }
607
608 /* re-enable interrupts */
609 GPIOD_INT_LEV &= ~0x2;
610 GPIOD_INT_CLR |= 0x2;
611 GPIOD_INT_EN |= 0x2;
612 }
Mark Arigoe66ddd72008-01-09 07:24:43 +0000613}
Robert Kuklad6c23b42008-03-05 21:52:45 +0000614#else
615void button_init_device(void){}
616#endif /* bootloader */
Mark Arigoe66ddd72008-01-09 07:24:43 +0000617
618/*
619 * Get button pressed from hardware
620 */
621int button_read_device(void)
622{
Mark Arigod8290752008-02-24 04:12:16 +0000623 int btn = int_btn;
624
Robert Kuklad6c23b42008-03-05 21:52:45 +0000625 if(button_hold())
626 return BUTTON_NONE;
627
Mark Arigod8290752008-02-24 04:12:16 +0000628 if (~GPIOA_INPUT_VAL & 0x40)
Robert Kukla12cc3cc2008-01-10 21:51:44 +0000629 btn |= BUTTON_POWER;
Mark Arigod8290752008-02-24 04:12:16 +0000630
Robert Kukla12cc3cc2008-01-10 21:51:44 +0000631 return btn;
Mark Arigoe66ddd72008-01-09 07:24:43 +0000632}
633
634bool button_hold(void)
635{
Robert Kukla12cc3cc2008-01-10 21:51:44 +0000636 return (GPIOD_INPUT_VAL & 0x10) ? false : true;
Mark Arigoe66ddd72008-01-09 07:24:43 +0000637}
638
639bool headphones_inserted(void)
640{
Robert Kuklac865a9b2008-03-13 17:27:14 +0000641 return (GPIOD_INPUT_VAL & 0x80) ? false : true;
Mark Arigoe66ddd72008-01-09 07:24:43 +0000642}