blob: a723ce89bad5e07083b2cdc1138e443748a07206 [file] [log] [blame]
Amaury Pouly08fb3f62011-05-01 13:02:46 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Amaury Pouly
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#include "button-target.h"
Amaury Poulyffee0b52011-05-04 18:00:22 +000022#include "system.h"
23#include "system-target.h"
24#include "pinctrl-imx233.h"
Amaury Pouly86e8c282011-05-11 22:38:09 +000025#include "generic_i2c.h"
26#include "synaptics-rmi.h"
27#include "lcd.h"
Amaury Poulya43509c2011-05-13 16:40:22 +000028#include "string.h"
Amaury Poulyf5d664a2011-10-27 10:38:19 +000029#include "usb.h"
Amaury Pouly86e8c282011-05-11 22:38:09 +000030
Amaury Pouly88f75d02011-07-02 02:21:06 +000031#ifndef BOOTLOADER
Amaury Pouly86e8c282011-05-11 22:38:09 +000032
Amaury Pouly7e211ff2011-11-17 19:13:09 +000033bool button_debug_screen(void)
Amaury Pouly86e8c282011-05-11 22:38:09 +000034{
35 char product_id[RMI_PRODUCT_ID_LEN];
36 rmi_read(RMI_PRODUCT_ID, RMI_PRODUCT_ID_LEN, product_id);
Amaury Poulya43509c2011-05-13 16:40:22 +000037 int x_max = rmi_read_single(RMI_2D_SENSOR_XMAX_MSB(0)) << 8 | rmi_read_single(RMI_2D_SENSOR_XMAX_LSB(0));
38 int y_max = rmi_read_single(RMI_2D_SENSOR_YMAX_MSB(0)) << 8 | rmi_read_single(RMI_2D_SENSOR_YMAX_LSB(0));
39 int func_presence = rmi_read_single(RMI_FUNCTION_PRESENCE(RMI_2D_TOUCHPAD_FUNCTION));
40 int sensor_prop = rmi_read_single(RMI_2D_SENSOR_PROP2(0));
41 int sensor_resol = rmi_read_single(RMI_2D_SENSOR_RESOLUTION(0));
42 int min_dist = rmi_read_single(RMI_2D_MIN_DIST);
43 int gesture_settings = rmi_read_single(RMI_2D_GESTURE_SETTINGS);
Amaury Pouly374a08a2011-11-30 18:39:22 +000044 int sensibility_counter = 0;
Amaury Poulya43509c2011-05-13 16:40:22 +000045 union
46 {
47 unsigned char data;
48 signed char value;
49 }sensitivity;
50 rmi_read(RMI_2D_SENSITIVITY_ADJ, 1, &sensitivity.data);
Amaury Pouly86e8c282011-05-11 22:38:09 +000051
Amaury Poulya43509c2011-05-13 16:40:22 +000052 /* Device to screen */
53 int zone_w = LCD_WIDTH;
54 int zone_h = (zone_w * y_max + x_max - 1) / x_max;
55 int zone_x = 0;
56 int zone_y = LCD_HEIGHT - zone_h;
57 #define DX2SX(x) (((x) * zone_w ) / x_max)
58 #define DY2SY(y) (zone_h - ((y) * zone_h ) / y_max)
59 struct viewport report_vp;
60 memset(&report_vp, 0, sizeof(report_vp));
61 report_vp.x = zone_x;
62 report_vp.y = zone_y;
63 report_vp.width = zone_w;
64 report_vp.height = zone_h;
65 struct viewport gesture_vp;
66 memset(&gesture_vp, 0, sizeof(gesture_vp));
Amaury Pouly7e211ff2011-11-17 19:13:09 +000067 gesture_vp.x = LCD_WIDTH / 2;
Amaury Poulya43509c2011-05-13 16:40:22 +000068 gesture_vp.y = zone_y - 80;
Amaury Pouly7e211ff2011-11-17 19:13:09 +000069 gesture_vp.width = LCD_WIDTH / 2;
Amaury Poulya43509c2011-05-13 16:40:22 +000070 gesture_vp.height = 80;
71
Amaury Pouly86e8c282011-05-11 22:38:09 +000072 while(1)
73 {
Amaury Poulya43509c2011-05-13 16:40:22 +000074 lcd_set_viewport(NULL);
Amaury Pouly86e8c282011-05-11 22:38:09 +000075 lcd_clear_display();
76 int btns = button_read_device();
77 lcd_putsf(0, 0, "button bitmap: %x", btns);
Amaury Poulya43509c2011-05-13 16:40:22 +000078 lcd_putsf(0, 1, "RMI: id=%s p=%x s=%x", product_id, func_presence, sensor_prop);
79 lcd_putsf(0, 2, "xmax=%d ymax=%d res=%d", x_max, y_max, sensor_resol);
80 lcd_putsf(0, 3, "attn=%d ctl=%x int=%x",
81 imx233_get_gpio_input_mask(0, 0x08000000) ? 0 : 1,
82 rmi_read_single(RMI_DEVICE_CONTROL),
83 rmi_read_single(RMI_INTERRUPT_REQUEST));
84 lcd_putsf(0, 4, "sensi: %d min_dist: %d", (int)sensitivity.value, min_dist);
85 lcd_putsf(0, 5, "gesture: %x", gesture_settings);
86
Amaury Pouly86e8c282011-05-11 22:38:09 +000087 union
88 {
89 unsigned char data[10];
90 struct
91 {
Amaury Poulya43509c2011-05-13 16:40:22 +000092 struct rmi_2d_absolute_data_t absolute;
93 struct rmi_2d_relative_data_t relative;
94 struct rmi_2d_gesture_data_t gesture;
95 }s;
Amaury Pouly86e8c282011-05-11 22:38:09 +000096 }u;
Amaury Poulya43509c2011-05-13 16:40:22 +000097 int absolute_x = u.s.absolute.x_msb << 8 | u.s.absolute.x_lsb;
98 int absolute_y = u.s.absolute.y_msb << 8 | u.s.absolute.y_lsb;
99 int nr_fingers = u.s.absolute.misc & 7;
100 bool gesture = (u.s.absolute.misc & 8) == 8;
101 int palm_width = u.s.absolute.misc >> 4;
Amaury Pouly86e8c282011-05-11 22:38:09 +0000102 rmi_read(RMI_DATA_REGISTER(0), 10, u.data);
Amaury Poulya43509c2011-05-13 16:40:22 +0000103 lcd_putsf(0, 6, "abs: %d %d %d", absolute_x, absolute_y, (int)u.s.absolute.z);
104 lcd_putsf(0, 7, "rel: %d %d", (int)u.s.relative.x, (int)u.s.relative.y);
105 lcd_putsf(0, 8, "gesture: %x %x", u.s.gesture.misc, u.s.gesture.flick);
106 lcd_putsf(0, 9, "misc: w=%d g=%d f=%d", palm_width, gesture, nr_fingers);
107
108 lcd_set_viewport(&report_vp);
109 lcd_set_drawinfo(DRMODE_SOLID, LCD_RGBPACK(0xff, 0, 0), LCD_BLACK);
110 lcd_drawrect(0, 0, zone_w, zone_h);
111 if(nr_fingers == 1)
112 {
113 lcd_set_drawinfo(DRMODE_SOLID, LCD_RGBPACK(0, 0, 0xff), LCD_BLACK);
114 lcd_drawline(DX2SX(absolute_x) - u.s.relative.x,
115 DY2SY(absolute_y) + u.s.relative.y,
116 DX2SX(absolute_x), DY2SY(absolute_y));
117 lcd_set_drawinfo(DRMODE_SOLID, LCD_RGBPACK(0, 0xff, 0), LCD_BLACK);
118 lcd_fillrect(DX2SX(absolute_x) - 1, DY2SY(absolute_y) - 1, 3, 3);
119 }
120 lcd_set_viewport(&gesture_vp);
121 lcd_set_drawinfo(DRMODE_SOLID, LCD_RGBPACK(0xff, 0xff, 0), LCD_BLACK);
122 if(u.s.gesture.misc & RMI_2D_GEST_MISC_CONFIRMED)
123 {
124 switch(u.s.gesture.misc & RMI_2D_GEST_MISC_TAP_CODE_BM)
125 {
126 case RMI_2D_GEST_MISC_NO_TAP: break;
127 case RMI_2D_GEST_MISC_SINGLE_TAP:
128 lcd_putsf(0, 0, "TAP!");
129 break;
130 case RMI_2D_GEST_MISC_DOUBLE_TAP:
131 lcd_putsf(0, 0, "DOUBLE TAP!");
132 break;
133 case RMI_2D_GEST_MISC_TAP_AND_HOLD:
134 lcd_putsf(0, 0, "TAP & HOLD!");
135 break;
136 default: break;
137 }
138
139 if(u.s.gesture.misc & RMI_2D_GEST_MISC_FLICK)
140 {
141 lcd_putsf(0, 1, "FLICK!");
142 int flick_x = u.s.gesture.flick & RMI_2D_GEST_FLICK_X_BM;
143 int flick_y = (u.s.gesture.flick & RMI_2D_GEST_FLICK_Y_BM) >> RMI_2D_GEST_FLICK_Y_BP;
144 #define SIGN4EXT(a) \
145 if(a & 8) a = -((a ^ 0xf) + 1);
146 SIGN4EXT(flick_x);
147 SIGN4EXT(flick_y);
148
149 int center_x = (LCD_WIDTH * 2) / 3;
150 int center_y = 40;
151 lcd_drawline(center_x, center_y, center_x + flick_x * 5, center_y - flick_y * 5);
152 }
153 }
Amaury Pouly86e8c282011-05-11 22:38:09 +0000154 lcd_update();
155
156 if(btns & BUTTON_POWER)
157 break;
Amaury Poulya43509c2011-05-13 16:40:22 +0000158 if(btns & BUTTON_VOL_DOWN || btns & BUTTON_VOL_UP)
159 {
160 if(btns & BUTTON_VOL_UP)
Amaury Pouly374a08a2011-11-30 18:39:22 +0000161 sensibility_counter++;
Amaury Poulya43509c2011-05-13 16:40:22 +0000162 if(btns & BUTTON_VOL_DOWN)
Amaury Pouly374a08a2011-11-30 18:39:22 +0000163 sensibility_counter--;
164 if((sensibility_counter == -15) || (sensibility_counter == 15))
165 {
166 sensitivity.value += (sensibility_counter / 15);
167 sensibility_counter = 0;
168 }
169 rmi_write(RMI_2D_SENSITIVITY_ADJ, 1, &sensitivity.data);
Amaury Poulya43509c2011-05-13 16:40:22 +0000170 }
171
Amaury Pouly86e8c282011-05-11 22:38:09 +0000172 yield();
173 }
Amaury Pouly7e211ff2011-11-17 19:13:09 +0000174
175 return true;
Amaury Pouly86e8c282011-05-11 22:38:09 +0000176}
Amaury Pouly08fb3f62011-05-01 13:02:46 +0000177
Amaury Pouly09b4c762011-10-02 14:44:31 +0000178struct button_area_t
179{
180 /* define a rectangle region */
181 int lx, ly;
182 int rx, ry;
183 int button;
184};
185
186static struct button_area_t button_areas[] =
187{
Amaury Pouly374a08a2011-11-30 18:39:22 +0000188 {1003, 658, 2006, 1316, BUTTON_SELECT},
189 {0, 658, 1003, 1316, BUTTON_LEFT},
190 {2006, 658, 3009, 1316, BUTTON_RIGHT},
191 {1003, 0 , 2006, 658, BUTTON_DOWN},
192 {1003, 1316, 2006, 1974, BUTTON_UP},
193 {2006, 1316, 3009, 1974, BUTTON_PLAYPAUSE},
194 {0, 1316, 1003, 1974, BUTTON_BACK},
195 {0, 0 , 1003, 658, BUTTON_BOTTOMLEFT},
196 {2006, 0 , 3009, 658, BUTTON_BOTTOMRIGHT},
Amaury Pouly09b4c762011-10-02 14:44:31 +0000197 {0, 0, 0, 0, 0},
198};
199
Amaury Poulyf5d664a2011-10-27 10:38:19 +0000200#define RMI_INTERRUPT 1
201
Amaury Pouly09b4c762011-10-02 14:44:31 +0000202static int touchpad_btns = 0;
203static long rmi_stack [DEFAULT_STACK_SIZE/sizeof(long)];
204static const char rmi_thread_name[] = "rmi";
Amaury Poulyf5d664a2011-10-27 10:38:19 +0000205static struct event_queue rmi_queue;
Amaury Pouly09b4c762011-10-02 14:44:31 +0000206
207static int find_button(int x, int y)
208{
209 struct button_area_t *area = button_areas;
210 for(; area->button != 0; area++)
211 {
212 if(area->lx <= x && x <= area->rx &&
213 area->ly <= y && y <= area->ry)
214 return area->button;
215 }
216 return 0;
217}
218
Amaury Pouly856fb702011-11-02 17:48:04 +0000219static int touchpad_read_device(void)
Amaury Pouly09b4c762011-10-02 14:44:31 +0000220{
221 return touchpad_btns;
222}
223
Amaury Pouly856fb702011-11-02 17:48:04 +0000224static void rmi_attn_cb(int bank, int pin)
Amaury Pouly09b4c762011-10-02 14:44:31 +0000225{
226 (void) bank;
227 (void) pin;
Amaury Poulyf5d664a2011-10-27 10:38:19 +0000228 /* the callback will not be fired until interrupt is enabled back so
229 * the queue will not overflow or contain multiple RMI_INTERRUPT events */
230 queue_post(&rmi_queue, RMI_INTERRUPT, 0);
Amaury Pouly09b4c762011-10-02 14:44:31 +0000231}
232
Amaury Pouly856fb702011-11-02 17:48:04 +0000233static void rmi_thread(void)
Amaury Pouly09b4c762011-10-02 14:44:31 +0000234{
Amaury Poulyf5d664a2011-10-27 10:38:19 +0000235 struct queue_event ev;
236
Amaury Pouly09b4c762011-10-02 14:44:31 +0000237 while(1)
238 {
Amaury Poulyf5d664a2011-10-27 10:38:19 +0000239 queue_wait(&rmi_queue, &ev);
240 /* handle usb connect and ignore all messages except rmi interrupts */
241 if(ev.id == SYS_USB_CONNECTED)
242 {
243 usb_acknowledge(SYS_USB_CONNECTED_ACK);
244 continue;
245 }
246 else if(ev.id != RMI_INTERRUPT)
247 continue;
Amaury Pouly09b4c762011-10-02 14:44:31 +0000248 /* clear interrupt */
249 rmi_read_single(RMI_INTERRUPT_REQUEST);
250 /* read data */
251 union
252 {
253 unsigned char data[10];
254 struct
255 {
256 struct rmi_2d_absolute_data_t absolute;
257 struct rmi_2d_relative_data_t relative;
258 struct rmi_2d_gesture_data_t gesture;
259 }s;
260 }u;
261 rmi_read(RMI_DATA_REGISTER(0), 10, u.data);
262 int absolute_x = u.s.absolute.x_msb << 8 | u.s.absolute.x_lsb;
263 int absolute_y = u.s.absolute.y_msb << 8 | u.s.absolute.y_lsb;
264 int nr_fingers = u.s.absolute.misc & 7;
265
Amaury Pouly374a08a2011-11-30 18:39:22 +0000266
Amaury Pouly84b97dd2011-12-26 17:45:54 +0000267 if(nr_fingers == 1)
268 touchpad_btns = find_button(absolute_x, absolute_y);
269 else
270 touchpad_btns = 0;
Amaury Pouly374a08a2011-11-30 18:39:22 +0000271
Amaury Poulyf5d664a2011-10-27 10:38:19 +0000272 /* enable interrupt */
273 imx233_setup_pin_irq(0, 27, true, true, false, &rmi_attn_cb);
Amaury Pouly09b4c762011-10-02 14:44:31 +0000274 }
275}
276
Amaury Pouly08fb3f62011-05-01 13:02:46 +0000277void button_init_device(void)
278{
Amaury Pouly86e8c282011-05-11 22:38:09 +0000279 /* Synaptics TouchPad information:
280 * - product id: 1533
281 * - nr function: 1 (0x10 = 2D touchpad)
282 * 2D Touchpad information (function 0x10)
283 * - nr data sources: 3
284 * - standard layout
285 * - extra data registers: 7
286 * - nr sensors: 1
287 * 2D Touchpad Sensor #0 information:
288 * - has relative data: yes
289 * - has palm detect: yes
290 * - has multi finger: yes
291 * - has enhanced gesture: yes
292 * - has scroller: no
293 * - has 2D scrollers: no
294 * - Maximum X: 3009
295 * - Maxumum Y: 1974
296 * - Resolution: 82
297 *
298 * ATTENTION line: B0P27 asserted low
Amaury Poulye36b20c2011-07-03 15:18:41 +0000299 *
300 * The B0P26 line seems to be related to the touchpad
Amaury Pouly86e8c282011-05-11 22:38:09 +0000301 */
Amaury Poulye36b20c2011-07-03 15:18:41 +0000302
Amaury Pouly09b4c762011-10-02 14:44:31 +0000303 /* touchpad CE ? */
Amaury Poulye36b20c2011-07-03 15:18:41 +0000304 imx233_set_pin_function(0, 26, PINCTRL_FUNCTION_GPIO);
305 imx233_enable_gpio_output(0, 26, false);
306 imx233_set_pin_drive_strength(0, 26, PINCTRL_DRIVE_8mA);
307
308 rmi_init(0x40);
309
Amaury Pouly7e211ff2011-11-17 19:13:09 +0000310 char product_id[RMI_PRODUCT_ID_LEN];
311 rmi_read(RMI_PRODUCT_ID, RMI_PRODUCT_ID_LEN, product_id);
Amaury Pouly374a08a2011-11-30 18:39:22 +0000312 /* The OF adjust the sensitivity based on product_id[1] compared to 2.
313 * Since it doesn't to work great, just hardcode the sensitivity to
314 * some reasonable value for now. */
315 rmi_write_single(RMI_2D_SENSITIVITY_ADJ, 13);
Amaury Pouly7e211ff2011-11-17 19:13:09 +0000316
Amaury Poulya43509c2011-05-13 16:40:22 +0000317 rmi_write_single(RMI_2D_GESTURE_SETTINGS,
318 RMI_2D_GESTURE_PRESS_TIME_300MS |
319 RMI_2D_GESTURE_FLICK_DIST_4MM << RMI_2D_GESTURE_FLICK_DIST_BP |
320 RMI_2D_GESTURE_FLICK_TIME_700MS << RMI_2D_GESTURE_FLICK_TIME_BP);
Amaury Pouly09b4c762011-10-02 14:44:31 +0000321
Amaury Poulyf5d664a2011-10-27 10:38:19 +0000322 queue_init(&rmi_queue, true);
Amaury Pouly09b4c762011-10-02 14:44:31 +0000323 create_thread(rmi_thread, rmi_stack, sizeof(rmi_stack), 0,
324 rmi_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU));
Amaury Poulyf5d664a2011-10-27 10:38:19 +0000325 /* enable interrupt */
326 imx233_setup_pin_irq(0, 27, true, true, false, &rmi_attn_cb);
Amaury Pouly08fb3f62011-05-01 13:02:46 +0000327}
328
Amaury Pouly88f75d02011-07-02 02:21:06 +0000329#else
330
331void button_init_device(void)
332{
Amaury Pouly09b4c762011-10-02 14:44:31 +0000333
334}
335
336int touchpad_read_device(void)
337{
338 return 0;
Amaury Pouly88f75d02011-07-02 02:21:06 +0000339}
340
341#endif
342
Amaury Pouly08fb3f62011-05-01 13:02:46 +0000343int button_read_device(void)
344{
Amaury Poulyffee0b52011-05-04 18:00:22 +0000345 int res = 0;
346 if(!imx233_get_gpio_input_mask(1, 0x40000000))
347 res |= BUTTON_VOL_DOWN;
348 /* The imx233 uses the voltage on the PSWITCH pin to detect power up/down
349 * events as well as recovery mode. Since the power button is the power button
350 * and the volume up button is recovery, it is not possible to know whether
351 * power button is down when volume up is down (except if there is another
352 * method but volume up and power don't seem to be wired to GPIO pins). */
Amaury Pouly856fb702011-11-02 17:48:04 +0000353 switch(__XTRACT(HW_POWER_STS, PSWITCH))
Amaury Poulyffee0b52011-05-04 18:00:22 +0000354 {
355 case 1: res |= BUTTON_POWER; break;
356 case 3: res |= BUTTON_VOL_UP; break;
357 default: break;
358 }
Amaury Pouly09b4c762011-10-02 14:44:31 +0000359 return res | touchpad_read_device();
Amaury Pouly08fb3f62011-05-01 13:02:46 +0000360}