10 #include <pthread-l4.h>
12 #include <l4/input/drv_reg.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>
30 static unsigned char kp_keycode[16] = {
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,
38 static Input_handler kp_handler;
40 static pthread_t _pthread;
42 static l4_cap_idx_t vbus = L4_INVALID_CAP;
43 static l4vbus_device_handle_t i2c_handle = 0;
46 #define TWL4030_SLAVENUM_NUM0 0x48
47 #define TWL4030_SLAVENUM_NUM1 0x49
48 #define TWL4030_SLAVENUM_NUM2 0x4a
49 #define TWL4030_SLAVENUM_NUM3 0x4b
54 unsigned char sid; /* Slave ID */
55 unsigned char base; /* base address */
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 },
85 static int twl4030_i2c_write_u8(unsigned mod_no, l4_uint8_t value, l4_uint8_t reg)
87 return l4vbus_i2c_write(vbus, i2c_handle, twl4030_map[mod_no].sid, twl4030_map[mod_no].base + reg, &value, 1);
91 static int twl4030_i2c_read_u8(unsigned mod_no, l4_uint8_t *value, l4_uint8_t reg)
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);
98 static int twl4030_i2c_read_u32(int mod_no, l4_uint8_t *value, l4_uint8_t reg)
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);
104 static int kp_read(int reg, l4_uint8_t *val)
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);
111 static int kp_write(int reg, l4_uint8_t val)
113 return l4vbus_i2c_write(vbus, i2c_handle, twl4030_map[TWL4030_MODULE_KEYPAD].sid,
114 twl4030_map[TWL4030_MODULE_KEYPAD].base + reg, &val, 1);
118 static int twl_init_irq(void)
123 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
125 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
127 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x1);
129 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x3);
131 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
133 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
136 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x3);
138 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x4);
140 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x7);
142 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x8);
146 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x62);
148 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x64);
150 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x1C);
152 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x1D);
154 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x1E);
156 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x22);
158 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x23);
160 ret |= twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, 0x24);
166 static int init_keypad(void)
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);
179 kp_read(REG_KEYP_ISR1, &v);
180 kp_read(REG_KEYP_ISR1, &v);
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);
189 ret |= kp_write(REG_KEYP_SIH_CTRL, 0x4);
190 // unmask all interrupts
191 ret |= kp_write(REG_KEYP_IMR1, 0);
197 static void drive_vibr(void)
200 l4_uint8_t v = (1<<3)|(1<<2)|1;
202 l4vbus_i2c_write(vbus, i2c_handle, 0x4b, 0x60, &v, 1);
205 //l4vbus_i2c_write(vbus, i2c_handle, 0x49, 0x92, &v, 1);
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]);
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);
224 static void reset_keypad(void)
226 kp_write(REG_KEYP_IMR1, 0xf);
229 static l4_uint8_t old_state[NUM_ROWS] = { 0 };
231 static int scan_key(void)
233 l4_uint8_t new_state[NUM_ROWS];
234 //unsigned long size = NUM_ROWS;
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]);
240 /* check for changes and print those */
242 for (row = 0; row < NUM_ROWS; row++)
244 int changed = new_state[row] ^ old_state[row];
250 for (col = 0; col < NUM_COLS; col++)
252 if (!(changed & (1 << col)))
254 int key_pressed = new_state[row] & (1 << col);
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);
262 memcpy(old_state, new_state, NUM_ROWS);
267 static int kp_irq_func(void)
269 l4_cap_idx_t irq_cap = l4re_util_cap_alloc();
270 l4_cap_idx_t thread_cap = pthread_l4_cap(_pthread);
273 l4_debugger_set_object_name(thread_cap, "kp-omap3.irq");
275 if (l4io_request_irq(7, irq_cap) < 0)
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()))
284 tag = l4_irq_receive(irq_cap, L4_IPC_NEVER);
285 if (l4_ipc_error(tag, l4_utcb()))
287 printf("[KEYP] Error: Receive irq failed\n");
291 kp_write(REG_KEYP_IMR1, 0xf);
296 l4_uint8_t value = 0;
297 kp_read(REG_KEYP_ISR1, &value);
298 kp_write(REG_KEYP_IMR1, 0x0);
302 static void* __irq_func(void *data)
305 int ret = kp_irq_func();
306 printf("[KEYP] Warning: irq handler returned with:%d\n", ret);
313 vbus = l4re_env_get_cap("vbus");
315 if (l4_is_invalid_cap(vbus))
317 printf("[KEYP] Failed to query vbus\n");
321 if (l4vbus_get_device_by_hid(vbus, 0, &i2c_handle, "i2c", 0, 0))
323 printf("[KEYP] ##### Cannot find I2C\n");
326 return init_keypad();
329 static const char *kp_get_info(void)
330 { return "ARM OMAP3EVM Keypad"; }
332 static int kp_probe(const char *name)
334 if (strcmp("OMAP_KP", name))
336 printf("[KEYP] I'm not the right driver for %s\n", name);
339 return !l4io_lookup_device("OMAP_KP", NULL, 0, 0);
342 static void kp_attach(Input_handler handler, void *priv)
344 kp_handler = handler;
346 pthread_attr_t thread_attr;
349 if ((err = pthread_attr_init(&thread_attr)) != 0)
350 printf("[KEYP] Error: Initializing pthread attr: %d\n", err);
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);
358 err = pthread_create(&_pthread, &thread_attr, __irq_func, 0);
360 printf("[KEYP] Error: Creating thread\n");
363 static void kp_enable(void)
367 printf("[KEYP] Error: Init failed!\n");
372 static void kp_disable(void)
377 static struct arm_input_ops arm_kp_ops_omap3 = {
378 .get_info = kp_get_info,
382 .disable = kp_disable,
385 arm_input_register(&arm_kp_ops_omap3);