1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2020/12/31 Bernard Add license info
9 */
10 #include <rthw.h>
11 #include <rtthread.h>
12 #include <rtdevice.h>
13
14 #include "board.h"
15 #include "interrupt.h"
16 #include "drv_mouse.h"
17 #include "drv_clcd.h"
18
19 #define DBG_TAG "drv.mouse"
20 #define DBG_LVL DBG_INFO
21 #include "rtdbg.h"
22
23 #ifdef BSP_DRV_MOUSE
24
25 #define MOUSE_ADDRESS (0x10007000)
26 #define MOUSE_IRQ_NUM (IRQ_VEXPRESS_A9_MOUSE)
27 #define MOUSE_XMAX (BSP_LCD_WIDTH)
28 #define MOUSE_YMAX (BSP_LCD_HEIGHT)
29
30 #define MOUSE_BUTTON_LEFT (0x01)
31 #define MOUSE_BUTTON_RIGHT (0x02)
32 #define MOUSE_BUTTON_MIDDLE (0x04)
33 #define MOUSE_BUTTON_DOWN (0x10)
34 #define MOUSE_BUTTON_UP (0x20)
35 #define MOUSE_BUTTON_MOVE (0x40)
36 #define MOUSE_BUTTON_WHELL (0x80)
37
38 #ifdef PKG_USING_GUIENGINE
39 #include <rtgui/event.h>
40 #include <rtgui/rtgui_server.h>
41 static rt_uint32_t emouse_id;
42 #elif defined(PKG_USING_LITTLEVGL2RTT)
43 #include <littlevgl2rtt.h>
44 #elif defined(PKG_USING_LVGL)
45 #include <lvgl.h>
46 extern void lv_port_indev_input(rt_int16_t x, rt_int16_t y, lv_indev_state_t state);
47 static rt_bool_t touch_down = RT_FALSE;
48 #endif /* PKG_USING_GUIENGINE */
49
50 typedef rt_uint32_t virtual_addr_t;
51
52 enum {
53 MOUSE_CR = 0x00,
54 MOUSE_STAT = 0x04,
55 MOUSE_DATA = 0x08,
56 MOUSE_CLKDIV = 0x0c,
57 MOUSE_IIR = 0x10,
58 };
59
60 struct mouse_pl050_pdata_t {
61 virtual_addr_t virt;
62 int irq;
63 int xmax, ymax;
64 int xpos, ypos;
65 unsigned char packet[4];
66 int index;
67 int obtn;
68 int type;
69 };
70
read8(uint32_t addr)71 rt_inline rt_uint8_t read8(uint32_t addr)
72 {
73 return (*((volatile rt_uint8_t *)(addr)));
74 }
75
write8(uint32_t addr,rt_uint8_t value)76 rt_inline void write8(uint32_t addr, rt_uint8_t value)
77 {
78 *((volatile rt_uint8_t *)(addr)) = value;
79 }
80
read32(uint32_t addr)81 rt_inline rt_uint32_t read32(uint32_t addr)
82 {
83 return (*((volatile rt_uint32_t *)(addr)));
84 }
85
write32(uint32_t addr,rt_uint32_t value)86 rt_inline void write32(uint32_t addr, rt_uint32_t value)
87 {
88 *((volatile rt_uint32_t *)(addr)) = value;
89 }
90
kmi_write(struct mouse_pl050_pdata_t * pdat,rt_uint8_t value)91 rt_inline int kmi_write(struct mouse_pl050_pdata_t * pdat, rt_uint8_t value)
92 {
93 int timeout = 1000;
94
95 while((read8(pdat->virt + MOUSE_STAT) & (1 << 6)) == 0 && timeout--);
96
97 if(timeout)
98 {
99 write8(pdat->virt + MOUSE_DATA, value);
100 while((read8(pdat->virt + MOUSE_STAT) & (1 << 4)) == 0);
101
102 if(read8(pdat->virt + MOUSE_DATA) == 0xfa)
103 return RT_TRUE;
104 }
105 return RT_FALSE;
106 }
107
kmi_read(struct mouse_pl050_pdata_t * pdat,rt_uint8_t * value)108 rt_inline int kmi_read(struct mouse_pl050_pdata_t * pdat, rt_uint8_t * value)
109 {
110 if((read8(pdat->virt + MOUSE_STAT) & (1 << 4)))
111 {
112 *value = read8(pdat->virt + MOUSE_DATA);
113 return RT_TRUE;
114 }
115 return RT_FALSE;
116 }
117
118
push_event_touch_move(int x,int y)119 void push_event_touch_move(int x, int y)
120 {
121 #ifdef PKG_USING_GUIENGINE
122 struct rtgui_event_mouse emouse;
123
124 emouse.parent.sender = RT_NULL;
125 emouse.wid = RT_NULL;
126
127 emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN;
128 emouse.parent.type = RTGUI_EVENT_MOUSE_MOTION;
129 emouse.x = x;
130 emouse.y = y;
131 emouse.ts = rt_tick_get();
132 emouse.id = emouse_id;
133
134 LOG_D("[line]:%d motion event id:%d x:%d y:%d", __LINE__, emouse.id, x, y);
135 rtgui_server_post_event(&emouse.parent, sizeof(emouse));
136 #elif defined(PKG_USING_LITTLEVGL2RTT)
137 littlevgl2rtt_send_input_event(x, y, LITTLEVGL2RTT_INPUT_MOVE);
138 #elif defined(PKG_USING_LVGL)
139 lv_port_indev_input(x, y, (touch_down == RT_TRUE) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL);
140 #endif
141 }
142
push_event_touch_begin(int x,int y)143 void push_event_touch_begin(int x, int y)
144 {
145 #ifdef PKG_USING_GUIENGINE
146 struct rtgui_event_mouse emouse;
147
148 emouse_id = rt_tick_get();
149
150 emouse.parent.sender = RT_NULL;
151 emouse.wid = RT_NULL;
152
153 emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
154 emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN;
155 emouse.x = x;
156 emouse.y = y;
157 emouse.ts = rt_tick_get();
158 emouse.id = emouse_id;
159 LOG_D("[line]:%d down event id:%d x:%d y:%d", __LINE__, emouse.id, x, y);
160 rtgui_server_post_event(&emouse.parent, sizeof(emouse));
161 #elif defined(PKG_USING_LITTLEVGL2RTT)
162 littlevgl2rtt_send_input_event(x, y, LITTLEVGL2RTT_INPUT_DOWN);
163 #elif defined(PKG_USING_LVGL)
164 touch_down = RT_TRUE;
165 lv_port_indev_input(x, y, (touch_down == RT_TRUE) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL);
166 #endif
167 }
168
push_event_touch_end(int x,int y)169 void push_event_touch_end(int x, int y)
170 {
171 #ifdef PKG_USING_GUIENGINE
172 struct rtgui_event_mouse emouse;
173
174 emouse.parent.sender = RT_NULL;
175 emouse.wid = RT_NULL;
176
177 emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
178 emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP;
179 emouse.x = x;
180 emouse.y = y;
181 emouse.ts = rt_tick_get();
182 emouse.id = emouse_id;
183
184 LOG_D("[line]:%d up event id:%d x:%d y:%d", __LINE__, emouse.id, x, y);
185 rtgui_server_post_event(&emouse.parent, sizeof(emouse));
186 #elif defined(PKG_USING_LITTLEVGL2RTT)
187 littlevgl2rtt_send_input_event(x, y, LITTLEVGL2RTT_INPUT_MOVE);
188 #elif defined(PKG_USING_LVGL)
189 touch_down = RT_FALSE;
190 lv_port_indev_input(x, y, (touch_down == RT_TRUE) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL);
191 #endif
192 }
193
mouse_pl050_interrupt(int irq,void * data)194 static void mouse_pl050_interrupt(int irq, void * data)
195 {
196 struct mouse_pl050_pdata_t * pdat = (struct mouse_pl050_pdata_t *)data;
197 int x, y, relx, rely, delta;
198 int btndown, btnup, btn;
199 int status = 0;
200
201 status = read8(pdat->virt + MOUSE_IIR);
202 while(status & (1 << 0))
203 {
204 pdat->packet[pdat->index] = read8(pdat->virt + MOUSE_DATA);
205 pdat->index = (pdat->index + 1) & 0x3;
206
207 if(pdat->index == 0)
208 {
209 btn = pdat->packet[0] & 0x7;
210 btndown = (btn ^ pdat->obtn) & btn;
211 btnup = (btn ^ pdat->obtn) & pdat->obtn;
212 pdat->obtn = btn;
213
214 if(pdat->packet[0] & 0x10)
215 relx = 0xffffff00 | pdat->packet[1];
216 else
217 relx = pdat->packet[1];
218
219 if(pdat->packet[0] & 0x20)
220 rely = 0xffffff00 | pdat->packet[2];
221 else
222 rely = pdat->packet[2];
223 rely = -rely;
224
225 delta = pdat->packet[3] & 0xf;
226 if(delta == 0xf)
227 delta = -1;
228
229 if(relx != 0)
230 {
231 pdat->xpos = pdat->xpos + relx;
232 if(pdat->xpos < 0)
233 pdat->xpos = 0;
234 if(pdat->xpos > pdat->xmax - 1)
235 pdat->xpos = pdat->xmax - 1;
236 }
237 if(rely != 0)
238 {
239 pdat->ypos = pdat->ypos + rely;
240 if(pdat->ypos < 0)
241 pdat->ypos = 0;
242 if(pdat->ypos > pdat->ymax - 1)
243 pdat->ypos = pdat->ymax - 1;
244 }
245 x = pdat->xpos;
246 y = pdat->ypos;
247
248 if((btn & (0x01 << 0)) && ((relx != 0) || (rely != 0)))
249 push_event_touch_move(x, y);
250
251 if(btndown & (0x01 << 0))
252 push_event_touch_begin(x, y);
253
254 if(btnup & (0x01 << 0))
255 push_event_touch_end(x, y);
256 }
257
258 status = read8(pdat->virt + MOUSE_IIR);
259 }
260 }
261
rt_hw_mouse_init(void)262 int rt_hw_mouse_init(void)
263 {
264 rt_uint8_t value;
265 rt_uint32_t id;
266 struct mouse_pl050_pdata_t *pdat;
267 virtual_addr_t virt = MOUSE_ADDRESS;
268 int irq = MOUSE_IRQ_NUM;
269
270 #ifdef RT_USING_SMART
271 virt = (virtual_addr_t)rt_ioremap((void*)MOUSE_ADDRESS, 0x1000);
272 #endif
273 id = (((read32(virt + 0xfec) & 0xff) << 24) |
274 ((read32(virt + 0xfe8) & 0xff) << 16) |
275 ((read32(virt + 0xfe4) & 0xff) << 8) |
276 ((read32(virt + 0xfe0) & 0xff) << 0));
277
278 if(((id >> 12) & 0xff) != 0x41 || (id & 0xfff) != 0x050)
279 {
280 LOG_E("read id fail id:0x%08x", id);
281 return -RT_ERROR;
282 }
283
284 pdat = rt_malloc(sizeof(struct mouse_pl050_pdata_t));
285 if(!pdat)
286 {
287 LOG_E("malloc memory failed");
288 return -RT_ERROR;
289 }
290 rt_memset(pdat, 0, sizeof(struct mouse_pl050_pdata_t));
291
292 pdat->virt = virt;
293 pdat->irq = irq;
294 pdat->xmax = MOUSE_XMAX;
295 pdat->ymax = MOUSE_YMAX;
296 pdat->xpos = pdat->xmax / 2;
297 pdat->ypos = pdat->ymax / 2;
298 pdat->packet[0] = 0;
299 pdat->packet[1] = 0;
300 pdat->packet[2] = 0;
301 pdat->packet[3] = 0;
302 pdat->index = 0;
303 pdat->obtn = 0;
304
305 write8(pdat->virt + MOUSE_CLKDIV, 0);
306 write8(pdat->virt + MOUSE_CR, (1 << 2));
307 kmi_write(pdat, 0xff);
308 kmi_read(pdat, &value);
309 kmi_write(pdat, 0xf3);
310 kmi_write(pdat, 200);
311 kmi_write(pdat, 0xf3);
312 kmi_write(pdat, 100);
313 kmi_write(pdat, 0xf3);
314 kmi_write(pdat, 80);
315 kmi_write(pdat, 0xf2);
316 kmi_read(pdat, &value);
317 kmi_read(pdat, &value);
318 kmi_write(pdat, 0xf3);
319 kmi_write(pdat, 100);
320 kmi_write(pdat, 0xe8);
321 kmi_write(pdat, 0x02);
322 kmi_write(pdat, 0xe6);
323 kmi_write(pdat, 0xf4);
324 kmi_read(pdat, &value);
325 kmi_read(pdat, &value);
326 kmi_read(pdat, &value);
327 kmi_read(pdat, &value);
328 write8(pdat->virt + MOUSE_CR, (1 << 2) | (1 << 4));
329
330 rt_hw_interrupt_install(pdat->irq, mouse_pl050_interrupt, (void *)pdat, "mouse");
331 rt_hw_interrupt_umask(pdat->irq);
332
333 return RT_EOK;
334 }
335 INIT_DEVICE_EXPORT(rt_hw_mouse_init);
336
337 #endif
338