summaryrefslogtreecommitdiff
path: root/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
diff options
context:
space:
mode:
authorTomasz Moń <desowin@gmail.com>2011-11-16 14:08:01 +0000
committerTomasz Moń <desowin@gmail.com>2011-11-16 14:08:01 +0000
commite8a8a1be43afe63079ae48ce1a9eb3052df3b1a4 (patch)
tree084e1cdf27a339ce58e24cff8fec8c31432b52db /firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
parent992d4eb775cac48e107e18d72783ebfb39c4234f (diff)
downloadrockbox-e8a8a1be43afe63079ae48ce1a9eb3052df3b1a4.tar.gz
rockbox-e8a8a1be43afe63079ae48ce1a9eb3052df3b1a4.zip
Sandisk Sansa Connect port (FS #12363)
Included are drivers for buttons, backlight, lcd, audio and storage. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31000 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c')
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c461
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 */
68static struct mutex avr_mtx;
69
70/* buttons thread */
71#define BTN_INTERRUPT 1
72static int btn = 0;
73static bool hold_switch;
74#ifndef BOOTLOADER
75static long btn_stack[DEFAULT_STACK_SIZE/sizeof(long)];
76static const char btn_thread_name[] = "buttons";
77static struct event_queue btn_queue;
78#endif
79
80static 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
88static 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() */
156static 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
220static 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
233static 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
267static 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
279void 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
301static 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
317static 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 */
325void 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
332void 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
340void 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
347void 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
354void 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
361void 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
368void 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
376void 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
404void GIO0(void) __attribute__ ((section(".icode")));
405void 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
417void 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
444int button_read_device(void)
445{
446 if(hold_switch)
447 return 0;
448 else
449 return btn;
450}
451
452bool button_hold(void)
453{
454 return hold_switch;
455}
456
457void lcd_enable(bool on)
458{
459 (void)on;
460}
461