From 6d4a452b142caeea8c069ba3d6296a3b7df55ed6 Mon Sep 17 00:00:00 2001 From: Evoke Zhang Date: Mon, 14 Jan 2019 20:56:01 +0800 Subject: [PATCH] backlight: ldim: add dev reg access api support [1/1] PD#TV-1481 Problem: need ldim_dev reg access uniform api Solution: add ldim_dev reg access uniform api Verify: x301 Change-Id: I72756d178ef70aac1f8b7fef842468f2e27a0ffe Signed-off-by: Evoke Zhang Conflicts: drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c include/linux/amlogic/media/vout/lcd/aml_ldim.h --- .../media/vout/backlight/aml_ldim/iw7027_bl.c | 34 ++ .../vout/backlight/aml_ldim/ldim_dev_drv.c | 389 ++++++++++++++++++ .../linux/amlogic/media/vout/lcd/aml_ldim.h | 7 +- 3 files changed, 429 insertions(+), 1 deletion(-) diff --git a/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c b/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c index 6c123d1d57c0..205d99dbdbd6 100644 --- a/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c +++ b/drivers/amlogic/media/vout/backlight/aml_ldim/iw7027_bl.c @@ -116,6 +116,37 @@ static int iw7027_wregs(struct spi_device *spi, unsigned char addr, return ret; } +static int iw7027_reg_write(unsigned char *buf, unsigned int len) +{ + int ret; + + if (len > 28) { + LDIMERR("%s: unsupport len: %d\n", __func__, len); + return -1; + } + + if (len > 1) + ret = iw7027_wreg(bl_iw7027->spi, buf[0], buf[1]); + else + ret = iw7027_wregs(bl_iw7027->spi, buf[0], &buf[1], (len - 1)); + + return ret; +} + +static int iw7027_reg_read(unsigned char *buf, unsigned int len) +{ + int ret; + + if (len > 1) { + LDIMERR("%s: unsupport len: %d\n", __func__, len); + return -1; + } + + ret = iw7027_rreg(bl_iw7027->spi, buf[0], &buf[0]); + + return ret; +} + static int ldim_power_cmd_dynamic_size(void) { unsigned char *table; @@ -687,6 +718,9 @@ static int iw7027_ldim_driver_update(struct aml_ldim_driver_s *ldim_drv) ldim_drv->device_power_off = iw7027_power_off; ldim_drv->device_bri_update = iw7027_smr; ldim_drv->device_bri_check = iw7027_check; + + ldim_drv->ldev_conf->dev_reg_write = iw7027_reg_write; + ldim_drv->ldev_conf->dev_reg_read = iw7027_reg_read; return 0; } diff --git a/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c b/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c index 455066dc412b..a26870933f34 100644 --- a/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c +++ b/drivers/amlogic/media/vout/backlight/aml_ldim/ldim_dev_drv.c @@ -83,8 +83,19 @@ struct ldim_dev_config_s ldim_dev_config = { .pwm_duty_max = 100, .pwm_duty_min = 1, }, + .analog_pwm_config = { + .pwm_method = BL_PWM_POSITIVE, + .pwm_port = BL_PWM_MAX, + .pwm_freq = 1000, + .pwm_duty_max = 100, + .pwm_duty_min = 10, + }, .bl_regnum = 0, + + .dim_range_update = NULL, + .dev_reg_write = NULL, + .dev_reg_read = NULL, }; static void ldim_gpio_probe(int index) @@ -1159,6 +1170,384 @@ ldim_get_config_err: return -1; } +static ssize_t ldim_dev_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + int ret = 0; + + ldim_dev_config_print(); + + return ret; +} + +static ssize_t ldim_dev_pwm_ldim_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + struct bl_pwm_config_s *bl_pwm; + ssize_t len = 0; + + bl_pwm = &ldim_dev_config.ldim_pwm_config; + if (bl_pwm->pwm_port < BL_PWM_MAX) { + len += sprintf(buf+len, + "ldim_pwm: freq=%d, pol=%d, duty_max=%d, duty_min=%d,", + bl_pwm->pwm_freq, bl_pwm->pwm_method, + bl_pwm->pwm_duty_max, bl_pwm->pwm_duty_min); + len += sprintf(buf+len, " duty_value=%d%%\n", bl_pwm->pwm_duty); + } + + return len; +} + +static ssize_t ldim_dev_pwm_ldim_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + unsigned int ret; + unsigned int val = 0; + struct bl_pwm_config_s *bl_pwm; + + bl_pwm = &ldim_dev_config.ldim_pwm_config; + if (bl_pwm->pwm_port >= BL_PWM_MAX) + return count; + + switch (buf[0]) { + case 'f': /* frequency */ + ret = sscanf(buf, "freq %d", &val); + if (ret == 1) { + bl_pwm->pwm_freq = val; + bl_pwm_config_init(bl_pwm); + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR("set ldim_pwm (port %d): freq = %dHz\n", + bl_pwm->pwm_port, bl_pwm->pwm_freq); + } + } else { + LDIMERR("invalid parameters\n"); + } + break; + case 'd': /* duty */ + ret = sscanf(buf, "duty %d", &val); + if (ret == 1) { + bl_pwm->pwm_duty = val; + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR("set ldim_pwm (port %d): duty = %d%%\n", + bl_pwm->pwm_port, bl_pwm->pwm_duty); + } + } else { + LDIMERR("invalid parameters\n"); + } + break; + case 'p': /* polarity */ + ret = sscanf(buf, "pol %d", &val); + if (ret == 1) { + bl_pwm->pwm_method = val; + bl_pwm_config_init(bl_pwm); + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR("set ldim_pwm (port %d): method = %d\n", + bl_pwm->pwm_port, bl_pwm->pwm_method); + } + } else { + LDIMERR("invalid parameters\n"); + } + break; + case 'm': + if (buf[1] == 'a') { /* max */ + ret = sscanf(buf, "max %d", &val); + if (ret == 1) { + bl_pwm->pwm_duty_max = val; + if (ldim_dev_config.dim_range_update) + ldim_dev_config.dim_range_update(); + bl_pwm_config_init(bl_pwm); + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR( + "set ldim_pwm (port %d): duty_max = %d%%\n", + bl_pwm->pwm_port, + bl_pwm->pwm_duty_max); + } + } else { + LDIMERR("invalid parameters\n"); + } + } else if (buf[1] == 'i') { /* min */ + ret = sscanf(buf, "min %d", &val); + if (ret == 1) { + bl_pwm->pwm_duty_min = val; + if (ldim_dev_config.dim_range_update) + ldim_dev_config.dim_range_update(); + bl_pwm_config_init(bl_pwm); + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR( + "set ldim_pwm (port %d): duty_min = %d%%\n", + bl_pwm->pwm_port, + bl_pwm->pwm_duty_min); + } + } else { + LDIMERR("invalid parameters\n"); + } + } + break; + default: + LDIMERR("wrong command\n"); + break; + } + + return count; +} + +static ssize_t ldim_dev_pwm_analog_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + struct bl_pwm_config_s *bl_pwm; + ssize_t len = 0; + + bl_pwm = &ldim_dev_config.analog_pwm_config; + if (bl_pwm->pwm_port < BL_PWM_VS) { + len += sprintf(buf+len, + "analog_pwm: freq=%d, pol=%d, duty_max=%d, duty_min=%d,", + bl_pwm->pwm_freq, bl_pwm->pwm_method, + bl_pwm->pwm_duty_max, bl_pwm->pwm_duty_min); + len += sprintf(buf+len, " duty_value=%d%%\n", bl_pwm->pwm_duty); + } + + return len; +} + +static ssize_t ldim_dev_pwm_analog_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + unsigned int ret; + unsigned int val = 0; + struct bl_pwm_config_s *bl_pwm; + + bl_pwm = &ldim_dev_config.analog_pwm_config; + if (bl_pwm->pwm_port >= BL_PWM_VS) + return count; + + switch (buf[0]) { + case 'f': /* frequency */ + ret = sscanf(buf, "freq %d", &val); + if (ret == 1) { + bl_pwm->pwm_freq = val; + bl_pwm_config_init(bl_pwm); + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR("set ldim_pwm (port %d): freq = %dHz\n", + bl_pwm->pwm_port, bl_pwm->pwm_freq); + } + } else { + LDIMERR("invalid parameters\n"); + } + break; + case 'd': /* duty */ + ret = sscanf(buf, "duty %d", &val); + if (ret == 1) { + bl_pwm->pwm_duty = val; + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR("set ldim_pwm (port %d): duty = %d%%\n", + bl_pwm->pwm_port, bl_pwm->pwm_duty); + } + } else { + LDIMERR("invalid parameters\n"); + } + break; + case 'p': /* polarity */ + ret = sscanf(buf, "pol %d", &val); + if (ret == 1) { + bl_pwm->pwm_method = val; + bl_pwm_config_init(bl_pwm); + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR("set ldim_pwm (port %d): method = %d\n", + bl_pwm->pwm_port, bl_pwm->pwm_method); + } + } else { + LDIMERR("invalid parameters\n"); + } + break; + case 'm': + if (buf[1] == 'a') { /* max */ + ret = sscanf(buf, "max %d", &val); + if (ret == 1) { + bl_pwm->pwm_duty_max = val; + bl_pwm_config_init(bl_pwm); + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR( + "set ldim_pwm (port %d): duty_max = %d%%\n", + bl_pwm->pwm_port, + bl_pwm->pwm_duty_max); + } + } else { + LDIMERR("invalid parameters\n"); + } + } else if (buf[1] == 'i') { /* min */ + ret = sscanf(buf, "min %d", &val); + if (ret == 1) { + bl_pwm->pwm_duty_min = val; + bl_pwm_config_init(bl_pwm); + ldim_set_duty_pwm(bl_pwm); + if (ldim_debug_print) { + LDIMPR( + "set ldim_pwm (port %d): duty_min = %d%%\n", + bl_pwm->pwm_port, + bl_pwm->pwm_duty_min); + } + } else { + LDIMERR("invalid parameters\n"); + } + } + break; + default: + LDIMERR("wrong command\n"); + break; + } + + return count; +} + +static unsigned char ldim_dev_reg; +static unsigned char ldim_dev_reg_dump_cnt; +static ssize_t ldim_dev_reg_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + unsigned char data; + ssize_t len = 0; + int ret; + + if (ldim_dev_config.dev_reg_read == NULL) + return sprintf(buf, "ldim dev_reg_read is null\n"); + + data = ldim_dev_reg; + ret = ldim_dev_config.dev_reg_read(&data, 1); + if (ret) { + len = sprintf(buf, "reg[0x%02x] read error\n", ldim_dev_reg); + } else { + len = sprintf(buf, "reg[0x%02x] = 0x%02x\n", + ldim_dev_reg, data); + } + + return len; +} + +static ssize_t ldim_dev_reg_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + unsigned int reg = 0, val = 0; + unsigned char data[2]; + unsigned int ret; + + ret = sscanf(buf, "%x %x", ®, &val); + if (ret == 1) { + if (reg > 0xff) { + LDIMERR("invalid reg address: 0x%x\n", reg); + return count; + } + ldim_dev_reg = (unsigned char)reg; + } else if (ret == 2) { + if (ldim_dev_config.dev_reg_write == NULL) { + LDIMERR("ldim dev_reg_write is null\n"); + return count; + } + if (reg > 0xff) { + LDIMERR("invalid reg address: 0x%x\n", reg); + return count; + } + ldim_dev_reg = (unsigned char)reg; + data[0] = ldim_dev_reg; + data[1] = (unsigned char)val; + ldim_dev_config.dev_reg_write(data, 2); + LDIMPR("write reg[0x%02x] = 0x%02x\n", data[0], data[1]); + } else { + LDIMERR("invalid parameters\n"); + } + + return count; +} + +static ssize_t ldim_dev_reg_dump_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + unsigned char *data; + ssize_t len = 0; + int i, ret; + + if (ldim_dev_config.dev_reg_read == NULL) + return sprintf(buf, "ldim dev_reg_read is null\n"); + + if (ldim_dev_reg_dump_cnt == 0) + return sprintf(buf, "ldim reg_dump_cnt is zero\n"); + + data = kcalloc(ldim_dev_reg_dump_cnt, + sizeof(unsigned char), GFP_KERNEL); + ret = ldim_dev_config.dev_reg_read(data, ldim_dev_reg_dump_cnt); + if (ret) { + len = sprintf(buf, "reg[0x%02x] read error\n", ldim_dev_reg); + } else { + len += sprintf(buf+len, "reg[0x%02x] = ", ldim_dev_reg); + for (i = 0; i < (ldim_dev_reg_dump_cnt - 1); i++) + len += sprintf(buf+len, "0x%02x,", data[i]); + len += sprintf(buf+len, "0x%02x\n", + data[ldim_dev_reg_dump_cnt - 1]); + } + kfree(data); + + return len; +} + +static ssize_t ldim_dev_reg_dump_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + unsigned int reg = 0, cnt = 0; + unsigned int ret; + + ret = sscanf(buf, "%x %d", ®, &cnt); + if (ret == 2) { + if (reg > 0xff) { + LDIMERR("invalid reg address: 0x%x\n", reg); + return count; + } + if (cnt > 0xff) { + LDIMERR("invalid reg cnt: %d\n", cnt); + return count; + } + ldim_dev_reg = (unsigned char)reg; + ldim_dev_reg_dump_cnt = (unsigned char)cnt; + } else { + LDIMERR("invalid parameters\n"); + } + + return count; +} + +static struct class_attribute ldim_dev_class_attrs[] = { + __ATTR(status, 0644, ldim_dev_show, NULL), + __ATTR(pwm_ldim, 0644, ldim_dev_pwm_ldim_show, ldim_dev_pwm_ldim_store), + __ATTR(pwm_analog, 0644, ldim_dev_pwm_analog_show, + ldim_dev_pwm_analog_store), + __ATTR(reg, 0644, ldim_dev_reg_show, ldim_dev_reg_store), + __ATTR(reg_dump, 0644, ldim_dev_reg_dump_show, ldim_dev_reg_dump_store), + __ATTR_NULL +}; + +static void ldim_dev_class_create(void) +{ + int ret; + + ldim_dev_class.name = kzalloc(10, GFP_KERNEL); + if (ldim_dev_class.name == NULL) { + LDIMERR("%s: malloc failed\n", __func__); + return; + } + sprintf((char *)ldim_dev_class.name, "ldim_dev"); + ldim_dev_class.class_attrs = ldim_dev_class_attrs; + ret = class_register(&ldim_dev_class); + if (ret < 0) + LDIMERR("register ldim_dev_class failed\n"); +} + static int ldim_dev_add_driver(struct aml_ldim_driver_s *ldim_drv) { struct ldim_dev_config_s *ldev_conf = ldim_drv->ldev_conf; diff --git a/include/linux/amlogic/media/vout/lcd/aml_ldim.h b/include/linux/amlogic/media/vout/lcd/aml_ldim.h index 66380831270f..c066b0539e6e 100644 --- a/include/linux/amlogic/media/vout/lcd/aml_ldim.h +++ b/include/linux/amlogic/media/vout/lcd/aml_ldim.h @@ -81,10 +81,15 @@ struct ldim_dev_config_s { unsigned int init_on_cnt; unsigned int init_off_cnt; - struct bl_pwm_config_s pwm_config; + struct bl_pwm_config_s ldim_pwm_config; + struct bl_pwm_config_s analog_pwm_config; unsigned short bl_regnum; unsigned short bl_mapping[LD_BLKREGNUM]; + + void (*dim_range_update)(void); + int (*dev_reg_write)(unsigned char *buf, unsigned int len); + int (*dev_reg_read)(unsigned char *buf, unsigned int len); }; /*******global API******/