From ae6e22e9b70c5aaf6ac8b195ae7a83ef215db821 Mon Sep 17 00:00:00 2001 From: "shaochan.liu" Date: Fri, 26 Jul 2019 16:07:02 +0800 Subject: [PATCH] lcd: add driver for pmu data check [2/2] PD#TV-6928 Problem: CS602 need pmu data check Solution: add i2c_CS602 driver with pmu data check Verify: t962x3_ab301 Change-Id: I1d1f33cbb63cb4f3b3fc308d610411091cb2a65d Signed-off-by: shaochan.liu --- MAINTAINERS | 3 + arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts | 7 + arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts | 7 + arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts | 7 + arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts | 7 + drivers/amlogic/media/vout/lcd/lcd_extern/Kconfig | 12 +- drivers/amlogic/media/vout/lcd/lcd_extern/Makefile | 3 +- .../amlogic/media/vout/lcd/lcd_extern/i2c_CS602.c | 347 +++++++++++++++++++++ .../amlogic/media/vout/lcd/lcd_extern/lcd_extern.c | 4 + .../amlogic/media/vout/lcd/lcd_extern/lcd_extern.h | 4 + 10 files changed, 399 insertions(+), 2 deletions(-) create mode 100644 drivers/amlogic/media/vout/lcd/lcd_extern/i2c_CS602.c diff --git a/MAINTAINERS b/MAINTAINERS index d980c44..307ec06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15132,3 +15132,6 @@ F: drivers/amlogic/drm/meson_vpu_pipeline.c F: drivers/amlogic/drm/meson_vpu_pipeline_traverse.c F: include/dt-bindings/display/meson-drm-ids.h +AMLOGIC LCD EXTERN DRIVER +M: Shaochan Liu +F: drivers/amlogic/media/vout/lcd/lcd_extern/i2c_CS602.c diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts index c2d23d3..4e3cfe7 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts @@ -2157,6 +2157,13 @@ reg = <0x74>; status = "okay"; }; + + lcd_extern_i2c3: lcd_extern_i2c@3 { + compatible = "lcd_ext, i2c"; + dev_name = "i2c_CS602"; + reg = <0x66>; + status = "disable"; + }; }; &pwm_ab { diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts index 21db453..bea8adc 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts @@ -2154,6 +2154,13 @@ reg = <0x74>; status = "okay"; }; + + lcd_extern_i2c3: lcd_extern_i2c@3 { + compatible = "lcd_ext, i2c"; + dev_name = "i2c_CS602"; + reg = <0x66>; + status = "disable"; + }; }; &pwm_ab { diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts index 690ee8b..e9c4c29 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts @@ -2154,6 +2154,13 @@ reg = <0x74>; status = "okay"; }; + + lcd_extern_i2c3: lcd_extern_i2c@3 { + compatible = "lcd_ext, i2c"; + dev_name = "i2c_CS602"; + reg = <0x66>; + status = "disable"; + }; }; &pwm_ab { diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts index 7c717e5..5871b9a 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts @@ -2147,6 +2147,13 @@ reg = <0x74>; status = "okay"; }; + + lcd_extern_i2c3: lcd_extern_i2c@3 { + compatible = "lcd_ext, i2c"; + dev_name = "i2c_CS602"; + reg = <0x66>; + status = "disable"; + }; }; &pwm_ab { diff --git a/drivers/amlogic/media/vout/lcd/lcd_extern/Kconfig b/drivers/amlogic/media/vout/lcd/lcd_extern/Kconfig index b346b01..50b3391 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_extern/Kconfig +++ b/drivers/amlogic/media/vout/lcd/lcd_extern/Kconfig @@ -45,6 +45,16 @@ config AMLOGIC_LCD_EXTERN_I2C_ANX6345 through the i2c interface to write data to the LCD, make its initialization +config AMLOGIC_LCD_EXTERN_I2C_CS602 + bool "lcd external i2c CS602 init driver" + default n + depends on AMLOGIC_LCD_EXTERN + help + Amlogic LCD external i2c_CS602 init driver support + Once the power on, according to the timing requirements, + through the i2c interface to write data to the LCD, + make its initialization + config AMLOGIC_LCD_EXTERN_SPI_LD070WS2 bool "lcd external spi LD070WS2 init driver" default n @@ -113,4 +123,4 @@ config AMLOGIC_LCD_EXTERN_MIPI_TL050FHV02CT Amlogic LCD external mipi_TL050FHV02CT init driver support Once the power on, according to the timing requirements, through the mipi interface to write data to the LCD, - make its initialization \ No newline at end of file + make its initialization diff --git a/drivers/amlogic/media/vout/lcd/lcd_extern/Makefile b/drivers/amlogic/media/vout/lcd/lcd_extern/Makefile index 376ffd6..5f1bd6f 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_extern/Makefile +++ b/drivers/amlogic/media/vout/lcd/lcd_extern/Makefile @@ -2,9 +2,10 @@ obj-$(CONFIG_AMLOGIC_LCD_EXTERN) += lcd_extern.o ext_default.o mipi_default.o obj-$(CONFIG_AMLOGIC_LCD_EXTERN_I2C_T5800Q) += i2c_T5800Q.o obj-$(CONFIG_AMLOGIC_LCD_EXTERN_I2C_ANX6862_7911) += i2c_ANX6862_7911.o obj-$(CONFIG_AMLOGIC_LCD_EXTERN_I2C_DLPC3439) += i2c_DLPC3439.o +obj-$(CONFIG_AMLOGIC_LCD_EXTERN_I2C_CS602) += i2c_CS602.o obj-$(CONFIG_AMLOGIC_LCD_EXTERN_SPI_LD070WS2) += spi_LD070WS2.o obj-$(CONFIG_AMLOGIC_LCD_EXTERN_MIPI_KD080D13) += mipi_KD080D13.o obj-$(CONFIG_AMLOGIC_LCD_EXTERN_MIPI_TV070WSM) += mipi_TV070WSM.o obj-$(CONFIG_AMLOGIC_LCD_EXTERN_MIPI_ST7701) += mipi_ST7701.o obj-$(CONFIG_AMLOGIC_LCD_EXTERN_MIPI_P070ACB) += mipi_P070ACB.o -obj-$(CONFIG_AMLOGIC_LCD_EXTERN_MIPI_TL050FHV02CT) += mipi_TL050FHV02CT.o \ No newline at end of file +obj-$(CONFIG_AMLOGIC_LCD_EXTERN_MIPI_TL050FHV02CT) += mipi_TL050FHV02CT.o diff --git a/drivers/amlogic/media/vout/lcd/lcd_extern/i2c_CS602.c b/drivers/amlogic/media/vout/lcd/lcd_extern/i2c_CS602.c new file mode 100644 index 0000000..63ebcb7 --- /dev/null +++ b/drivers/amlogic/media/vout/lcd/lcd_extern/i2c_CS602.c @@ -0,0 +1,347 @@ +/* + * drivers/amlogic/media/vout/lcd/lcd_extern/i2c_T5800Q.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lcd_extern.h" + +#define LCD_EXTERN_NAME "i2c_CS602" +#define LCD_EXTERN_I2C_ADDR (0x66) /* 7bit address */ +#define LCD_EXTERN_I2C_BUS LCD_EXTERN_I2C_BUS_2 + +static struct lcd_extern_config_s *ext_config; +static struct aml_lcd_extern_i2c_dev_s *i2c_dev; + +#define LCD_EXTERN_CMD_SIZE LCD_EXT_CMD_SIZE_DYNAMIC + +static int lcd_extern_reg_read(unsigned char reg, unsigned char *buf) +{ + int ret = 0; + + return ret; +} + +static int lcd_extern_reg_write(unsigned char *buf, unsigned int len) +{ + int ret = 0; + + if (buf == NULL) { + EXTERR("%s: buf is full\n", __func__); + return -1; + } + + if (!len) { + EXTERR("%s: invalid len\n", __func__); + return -1; + } + + ret = lcd_extern_i2c_write(i2c_dev->client, buf, len); + return ret; +} + +static int lcd_extern_init_check(int len) +{ + int ret = 0; + unsigned char *chk_table; + int i; + + chk_table = kmalloc((sizeof(unsigned char) * len), + GFP_KERNEL); + if (chk_table == NULL) { + EXTERR("%s: failed to alloc chk_table, not enough memory\n", + LCD_EXTERN_NAME); + return ret; + } + memset(chk_table, 0, len); + + if (i2c_dev->client == NULL) { + EXTERR("%s: invalid i2c client\n", __func__); + return -1; + } + ret = lcd_extern_i2c_read(i2c_dev->client, chk_table, len); + if (ret == 0) { + for (i = 0; i < len; i++) { + if (chk_table[i] != ext_config->table_init_on[i+3]) + return -1; + } + } + + return 0; +} + +static int lcd_extern_power_cmd_dynamic_size(unsigned char *table, int flag) +{ + int i = 0, j, step = 0, max_len = 0; + unsigned char type, cmd_size; + int delay_ms, ret = 0; + + if (flag) + max_len = ext_config->table_init_on_cnt; + else + max_len = ext_config->table_init_off_cnt; + + while ((i + 1) < max_len) { + type = table[i]; + if (type == LCD_EXT_CMD_TYPE_END) + break; + if (lcd_debug_print_flag) { + EXTPR("%s: step %d: type=0x%02x, cmd_size=%d\n", + __func__, step, type, table[i+1]); + } + cmd_size = table[i+1]; + if (cmd_size == 0) + goto power_cmd_dynamic_next; + if ((i + 2 + cmd_size) > max_len) + break; + + if (type == LCD_EXT_CMD_TYPE_NONE) { + /* do nothing */ + } else if (type == LCD_EXT_CMD_TYPE_GPIO) { + if (cmd_size < 2) { + EXTERR( + "step %d: invalid cmd_size %d for GPIO\n", + step, cmd_size); + goto power_cmd_dynamic_next; + } + if (table[i+2] < LCD_GPIO_MAX) + lcd_extern_gpio_set(table[i+2], table[i+3]); + if (cmd_size > 2) { + if (table[i+4] > 0) + mdelay(table[i+4]); + } + } else if (type == LCD_EXT_CMD_TYPE_DELAY) { + delay_ms = 0; + for (j = 0; j < cmd_size; j++) + delay_ms += table[i+2+j]; + if (delay_ms > 0) + mdelay(delay_ms); + } else if (type == LCD_EXT_CMD_TYPE_CMD) { + if (i2c_dev == NULL) { + EXTERR("invalid i2c device\n"); + return -1; + } + ret = lcd_extern_reg_write(&table[i+2], cmd_size); + } else if (type == LCD_EXT_CMD_TYPE_CMD_DELAY) { + if (i2c_dev == NULL) { + EXTERR("invalid i2c device\n"); + return -1; + } + ret = lcd_extern_reg_write(&table[i+2], (cmd_size-1)); + if (table[i+cmd_size+1] > 0) + mdelay(table[i+cmd_size+1]); + } else { + EXTERR("%s: %s(%d): type 0x%02x invalid\n", + __func__, ext_config->name, + ext_config->index, type); + } +power_cmd_dynamic_next: + i += (cmd_size + 2); + step++; + } + + return ret; +} + +static int lcd_extern_power_cmd_fixed_size(unsigned char *table, int flag) +{ + int i = 0, j, step = 0, max_len = 0; + unsigned char type, cmd_size; + int delay_ms, ret = 0; + + cmd_size = ext_config->cmd_size; + if (cmd_size < 2) { + EXTERR("%s: invalid cmd_size %d\n", __func__, cmd_size); + return -1; + } + + if (flag) + max_len = ext_config->table_init_on_cnt; + else + max_len = ext_config->table_init_off_cnt; + + while ((i + cmd_size) <= max_len) { + type = table[i]; + if (type == LCD_EXT_CMD_TYPE_END) + break; + if (lcd_debug_print_flag) { + EXTPR("%s: step %d: type=0x%02x, cmd_size=%d\n", + __func__, step, type, cmd_size); + } + if (type == LCD_EXT_CMD_TYPE_NONE) { + /* do nothing */ + } else if (type == LCD_EXT_CMD_TYPE_GPIO) { + if (table[i+1] < LCD_GPIO_MAX) + lcd_extern_gpio_set(table[i+1], table[i+2]); + if (cmd_size > 3) { + if (table[i+3] > 0) + mdelay(table[i+3]); + } + } else if (type == LCD_EXT_CMD_TYPE_DELAY) { + delay_ms = 0; + for (j = 0; j < (cmd_size - 1); j++) + delay_ms += table[i+1+j]; + if (delay_ms > 0) + mdelay(delay_ms); + } else if (type == LCD_EXT_CMD_TYPE_CMD) { + if (i2c_dev == NULL) { + EXTERR("invalid i2c device\n"); + return -1; + } + ret = lcd_extern_reg_write(&table[i+1], (cmd_size-1)); + } else if (type == LCD_EXT_CMD_TYPE_CMD_DELAY) { + if (i2c_dev == NULL) { + EXTERR("invalid i2c device\n"); + return -1; + } + ret = lcd_extern_reg_write(&table[i+1], (cmd_size-2)); + if (table[i+cmd_size-1] > 0) + mdelay(table[i+cmd_size-1]); + } else { + EXTERR("%s: %s(%d): type 0x%02x invalid\n", + __func__, ext_config->name, + ext_config->index, type); + } + i += cmd_size; + step++; + } + + return ret; +} + +static int lcd_extern_power_ctrl(int flag) +{ + unsigned char *table; + unsigned char cmd_size; + unsigned char check_data; + unsigned char check_len = 1; + int ret = 0; + int i = 0; + + cmd_size = ext_config->cmd_size; + if (flag) + table = ext_config->table_init_on; + else + table = ext_config->table_init_off; + if (cmd_size < 1) { + EXTERR("%s: cmd_size %d is invalid\n", __func__, cmd_size); + return -1; + } + if (table == NULL) { + EXTERR("%s: init_table %d is NULL\n", __func__, flag); + return -1; + } + + ret = lcd_extern_init_check(cmd_size); + if (!ret) { + if (cmd_size == LCD_EXT_CMD_SIZE_DYNAMIC) + ret = lcd_extern_power_cmd_dynamic_size(table, flag); + else + ret = lcd_extern_power_cmd_fixed_size(table, flag); + } + + for (i = 0; i < 10; i++) { + ret = lcd_extern_i2c_read(i2c_dev->client, + &check_data, check_len); + if (!((ret >> 6) & 0x1)) { + if (cmd_size == LCD_EXT_CMD_SIZE_DYNAMIC) + ret = + lcd_extern_power_cmd_dynamic_size(table, flag); + else + ret = + lcd_extern_power_cmd_fixed_size(table, flag); + } else + break; + } + + EXTPR("%s: %s(%d): %d\n", + __func__, ext_config->name, ext_config->index, flag); + return ret; +} + +static int lcd_extern_power_on(void) +{ + int ret; + + lcd_extern_pinmux_set(1); + ret = lcd_extern_power_ctrl(1); + return ret; +} + +static int lcd_extern_power_off(void) +{ + int ret; + + ret = lcd_extern_power_ctrl(0); + lcd_extern_pinmux_set(0); + return ret; +} + +static int lcd_extern_driver_update(struct aml_lcd_extern_driver_s *ext_drv) +{ + if (ext_drv == NULL) { + EXTERR("%s driver is null\n", LCD_EXTERN_NAME); + return -1; + } + + if (ext_drv->config->table_init_loaded == 0) { + EXTERR("%s: table_init is invalid\n", ext_drv->config->name); + return -1; + } + + ext_drv->power_on = lcd_extern_power_on; + ext_drv->power_off = lcd_extern_power_off; + ext_drv->reg_read = lcd_extern_reg_read; + + return 0; +} + +int aml_lcd_extern_i2c_CS602_probe(struct aml_lcd_extern_driver_s *ext_drv) +{ + int ret = 0; + + ext_config = ext_drv->config; + + i2c_dev = lcd_extern_get_i2c_device(ext_config->i2c_addr); + if (i2c_dev == NULL) { + EXTERR("invalid i2c device\n"); + return -1; + } + EXTPR("get i2c device: %s, addr 0x%02x OK\n", + i2c_dev->name, i2c_dev->client->addr); + + ret = lcd_extern_driver_update(ext_drv); + EXTPR("%s: %d\n", __func__, ret); + return ret; +} + +int aml_lcd_extern_i2c_CS602_remove(void) +{ + i2c_dev = NULL; + ext_config = NULL; + + return 0; +} + diff --git a/drivers/amlogic/media/vout/lcd/lcd_extern/lcd_extern.c b/drivers/amlogic/media/vout/lcd/lcd_extern/lcd_extern.c index 0de4274..9bb3f72 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_extern/lcd_extern.c +++ b/drivers/amlogic/media/vout/lcd/lcd_extern/lcd_extern.c @@ -1468,6 +1468,10 @@ static int lcd_extern_add_i2c(struct aml_lcd_extern_driver_s *ext_drv) #ifdef CONFIG_AMLOGIC_LCD_EXTERN_I2C_DLPC3439 ret = aml_lcd_extern_i2c_DLPC3439_probe(ext_drv); #endif + } else if (strcmp(ext_drv->config->name, "i2c_CS602") == 0) { +#ifdef CONFIG_AMLOGIC_LCD_EXTERN_I2C_CS602 + ret = aml_lcd_extern_i2c_CS602_probe(ext_drv); +#endif } else if (strcmp(ext_drv->config->name, "i2c_ANX6862_7911") == 0) { #ifdef CONFIG_AMLOGIC_LCD_EXTERN_I2C_ANX6862_7911 ret = aml_lcd_extern_i2c_ANX6862_7911_probe(ext_drv); diff --git a/drivers/amlogic/media/vout/lcd/lcd_extern/lcd_extern.h b/drivers/amlogic/media/vout/lcd/lcd_extern/lcd_extern.h index f3f8854..16ca81c 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_extern/lcd_extern.h +++ b/drivers/amlogic/media/vout/lcd/lcd_extern/lcd_extern.h @@ -71,6 +71,10 @@ extern int aml_lcd_extern_i2c_tc101_probe( extern int aml_lcd_extern_i2c_anx6345_probe( struct aml_lcd_extern_driver_s *ext_drv); #endif +#ifdef CONFIG_AMLOGIC_LCD_EXTERN_I2C_CS602 +extern int aml_lcd_extern_i2c_CS602_probe( + struct aml_lcd_extern_driver_s *ext_drv); +#endif #ifdef CONFIG_AMLOGIC_LCD_EXTERN_SPI_LD070WS2 extern int aml_lcd_extern_spi_LD070WS2_probe( struct aml_lcd_extern_driver_s *ext_drv); -- 2.7.4