diff options
Diffstat (limited to 'firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c')
-rw-r--r-- | firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c new file mode 100644 index 0000000000..3a6a748621 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c | |||
@@ -0,0 +1,461 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Tomasz Moń | ||
11 | * | ||
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. | ||
16 | * | ||
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 <stdio.h> | ||
23 | #include "config.h" | ||
24 | #include "system.h" | ||
25 | #include "kernel.h" | ||
26 | #include "logf.h" | ||
27 | #include "avr-sansaconnect.h" | ||
28 | #include "uart-target.h" | ||
29 | #include "button.h" | ||
30 | #include "backlight.h" | ||
31 | #include "powermgmt.h" | ||
32 | |||
33 | //#define BUTTON_DEBUG | ||
34 | |||
35 | #ifdef BUTTON_DEBUG | ||
36 | #include "lcd-target.h" | ||
37 | #include "lcd.h" | ||
38 | #include "font.h" | ||
39 | #include "common.h" | ||
40 | #endif | ||
41 | |||
42 | #ifdef BUTTON_DEBUG | ||
43 | #define dbgprintf DEBUGF | ||
44 | #else | ||
45 | #define dbgprintf(...) | ||
46 | #endif | ||
47 | |||
48 | #define CMD_SYNC 0xAA | ||
49 | #define CMD_CLOSE 0xCC | ||
50 | #define CMD_LCM_POWER 0xC9 | ||
51 | #define LCM_POWER_OFF 0x00 | ||
52 | #define LCM_POWER_ON 0x01 | ||
53 | #define LCM_POWER_SLEEP 0x02 | ||
54 | #define LCM_POWER_WAKE 0x03 | ||
55 | #define LCM_REPOWER_ON 0x04 | ||
56 | |||
57 | #define CMD_STATE 0xBB | ||
58 | #define CMD_VER 0xBC | ||
59 | #define CMD_WHEEL_EN 0xD0 | ||
60 | #define CMD_SET_INTCHRG 0xD1 | ||
61 | #define CMD_CODEC_RESET 0xD7 | ||
62 | #define CMD_FILL 0xFF | ||
63 | |||
64 | #define CMD_SYS_CTRL 0xDA | ||
65 | #define SYS_CTRL_POWEROFF 0x00 | ||
66 | |||
67 | /* protects spi avr commands from concurrent access */ | ||
68 | static struct mutex avr_mtx; | ||
69 | |||
70 | /* buttons thread */ | ||
71 | #define BTN_INTERRUPT 1 | ||
72 | static int btn = 0; | ||
73 | static bool hold_switch; | ||
74 | #ifndef BOOTLOADER | ||
75 | static long btn_stack[DEFAULT_STACK_SIZE/sizeof(long)]; | ||
76 | static const char btn_thread_name[] = "buttons"; | ||
77 | static struct event_queue btn_queue; | ||
78 | #endif | ||
79 | |||
80 | static inline unsigned short be2short(unsigned char* buf) | ||
81 | { | ||
82 | return (unsigned short)((buf[0] << 8) | buf[1]); | ||
83 | } | ||
84 | |||
85 | #define BUTTON_DIRECT_MASK (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN | BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_NEXT | BUTTON_PREV) | ||
86 | |||
87 | #ifndef BOOTLOADER | ||
88 | static void handle_wheel(unsigned char wheel) | ||
89 | { | ||
90 | static int key = 0; | ||
91 | static unsigned char velocity = 0; | ||
92 | static unsigned long wheel_delta = 1ul << 24; | ||
93 | static unsigned char wheel_prev = 0; | ||
94 | static long next_backlight_on = 0; | ||
95 | static int prev_key = -1; | ||
96 | static int prev_key_post = 0; | ||
97 | |||
98 | if (TIME_AFTER(current_tick, next_backlight_on)) | ||
99 | { | ||
100 | backlight_on(); | ||
101 | reset_poweroff_timer(); | ||
102 | next_backlight_on = current_tick + HZ/4; | ||
103 | } | ||
104 | |||
105 | if (wheel_prev < wheel) | ||
106 | { | ||
107 | key = BUTTON_SCROLL_FWD; | ||
108 | velocity = wheel - wheel_prev; | ||
109 | } | ||
110 | else if (wheel_prev > wheel) | ||
111 | { | ||
112 | key = BUTTON_SCROLL_BACK; | ||
113 | velocity = wheel_prev - wheel; | ||
114 | } | ||
115 | |||
116 | if (prev_key != key && velocity < 2 /* filter "rewinds" */) | ||
117 | { | ||
118 | /* direction reversal */ | ||
119 | prev_key = key; | ||
120 | wheel_delta = 1ul << 24; | ||
121 | return; | ||
122 | } | ||
123 | |||
124 | /* TODO: take velocity into account */ | ||
125 | if (queue_empty(&button_queue)) | ||
126 | { | ||
127 | if (prev_key_post == key) | ||
128 | { | ||
129 | key |= BUTTON_REPEAT; | ||
130 | } | ||
131 | |||
132 | /* Post directly, don't update btn as avr doesn't give | ||
133 | interrupt on scroll stop */ | ||
134 | queue_post(&button_queue, key, wheel_delta); | ||
135 | |||
136 | wheel_delta = 1ul << 24; | ||
137 | |||
138 | prev_key_post = key; | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | /* skipped post - increment delta and limit to 7 bits */ | ||
143 | wheel_delta += 1ul << 24; | ||
144 | |||
145 | if (wheel_delta > (0x7ful << 24)) | ||
146 | wheel_delta = 0x7ful << 24; | ||
147 | } | ||
148 | |||
149 | wheel_prev = wheel; | ||
150 | |||
151 | prev_key = key; | ||
152 | } | ||
153 | #endif | ||
154 | |||
155 | /* buf must be 11-byte array of byte (reply from avr_hid_get_state() */ | ||
156 | static void parse_button_state(unsigned char *buf) | ||
157 | { | ||
158 | unsigned short main_btns_state = be2short(&buf[4]); | ||
159 | #ifdef BUTTON_DEBUG | ||
160 | unsigned short main_btns_changed = be2short(&buf[6]); | ||
161 | #endif | ||
162 | |||
163 | /* make sure other bits doesn't conflict with our "free bits" buttons */ | ||
164 | main_btns_state &= BUTTON_DIRECT_MASK; | ||
165 | |||
166 | if (buf[3] & 0x01) /* is power button pressed? */ | ||
167 | { | ||
168 | main_btns_state |= BUTTON_POWER; | ||
169 | } | ||
170 | |||
171 | btn = main_btns_state; | ||
172 | |||
173 | #ifndef BOOTLOADER | ||
174 | /* check if stored hold_switch state changed (prevents lost changes) */ | ||
175 | if ((buf[3] & 0x20) /* hold change notification */ || | ||
176 | (hold_switch != ((buf[3] & 0x02) >> 1))) | ||
177 | { | ||
178 | #endif | ||
179 | hold_switch = (buf[3] & 0x02) >> 1; | ||
180 | #ifdef BUTTON_DEBUG | ||
181 | dbgprintf("HOLD changed (%d)", hold_switch); | ||
182 | #endif | ||
183 | #ifndef BOOTLOADER | ||
184 | backlight_hold_changed(hold_switch); | ||
185 | } | ||
186 | #endif | ||
187 | #ifndef BOOTLOADER | ||
188 | if ((hold_switch == false) && (buf[3] & 0x80)) /* scrollwheel change */ | ||
189 | { | ||
190 | handle_wheel(buf[2]); | ||
191 | } | ||
192 | #endif | ||
193 | |||
194 | #ifdef BUTTON_DEBUG | ||
195 | if (buf[3] & 0x10) /* power button change */ | ||
196 | { | ||
197 | /* power button state has changed */ | ||
198 | main_btns_changed |= BUTTON_POWER; | ||
199 | } | ||
200 | |||
201 | if (btn & BUTTON_LEFT) dbgprintf("LEFT"); | ||
202 | if (btn & BUTTON_UP) dbgprintf("UP"); | ||
203 | if (btn & BUTTON_RIGHT) dbgprintf("RIGHT"); | ||
204 | if (btn & BUTTON_DOWN) dbgprintf("DOWN"); | ||
205 | if (btn & BUTTON_SELECT) dbgprintf("SELECT"); | ||
206 | if (btn & BUTTON_VOL_UP) dbgprintf("VOL UP"); | ||
207 | if (btn & BUTTON_VOL_DOWN) dbgprintf("VOL DOWN"); | ||
208 | if (btn & BUTTON_NEXT) dbgprintf("NEXT"); | ||
209 | if (btn & BUTTON_PREV) dbgprintf("PREV"); | ||
210 | if (btn & BUTTON_POWER) dbgprintf("POWER"); | ||
211 | if (btn & BUTTON_HOLD) dbgprintf("HOLD"); | ||
212 | if (btn & BUTTON_SCROLL_FWD) dbgprintf("SCROLL FWD"); | ||
213 | if (btn & BUTTON_SCROLL_BACK) dbgprintf("SCROLL BACK"); | ||
214 | #endif | ||
215 | } | ||
216 | |||
217 | /* HID Slave Select - GIO14 */ | ||
218 | #define HID_SS (1<<14) | ||
219 | |||
220 | static inline void select_hid(bool on) | ||
221 | { | ||
222 | if (on == true) | ||
223 | { | ||
224 | /* SS is active low */ | ||
225 | IO_GIO_BITCLR0 = HID_SS; | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | IO_GIO_BITSET0 = HID_SS; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | static void spi_txrx(unsigned char *buf_tx, unsigned char *buf_rx, int n) | ||
234 | { | ||
235 | int i; | ||
236 | unsigned short rxdata; | ||
237 | |||
238 | mutex_lock(&avr_mtx); | ||
239 | |||
240 | bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF1); | ||
241 | IO_SERIAL1_TX_ENABLE = 0x0001; | ||
242 | select_hid(true); | ||
243 | |||
244 | for (i = 0; i<n; i++) | ||
245 | { | ||
246 | IO_SERIAL1_TX_DATA = buf_tx[i]; | ||
247 | udelay(100); | ||
248 | |||
249 | do | ||
250 | { | ||
251 | rxdata = IO_SERIAL1_RX_DATA; | ||
252 | } while (rxdata & (1<<8)); | ||
253 | |||
254 | if (buf_rx != NULL) | ||
255 | buf_rx[i] = rxdata & 0xFF; | ||
256 | |||
257 | //udelay(100); | ||
258 | } | ||
259 | |||
260 | select_hid(false); | ||
261 | IO_SERIAL1_TX_ENABLE = 0; | ||
262 | bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF1); | ||
263 | |||
264 | mutex_unlock(&avr_mtx); | ||
265 | } | ||
266 | |||
267 | static void avr_hid_sync(void) | ||
268 | { | ||
269 | int i; | ||
270 | unsigned char prg[4] = {CMD_SYNC, CMD_VER, CMD_FILL, CMD_CLOSE}; | ||
271 | |||
272 | /* Send SYNC three times */ | ||
273 | for (i = 0; i<3; i++) | ||
274 | { | ||
275 | spi_txrx(prg, NULL, sizeof(prg)); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | void avr_hid_init(void) | ||
280 | { | ||
281 | /* | ||
282 | setup alternate GIO functions: | ||
283 | GIO29 - SIF1 Enable | ||
284 | GIO30 - SIF1 Clock | ||
285 | GIO31 - SIF1 Data In | ||
286 | GIO32 - SIF1 Data Out | ||
287 | */ | ||
288 | IO_GIO_FSEL2 = (IO_GIO_FSEL2 & 0x00FF) | 0xAA00; | ||
289 | |||
290 | bitclr16(&IO_GIO_DIR0, HID_SS); /* set GIO14 as output */ | ||
291 | |||
292 | /* RATE = 219 (0xDB) -> 200 kHz */ | ||
293 | IO_SERIAL1_MODE = 0x6DB; | ||
294 | |||
295 | mutex_init(&avr_mtx); | ||
296 | |||
297 | avr_hid_sync(); | ||
298 | } | ||
299 | |||
300 | |||
301 | static void avr_hid_get_state(void) | ||
302 | { | ||
303 | static unsigned char cmd[11] = {CMD_SYNC, CMD_STATE, | ||
304 | CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, | ||
305 | CMD_CLOSE}; | ||
306 | |||
307 | static unsigned char buf[11]; | ||
308 | static unsigned char cmd_empty[1] = {0xCC}; | ||
309 | |||
310 | spi_txrx(cmd, buf, sizeof(cmd)); | ||
311 | |||
312 | spi_txrx(cmd_empty, NULL, 1); /* request interrupt on button press */ | ||
313 | |||
314 | parse_button_state(buf); | ||
315 | } | ||
316 | |||
317 | static void avr_hid_enable_wheel(void) | ||
318 | { | ||
319 | unsigned char wheel_en[4] = {CMD_SYNC, CMD_WHEEL_EN, 0x01, CMD_CLOSE}; | ||
320 | |||
321 | spi_txrx(wheel_en, NULL, sizeof(wheel_en)); | ||
322 | } | ||
323 | |||
324 | /* command that is sent by "hidtool -J 1" issued on every OF boot */ | ||
325 | void avr_hid_enable_charger(void) | ||
326 | { | ||
327 | unsigned char charger_en[4] = {CMD_SYNC, CMD_SET_INTCHRG, 0x01, CMD_CLOSE}; | ||
328 | |||
329 | spi_txrx(charger_en, NULL, sizeof(charger_en)); | ||
330 | } | ||
331 | |||
332 | void avr_hid_lcm_sleep(void) | ||
333 | { | ||
334 | unsigned char lcm_sleep[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_SLEEP, CMD_CLOSE}; | ||
335 | |||
336 | spi_txrx(lcm_sleep, NULL, sizeof(lcm_sleep)); | ||
337 | } | ||
338 | |||
339 | |||
340 | void avr_hid_lcm_wake(void) | ||
341 | { | ||
342 | unsigned char lcm_wake[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_WAKE, CMD_CLOSE}; | ||
343 | |||
344 | spi_txrx(lcm_wake, NULL, sizeof(lcm_wake)); | ||
345 | } | ||
346 | |||
347 | void avr_hid_lcm_power_on(void) | ||
348 | { | ||
349 | unsigned char lcm_power_on[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_ON, CMD_CLOSE}; | ||
350 | |||
351 | spi_txrx(lcm_power_on, NULL, sizeof(lcm_power_on)); | ||
352 | } | ||
353 | |||
354 | void avr_hid_lcm_power_off(void) | ||
355 | { | ||
356 | unsigned char lcm_power_off[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_OFF, CMD_CLOSE}; | ||
357 | |||
358 | spi_txrx(lcm_power_off, NULL, sizeof(lcm_power_off)); | ||
359 | } | ||
360 | |||
361 | void avr_hid_reset_codec(void) | ||
362 | { | ||
363 | unsigned char codec_reset[4] = {CMD_SYNC, CMD_CODEC_RESET, CMD_CLOSE, CMD_FILL}; | ||
364 | |||
365 | spi_txrx(codec_reset, NULL, sizeof(codec_reset)); | ||
366 | } | ||
367 | |||
368 | void avr_hid_power_off(void) | ||
369 | { | ||
370 | unsigned char prg[4] = {CMD_SYNC, CMD_SYS_CTRL, SYS_CTRL_POWEROFF, CMD_CLOSE}; | ||
371 | |||
372 | spi_txrx(prg, NULL, sizeof(prg)); | ||
373 | } | ||
374 | |||
375 | #ifndef BOOTLOADER | ||
376 | void btn_thread(void) | ||
377 | { | ||
378 | struct queue_event ev; | ||
379 | |||
380 | while (1) | ||
381 | { | ||
382 | queue_wait(&btn_queue, &ev); | ||
383 | |||
384 | /* Ignore all messages except BTN_INTERRUPT */ | ||
385 | if (ev.id != BTN_INTERRUPT) | ||
386 | continue; | ||
387 | |||
388 | /* Enable back button interrupt */ | ||
389 | IO_INTC_EINT1 |= INTR_EINT1_EXT0; | ||
390 | |||
391 | /* Read buttons state */ | ||
392 | avr_hid_get_state(); | ||
393 | |||
394 | yield(); | ||
395 | |||
396 | if (queue_empty(&btn_queue) && ((IO_GIO_BITSET0 & 0x1) == 0)) | ||
397 | { | ||
398 | /* for some reason we have lost next interrupt */ | ||
399 | queue_post(&btn_queue, BTN_INTERRUPT, 0); | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | |||
404 | void GIO0(void) __attribute__ ((section(".icode"))); | ||
405 | void GIO0(void) | ||
406 | { | ||
407 | /* Clear interrupt */ | ||
408 | IO_INTC_IRQ1 = (1 << 5); | ||
409 | /* Disable interrupt */ | ||
410 | IO_INTC_EINT1 &= ~INTR_EINT1_EXT0; | ||
411 | |||
412 | /* interrupt will be enabled back after button read */ | ||
413 | queue_post(&btn_queue, BTN_INTERRUPT, 0); | ||
414 | } | ||
415 | #endif | ||
416 | |||
417 | void button_init_device(void) | ||
418 | { | ||
419 | btn = 0; | ||
420 | hold_switch = false; | ||
421 | #ifndef BOOTLOADER | ||
422 | queue_init(&btn_queue, true); | ||
423 | create_thread(btn_thread, btn_stack, sizeof(btn_stack), 0, | ||
424 | btn_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) | ||
425 | IF_COP(, CPU)); | ||
426 | #endif | ||
427 | IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */ | ||
428 | |||
429 | /* Enable wheel */ | ||
430 | avr_hid_enable_wheel(); | ||
431 | /* Read button status and tell avr we want interrupt on next change */ | ||
432 | avr_hid_get_state(); | ||
433 | |||
434 | #ifndef BOOTLOADER | ||
435 | IO_GIO_IRQPORT |= 0x01; /* Enable GIO0 external interrupt */ | ||
436 | IO_GIO_INV0 &= ~0x01; /* Clear INV for GIO0 (falling edge detection) */ | ||
437 | IO_GIO_IRQEDGE &= ~0x01; /* Set edge detection (falling) */ | ||
438 | |||
439 | /* Enable GIO0 interrupt */ | ||
440 | IO_INTC_EINT1 |= INTR_EINT1_EXT0; | ||
441 | #endif | ||
442 | } | ||
443 | |||
444 | int button_read_device(void) | ||
445 | { | ||
446 | if(hold_switch) | ||
447 | return 0; | ||
448 | else | ||
449 | return btn; | ||
450 | } | ||
451 | |||
452 | bool button_hold(void) | ||
453 | { | ||
454 | return hold_switch; | ||
455 | } | ||
456 | |||
457 | void lcd_enable(bool on) | ||
458 | { | ||
459 | (void)on; | ||
460 | } | ||
461 | |||