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  * 2019-03-12     ZYH          first version
9  */
10 
11 
12 #include <rtthread.h>
13 
14 #ifdef BSP_USING_LCD
15 
16 #include <rtdevice.h>
17 #include "drv_lcd.h"
18 #include <board.h>
19 #include <gpiohs.h>
20 #include <drivers/dev_spi.h>
21 #include <spi.h>
22 #include <drv_io_config.h>
23 #include <rthw.h>
24 #include "dmalock.h"
25 #include "sleep.h"
26 
27 #define DBG_TAG  "LCD"
28 #define DBG_LVL  DBG_WARNING
29 #include <rtdbg.h>
30 
31 #define NO_OPERATION            0x00
32 #define SOFTWARE_RESET          0x01
33 #define READ_ID                 0x04
34 #define READ_STATUS             0x09
35 #define READ_POWER_MODE         0x0A
36 #define READ_MADCTL             0x0B
37 #define READ_PIXEL_FORMAT       0x0C
38 #define READ_IMAGE_FORMAT       0x0D
39 #define READ_SIGNAL_MODE        0x0E
40 #define READ_SELT_DIAG_RESULT   0x0F
41 #define SLEEP_ON                0x10
42 #define SLEEP_OFF               0x11
43 #define PARTIAL_DISPALY_ON      0x12
44 #define NORMAL_DISPALY_ON       0x13
45 #define INVERSION_DISPALY_OFF   0x20
46 #define INVERSION_DISPALY_ON    0x21
47 #define GAMMA_SET               0x26
48 #define DISPALY_OFF             0x28
49 #define DISPALY_ON              0x29
50 #define HORIZONTAL_ADDRESS_SET  0x2A
51 #define VERTICAL_ADDRESS_SET    0x2B
52 #define MEMORY_WRITE            0x2C
53 #define COLOR_SET               0x2D
54 #define MEMORY_READ             0x2E
55 #define PARTIAL_AREA            0x30
56 #define VERTICAL_SCROL_DEFINE   0x33
57 #define TEAR_EFFECT_LINE_OFF    0x34
58 #define TEAR_EFFECT_LINE_ON     0x35
59 #define MEMORY_ACCESS_CTL       0x36
60 #define VERTICAL_SCROL_S_ADD    0x37
61 #define IDLE_MODE_OFF           0x38
62 #define IDLE_MODE_ON            0x39
63 #define PIXEL_FORMAT_SET        0x3A
64 #define WRITE_MEMORY_CONTINUE   0x3C
65 #define READ_MEMORY_CONTINUE    0x3E
66 #define SET_TEAR_SCANLINE       0x44
67 #define GET_SCANLINE            0x45
68 #define WRITE_BRIGHTNESS        0x51
69 #define READ_BRIGHTNESS         0x52
70 #define WRITE_CTRL_DISPALY      0x53
71 #define READ_CTRL_DISPALY       0x54
72 #define WRITE_BRIGHTNESS_CTL    0x55
73 #define READ_BRIGHTNESS_CTL     0x56
74 #define WRITE_MIN_BRIGHTNESS    0x5E
75 #define READ_MIN_BRIGHTNESS     0x5F
76 #define READ_ID1                0xDA
77 #define READ_ID2                0xDB
78 #define READ_ID3                0xDC
79 #define RGB_IF_SIGNAL_CTL       0xB0
80 #define NORMAL_FRAME_CTL        0xB1
81 #define IDLE_FRAME_CTL          0xB2
82 #define PARTIAL_FRAME_CTL       0xB3
83 #define INVERSION_CTL           0xB4
84 #define BLANK_PORCH_CTL         0xB5
85 #define DISPALY_FUNCTION_CTL    0xB6
86 #define ENTRY_MODE_SET          0xB7
87 #define BACKLIGHT_CTL1          0xB8
88 #define BACKLIGHT_CTL2          0xB9
89 #define BACKLIGHT_CTL3          0xBA
90 #define BACKLIGHT_CTL4          0xBB
91 #define BACKLIGHT_CTL5          0xBC
92 #define BACKLIGHT_CTL7          0xBE
93 #define BACKLIGHT_CTL8          0xBF
94 #define POWER_CTL1              0xC0
95 #define POWER_CTL2              0xC1
96 #define VCOM_CTL1               0xC5
97 #define VCOM_CTL2               0xC7
98 #define NV_MEMORY_WRITE         0xD0
99 #define NV_MEMORY_PROTECT_KEY   0xD1
100 #define NV_MEMORY_STATUS_READ   0xD2
101 #define READ_ID4                0xD3
102 #define POSITIVE_GAMMA_CORRECT  0xE0
103 #define NEGATIVE_GAMMA_CORRECT  0xE1
104 #define DIGITAL_GAMMA_CTL1      0xE2
105 #define DIGITAL_GAMMA_CTL2      0xE3
106 #define INTERFACE_CTL           0xF6
107 
108 #define LCD_SPI_CHANNEL             SPI_DEVICE_0
109 #define LCD_SPI_CHIP_SELECT         SPI_CHIP_SELECT_0
110 
111 #if     defined(BSP_BOARD_K210_OPENMV_TEST)
112 #define LCD_SCAN_DIR           DIR_YX_LRUD
113 #elif   defined(BSP_BOARD_K210_DRACO)
114 #define LCD_SCAN_DIR           DIR_YX_LRUD
115 #elif   defined(BSP_BOARD_KD233)
116 #define LCD_SCAN_DIR           (DIR_YX_RLUD | 0x08)
117 #elif   defined(BSP_BOARD_USER)
118 /*user define.*/
119 #define LCD_SCAN_DIR           DIR_YX_RLUD
120 #endif
121 
122 typedef struct lcd_8080_device
123 {
124     struct rt_device parent;
125     struct rt_device_graphic_info lcd_info;
126     int spi_channel;
127     int cs;
128     int dc_pin;
129 #if BSP_LCD_RST_PIN >= 0
130     int rst_pin;
131 #endif
132 #if BSP_LCD_BACKLIGHT_PIN >= 0
133     int backlight_pin;
134 #endif
135     int dma_channel;
136 } * lcd_8080_device_t;
137 
138 static struct lcd_8080_device _lcddev;
139 
drv_lcd_cmd(lcd_8080_device_t lcd,rt_uint8_t cmd)140 static void drv_lcd_cmd(lcd_8080_device_t lcd, rt_uint8_t cmd)
141 {
142     gpiohs_set_pin(lcd->dc_pin, GPIO_PV_LOW);
143     spi_init(lcd->spi_channel, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
144     spi_init_non_standard(lcd->spi_channel, 8 /*instrction length*/, 0 /*address length*/, 0 /*wait cycles*/,
145                           SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
146     spi_send_data_normal_dma(lcd->dma_channel, lcd->spi_channel, lcd->cs, &cmd, 1, SPI_TRANS_CHAR);
147 }
148 
drv_lcd_data_byte(lcd_8080_device_t lcd,rt_uint8_t * data_buf,rt_uint32_t length)149 static void drv_lcd_data_byte(lcd_8080_device_t lcd, rt_uint8_t *data_buf, rt_uint32_t length)
150 {
151     gpiohs_set_pin(lcd->dc_pin, GPIO_PV_HIGH);
152     spi_init(lcd->spi_channel, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
153     spi_init_non_standard(lcd->spi_channel, 8 /*instrction length*/, 0 /*address length*/, 0 /*wait cycles*/,
154                           SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
155     spi_send_data_normal_dma(lcd->dma_channel, lcd->spi_channel, lcd->cs, data_buf, length, SPI_TRANS_CHAR);
156 }
157 
drv_lcd_data_half_word(lcd_8080_device_t lcd,rt_uint16_t * data_buf,rt_uint32_t length)158 static void drv_lcd_data_half_word(lcd_8080_device_t lcd, rt_uint16_t *data_buf, rt_uint32_t length)
159 {
160     gpiohs_set_pin(lcd->dc_pin, GPIO_PV_HIGH);
161     spi_init(lcd->spi_channel, SPI_WORK_MODE_0, SPI_FF_OCTAL, 16, 0);
162     spi_init_non_standard(lcd->spi_channel, 16 /*instrction length*/, 0 /*address length*/, 0 /*wait cycles*/,
163                           SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
164     spi_send_data_normal_dma(lcd->dma_channel, lcd->spi_channel, lcd->cs, data_buf, length, SPI_TRANS_SHORT);
165 }
166 
drv_lcd_data_word(lcd_8080_device_t lcd,rt_uint32_t * data_buf,rt_uint32_t length)167 static void drv_lcd_data_word(lcd_8080_device_t lcd, rt_uint32_t *data_buf, rt_uint32_t length)
168 {
169     gpiohs_set_pin(lcd->dc_pin, GPIO_PV_HIGH);
170     spi_init(lcd->spi_channel, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0);
171     spi_init_non_standard(lcd->spi_channel, 0 /*instrction length*/, 32 /*address length*/, 0 /*wait cycles*/,
172                           SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
173     spi_send_data_normal_dma(lcd->dma_channel, lcd->spi_channel, lcd->cs, data_buf, length, SPI_TRANS_INT);
174 }
175 
drv_lcd_hw_init(lcd_8080_device_t lcd)176 static void drv_lcd_hw_init(lcd_8080_device_t lcd)
177 {
178 #if BSP_LCD_RST_PIN >= 0
179     {
180         gpiohs_set_drive_mode(lcd->rst_pin, GPIO_DM_OUTPUT);
181         gpiohs_set_pin(lcd->rst_pin, GPIO_PV_LOW);
182         msleep(20);
183         gpiohs_set_pin(lcd->rst_pin, GPIO_PV_HIGH);
184         msleep(20);
185     }
186 #endif
187 #if BSP_LCD_BACKLIGHT_PIN >= 0
188     {
189         gpiohs_set_drive_mode(lcd->backlight_pin, GPIO_DM_OUTPUT);
190 #if defined(BSP_LCD_BACKLIGHT_ACTIVE_LOW)
191         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_LOW);
192 #elif defined(BSP_LCD_BACKLIGHT_ACTIVE_HIGH)
193         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_HIGH);
194 #else
195         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_LOW);
196 #endif
197     }
198 #endif
199 
200     gpiohs_set_drive_mode(lcd->dc_pin, GPIO_DM_OUTPUT);
201     gpiohs_set_pin(lcd->dc_pin, GPIO_PV_HIGH);
202     spi_init(lcd->spi_channel, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
203     spi_set_clk_rate(lcd->spi_channel, BSP_LCD_CLK_FREQ);
204 }
205 
drv_lcd_set_direction(lcd_8080_device_t lcd,lcd_dir_t dir)206 static void drv_lcd_set_direction(lcd_8080_device_t lcd, lcd_dir_t dir)
207 {
208     if (dir & DIR_XY_MASK)
209     {
210         lcd->lcd_info.width = BSP_LCD_Y_MAX;
211         lcd->lcd_info.height = BSP_LCD_X_MAX;
212     }
213     else
214     {
215         lcd->lcd_info.width = BSP_LCD_X_MAX;
216         lcd->lcd_info.height = BSP_LCD_Y_MAX;
217     }
218 
219     drv_lcd_cmd(lcd, MEMORY_ACCESS_CTL);
220     drv_lcd_data_byte(lcd, (rt_uint8_t *)&dir, 1);
221 }
222 
drv_lcd_set_area(lcd_8080_device_t lcd,rt_uint16_t x1,rt_uint16_t y1,rt_uint16_t x2,rt_uint16_t y2)223 static void drv_lcd_set_area(lcd_8080_device_t lcd, rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2)
224 {
225     rt_uint8_t data[4] = {0};
226 
227     data[0] = (rt_uint8_t)(x1 >> 8);
228     data[1] = (rt_uint8_t)(x1);
229     data[2] = (rt_uint8_t)(x2 >> 8);
230     data[3] = (rt_uint8_t)(x2);
231     drv_lcd_cmd(lcd, HORIZONTAL_ADDRESS_SET);
232     drv_lcd_data_byte(lcd, data, 4);
233 
234     data[0] = (rt_uint8_t)(y1 >> 8);
235     data[1] = (rt_uint8_t)(y1);
236     data[2] = (rt_uint8_t)(y2 >> 8);
237     data[3] = (rt_uint8_t)(y2);
238     drv_lcd_cmd(lcd, VERTICAL_ADDRESS_SET);
239     drv_lcd_data_byte(lcd, data, 4);
240 
241     drv_lcd_cmd(lcd, MEMORY_WRITE);
242 }
243 
drv_lcd_set_pixel(lcd_8080_device_t lcd,uint16_t x,uint16_t y,uint16_t color)244 static void drv_lcd_set_pixel(lcd_8080_device_t lcd, uint16_t x, uint16_t y, uint16_t color)
245 {
246     drv_lcd_set_area(lcd, x, y, x, y);
247     drv_lcd_data_half_word(lcd, &color, 1);
248 }
249 
drv_lcd_clear(lcd_8080_device_t lcd,uint16_t color)250 static void drv_lcd_clear(lcd_8080_device_t lcd, uint16_t color)
251 {
252     uint32_t data = ((uint32_t)color << 16) | (uint32_t)color;
253 
254     drv_lcd_set_area(lcd, 0, 0, lcd->lcd_info.width - 1, lcd->lcd_info.height - 1);
255     gpiohs_set_pin(lcd->dc_pin, GPIO_PV_HIGH);
256     spi_init(lcd->spi_channel, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0);
257     spi_init_non_standard(lcd->spi_channel, 0 /*instrction length*/, 32 /*address length*/, 0 /*wait cycles*/,
258                           SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
259     spi_fill_data_dma(lcd->dma_channel, lcd->spi_channel, lcd->cs, (const uint32_t *)&data, lcd->lcd_info.width * lcd->lcd_info.height / 2);
260 }
261 
rt_bitblt(rt_uint16_t * dest,int dest_segment,int dest_common,int dest_x,int dest_y,int width,int height,rt_uint16_t * src,int src_segment,int src_common,int src_x,int src_y)262 static void rt_bitblt(rt_uint16_t * dest, int dest_segment, int dest_common, int dest_x, int dest_y, int width, int height,
263         rt_uint16_t *src, int src_segment, int src_common, int src_x, int src_y)
264 {
265     int sx0, sx1, sy0, sy1;
266     int dx0, dx1, dy0, dy1;
267     rt_uint16_t *buff_src;
268     rt_uint16_t *buff_dest;
269     int x, y;
270 
271     if (width <= 0) {
272         return;
273     }
274     if (height <= 0) {
275         return;
276     }
277 
278     sx0 = src_x;
279     sy0 = src_y;
280     sx1 = sx0 + width - 1;
281     sy1 = sy0 + height - 1;
282     dx0 = dest_x;
283     dy0 = dest_y;
284     dx1 = dx0 + width - 1;
285     dy1 = dy0 + height - 1;
286 
287     if (sx0 < 0) {
288         dx0 -= sx0;
289         sx0 = 0;
290     }
291     if (sy0 < 0) {
292         dy0 -= sy0;
293         sy0 = 0;
294     }
295     if (sx1 >= src_segment) {
296         dx1 -= (sx1 - src_segment + 1);
297         sx1 = src_segment - 1;
298     }
299     if (sy1 >= src_common) {
300         dy1 -= (sy1 - src_common + 1);
301         sy1 = src_common - 1;
302     }
303 
304     if (dx0 < 0) {
305         sx0 -= dx0;
306         dx0 = 0;
307     }
308     if (dy0 < 0) {
309         sy0 -= dy0;
310         dy0 = 0;
311     }
312     if (dx1 >= dest_segment) {
313         sx1 -= (dx1 - dest_segment + 1);
314         dx1 = dest_segment - 1;
315     }
316     if (dy1 >= dest_common) {
317         sy1 -= (dy1 - dest_common + 1);
318         dy1 = dest_common - 1;
319     }
320 
321     if (sx1 < 0 || sx0 >= src_segment) {
322         return;
323     }
324     if (sy1 < 0 || sy0 >= src_common) {
325         return;
326     }
327     if (dx1 < 0 || dx0 >= dest_segment) {
328         return;
329     }
330     if (dy1 < 0 || dy0 >= dest_common) {
331         return;
332     }
333 
334     if ((rt_ubase_t)dest < (rt_ubase_t)src) {
335         buff_src = src + (sy0 * src_segment) + sx0;
336         buff_dest = dest + (dy0 * dest_segment) + dx0;
337         for (y = sy0; y <= sy1; y++) {
338             src = buff_src;
339             dest = buff_dest;
340             for (x = sx0; x <= sx1; x++) {
341                 *dest++ = *src++;
342             }
343             buff_src += src_segment;
344             buff_dest += dest_segment;
345         }
346     } else {
347         buff_src = src + (sy1 * src_segment) + sx1;
348         buff_dest = dest + (dy1 * dest_segment) + dx1;
349         for (y = sy1; y >= sy0; y--) {
350             src = buff_src;
351             dest = buff_dest;
352             for (x = sx1; x >= sx0; x--) {
353                 *dest-- = *src--;
354             }
355             buff_src -= src_segment;
356             buff_dest -= dest_segment;
357         }
358     }
359 }
360 
drv_lcd_rect_update(lcd_8080_device_t lcd,uint16_t x1,uint16_t y1,uint16_t width,uint16_t height)361 static void drv_lcd_rect_update(lcd_8080_device_t lcd, uint16_t x1, uint16_t y1, uint16_t width, uint16_t height)
362 {
363     static rt_uint16_t * rect_buffer = RT_NULL;
364     if(!rect_buffer)
365     {
366         rect_buffer = rt_malloc_align(lcd->lcd_info.height * lcd->lcd_info.width * (lcd->lcd_info.bits_per_pixel / 8), 64);
367         if(!rect_buffer)
368         {
369             return;
370         }
371     }
372     if(x1 == 0 && y1 == 0 && width == lcd->lcd_info.width && height == lcd->lcd_info.height)
373     {
374         drv_lcd_set_area(lcd, x1, y1, x1 + width - 1, y1 + height - 1);
375         drv_lcd_data_half_word(lcd, (rt_uint32_t *)lcd->lcd_info.framebuffer, width * height);
376     }
377     else
378     {
379         rt_bitblt(rect_buffer, width, height, 0, 0, width, height,
380         (rt_uint16_t *)lcd->lcd_info.framebuffer, lcd->lcd_info.width, lcd->lcd_info.height, x1, y1);
381         drv_lcd_set_area(lcd, x1, y1, x1 + width - 1, y1 + height - 1);
382         drv_lcd_data_half_word(lcd, (rt_uint16_t *)rect_buffer, width * height);
383     }
384 }
385 
drv_lcd_init(rt_device_t dev)386 static rt_err_t drv_lcd_init(rt_device_t dev)
387 {
388     rt_err_t ret = RT_EOK;
389     lcd_8080_device_t lcd = (lcd_8080_device_t)dev;
390     rt_uint8_t data = 0;
391 
392     if(!lcd)
393     {
394         return -RT_ERROR;
395     }
396     drv_lcd_hw_init(lcd);
397     /* reset LCD */
398     drv_lcd_cmd(lcd, SOFTWARE_RESET);
399     rt_thread_mdelay(100);
400 
401     /* Enter normal status */
402     drv_lcd_cmd(lcd, SLEEP_OFF);
403     rt_thread_mdelay(100);
404 
405     /* pixel format rgb565 */
406     drv_lcd_cmd(lcd, PIXEL_FORMAT_SET);
407     data = 0x55;
408     drv_lcd_data_byte(lcd, &data, 1);
409 
410     /* set direction */
411     drv_lcd_set_direction(lcd, LCD_SCAN_DIR);
412 
413     lcd->lcd_info.framebuffer = rt_malloc_align(lcd->lcd_info.height * lcd->lcd_info.width * (lcd->lcd_info.bits_per_pixel / 8), 64);
414     RT_ASSERT(lcd->lcd_info.framebuffer);
415 
416     uint16_t *framebuffer = (uint16_t *)(lcd->lcd_info.framebuffer);
417     for(uint32_t i=0; i<(lcd->lcd_info.height * lcd->lcd_info.width * (lcd->lcd_info.bits_per_pixel / 8))/2; i++) {
418         framebuffer[i] = BLACK;
419     }
420     /*display on*/
421     #ifdef BSP_BOARD_K210_DRACO
422     drv_lcd_cmd(lcd, INVERSION_DISPALY_ON);
423     #endif
424     drv_lcd_cmd(lcd, DISPALY_ON);
425 
426     /* set to black */
427     drv_lcd_clear(lcd, BLACK);
428     return ret;
429 }
430 
drv_lcd_open(rt_device_t dev,rt_uint16_t oflag)431 static rt_err_t drv_lcd_open(rt_device_t dev, rt_uint16_t oflag)
432 {
433 
434     /* Not need */
435 
436     return RT_EOK;
437 }
438 
drv_lcd_close(rt_device_t dev)439 static rt_err_t drv_lcd_close(rt_device_t dev)
440 {
441 
442     /* Not need */
443 
444     return RT_EOK;
445 }
446 
drv_lcd_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)447 static rt_ssize_t drv_lcd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
448 {
449 
450     /* Not need */
451 
452     return 0;
453 }
454 
drv_lcd_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)455 static rt_ssize_t drv_lcd_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
456 {
457 
458     /* Not need */
459 
460     return 0;
461 }
462 
drv_lcd_control(rt_device_t dev,int cmd,void * args)463 static rt_err_t drv_lcd_control(rt_device_t dev, int cmd, void *args)
464 {
465     rt_err_t ret = RT_EOK;
466     lcd_8080_device_t lcd = (lcd_8080_device_t)dev;
467     rt_base_t level;
468     struct rt_device_rect_info* rect_info = (struct rt_device_rect_info*)args;
469 
470     RT_ASSERT(dev != RT_NULL);
471 
472     switch (cmd)
473     {
474     case RTGRAPHIC_CTRL_RECT_UPDATE:
475         if(!rect_info)
476         {
477             LOG_E("RTGRAPHIC_CTRL_RECT_UPDATE error args");
478             return -RT_ERROR;
479         }
480         drv_lcd_rect_update(lcd, rect_info->x, rect_info->y, rect_info->width, rect_info->height);
481         break;
482 
483 #if BSP_LCD_BACKLIGHT_PIN >= 0
484     case RTGRAPHIC_CTRL_POWERON:
485 #if defined(BSP_LCD_BACKLIGHT_ACTIVE_LOW)
486         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_LOW);
487 #elif defined(BSP_LCD_BACKLIGHT_ACTIVE_HIGH)
488         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_HIGH);
489 #else
490         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_LOW);
491 #endif
492         break;
493 
494     case RTGRAPHIC_CTRL_POWEROFF:
495 #if defined(BSP_LCD_BACKLIGHT_ACTIVE_LOW)
496         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_HIGH);
497 #elif defined(BSP_LCD_BACKLIGHT_ACTIVE_HIGH)
498         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_LOW);
499 #else
500         gpiohs_set_pin(lcd->backlight_pin, GPIO_PV_HIGH);
501 #endif
502         break;
503 #endif /* BSP_LCD_BACKLIGHT_PIN >= 0 */
504 
505     case RTGRAPHIC_CTRL_GET_INFO:
506         *(struct rt_device_graphic_info *)args = lcd->lcd_info;
507         break;
508 
509     case RTGRAPHIC_CTRL_SET_MODE:
510         ret = -RT_ENOSYS;
511         break;
512     case RTGRAPHIC_CTRL_GET_EXT:
513         ret = -RT_ENOSYS;
514         break;
515     default:
516         LOG_E("drv_lcd_control cmd: %d", cmd);
517         break;
518     }
519 
520     return ret;
521 }
522 
523 #ifdef RT_USING_DEVICE_OPS
524 const static struct rt_device_ops drv_lcd_ops =
525 {
526     drv_lcd_init,
527     drv_lcd_open,
528     drv_lcd_close,
529     drv_lcd_read,
530     drv_lcd_write,
531     drv_lcd_control
532 };
533 #endif
534 
535 
rt_hw_lcd_init(void)536 int rt_hw_lcd_init(void)
537 {
538     rt_err_t ret = RT_EOK;
539     lcd_8080_device_t lcd_dev = &_lcddev;
540 
541     lcd_dev->cs                         = SPI_CHIP_SELECT_0;
542     lcd_dev->dc_pin                     = LCD_DC_PIN;
543 #if BSP_LCD_RST_PIN >= 0
544     lcd_dev->rst_pin                    = LCD_RST_PIN;
545 #endif
546 #if BSP_LCD_BACKLIGHT_PIN >= 0
547     lcd_dev->backlight_pin              = LCD_BACKLIGHT_PIN;
548 #endif
549     dmalock_sync_take(&lcd_dev->dma_channel, RT_WAITING_FOREVER);
550     lcd_dev->spi_channel                = SPI_DEVICE_0;
551     lcd_dev->lcd_info.bits_per_pixel    = 16;
552     lcd_dev->lcd_info.pixel_format      = RTGRAPHIC_PIXEL_FORMAT_RGB565;
553 
554     lcd_dev->parent.type        = RT_Device_Class_Graphic;
555     lcd_dev->parent.rx_indicate = RT_NULL;
556     lcd_dev->parent.tx_complete = RT_NULL;
557 
558 #ifdef RT_USING_DEVICE_OPS
559     lcd_dev->parent.ops        = &drv_lcd_ops;
560 #else
561     lcd_dev->parent.init    = drv_lcd_init;
562     lcd_dev->parent.open    = drv_lcd_open;
563     lcd_dev->parent.close   = drv_lcd_close;
564     lcd_dev->parent.read    = drv_lcd_read;
565     lcd_dev->parent.write   = drv_lcd_write;
566     lcd_dev->parent.control = drv_lcd_control;
567 #endif
568 
569     lcd_dev->parent.user_data = RT_NULL;
570 
571     ret = rt_device_register(&lcd_dev->parent, "lcd", RT_DEVICE_FLAG_RDWR);
572 
573     return ret;
574 }
575 INIT_DEVICE_EXPORT(rt_hw_lcd_init);
576 
lcd_set_direction(lcd_dir_t dir)577 void lcd_set_direction(lcd_dir_t dir)
578 {
579     drv_lcd_set_direction(&_lcddev, dir);
580 }
581 
582 #endif
583