#include "ep2108s.h" #include #include #include #include #include static void LCD_power_on(u32 sel); static void LCD_power_off(u32 sel); static void LCD_bl_open(u32 sel); static void LCD_bl_close(u32 sel); static void LCD_panel_init(u32 sel); static void LCD_panel_exit(u32 sel); #define REGFLAG_DELAY 0xFE #define REGFLAG_END_OF_TABLE 0xFD #define SPI_SCL_IDX 0 // lcd_gpio_0 = PE2 default 0 #define SPI_SDA_IDX 1 // lcd_gpio_1 = PE3 default 0 #define SPI_CS_IDX 2 // lcd_gpio_2 = PE1 default 1 #define PANEL_RST_IDX 3 // lcd_gpio_3 = PE4 default 1 static DEFINE_MUTEX(lcd_spi_mutex); static void io_exp_set(u32 sel, u32 idx, u8 val) { sunxi_lcd_gpio_set_value(sel, idx, val); } static void lcd_spi_send(u32 sel, u8 cmd_mode, u8 data) { int i; unsigned long irq_flags; mutex_lock(&lcd_spi_mutex); local_irq_save(irq_flags); io_exp_set(sel, SPI_CS_IDX, 0); udelay(1); // rs eg cmd/data io_exp_set(sel, SPI_SDA_IDX, cmd_mode); io_exp_set(sel, SPI_SCL_IDX, 0); udelay(1); io_exp_set(sel, SPI_SCL_IDX, 1); udelay(1); // i from 7 downto 0,高位先出 for (i = 7; i >= 0; i--) { io_exp_set(sel, SPI_SDA_IDX, (data >> i) & 1); io_exp_set(sel, SPI_SCL_IDX, 0); udelay(1); io_exp_set(sel, SPI_SCL_IDX, 1); udelay(1); } io_exp_set(sel, SPI_CS_IDX, 1); udelay(1); // return to 0 free io_exp_set(sel, SPI_SCL_IDX, 0); io_exp_set(sel, SPI_SDA_IDX, 0); local_irq_restore(irq_flags); mutex_unlock(&lcd_spi_mutex); } #define write_cmd(sel, cmd) lcd_spi_send(sel, 0, cmd) #define write_data(sel, dat) lcd_spi_send(sel, 1, dat) #define panel_reset(val) io_exp_set(sel, PANEL_RST_IDX, val) struct ep2108s_cmd { u8 cmd; u8 count; u8 para[16]; }; static const struct ep2108s_cmd ep2108s_init_cmds[] = { {0xFF, 5, {0x77,0x01,0x00,0x00,0x10}}, {0xC0, 2, {0x3B,0x00}}, {0xC1, 2, {0x0B,0x02}}, {0xC2, 2, {0x07,0x02}}, {0xCC, 1, {0x10}}, {0xB0, 16, {0x00,0x11,0x16,0x0E,0x11,0x06,0x05,0x09,0x08,0x21,0x06,0x13,0x10,0x29,0x31,0x18}}, {0xB1, 16, {0x00,0x11,0x16,0x0E,0x11,0x07,0x05,0x09,0x09,0x21,0x05,0x13,0x11,0x2A,0x31,0x18}}, {0xFF, 5, {0x77,0x01,0x00,0x00,0x11}}, {0xB0, 1, {0x6D}}, {0xB1, 1, {0x37}}, {0xB2, 1, {0x81}}, {0xB3, 1, {0x80}}, {0xB5, 1, {0x43}}, {0xB7, 1, {0x85}}, {0xB8, 1, {0x20}}, {0xC1, 1, {0x78}}, {0xC2, 1, {0x78}}, {0xD0, 1, {0x88}}, {REGFLAG_DELAY, 100, {}}, {0xE0, 3, {0x00,0x00,0x02}}, {0xE1, 10, {0x03,0xA0,0x00,0x00,0x04,0xA0,0x00,0x00,0x00,0x20,0x20}}, {0xE2, 13, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, {0xE3, 4, {0x00,0x00,0x11,0x00}}, {0xE4, 2, {0x22,0x00}}, {0xE5, 16, {0x05,0xEC,0xA0,0xA0,0x07,0xEE,0xA0,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, {0xE6, 4, {0x00,0x00,0x11,0x00}}, {0xE7, 2, {0x22,0x00}}, {0xE8, 16, {0x06,0xED,0xA0,0xA0,0x08,0xEF,0xA0,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, {0xEB, 7, {0x00,0x00,0x40,0x40,0x00,0x00,0x00}}, {0xED, 16, {0xFF,0xFF,0xFF,0xBA,0x0A,0xBF,0x45,0xFF,0xFF,0x54,0xFB,0xA0,0xAB,0xFF,0xFF,0xFF}}, {0xEF, 6, {0x10,0x0D,0x04,0x08,0x3F,0x1F}}, {0xFF, 5, {0x77,0x01,0x00,0x00,0x13}}, {0xEF, 1, {0x08}}, {0xFF, 5, {0x77,0x01,0x00,0x00,0x00}}, {0x11, 0, {}}, {REGFLAG_DELAY, 120, {}}, {0x29, 0, {}}, {0x36, 1, {0x08}}, {0x3A, 1, {0x77}}, {REGFLAG_END_OF_TABLE, 0, {}} }; static void ep2108s_send_cmds(u32 sel) { int i, j; for (i = 0;; i++) { const struct ep2108s_cmd *c = &ep2108s_init_cmds[i]; if (c->cmd == REGFLAG_END_OF_TABLE) break; if (c->cmd == REGFLAG_DELAY) { pr_info("EP2108S DELAY %d ms\n", c->count); sunxi_lcd_delay_ms(c->count); continue; } pr_info("EP2108S Write Reg CMD:0x%02X, param count:%d\n", c->cmd, c->count); write_cmd(sel, c->cmd); for (j = 0; j < c->count; j++) write_data(sel, c->para[j]); } } static void LCD_panel_init(u32 sel) { pr_info("EP2108S: panel register init start\n"); ep2108s_send_cmds(sel); pr_info("panel ep2108s init success"); } static void LCD_cfg_panel_info(panel_extend_para *info) { u32 i = 0, j = 0; u32 items; u8 lcd_gamma_tbl[][2] = { {0, 0}, {15, 15}, {30, 30}, {45, 45}, {60, 60}, {75, 75}, {90, 90}, {105, 105}, {120, 120}, {135, 135}, {150, 150}, {165, 165}, {180, 180}, {195, 195}, {210, 210}, {225, 225}, {240, 240}, {255, 255}, }; u32 lcd_cmap_tbl[2][3][4] = { { {LCD_CMAP_G0, LCD_CMAP_B1, LCD_CMAP_G2, LCD_CMAP_B3}, {LCD_CMAP_B0, LCD_CMAP_R1, LCD_CMAP_B2, LCD_CMAP_R3}, {LCD_CMAP_R0, LCD_CMAP_G1, LCD_CMAP_R2, LCD_CMAP_G3}, }, { {LCD_CMAP_B3, LCD_CMAP_G2, LCD_CMAP_B1, LCD_CMAP_G0}, {LCD_CMAP_R3, LCD_CMAP_B2, LCD_CMAP_R1, LCD_CMAP_B0}, {LCD_CMAP_G3, LCD_CMAP_R2, LCD_CMAP_R1, LCD_CMAP_R0}, }, }; items = sizeof(lcd_gamma_tbl) / 2; for (i = 0; i < items - 1; i++) { u32 num = lcd_gamma_tbl[i + 1][0] - lcd_gamma_tbl[i][0]; for (j = 0; j < num; j++) { u32 value = 0; value = lcd_gamma_tbl[i][1] + ((lcd_gamma_tbl[i + 1][1] - lcd_gamma_tbl[i][1]) * j) / num; info->lcd_gamma_tbl[lcd_gamma_tbl[i][0] + j] = (value << 16) + (value << 8) + value; } } info->lcd_gamma_tbl[255] = (lcd_gamma_tbl[items - 1][1] << 16) + (lcd_gamma_tbl[items - 1][1] << 8) + lcd_gamma_tbl[items - 1][1]; memcpy(info->lcd_cmap_tbl, lcd_cmap_tbl, sizeof(lcd_cmap_tbl)); } static s32 LCD_open_flow(u32 sel) { pr_info("EP2108S: open flow start\n"); LCD_power_on(sel); sunxi_lcd_delay_ms(30); LCD_panel_init(sel); sunxi_lcd_delay_ms(200); sunxi_lcd_tcon_enable(sel); sunxi_lcd_delay_ms(100); LCD_bl_open(sel); pr_info("EP2108S: open flow complete\n"); return 0; } static s32 LCD_close_flow(u32 sel) { pr_info("EP2108S: close flow start\n"); LCD_CLOSE_FUNC(sel, LCD_bl_close,0); LCD_CLOSE_FUNC(sel, sunxi_lcd_tcon_disable, 50); LCD_CLOSE_FUNC(sel, LCD_panel_exit, 10); LCD_CLOSE_FUNC(sel, LCD_power_off, 10); pr_info("EP2108S: close flow complete\n"); return 0; } static void LCD_power_on(u32 sel) { pr_info("EP2108S: power_on start, init IOE gpio\n"); sunxi_lcd_pin_cfg(sel, 1); pr_info("EP2108S: reset pull low start\n"); panel_reset(0); sunxi_lcd_delay_ms(50); pr_info("EP2108S: reset pull high start\n"); panel_reset(1); sunxi_lcd_delay_ms(120); pr_info("EP2108S: hardware reset finish, wait IC stable done\n"); } static void LCD_power_off(u32 sel) { panel_reset(0); sunxi_lcd_delay_ms(10); sunxi_lcd_pin_cfg(sel, 0); } static void LCD_panel_exit(u32 sel) { write_cmd(sel, 0x28); sunxi_lcd_delay_ms(20); write_cmd(sel, 0x10); sunxi_lcd_delay_ms(120); panel_reset(0); sunxi_lcd_delay_ms(30); } static void LCD_bl_open(u32 sel) { // sunxi_lcd_pwm_enable(sel); // sunxi_lcd_backlight_enable(sel); } static void LCD_bl_close(u32 sel) { // sunxi_lcd_backlight_disable(sel); // sunxi_lcd_pwm_disable(sel); } static s32 LCD_user_defined_func(u32 sel, u32 para1, u32 para2, u32 para3) { return 0; } struct __lcd_panel_t ep2108s_panel = { .name = "ep2108s", .func = { .cfg_panel_info = LCD_cfg_panel_info, .cfg_open_flow = LCD_open_flow, .cfg_close_flow = LCD_close_flow, .lcd_user_defined_func = LCD_user_defined_func, }, };