]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/drivers/input/src/kp-omap3.c
Update
[l4.git] / l4 / pkg / drivers / input / src / kp-omap3.c
1 /*
2  * OMAP keypad driver
3  */
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 #include <pthread.h>
10 #include <pthread-l4.h>
11
12 #include <l4/input/drv_reg.h>
13 #include <l4/io/io.h>
14 #include <l4/re/c/namespace.h>
15 #include <l4/re/c/util/cap_alloc.h>
16 #include <l4/re/event_enums.h>
17 #include <l4/util/util.h>
18 #include <l4/sys/irq.h>
19 #include <l4/sys/thread.h>
20 #include <l4/sys/debugger.h>
21 #include <l4/vbus/vbus.h>
22 #include <l4/vbus/vbus_i2c.h>
23
24 #include "kp-omap.h"
25
26
27 #define NUM_ROWS 5
28 #define NUM_COLS 4
29
30 static unsigned char kp_keycode[16] = {
31
32     L4RE_KEY_1, L4RE_KEY_2, L4RE_KEY_3, L4RE_KEY_4,
33     L4RE_KEY_5, L4RE_KEY_6, L4RE_KEY_7, L4RE_KEY_8,
34     L4RE_KEY_9, L4RE_KEY_0, L4RE_KEY_A, L4RE_KEY_B,
35     L4RE_KEY_C, L4RE_KEY_D, L4RE_KEY_E, L4RE_KEY_F,
36 };
37
38 static Input_handler kp_handler;
39 static void* kp_priv;
40 static pthread_t _pthread;
41
42 static l4_cap_idx_t vbus = L4_INVALID_CAP;
43 static l4vbus_device_handle_t i2c_handle = 0;
44
45 /* I2C slave ID */
46 #define TWL4030_SLAVENUM_NUM0 0x48
47 #define TWL4030_SLAVENUM_NUM1 0x49
48 #define TWL4030_SLAVENUM_NUM2 0x4a
49 #define TWL4030_SLAVENUM_NUM3 0x4b
50
51 /* Module Mapping */
52 struct twl4030mapping
53 {
54   unsigned char sid;    /* Slave ID */
55   unsigned char base;   /* base address */
56 };
57
58 /* mapping the module id to slave id and base address */
59 static struct twl4030mapping twl4030_map[TWL4030_MODULES + 1] = {
60       { TWL4030_SLAVENUM_NUM0, TWL4030_BASE_USB },
61       { TWL4030_SLAVENUM_NUM1, TWL4030_BASE_AUDIO_VOICE },
62       { TWL4030_SLAVENUM_NUM1, TWL4030_BASE_GPIO },
63       { TWL4030_SLAVENUM_NUM1, TWL4030_BASE_INTBR },
64       { TWL4030_SLAVENUM_NUM1, TWL4030_BASE_PIH },
65       { TWL4030_SLAVENUM_NUM1, TWL4030_BASE_TEST },
66       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_KEYPAD },
67       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_MADC },
68       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_INTERRUPTS },
69       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_LED },
70       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_MAIN_CHARGE },
71       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_PRECHARGE },
72       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_PWM0 },
73       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_PWM1 },
74       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_PWMA },
75       { TWL4030_SLAVENUM_NUM2, TWL4030_BASE_PWMB },
76       { TWL4030_SLAVENUM_NUM3, TWL4030_BASE_BACKUP },
77       { TWL4030_SLAVENUM_NUM3, TWL4030_BASE_INT },
78       { TWL4030_SLAVENUM_NUM3, TWL4030_BASE_PM_MASTER },
79       { TWL4030_SLAVENUM_NUM3, TWL4030_BASE_PM_RECIEVER },
80       { TWL4030_SLAVENUM_NUM3, TWL4030_BASE_RTC },
81       { TWL4030_SLAVENUM_NUM3, TWL4030_BASE_SECURED_REG },
82 };
83
84 #if 1
85 static int twl4030_i2c_write_u8(unsigned mod_no, l4_uint8_t value, l4_uint8_t reg)
86 {
87   return l4vbus_i2c_write(vbus, i2c_handle, twl4030_map[mod_no].sid, twl4030_map[mod_no].base + reg, &value, 1);
88 }
89 #endif
90 #if 0
91 static int twl4030_i2c_read_u8(unsigned mod_no, l4_uint8_t *value, l4_uint8_t reg)
92 {
93   unsigned long size = 1;
94   return l4vbus_i2c_read(vbus, i2c_handle, twl4030_map[mod_no].sid, twl4030_map[mod_no].base + reg, value, &size);
95 }
96 #endif
97
98 static int twl4030_i2c_read_u32(int mod_no, l4_uint8_t *value, l4_uint8_t reg)
99 {
100   unsigned long size = 4;
101   return l4vbus_i2c_read(vbus, i2c_handle, twl4030_map[mod_no].sid, twl4030_map[mod_no].base + reg, value, &size);
102 }
103
104 static int kp_read(int reg, l4_uint8_t *val)
105 {
106   unsigned long size = 1;
107   return l4vbus_i2c_read(vbus, i2c_handle, twl4030_map[TWL4030_MODULE_KEYPAD].sid,
108                          twl4030_map[TWL4030_MODULE_KEYPAD].base + reg, val, &size);
109 }
110
111 static int kp_write(int reg, l4_uint8_t val)
112 {
113   return l4vbus_i2c_write(vbus, i2c_handle, twl4030_map[TWL4030_MODULE_KEYPAD].sid,
114                           twl4030_map[TWL4030_MODULE_KEYPAD].base + reg, &val, 1);
115 }
116
117 #if 1
118 static int twl_init_irq(void)
119 {
120   int ret = 0;
121
122   /* PWR_ISR1 */
123   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
124   /* PWR_ISR2 */
125   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
126   /* PWR_IMR1 */
127   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x1);
128   /* PWR_IMR2 */
129   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x3);
130   /* PWR_ISR1 */
131   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
132   /* PWR_ISR2 */
133   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
134   
135   /* BCIIMR1_1 */
136   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x3);
137   /* BCIIMR1_2 */
138   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x4);
139   /* BCIIMR2_1 */
140   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x7);
141   /* BCIIMR2_2 */
142   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x8);
143   
144   /* MADC */
145   /* MADC_IMR1 */
146   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x62);
147   /* MADC_IMR2 */
148   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x64);
149   /* GPIO_IMR1A */
150   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x1C);
151   /* GPIO_IMR2A */
152   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x1D);
153   /* GPIO_IMR3A */
154   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x1E);
155   /* GPIO_IMR1B */
156   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x22);
157   /* GPIO_IMR2B */
158   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x23);
159   /* GPIO_IMR3B */
160   ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x24);
161
162   return ret;
163 }
164 #endif
165
166 static int init_keypad(void)
167 {
168   int ret = 0;
169
170   twl_init_irq();
171
172   // Enable software mode and keypad power on
173   ret = kp_write(REG_KEYP_CTRL_REG, 0x43);
174   // Mask all interrupts
175   ret |= kp_write(REG_KEYP_IMR1, 0x0f);
176     {
177       /* Clear ISR */
178       l4_uint8_t v;
179       kp_read(REG_KEYP_ISR1, &v);
180       kp_read(REG_KEYP_ISR1, &v);
181     }
182   // Trigger interrupts on rising edge
183   ret |= kp_write(REG_KEYP_EDR, 0xaa);
184   // Set pre scalar field
185   ret |= kp_write(REG_LK_PTV_REG, 4 << 5);
186   // Set key debounce time 
187   ret |= kp_write(REG_KEY_DEB_REG, 0x3f);
188   // Enable COR-mode
189   ret |= kp_write(REG_KEYP_SIH_CTRL, 0x4);
190   // unmask all interrupts
191   ret |= kp_write(REG_KEYP_IMR1, 0);
192
193   return ret;
194 }
195
196 #if 0
197 static void drive_vibr(void)
198 {
199   // VIBRATOR_CFG
200   l4_uint8_t v = (1<<3)|(1<<2)|1;
201   unsigned long s = 1;
202   l4vbus_i2c_write(vbus, i2c_handle, 0x4b, 0x60, &v, 1);
203   // configure mux
204   //v = 0x10;
205   //l4vbus_i2c_write(vbus, i2c_handle, 0x49, 0x92, &v, 1);
206   
207   l4_uint16_t w = (0x4 << 13)|(0x1 << 12)|(0x1 << 4)|(0xe);
208   l4_uint8_t *p = (l4_uint8_t *)(&w);
209   l4vbus_i2c_write(vbus, i2c_handle, 0x4b, 0x4b, &(p[1]), 1);
210   l4vbus_i2c_write(vbus, i2c_handle, 0x4b, 0x4c, &(p[0]), 1);
211   printf("WRITE:%x %x\n", p[1], p[0]);
212   
213   l4vbus_i2c_read(vbus, i2c_handle, 0x4b, 0x73, &v, &s);
214   printf("VAUX1_TYPE:%x\n", v);
215   l4vbus_i2c_read(vbus, i2c_handle, 0x4b, 0x74, &v, &s);
216   printf("VAUX1_REMAP:%x\n", v);
217   l4vbus_i2c_read(vbus, i2c_handle, 0x4b, 0x75, &v, &s);
218   printf("VAUX1_DEDICATED:%x\n", v);
219   l4vbus_i2c_read(vbus, i2c_handle, 0x4b, 0x76, &v, &s);
220   printf("VAUX1_DEV_GRP:%x\n", v);
221 }
222 #endif
223
224 static void reset_keypad(void)
225 {
226   kp_write(REG_KEYP_IMR1, 0xf);
227 }
228
229 static l4_uint8_t old_state[NUM_ROWS] = { 0 };
230
231 static int scan_key(void)
232 {
233   l4_uint8_t new_state[NUM_ROWS];
234   //unsigned long size = NUM_ROWS;
235
236   twl4030_i2c_read_u32(TWL4030_MODULE_KEYPAD, new_state, REG_FULL_CODE_7_0);
237   printf("[KEYP] state:%x %x %x %x %x\n",
238       new_state[0], new_state[1], new_state[2], new_state[3], new_state[4]);
239         
240   /* check for changes and print those */
241   int row = 0;
242   for (row = 0; row < NUM_ROWS; row++)
243     {
244       int changed = new_state[row] ^ old_state[row];
245
246       if (!changed)
247         continue;
248
249       int col = 0;
250       for (col = 0; col < NUM_COLS; col++)
251         {
252           if (!(changed & (1 << col)))
253             continue;
254           int key_pressed = new_state[row] & (1 << col);
255
256           printf("***********************key %s:row:%d col:%d\n", key_pressed ? "pressed" : "released", row, col);
257           Input_event ev = { L4RE_EV_KEY, kp_keycode[row * NUM_COLS + col], key_pressed };
258           kp_handler(ev, kp_priv);
259       }
260   }
261
262   memcpy(old_state, new_state, NUM_ROWS);
263
264   return 0;
265 }
266
267 static int kp_irq_func(void)
268 {
269   l4_cap_idx_t irq_cap = l4re_util_cap_alloc();
270   l4_cap_idx_t thread_cap = pthread_l4_cap(_pthread);
271   l4_msgtag_t tag;
272
273   l4_debugger_set_object_name(thread_cap, "kp-omap3.irq");
274   
275   if (l4io_request_irq(7, irq_cap) < 0)
276     return -2;
277   // was L4_IRQ_F_LEVEL_LOW
278   tag = l4_irq_attach(irq_cap, 0, thread_cap);
279   if (l4_ipc_error(tag, l4_utcb()))
280     return -3;
281
282   while (1)
283     {
284       tag = l4_irq_receive(irq_cap, L4_IPC_NEVER);
285       if (l4_ipc_error(tag, l4_utcb()))
286         {
287           printf("[KEYP] Error: Receive irq failed\n");
288           continue;
289         }
290
291       kp_write(REG_KEYP_IMR1, 0xf);
292      
293       if (kp_handler)
294         scan_key();
295
296       l4_uint8_t value = 0;
297       kp_read(REG_KEYP_ISR1, &value);
298       kp_write(REG_KEYP_IMR1, 0x0);
299     }
300 }
301
302 static void* __irq_func(void *data)
303 {
304   (void)data;
305   int ret = kp_irq_func();
306   printf("[KEYP] Warning: irq handler returned with:%d\n", ret);
307   l4_sleep_forever();
308 }
309
310 static
311 int kp_init(void)
312 {
313   vbus = l4re_env_get_cap("vbus");
314
315   if (l4_is_invalid_cap(vbus))
316     {
317       printf("[KEYP] Failed to query vbus\n");
318       return -1;
319     }
320
321   if (l4vbus_get_device_by_hid(vbus, 0, &i2c_handle, "i2c", 0, 0))
322     {
323       printf("[KEYP] ##### Cannot find I2C\n");
324     }
325
326   return init_keypad();
327 }
328
329 static const char *kp_get_info(void)
330 { return "ARM OMAP3EVM Keypad"; }
331
332 static int kp_probe(const char *name)
333 {
334   if (strcmp("OMAP_KP", name))
335     {
336       printf("[KEYP] I'm not the right driver for %s\n", name);
337       return 0;
338     }
339   return !l4io_lookup_device("OMAP_KP", NULL, 0, 0);
340 }
341
342 static void kp_attach(Input_handler handler, void *priv)
343
344   kp_handler = handler;
345   kp_priv = priv;
346   pthread_attr_t thread_attr;
347
348   int err;
349   if ((err = pthread_attr_init(&thread_attr)) != 0)
350     printf("[KEYP] Error: Initializing pthread attr: %d\n", err);
351
352   struct sched_param sp;
353   sp.sched_priority = 0x20;
354   pthread_attr_setschedpolicy(&thread_attr, SCHED_L4);
355   pthread_attr_setschedparam(&thread_attr, &sp);
356   pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);
357   
358   err = pthread_create(&_pthread, &thread_attr, __irq_func, 0);
359   if (err != 0)
360     printf("[KEYP] Error: Creating thread\n");
361 }
362
363 static void kp_enable(void)
364 {
365   if (kp_init())
366     {
367       printf("[KEYP] Error: Init failed!\n");
368       return;
369     }
370 }
371
372 static void kp_disable(void)
373 {
374   reset_keypad();
375 }
376
377 static struct arm_input_ops arm_kp_ops_omap3 = {
378     .get_info           = kp_get_info,
379     .probe              = kp_probe,
380     .attach             = kp_attach,
381     .enable             = kp_enable,
382     .disable            = kp_disable,
383 };
384
385 arm_input_register(&arm_kp_ops_omap3);