mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 20:32:04 +09:00
backlight: ldim: add fault reset handle for iw7027 [1/1]
PD#SWPL-1161 Problem: sometims iw7027 work failure, need reset to recovery Solution: add reset handler triggered by fault pin Verify: txlx r311 Change-Id: I9c65f0b982ac5e52ff9bd5e43f9df516df2af184 Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
This commit is contained in:
@@ -2288,12 +2288,34 @@ static struct notifier_block aml_bl_off_nb = {
|
||||
.priority = LCD_PRIORITY_POWER_BL_OFF,
|
||||
};
|
||||
|
||||
static inline int aml_bl_pwm_vs_lcd_update(struct bl_pwm_config_s *bl_pwm)
|
||||
{
|
||||
unsigned int cnt;
|
||||
|
||||
if (bl_pwm == NULL) {
|
||||
BLERR("%s: bl_pwm is null\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cnt = bl_vcbus_read(ENCL_VIDEO_MAX_LNCNT) + 1;
|
||||
if (cnt != bl_pwm->pwm_cnt) {
|
||||
bl_pwm_config_init(bl_pwm);
|
||||
if (brightness_bypass)
|
||||
bl_set_duty_pwm(bl_pwm);
|
||||
else
|
||||
aml_bl_update_status(bl_drv->bldev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aml_bl_lcd_update_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct bl_pwm_config_s *bl_pwm = NULL;
|
||||
#ifdef CONFIG_AMLOGIC_LOCAL_DIMMING
|
||||
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
|
||||
unsigned int *frame_rate;
|
||||
#endif
|
||||
|
||||
/* If we aren't interested in this event, skip it immediately */
|
||||
@@ -2308,13 +2330,8 @@ static int aml_bl_lcd_update_notifier(struct notifier_block *nb,
|
||||
case BL_CTRL_PWM:
|
||||
if (bl_drv->bconf->bl_pwm->pwm_port == BL_PWM_VS) {
|
||||
bl_pwm = bl_drv->bconf->bl_pwm;
|
||||
if (bl_pwm) {
|
||||
bl_pwm_config_init(bl_pwm);
|
||||
if (brightness_bypass)
|
||||
bl_set_duty_pwm(bl_pwm);
|
||||
else
|
||||
aml_bl_update_status(bl_drv->bldev);
|
||||
}
|
||||
if (bl_pwm)
|
||||
aml_bl_pwm_vs_lcd_update(bl_pwm);
|
||||
}
|
||||
break;
|
||||
case BL_CTRL_PWM_COMBO:
|
||||
@@ -2322,16 +2339,16 @@ static int aml_bl_lcd_update_notifier(struct notifier_block *nb,
|
||||
bl_pwm = bl_drv->bconf->bl_pwm_combo0;
|
||||
else if (bl_drv->bconf->bl_pwm_combo1->pwm_port == BL_PWM_VS)
|
||||
bl_pwm = bl_drv->bconf->bl_pwm_combo1;
|
||||
if (bl_pwm) {
|
||||
bl_pwm_config_init(bl_pwm);
|
||||
if (brightness_bypass)
|
||||
bl_set_duty_pwm(bl_pwm);
|
||||
else
|
||||
aml_bl_update_status(bl_drv->bldev);
|
||||
}
|
||||
if (bl_pwm)
|
||||
aml_bl_pwm_vs_lcd_update(bl_pwm);
|
||||
break;
|
||||
#ifdef CONFIG_AMLOGIC_LOCAL_DIMMING
|
||||
case BL_CTRL_LOCAL_DIMMING:
|
||||
if (data) {
|
||||
frame_rate = (unsigned int *)data;
|
||||
ldim_drv->vsync_change_flag =
|
||||
(unsigned char)(*frame_rate);
|
||||
}
|
||||
if (ldim_drv->pwm_vs_update)
|
||||
ldim_drv->pwm_vs_update();
|
||||
break;
|
||||
|
||||
@@ -46,9 +46,11 @@
|
||||
#define IW7027_REG_CHIPID 0x7f
|
||||
#define IW7027_CHIPID 0x28
|
||||
|
||||
#define IW7027_POWER_ON 0
|
||||
#define IW7027_POWER_RESET 1
|
||||
#define VSYNC_INFO_FREQUENT 30
|
||||
|
||||
static int iw7027_on_flag;
|
||||
static unsigned short vsync_cnt;
|
||||
static unsigned short fault_cnt;
|
||||
|
||||
static DEFINE_MUTEX(iw7027_spi_mutex);
|
||||
|
||||
@@ -247,8 +249,6 @@ static int iw7027_hw_init_on(void)
|
||||
unsigned char reg_chk, reg_duty_chk;
|
||||
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
|
||||
|
||||
mutex_lock(&iw7027_spi_mutex);
|
||||
|
||||
/* step 1: system power_on */
|
||||
ldim_gpio_set(ldim_drv->ldev_conf->en_gpio,
|
||||
ldim_drv->ldev_conf->en_gpio_on);
|
||||
@@ -295,8 +295,6 @@ static int iw7027_hw_init_on(void)
|
||||
}
|
||||
LDIMPR("%s: calibration done: [%d] = %x\n", __func__, i, reg_duty_chk);
|
||||
|
||||
mutex_unlock(&iw7027_spi_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -304,15 +302,11 @@ static int iw7027_hw_init_off(void)
|
||||
{
|
||||
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
|
||||
|
||||
mutex_lock(&iw7027_spi_mutex);
|
||||
|
||||
ldim_gpio_set(ldim_drv->ldev_conf->en_gpio,
|
||||
ldim_drv->ldev_conf->en_gpio_off);
|
||||
ldim_drv->pinmux_ctrl(0);
|
||||
ldim_pwm_off(&(ldim_drv->ldev_conf->pwm_config));
|
||||
|
||||
mutex_unlock(&iw7027_spi_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -387,6 +381,48 @@ static int iw7027_spi_dump_dim(char *buf)
|
||||
return len;
|
||||
}
|
||||
|
||||
static int fault_cnt_save;
|
||||
static int fault_check_cnt;
|
||||
static int iw7027_fault_handler(unsigned int gpio)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (gpio >= BL_GPIO_NUM_MAX)
|
||||
return 0;
|
||||
|
||||
if (fault_check_cnt++ > 200) { /* clear fault flag for a cycle */
|
||||
fault_check_cnt = 0;
|
||||
fault_cnt = 0;
|
||||
fault_cnt_save = 0;
|
||||
}
|
||||
|
||||
if (ldim_debug_print) {
|
||||
if (vsync_cnt == 0) {
|
||||
LDIMPR("%s: fault_cnt: %d, fault_check_cnt: %d\n",
|
||||
__func__, fault_cnt, fault_check_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
val = ldim_gpio_get(gpio);
|
||||
if (val == 0)
|
||||
return 0;
|
||||
|
||||
fault_cnt++;
|
||||
if (fault_cnt_save != fault_cnt) {
|
||||
fault_cnt_save = fault_cnt;
|
||||
LDIMPR("%s: fault_cnt: %d\n", __func__, fault_cnt);
|
||||
}
|
||||
if (fault_cnt <= 10) {
|
||||
iw7027_wreg(bl_iw7027->spi, 0x61, 0x0f);
|
||||
} else {
|
||||
iw7027_hw_init_on();
|
||||
fault_cnt = 0;
|
||||
fault_cnt_save = 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned int dim_max, dim_min;
|
||||
static inline unsigned int iw7027_get_value(unsigned int level)
|
||||
{
|
||||
@@ -397,7 +433,6 @@ static inline unsigned int iw7027_get_value(unsigned int level)
|
||||
return val;
|
||||
}
|
||||
|
||||
static int smr_cnt;
|
||||
static int iw7027_smr(unsigned short *buf, unsigned char len)
|
||||
{
|
||||
int i;
|
||||
@@ -405,22 +440,22 @@ static int iw7027_smr(unsigned short *buf, unsigned char len)
|
||||
unsigned short *mapping, num;
|
||||
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
|
||||
|
||||
if (smr_cnt++ >= 30)
|
||||
smr_cnt = 0;
|
||||
if (vsync_cnt++ >= VSYNC_INFO_FREQUENT)
|
||||
vsync_cnt = 0;
|
||||
|
||||
if (iw7027_on_flag == 0) {
|
||||
if (smr_cnt == 0)
|
||||
if (vsync_cnt == 0)
|
||||
LDIMPR("%s: on_flag=%d\n", __func__, iw7027_on_flag);
|
||||
return 0;
|
||||
}
|
||||
num = ldim_drv->ldev_conf->bl_regnum;
|
||||
if (len != num) {
|
||||
if (smr_cnt == 0)
|
||||
if (vsync_cnt == 0)
|
||||
LDIMERR("%s: data len %d invalid\n", __func__, len);
|
||||
return -1;
|
||||
}
|
||||
if (val_brightness == NULL) {
|
||||
if (smr_cnt == 0)
|
||||
if (vsync_cnt == 0)
|
||||
LDIMERR("%s: val_brightness is null\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
@@ -431,9 +466,16 @@ static int iw7027_smr(unsigned short *buf, unsigned char len)
|
||||
dim_max = ldim_drv->ldev_conf->dim_max;
|
||||
dim_min = ldim_drv->ldev_conf->dim_min;
|
||||
|
||||
if (ldim_drv->vsync_change_flag == 50) {
|
||||
iw7027_wreg(bl_iw7027->spi, 0x31, 0xd7);
|
||||
ldim_drv->vsync_change_flag = 0;
|
||||
} else if (ldim_drv->vsync_change_flag == 60) {
|
||||
iw7027_wreg(bl_iw7027->spi, 0x31, 0xd3);
|
||||
ldim_drv->vsync_change_flag = 0;
|
||||
}
|
||||
if (bl_iw7027->test_mode) {
|
||||
if (test_brightness == NULL) {
|
||||
if (smr_cnt == 0)
|
||||
if (vsync_cnt == 0)
|
||||
LDIMERR("test_brightness is null\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -458,18 +500,51 @@ static int iw7027_smr(unsigned short *buf, unsigned char len)
|
||||
|
||||
iw7027_wregs(bl_iw7027->spi, 0x40, val_brightness, (num * 2));
|
||||
|
||||
if (ldim_drv->ldev_conf->fault_check)
|
||||
iw7027_fault_handler(ldim_drv->ldev_conf->lamp_err_gpio);
|
||||
|
||||
mutex_unlock(&iw7027_spi_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iw7027_check(void)
|
||||
{
|
||||
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
|
||||
int ret = 0;
|
||||
|
||||
if (vsync_cnt++ >= VSYNC_INFO_FREQUENT)
|
||||
vsync_cnt = 0;
|
||||
|
||||
if (iw7027_on_flag == 0) {
|
||||
if (vsync_cnt == 0)
|
||||
LDIMPR("%s: on_flag=%d\n", __func__, iw7027_on_flag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_lock(&iw7027_spi_mutex);
|
||||
|
||||
if (ldim_drv->ldev_conf->fault_check)
|
||||
ret = iw7027_fault_handler(ldim_drv->ldev_conf->lamp_err_gpio);
|
||||
|
||||
mutex_unlock(&iw7027_spi_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iw7027_power_on(void)
|
||||
{
|
||||
if (iw7027_on_flag) {
|
||||
LDIMPR("%s: iw7027 is already on, exit\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_lock(&iw7027_spi_mutex);
|
||||
iw7027_hw_init_on();
|
||||
iw7027_on_flag = 1;
|
||||
vsync_cnt = 0;
|
||||
fault_cnt = 0;
|
||||
mutex_unlock(&iw7027_spi_mutex);
|
||||
|
||||
LDIMPR("%s: ok\n", __func__);
|
||||
return 0;
|
||||
@@ -477,8 +552,10 @@ static int iw7027_power_on(void)
|
||||
|
||||
static int iw7027_power_off(void)
|
||||
{
|
||||
mutex_lock(&iw7027_spi_mutex);
|
||||
iw7027_on_flag = 0;
|
||||
iw7027_hw_init_off();
|
||||
mutex_unlock(&iw7027_spi_mutex);
|
||||
|
||||
LDIMPR("%s: ok\n", __func__);
|
||||
return 0;
|
||||
@@ -492,11 +569,7 @@ static ssize_t iw7027_show(struct class *class,
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (!strcmp(attr->attr.name, "mode")) {
|
||||
ret = sprintf(buf, "0x%02x\n", bl->spi->mode);
|
||||
} else if (!strcmp(attr->attr.name, "speed")) {
|
||||
ret = sprintf(buf, "%d\n", bl->spi->max_speed_hz);
|
||||
} else if (!strcmp(attr->attr.name, "test")) {
|
||||
if (!strcmp(attr->attr.name, "test")) {
|
||||
ret = sprintf(buf, "test mode=%d\n", bl->test_mode);
|
||||
} else if (!strcmp(attr->attr.name, "brightness")) {
|
||||
if (test_brightness == NULL) {
|
||||
@@ -511,13 +584,15 @@ static ssize_t iw7027_show(struct class *class,
|
||||
ret = sprintf(buf, "iw7027 status:\n"
|
||||
"dev_index = %d\n"
|
||||
"on_flag = %d\n"
|
||||
"fault_cnt = %d\n"
|
||||
"en_on = %d\n"
|
||||
"en_off = %d\n"
|
||||
"cs_hold_delay = %d\n"
|
||||
"cs_clk_delay = %d\n"
|
||||
"dim_max = 0x%03x\n"
|
||||
"dim_min = 0x%03x\n",
|
||||
ldim_drv->dev_index, iw7027_on_flag,
|
||||
ldim_drv->dev_index,
|
||||
iw7027_on_flag, fault_cnt,
|
||||
ldim_drv->ldev_conf->en_gpio_on,
|
||||
ldim_drv->ldev_conf->en_gpio_off,
|
||||
ldim_drv->ldev_conf->cs_hold_delay,
|
||||
@@ -546,19 +621,9 @@ static ssize_t iw7027_store(struct class *class,
|
||||
int i;
|
||||
|
||||
if (!strcmp(attr->attr.name, "init")) {
|
||||
mutex_lock(&iw7027_spi_mutex);
|
||||
iw7027_hw_init_on();
|
||||
} else if (!strcmp(attr->attr.name, "mode")) {
|
||||
i = kstrtouint(buf, 10, &val);
|
||||
if (i == 1)
|
||||
bl->spi->mode = val;
|
||||
else
|
||||
LDIMERR("%s: invalid args\n", __func__);
|
||||
} else if (!strcmp(attr->attr.name, "speed")) {
|
||||
i = kstrtouint(buf, 10, &val);
|
||||
if (i == 1)
|
||||
bl->spi->max_speed_hz = val*1000;
|
||||
else
|
||||
LDIMERR("%s: invalid args\n", __func__);
|
||||
mutex_unlock(&iw7027_spi_mutex);
|
||||
} else if (!strcmp(attr->attr.name, "reg")) {
|
||||
if (buf[0] == 'w') {
|
||||
i = sscanf(buf, "w %x %x", &val, &val2);
|
||||
@@ -605,9 +670,7 @@ static ssize_t iw7027_store(struct class *class,
|
||||
}
|
||||
|
||||
static struct class_attribute iw7027_class_attrs[] = {
|
||||
__ATTR(init, 0644, iw7027_show, iw7027_store),
|
||||
__ATTR(mode, 0644, iw7027_show, iw7027_store),
|
||||
__ATTR(speed, 0644, iw7027_show, iw7027_store),
|
||||
__ATTR(init, 0644, NULL, iw7027_store),
|
||||
__ATTR(reg, 0644, iw7027_show, iw7027_store),
|
||||
__ATTR(test, 0644, iw7027_show, iw7027_store),
|
||||
__ATTR(brightness, 0644, iw7027_show, iw7027_store),
|
||||
@@ -623,6 +686,7 @@ static int iw7027_ldim_driver_update(struct aml_ldim_driver_s *ldim_drv)
|
||||
ldim_drv->device_power_on = iw7027_power_on;
|
||||
ldim_drv->device_power_off = iw7027_power_off;
|
||||
ldim_drv->device_bri_update = iw7027_smr;
|
||||
ldim_drv->device_bri_check = iw7027_check;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -636,6 +700,8 @@ int ldim_dev_iw7027_probe(struct aml_ldim_driver_s *ldim_drv)
|
||||
}
|
||||
|
||||
iw7027_on_flag = 0;
|
||||
vsync_cnt = 0;
|
||||
fault_cnt = 0;
|
||||
|
||||
bl_iw7027 = kzalloc(sizeof(struct iw7027_s), GFP_KERNEL);
|
||||
if (bl_iw7027 == NULL) {
|
||||
|
||||
@@ -321,12 +321,21 @@ static int ldim_pwm_pinmux_ctrl(int status)
|
||||
|
||||
static int ldim_pwm_vs_update(void)
|
||||
{
|
||||
struct bl_pwm_config_s *bl_pwm = NULL;
|
||||
struct bl_pwm_config_s *bl_pwm = &ldim_dev_config.pwm_config;
|
||||
unsigned int cnt;
|
||||
int ret = 0;
|
||||
|
||||
bl_pwm = &ldim_dev_config.pwm_config;
|
||||
bl_pwm_config_init(bl_pwm);
|
||||
ldim_set_duty_pwm(bl_pwm);
|
||||
if (bl_pwm->pwm_port != BL_PWM_VS)
|
||||
return 0;
|
||||
|
||||
if (ldim_debug_print)
|
||||
LDIMPR("%s\n", __func__);
|
||||
|
||||
cnt = bl_vcbus_read(ENCL_VIDEO_MAX_LNCNT) + 1;
|
||||
if (cnt != bl_pwm->pwm_cnt) {
|
||||
bl_pwm_config_init(bl_pwm);
|
||||
ldim_set_duty_pwm(bl_pwm);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -466,9 +475,11 @@ static void ldim_dev_config_print(void)
|
||||
LDIMPR("%s:\n", __func__);
|
||||
|
||||
pr_info("valid_flag = %d\n"
|
||||
"dev_index = %d\n",
|
||||
"dev_index = %d\n"
|
||||
"vsync_change_flag = %d\n",
|
||||
ldim_drv->valid_flag,
|
||||
ldim_drv->dev_index);
|
||||
ldim_drv->dev_index,
|
||||
ldim_drv->vsync_change_flag);
|
||||
if (ldim_drv->ldev_conf == NULL) {
|
||||
LDIMERR("%s: device config is null\n", __func__);
|
||||
return;
|
||||
|
||||
@@ -1745,6 +1745,7 @@ static struct aml_ldim_driver_s ldim_driver = {
|
||||
.valid_flag = 0, /* default invalid, active when bl_ctrl_method=ldim */
|
||||
.dev_index = 0xff,
|
||||
.static_pic_flag = 0,
|
||||
.vsync_change_flag = 0,
|
||||
.pinmux_flag = 0xff,
|
||||
.ldim_conf = &ldim_config,
|
||||
.ldev_conf = NULL,
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
/*20180730: algorithm clear up */
|
||||
/*20180820: pq tooling support, espically optimize some alg parameters */
|
||||
/*20181101: fix ldim_op_func null mistake, add new spi api support */
|
||||
#define LDIM_DRV_VER "20181101"
|
||||
/*20181203: add 50/60hz change & iw7027 error handle support */
|
||||
#define LDIM_DRV_VER "20181203"
|
||||
|
||||
extern unsigned char ldim_debug_print;
|
||||
|
||||
|
||||
@@ -1066,7 +1066,7 @@ int lcd_vmode_change(struct lcd_config_s *pconf)
|
||||
|
||||
void lcd_venc_change(struct lcd_config_s *pconf)
|
||||
{
|
||||
unsigned int htotal, vtotal;
|
||||
unsigned int htotal, vtotal, frame_rate;
|
||||
|
||||
htotal = lcd_vcbus_read(ENCL_VIDEO_MAX_PXCNT) + 1;
|
||||
vtotal = lcd_vcbus_read(ENCL_VIDEO_MAX_LNCNT) + 1;
|
||||
@@ -1084,8 +1084,10 @@ void lcd_venc_change(struct lcd_config_s *pconf)
|
||||
pconf->lcd_basic.v_period);
|
||||
}
|
||||
|
||||
if (pconf->lcd_basic.v_period != vtotal)
|
||||
aml_lcd_notifier_call_chain(LCD_EVENT_BACKLIGHT_UPDATE, NULL);
|
||||
frame_rate = (pconf->lcd_timing.sync_duration_num * 100) /
|
||||
pconf->lcd_timing.sync_duration_den;
|
||||
frame_rate = (frame_rate + 50) / 100;
|
||||
aml_lcd_notifier_call_chain(LCD_EVENT_BACKLIGHT_UPDATE, &frame_rate);
|
||||
}
|
||||
|
||||
void lcd_if_enable_retry(struct lcd_config_s *pconf)
|
||||
|
||||
@@ -92,6 +92,7 @@ struct aml_ldim_driver_s {
|
||||
unsigned char valid_flag;
|
||||
unsigned char dev_index;
|
||||
unsigned char static_pic_flag;
|
||||
unsigned char vsync_change_flag;
|
||||
unsigned char pinmux_flag;
|
||||
|
||||
struct ldim_config_s *ldim_conf;
|
||||
|
||||
Reference in New Issue
Block a user