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