summaryrefslogtreecommitdiff
path: root/firmware/target/arm/olympus/mrobe-100/button-mr100.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/olympus/mrobe-100/button-mr100.c')
-rw-r--r--firmware/target/arm/olympus/mrobe-100/button-mr100.c564
1 files changed, 556 insertions, 8 deletions
diff --git a/firmware/target/arm/olympus/mrobe-100/button-mr100.c b/firmware/target/arm/olympus/mrobe-100/button-mr100.c
index 49561cb8d7..43db2c5f6d 100644
--- a/firmware/target/arm/olympus/mrobe-100/button-mr100.c
+++ b/firmware/target/arm/olympus/mrobe-100/button-mr100.c
@@ -27,14 +27,562 @@
27#include "backlight-target.h" 27#include "backlight-target.h"
28#include "system.h" 28#include "system.h"
29 29
30void button_init_device(void) 30#define LOGF_ENABLE
31#include "logf.h"
32
33/* Driver for the Synaptics Touchpad based on the "Synaptics Modular Embedded
34 Protocol: 3-Wire Interface Specification" documentation */
35
36#define ACK (GPIOD_INPUT_VAL & 0x1)
37#define ACK_HI GPIOD_OUTPUT_VAL |= 0x1
38#define ACK_LO GPIOD_OUTPUT_VAL &= ~0x1
39
40#define CLK ((GPIOD_INPUT_VAL & 0x2) >> 1)
41#define CLK_HI GPIOD_OUTPUT_VAL |= 0x2
42#define CLK_LO GPIOD_OUTPUT_VAL &= ~0x2
43
44#define DATA ((GPIOD_INPUT_VAL & 0x4) >> 2)
45#define DATA_HI GPIOD_OUTPUT_EN |= 0x4; GPIOD_OUTPUT_VAL |= 0x4
46#define DATA_LO GPIOD_OUTPUT_EN |= 0x4; GPIOD_OUTPUT_VAL &= ~0x4
47
48#define LO 0
49#define HI 1
50
51#define STATUS_READY 1
52#define READ_RETRY 8
53#define READ_ERROR -1
54
55#define HELLO_HEADER 0x19
56#define HELLO_ID 0x1
57#define BUTTONS_HEADER 0x1a
58#define BUTTONS_ID 0x9
59#define ABSOLUTE_HEADER 0x0b
60
61static int syn_status = 0;
62static int int_btn = BUTTON_NONE;
63
64static int syn_wait_clk_change(unsigned int val)
65{
66 int i;
67
68 for (i = 0; i < 10000; i++)
69 {
70 if (CLK == val)
71 return 1;
72 }
73
74 return 0;
75}
76
77static inline int syn_get_data(void)
78{
79 GPIOD_OUTPUT_EN &= ~0x4;
80 return DATA;
81}
82
83static void syn_wait_guest_flush(void)
84{
85 /* Flush receiving (flushee) state:
86 handshake until DATA goes high during P3 stage */
87 if (CLK == LO)
88 {
89 ACK_HI; /* P1 -> P2 */
90 syn_wait_clk_change(HI); /* P2 -> P3 */
91 }
92
93 while (syn_get_data() == LO)
94 {
95 ACK_HI; /* P3 -> P0 */
96 syn_wait_clk_change(LO); /* P0 -> P1 */
97 ACK_LO; /* P1 -> P2 */
98 syn_wait_clk_change(HI); /* P2 -> P3 */
99 }
100
101 /* Continue handshaking until back to P0 */
102 ACK_HI; /* P3 -> P0 */
103}
104
105static void syn_flush(void)
106{
107 int i;
108
109 logf("syn_flush...");
110
111 /* Flusher holds DATA low for at least 36 handshake cycles */
112 DATA_LO;
113
114 for (i = 0; i < 36; i++)
115 {
116 syn_wait_clk_change(LO); /* P0 -> P1 */
117 ACK_LO; /* P1 -> P2 */
118 syn_wait_clk_change(HI); /* P2 -> P3 */
119 ACK_HI; /* P3 -> P0 */
120 }
121
122 /* Raise DATA in P1 stage */
123 syn_wait_clk_change(LO); /* P0 -> P1 */
124 DATA_HI;
125
126 /* After a flush, the flushing device enters a flush-receiving (flushee)
127 state */
128 syn_wait_guest_flush();
129}
130
131static int syn_send_data(int *data, int len)
132{
133 int i, bit;
134 int parity = 0;
135
136 logf("syn_send_data...");
137
138 /* 1. Lower DATA line to issue a request-to-send to guest */
139 DATA_LO;
140
141 /* 2. Wait for guest to lower CLK */
142 syn_wait_clk_change(LO);
143
144 /* 3. Lower ACK (with DATA still low) */
145 ACK_LO;
146
147 /* 4. Wait for guest to raise CLK */
148 syn_wait_clk_change(HI);
149
150 /* 5. Send data */
151 for (i = 0; i < len; i++)
152 {
153 logf(" sending byte: %d", data[i]);
154
155 bit = 0;
156 while (bit < 8)
157 {
158 /* 5a. Drive data low if bit is 0, or high if bit is 1 */
159 if (data[i] & (1 << bit))
160 {
161 DATA_HI;
162 parity++;
163 }
164 else
165 {
166 DATA_LO;
167 }
168 bit++;
169
170 /* 5b. Invert ACK to indicate that the data bit is ready */
171 ACK_HI;
172
173 /* 5c. Wait for guest to invert CLK */
174 syn_wait_clk_change(LO);
175
176 /* Repeat for next bit */
177 if (data[i] & (1 << bit))
178 {
179 DATA_HI;
180 parity++;
181 }
182 else
183 {
184 DATA_LO;
185 }
186 bit++;
187
188 ACK_LO;
189
190 syn_wait_clk_change(HI);
191 }
192 }
193
194 /* 7. Transmission termination sequence: */
195 /* 7a. Host may put parity bit on DATA. Hosts that do not generate
196 parity should set DATA high. Parity is 1 if there's an odd
197 number of '1' bits, or 0 if there's an even number of '1' bits. */
198 parity = parity % 2;
199 logf(" send parity = %d", parity);
200 if (parity)
201 {
202 DATA_HI;
203 }
204 else
205 {
206 DATA_LO;
207 }
208
209 /* 7b. Raise ACK to indicate that the optional parity bit is ready */
210 ACK_HI;
211
212 /* 7c. Guest lowers CLK */
213 syn_wait_clk_change(LO);
214
215 /* 7d. Pull DATA high (if parity bit was 0) */
216 DATA_HI;
217
218 /* 7e. Lower ACK to indicate that the stop bit is ready */
219 ACK_LO;
220
221 /* 7f. Guest raises CLK */
222 syn_wait_clk_change(HI);
223
224 /* 7g. If DATA is low, guest is flushing this transfer. Host should
225 enter the flushee state. */
226 if (syn_get_data() == LO)
227 {
228 logf(" module flushing");
229 syn_wait_guest_flush();
230 return -1;
231 }
232
233 /* 7h. Host raises ACK and the link enters the idle state */
234 ACK_HI;
235
236 return len;
237}
238
239static int syn_read_data(int *data, int data_len)
31{ 240{
32 /* taken from the mr-100 bootloader (offset 0x1e72) */ 241 int i, len, bit, parity, tmp;
33 //~ DEV_EN |= 0x20000; /* enable the touchpad ?? */ 242 int *data_ptr;
243
244 logf("syn_read_data...");
245
246 /* 1. Guest drives CLK low */
247 if (CLK != LO)
248 return 0;
249
250 /* 1a. If the host is willing to receive a packet it lowers ACK */
251 ACK_LO;
252
253 /* 2. Guest may issue a request-to-send by lowering DATA. If the
254 guest decides not to transmit a packet, it may abort the
255 transmission by not lowering DATA. */
256
257 /* 3. The guest raises CLK */
258 syn_wait_clk_change(HI);
259
260 /* 4. If the guest is still driving DATA low, the transfer is commited
261 to occur. Otherwise, the transfer is aborted. In either case,
262 the host raises ACK. */
263 if (syn_get_data() == HI)
264 {
265 logf(" read abort");
266
267 ACK_HI;
268 return READ_ERROR;
269 }
270 else
271 {
272 ACK_HI;
273 }
274
275 /* 5. Read the incoming data packet */
276 i = 0;
277 len = 0;
278 parity = 0;
279 while (i <= len)
280 {
281 bit = 0;
282
283 if (i < data_len)
284 data_ptr = &data[i];
285 else
286 data_ptr = &tmp;
287
288 *data_ptr = 0;
289 while (bit < 8)
290 {
291 /* 5b. Guset inverts CLK to indicate that data is ready */
292 syn_wait_clk_change(LO);
293
294 /* 5d. Read the data bit from DATA */
295 if (syn_get_data() == HI)
296 {
297 *data_ptr |= (1 << bit);
298 parity++;
299 }
300 bit++;
34 301
302 /* 5e. Invert ACK to indicate that data has been read */
303 ACK_LO;
304
305 /* Repeat for next bit */
306 syn_wait_clk_change(HI);
307
308 if (syn_get_data() == HI)
309 {
310 *data_ptr |= (1 << bit);
311 parity++;
312 }
313 bit++;
314
315 ACK_HI;
316 }
317
318 /* First byte is the packet header */
319 if (i == 0)
320 {
321 /* Format control (bit 3) should be 1 */
322 if (*data_ptr & 0x8)
323 {
324 /* Packet length is bits 0:2 */
325 len = *data_ptr & 0x7;
326 logf(" packet length = %d", len);
327 }
328 else
329 {
330 logf(" invalid format ctrl bit");
331 return READ_ERROR;
332 }
333 }
334
335 i++;
336 }
337
338 /* 7. Transmission termination cycle */
339 /* 7a. The guest generates a parity bit on DATA */
340 /* 7b. The host waits for guest to lower CLK */
341 syn_wait_clk_change(LO);
342
343 /* 7c. The host verifies the parity bit is correct */
344 parity = parity % 2;
345 logf(" parity check: %d / %d", syn_get_data(), parity);
346 /* TODO: parity error handling */
347
348 /* 7d. The host lowers ACK */
349 ACK_LO;
350
351 /* 7e. The host waits for the guest to raise CLK indicating
352 that the stop bit is ready */
353 syn_wait_clk_change(HI);
354
355 /* 7f. The host reads DATA and verifies that it is 1 */
356 if (syn_get_data() == LO)
357 {
358 logf(" framing error");
359
360 ACK_HI;
361 return READ_ERROR;
362 }
363
364 ACK_HI;
365
366 return len;
367}
368
369static int syn_read_device(int *data, int len)
370{
371 int i;
372 int ret = READ_ERROR;
373
374 for (i = 0; i < READ_RETRY; i++)
375 {
376 if (syn_wait_clk_change(LO))
377 {
378 /* module is sending data */
379 ret = syn_read_data(data, len);
380 if (ret != READ_ERROR)
381 return ret;
382
383 syn_flush();
384 }
385 else
386 {
387 /* module is idle */
388 return 0;
389 }
390 }
391
392 return ret;
393}
394
395static int syn_reset(void)
396{
397 int val, id;
398 int data[2];
399
400 logf("syn_reset...");
401
402 /* reset module 0 */
403 val = (0 << 4) | (1 << 3) | 0;
404 syn_send_data(&val, 1);
405
406 val = syn_read_device(data, 2);
407 if (val == 1)
408 {
409 val = data[0] & 0xff; /* packet header */
410 id = (data[1] >> 4) & 0xf; /* packet id */
411 if ((val == HELLO_HEADER) && (id == HELLO_ID))
412 {
413 logf(" module 0 reset");
414 return 1;
415 }
416 }
417
418 logf(" reset failed");
419 return 0;
420}
421
422#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
423static void syn_info(void)
424{
425 int i, val;
426 int data[8];
427
428 logf("syn_info...");
429
430 /* module base info */
431 logf("module base info:");
432 data[0] = (0 << 4) | (0 << 3) | 1;
433 data[1] = 0x80;
434 syn_send_data(data, 2);
435 val = syn_read_device(data, 8);
436 if (val > 0)
437 {
438 for (i = 0; i < 8; i++)
439 logf(" data[%d] = 0x%02x", i, data[i]);
440 }
441
442 /* module product info */
443 logf("module product info:");
444 data[0] = (0 << 4) | (0 << 3) | 1;
445 data[1] = 0x81;
446 syn_send_data(data, 2);
447 val = syn_read_device(data, 8);
448 if (val > 0)
449 {
450 for (i = 0; i < 8; i++)
451 logf(" data[%d] = 0x%02x", i, data[i]);
452 }
453
454 /* module serialization */
455 logf("module serialization:");
456 data[0] = (0 << 4) | (0 << 3) | 1;
457 data[1] = 0x82;
458 syn_send_data(data, 2);
459 val = syn_read_device(data, 8);
460 if (val > 0)
461 {
462 for (i = 0; i < 8; i++)
463 logf(" data[%d] = 0x%02x", i, data[i]);
464 }
465
466 /* 1-D sensor info */
467 logf("1-d sensor info:");
468 data[0] = (0 << 4) | (0 << 3) | 1;
469 data[1] = 0x80 + 0x20;
470 syn_send_data(data, 2);
471 val = syn_read_device(data, 8);
472 if (val > 0)
473 {
474 for (i = 0; i < 8; i++)
475 logf(" data[%d] = 0x%02x", i, data[i]);
476 }
477}
478#endif
479
480void button_init_device(void)
481{
35 /* enable touchpad leds */ 482 /* enable touchpad leds */
36 GPIOA_ENABLE |= 0xff; 483 GPIOA_ENABLE |= BUTTONLIGHT_ALL;
37 GPIOA_OUTPUT_EN |= BUTTONLIGHT_ALL; 484 GPIOA_OUTPUT_EN |= BUTTONLIGHT_ALL;
485
486 /* enable touchpad */
487 GPO32_ENABLE |= 0x40000000;
488 GPO32_VAL &= ~0x40000000;
489
490 /* enable ACK, CLK, DATA lines */
491 GPIOD_ENABLE |= (0x1 | 0x2 | 0x4);
492
493 GPIOD_OUTPUT_EN |= 0x1; /* ACK */
494 GPIOD_OUTPUT_VAL |= 0x1; /* high */
495
496 GPIOD_OUTPUT_EN &= ~0x2; /* CLK */
497
498 GPIOD_OUTPUT_EN |= 0x4; /* DATA */
499 GPIOD_OUTPUT_VAL |= 0x4; /* high */
500
501 syn_flush();
502
503 if (syn_reset())
504 {
505#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
506 syn_info();
507#endif
508
509 syn_status = STATUS_READY;
510
511 /* enable interrupts */
512 GPIOD_INT_LEV &= ~0x2;
513 GPIOD_INT_CLR |= 0x2;
514 GPIOD_INT_EN |= 0x2;
515
516 CPU_INT_EN |= HI_MASK;
517 CPU_HI_INT_EN |= GPIO0_MASK;
518 }
519}
520
521/*
522 * Button interrupt handler
523 */
524void button_int(void)
525{
526 int data[4];
527 int val, id;
528
529 int_btn = BUTTON_NONE;
530
531 if (syn_status == STATUS_READY)
532 {
533 /* disable interrupt while we read the touchpad */
534 GPIOD_INT_EN &= ~0x2;
535
536 val = syn_read_device(data, 4);
537 if (val > 0)
538 {
539 val = data[0] & 0xff; /* packet header */
540 id = (data[1] >> 4) & 0xf; /* packet id */
541
542 logf("button_read_device...");
543 logf(" data[0] = 0x%08x", data[0]);
544 logf(" data[1] = 0x%08x", data[1]);
545 logf(" data[2] = 0x%08x", data[2]);
546 logf(" data[3] = 0x%08x", data[3]);
547
548 if ((val == BUTTONS_HEADER) && (id == BUTTONS_ID))
549 {
550 /* Buttons packet - touched one of the 5 "buttons" */
551 if (data[1] & 0x1)
552 int_btn |= BUTTON_PLAY;
553 if (data[1] & 0x2)
554 int_btn |= BUTTON_MENU;
555 if (data[1] & 0x4)
556 int_btn |= BUTTON_LEFT;
557 if (data[1] & 0x8)
558 int_btn |= BUTTON_DISPLAY;
559 if (data[2] & 0x1)
560 int_btn |= BUTTON_RIGHT;
561
562 /* An Absolute packet should follow which we ignore */
563 val = syn_read_device(data, 4);
564
565 logf(" int_btn = 0x%04x", int_btn);
566 }
567 else if (val == ABSOLUTE_HEADER)
568 {
569 /* Absolute packet - the finger is on the vertical strip.
570 Position ranges from 1-4095, with 1 at the bottom. */
571 val = ((data[1] >> 4) << 8) | data[2]; /* position */
572 if ((val > 0) && (val <= 1365))
573 int_btn |= BUTTON_DOWN;
574 else if ((val > 1365) && (val <= 2730))
575 int_btn |= BUTTON_SELECT;
576 else if ((val > 2730) && (val <= 4095))
577 int_btn |= BUTTON_UP;
578 }
579 }
580
581 /* re-enable interrupts */
582 GPIOD_INT_LEV &= ~0x2;
583 GPIOD_INT_CLR |= 0x2;
584 GPIOD_INT_EN |= 0x2;
585 }
38} 586}
39 587
40/* 588/*
@@ -42,11 +590,11 @@ void button_init_device(void)
42 */ 590 */
43int button_read_device(void) 591int button_read_device(void)
44{ 592{
45 int btn = BUTTON_NONE; 593 int btn = int_btn;
46 594
47 if(~GPIOA_INPUT_VAL & 0x40) 595 if (~GPIOA_INPUT_VAL & 0x40)
48 btn |= BUTTON_POWER; 596 btn |= BUTTON_POWER;
49 597
50 return btn; 598 return btn;
51} 599}
52 600