From 7dc13d44f037b91aeedea66f4ca77733d4ab9e74 Mon Sep 17 00:00:00 2001 From: xingbin Date: Mon, 12 Nov 2018 21:24:03 +0800 Subject: [PATCH] (CR):[Kane]:add backlight i2c device for high light mode Change-Id: I9b5e8171f4446ce26a823b66908917876e6b11a1 Signed-off-by: xingbin --- .../dts/exynos/exynos9610-display-lcd.dtsi | 11 + arch/arm64/configs/robusta2_evb_defconfig | 2 + arch/arm64/configs/wing_defconfig | 4 +- drivers/video/backlight/Kconfig | 20 + drivers/video/backlight/Makefile | 2 + drivers/video/backlight/lm36923.c | 379 ++++++++++++++++++ drivers/video/backlight/lm36923.h | 126 ++++++ drivers/video/backlight/sgm37603a.c | 379 ++++++++++++++++++ drivers/video/backlight/sgm37603a.h | 114 ++++++ 9 files changed, 1036 insertions(+), 1 deletion(-) mode change 100644 => 100755 drivers/video/backlight/Kconfig mode change 100644 => 100755 drivers/video/backlight/Makefile create mode 100755 drivers/video/backlight/lm36923.c create mode 100755 drivers/video/backlight/lm36923.h create mode 100755 drivers/video/backlight/sgm37603a.c create mode 100755 drivers/video/backlight/sgm37603a.h diff --git a/arch/arm64/boot/dts/exynos/exynos9610-display-lcd.dtsi b/arch/arm64/boot/dts/exynos/exynos9610-display-lcd.dtsi index 1c174883d032..87d8a81ac890 100755 --- a/arch/arm64/boot/dts/exynos/exynos9610-display-lcd.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos9610-display-lcd.dtsi @@ -365,3 +365,14 @@ }; }; }; + +&hsi2c_3 { + status = "okay"; + samsung,reset-before-trans; + clock-frequency = <400000>; + + backlight_i2c@36 { + compatible = "backlight_i2c"; + reg = <0x36>; + }; +}; diff --git a/arch/arm64/configs/robusta2_evb_defconfig b/arch/arm64/configs/robusta2_evb_defconfig index ac176d8515a5..a63a8eb0f1cf 100755 --- a/arch/arm64/configs/robusta2_evb_defconfig +++ b/arch/arm64/configs/robusta2_evb_defconfig @@ -561,3 +561,5 @@ CONFIG_AW8695_HAPTIC=y CONFIG_MOT_UTAG=y CONFIG_HWMON=y CONFIG_SENSORS_NTC_THERMISTOR=y +CONFIG_BACKLIGHT_SGM37603=y +CONFIG_BACKLIGHT_LM36923=y diff --git a/arch/arm64/configs/wing_defconfig b/arch/arm64/configs/wing_defconfig index ea1f260b25fc..945c12328aa3 100755 --- a/arch/arm64/configs/wing_defconfig +++ b/arch/arm64/configs/wing_defconfig @@ -543,4 +543,6 @@ CONFIG_INPUT_EGISTEC_320=y CONFIG_AW8695_HAPTIC=y CONFIG_MOT_UTAG=y CONFIG_HWMON=y -CONFIG_SENSORS_NTC_THERMISTOR=y \ No newline at end of file +CONFIG_SENSORS_NTC_THERMISTOR=y +CONFIG_BACKLIGHT_SGM37603=y +CONFIG_BACKLIGHT_LM36923=y \ No newline at end of file diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig old mode 100644 new mode 100755 index 4e1d2ad50ba1..094b640354dd --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -467,6 +467,26 @@ config BACKLIGHT_ARCXCNN If you have an ARCxCnnnn family backlight say Y to enable the backlight driver. +config BACKLIGHT_SGM37603 + tristate "sgm37603 backlight support" + depends on I2C + default n + help + This driver is backlight. + + To compile this driver as a module, choose M here. The module will be called lcd. + It is a driver support bias vendor SGM37603A. + +config BACKLIGHT_LM36923 + tristate "lm36923 backlight support" + depends on I2C + default n + help + This driver is backlight. + + To compile this driver as a module, choose M here. The module will be called lcd. + It is a driver support bias vendor like LM36923. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile old mode 100644 new mode 100755 index 5e28f01c8391..fd65ffe79e20 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -57,3 +57,5 @@ obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o +obj-$(CONFIG_BACKLIGHT_SGM37603) += sgm37603a.o +obj-$(CONFIG_BACKLIGHT_LM36923) += lm36923.o diff --git a/drivers/video/backlight/lm36923.c b/drivers/video/backlight/lm36923.c new file mode 100755 index 000000000000..0774708c1151 --- /dev/null +++ b/drivers/video/backlight/lm36923.c @@ -0,0 +1,379 @@ +/* Date: 2018/11/9 10:00:00 + * Revision: 1.0 + */ + +/* + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + + * (C) Copyright 2011 Bosch Sensortec GmbH + * All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif +#include +#include "lm36923.h" + +#define LM_I2C_NAME "lm" + +static int chipid=-1; //used for compatibility +static unsigned char lm_data[LM_REG_NUM]; + +static struct lm36923_data* lmdata; +static struct backlight_device *bd; +//LM36923 +static void lm_get_reg_val(struct lm36923_data *i2c_data){ + int i; + for(i=0; iname); + else + return scnprintf(buf, PAGE_SIZE, "NULL\n"); +} + +static ssize_t lm36923_mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm36923_data *i2c_data = lmdata; + if(i2c_data != NULL) + return scnprintf(buf, PAGE_SIZE, "%d\n", i2c_data->mode); + else + return scnprintf(buf, PAGE_SIZE, "NULL\n"); +} + +static ssize_t lm36923_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned int value = 0; + struct lm36923_data *i2c_data = lmdata; + + if(!count || i2c_data==NULL){ + pr_err("count=0 or i2c_data is NULL pointer\n"); + return -EINVAL; + } + + ret = kstrtouint(buf, 0, &value); + if (ret < 0 || (value!=0&&value!=1)){ + pr_err("wrong params. should be 0 or 1\n"); + return ret; + } + + pr_err("%s: current mode=%d, now write to %d\n", __func__, i2c_data->mode, value); + + if(1 == value){ + mutex_lock(&i2c_data->lock); + ret = backlight_i2c_write_bits(i2c_data,lm_hl_data[0][0],LM_LSB_MASK,lm_hl_data[0][1]); //write LSB + if(ret < 0){ + pr_err("HL mode:write lm chip LSB bit error\n"); + mutex_unlock(&i2c_data->lock); + goto exit; + } + + ret = backlight_i2c_write(i2c_data,lm_hl_data[1][0],lm_hl_data[1][1]); //write MSB + if(ret < 0){ + pr_err("HL mode:write lm chip MSB error\n"); + mutex_unlock(&i2c_data->lock); + goto exit; + } + i2c_data->mode = value; + mutex_unlock(&i2c_data->lock); + } + else if(0 == value){ + mutex_lock(&i2c_data->lock); + ret = backlight_i2c_write_bits(i2c_data,lm_nr_data[0][0],LM_LSB_MASK,lm_nr_data[0][1]); //write LSB + if(ret < 0){ + pr_err("NR mode:write lm chip LSB bit error\n"); + mutex_unlock(&i2c_data->lock); + goto exit; + } + + ret = backlight_i2c_write(i2c_data,lm_nr_data[1][0],lm_nr_data[1][1]); //write MSB + if(ret < 0){ + pr_err("NR mode:write lm chip MSB error\n"); + mutex_unlock(&i2c_data->lock); + goto exit; + } + i2c_data->mode = value; + mutex_unlock(&i2c_data->lock); + } + else{ + pr_err("the error echo value, 0 or 1 is allowed only\n"); + } +exit: + return count; +} + +static ssize_t lm36923_chip_reg_show(struct device *dev, + struct device_attribute *attr,char *buf) +{ + int i; + char reg_data_show[180]=""; + char reg_tmp[13]; + struct lm36923_data *i2c_data = lmdata; + + if(i2c_data == NULL) + return scnprintf(buf, PAGE_SIZE, "NULL\n"); + lm_get_reg_val(i2c_data); + for(i=0; i chip_reg\n"); + } + return count; +} + +static DEVICE_ATTR(chip_reg, 0644, lm36923_chip_reg_show, lm36923_chip_reg_store); +static DEVICE_ATTR(hbm_mode, 0644, lm36923_mode_show, lm36923_mode_store); +static DEVICE_ATTR(chip_name, 0444, lm36923_chip_name_show, NULL); + +static struct attribute *lm36923_attributes[] = { + &dev_attr_hbm_mode.attr, + &dev_attr_chip_name.attr, + &dev_attr_chip_reg.attr, + NULL +}; + +static struct attribute_group lm36923_attribute_group = { + .attrs = lm36923_attributes +}; + +/************************************************************ +* +* backlight i2c device init +* +* +*************************************************************/ +static int lm36923_parse_dt(struct device *dev, + struct lm36923_data *pdata, struct device_node *np) +{ + u32 regaddr; + int ret; + + ret = of_property_read_u32(np, "reg", ®addr); + if(ret){ + printk(KERN_ERR "parse backlight_i2c dtsi node failed"); + return -EINVAL; + } + + return 0; +} + +static int getChipId(struct device *dev){ + int ret; + unsigned char value = 0; + struct lm36923_data *i2c_data = lmdata; + + if(i2c_data == NULL){ + pr_err("%s: i2c_data is NULL\n"); + return 1; + } + + ret = backlight_i2c_read(i2c_data,BACKLIGHT_CHIP_ID_REG,&value); + if(ret < 0){ + pr_err("%s: get 0x10 register for compatibility error\n"); + return 1; + } + printk(KERN_ERR "%s:read chip id reg:0x%x, value=0x%x\n",__func__,BACKLIGHT_CHIP_ID_REG,value); + return (value&BACKLIGHT_CHIP_ID_REG_MASK)>>4; +} + + +static int lm36923_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct lm36923_data *data; + struct device_node *np=client->dev.of_node; + + pr_err("%s: enter\n",__func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_info(KERN_ERR "i2c_check_functionality error\n"); + return -EIO; + } + + data = devm_kzalloc(&client->dev,sizeof(struct lm36923_data), GFP_KERNEL); + if (!data) { + pr_err("%s: kzalloc error\n",__func__); + return -ENOMEM; + } + + data->bk_i2c_client = client; + mutex_init(&data->lock); + data->mode = 0; + + i2c_set_clientdata(client, data); + lmdata=data; + + if (np) { + ret = lm36923_parse_dt(&client->dev, data, np); + if (ret) { + dev_err(&client->dev,"Unable to parse platfrom data err=%d\n", ret); + goto kfree_exit; + } + }else{ + dev_err(&client->dev,"backlight_i2c dtsi node not exists\n"); + ret = -ENODEV; + goto kfree_exit; + + } + + chipid=getChipId(&client->dev); + printk(KERN_ERR "%s: chipid=%d\n", __func__,chipid); + + if(0==chipid){ + printk(KERN_ERR "lm36923 chip\n"); + mutex_lock(&data->lock); + data->name="lm36923\0"; + ret = backlight_i2c_write_bits(data,lm_nr_data[0][0],LM_LSB_MASK,lm_nr_data[0][1]); + if(ret < 0){ + pr_err("%s:NR mode:write lm chip LSB bit error\n",__func__); + } + + ret = backlight_i2c_write(data,lm_nr_data[1][0],lm_nr_data[1][1]); //write MSB + if(ret < 0){ + pr_err("%s:NR mode:write lm chip MSB error\n",__func__); + } + mutex_unlock(&data->lock); + } + else{ + dev_err(&client->dev,"wrong chipid\n"); + ret = -1; + goto kfree_exit; + } + + bd = backlight_device_register("hbm", NULL, NULL, NULL, NULL); + if (IS_ERR(bd)){ + pr_err("sgm failed to register backlight device!\n"); + ret= -1; + goto kfree_node; + } + + ret = sysfs_create_group(&bd->dev.kobj, &lm36923_attribute_group); + if(ret < 0){ + dev_err(&bd->dev,"Unable to create backlight_i2c_attribute\n"); + goto kfree_sysfs; + } + return 0; + +kfree_sysfs: + sysfs_remove_group(&bd->dev.kobj, &lm36923_attribute_group); +kfree_node: + backlight_device_unregister(bd); +kfree_exit: + mutex_destroy(&data->lock); + return ret; +} + +static int lm36923_remove(struct i2c_client *client) +{ + struct lm36923_data *data = lmdata; + if(lmdata != NULL) + mutex_destroy(&data->lock); + sysfs_remove_group(&bd->dev.kobj, &lm36923_attribute_group); + backlight_device_unregister(bd); + return 0; +} + +static const struct i2c_device_id lm36923_id[] = { + { LM_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm36923_id); + +static struct of_device_id lm36923_match_table[] = { + { .compatible = "backlight_i2c", }, + { }, +}; + +static struct i2c_driver lm36923_driver = { + .driver = { + .owner = THIS_MODULE, + .name = LM_I2C_NAME, + .of_match_table = lm36923_match_table, + }, + .id_table = lm36923_id, + .probe = lm36923_probe, + .remove = lm36923_remove, + +}; + +static int __init lm36923_init(void) +{ + int ret=0; + pr_info("lm36923_init\n"); + + ret = i2c_add_driver(&lm36923_driver); + pr_info("lm36923_init ret=%d\n",ret); + if(ret){ + pr_err("fail to add lm36923_driver\n"); + return ret; + } + + return 0; +} + +static void __exit lm36923_exit(void) +{ + pr_info("lm36923_exit\n"); + i2c_del_driver(&lm36923_driver); +} + +MODULE_DESCRIPTION("LCD_BACKLIGHT davicom ic driver"); +MODULE_LICENSE("GPL"); + +module_init(lm36923_init); +module_exit(lm36923_exit); \ No newline at end of file diff --git a/drivers/video/backlight/lm36923.h b/drivers/video/backlight/lm36923.h new file mode 100755 index 000000000000..1f0905c7c8ee --- /dev/null +++ b/drivers/video/backlight/lm36923.h @@ -0,0 +1,126 @@ +#ifndef _LM36923_H_ +#define _LM36923_H_ + +#include +#include + +#define BK_I2C_RETRIES 1 //times for try i2c write/read operation +#define BK_I2C_RETRY_DELAY 1 //time between the current and the last try + +//reg addr used for compatibility +#define BACKLIGHT_CHIP_ID_REG 0x10 //chip id +#define BACKLIGHT_CHIP_ID_REG_MASK 0x10 +#define LM_LSB_MASK 0x07 + +//lm +#define LM_REG_NUM 13 +#define LM_REV_REG 0x00 +#define LM_SFRESET_REG 0x01 +#define LM_ENABLE_REG 0x10 +#define LM_BRCTL_REG 0x11 +#define LM_PWMCTL_REG 0x12 +#define LM_BSTCTL_REG 0x13 +#define LM_AUTOFRQ_HIGH_TH 0x15 +#define LM_AUTOFRQ_LOW_TH 0x16 +#define LM_BK_AD_TRH 0x17 +#define LM_BR_LSB_REG 0x18 +#define LM_BR_MSB_REG 0x19 +#define LM_FLTCTL_REG 0x1E +#define LM_FLTFLAG_REG 0x1F + +unsigned char lm_reg[LM_REG_NUM]={ + LM_REV_REG, + LM_SFRESET_REG, + LM_ENABLE_REG, + LM_BRCTL_REG, + LM_PWMCTL_REG, + LM_BSTCTL_REG, + LM_AUTOFRQ_HIGH_TH, + LM_AUTOFRQ_LOW_TH, + LM_BK_AD_TRH, + LM_BR_LSB_REG, + LM_BR_MSB_REG, + LM_FLTCTL_REG, + LM_FLTFLAG_REG +}; + +struct lm36923_data { + struct i2c_client *bk_i2c_client; + struct mutex lock; + unsigned char mode; + char* name; +}; + +//lm 36923 +unsigned char lm_nr_data[][2]= +{ + {0x18, 0x06}, + {0x19, 0xCC}, +}; + +unsigned char lm_hl_data[][2]= +{ + {0x18, 0x07}, + {0x19, 0xFF}, +}; +static int backlight_i2c_write(struct lm36923_data *i2c_data, + unsigned char reg_addr, unsigned char reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + + while(cnt < BK_I2C_RETRIES) { + ret = i2c_smbus_write_byte_data(i2c_data->bk_i2c_client, reg_addr, reg_data); + if(ret < 0) { + pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt, ret); + }else { + break; + } + cnt ++; + msleep(BK_I2C_RETRY_DELAY); + } + + return ret; +} + +static int backlight_i2c_read(struct lm36923_data *i2c_data, + unsigned char reg_addr, unsigned char *reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + + while(cnt < BK_I2C_RETRIES) { + ret = i2c_smbus_read_byte_data(i2c_data->bk_i2c_client, reg_addr); + if(ret < 0) { + pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt, ret); + }else { + *reg_data = ret; + break; + } + cnt ++; + msleep(BK_I2C_RETRY_DELAY); + } + + return ret; +} + +static int backlight_i2c_write_bits(struct lm36923_data *i2c_data, + unsigned char reg_addr, unsigned char mask, unsigned char reg_data) +{ + int ret = -1; + unsigned char reg_val = 0; + + ret = backlight_i2c_read(i2c_data, reg_addr, ®_val); + if(ret < 0) { + pr_err("%s: read reg[0x%x] last value error\n", __func__, reg_addr); + } + reg_val &= (~mask); + reg_val |= (reg_data&mask); + msleep(1); + ret = backlight_i2c_write(i2c_data, reg_addr, reg_val); + if(ret < 0) { + pr_err("%s: write new value[0x%x] to reg[0x%x] error\n", __func__, reg_val ,reg_addr); + } + return ret; +} +#endif \ No newline at end of file diff --git a/drivers/video/backlight/sgm37603a.c b/drivers/video/backlight/sgm37603a.c new file mode 100755 index 000000000000..36d1d53b46f6 --- /dev/null +++ b/drivers/video/backlight/sgm37603a.c @@ -0,0 +1,379 @@ +/* Date: 2018/11/9 10:00:00 + * Revision: 1.0 + */ + +/* + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + + * (C) Copyright 2011 Bosch Sensortec GmbH + * All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif +#include +#include "sgm37603a.h" + +#define SGM_I2C_NAME "sgm" + +static int chipid=-1; //used for compatibility +static unsigned char sgm_data[SGM_REG_NUM]; + +static struct sgm37603a_data* sgmdata; +static struct backlight_device *bd; + +//SGM37603A +static void sgm_get_reg_val(struct sgm37603a_data *i2c_data){ + int i; + for(i=0; iname); + else + return scnprintf(buf, PAGE_SIZE, "NULL\n"); +} + +static ssize_t sgm37603a_mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sgm37603a_data *i2c_data = sgmdata; + if(i2c_data != NULL) + return scnprintf(buf, PAGE_SIZE, "%d\n", i2c_data->mode); + else + return scnprintf(buf, PAGE_SIZE, "NULL\n"); +} + +static ssize_t sgm37603a_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned int value = 0; + struct sgm37603a_data *i2c_data = sgmdata; + + if(!count || i2c_data==NULL){ + pr_err("count=0 or i2c_data is NULL pointer\n"); + return -EINVAL; + } + + ret = kstrtouint(buf, 0, &value); + if (ret < 0 || (value!=0&&value!=1)){ + pr_err("wrong params. should be 0 or 1\n"); + return ret; + } + + pr_err("%s: current mode=%d, now write to %d\n", __func__, i2c_data->mode, value); + + if(1 == value){ + mutex_lock(&i2c_data->lock); + ret = backlight_i2c_write_bits(i2c_data,sgm_hl_data[0][0],SGM_LSB_MASK,sgm_hl_data[0][1]); //write LSB + if(ret < 0){ + pr_err("HL mode:write sgm chip LSB bit error\n"); + mutex_unlock(&i2c_data->lock); + goto exit; + } + + ret = backlight_i2c_write(i2c_data,sgm_hl_data[1][0],sgm_hl_data[1][1]); //write MSB + if(ret < 0){ + pr_err("HL mode:write sgm chip MSB error\n"); + mutex_unlock(&i2c_data->lock); + goto exit; + } + i2c_data->mode = value; + mutex_unlock(&i2c_data->lock); + } + else if(0 == value){ + mutex_lock(&i2c_data->lock); + ret = backlight_i2c_write_bits(i2c_data,sgm_nr_data[0][0],SGM_LSB_MASK,sgm_nr_data[0][1]); //write LSB + if(ret < 0){ + pr_err("NR mode:write sgm chip LSB bit error\n"); + mutex_unlock(&i2c_data->lock); + goto exit; + } + + ret = backlight_i2c_write(i2c_data,sgm_nr_data[1][0],sgm_nr_data[1][1]); //write MSB + if(ret < 0){ + pr_err("NR mode:write sgm chip MSB error\n"); + mutex_unlock(&i2c_data->lock); + goto exit; + } + i2c_data->mode = value; + mutex_unlock(&i2c_data->lock); + } + else{ + pr_err("the error echo value, 0 or 1 is allowed only\n"); + } +exit: + return count; +} + +static ssize_t sgm37603a_chip_reg_show(struct device *dev, + struct device_attribute *attr,char *buf) +{ + int i; + char reg_data_show[180]=""; + char reg_tmp[13]; + struct sgm37603a_data *i2c_data = sgmdata; + + if(i2c_data == NULL) + return scnprintf(buf, PAGE_SIZE, "NULL\n"); + + sgm_get_reg_val(i2c_data); + for(i=0; i chip_reg\n"); + } + return count; +} + +static DEVICE_ATTR(chip_reg, 0644, sgm37603a_chip_reg_show, sgm37603a_chip_reg_store); +static DEVICE_ATTR(hbm_mode, 0644, sgm37603a_mode_show, sgm37603a_mode_store); +static DEVICE_ATTR(chip_name, 0444, sgm37603a_chip_name_show, NULL); + +static struct attribute *sgm37603a_attributes[] = { + &dev_attr_hbm_mode.attr, + &dev_attr_chip_name.attr, + &dev_attr_chip_reg.attr, + NULL +}; + +static struct attribute_group sgm37603a_attribute_group = { + .attrs = sgm37603a_attributes +}; + +/************************************************************ +* +* backlight i2c device init +* +* +*************************************************************/ +static int sgm37603a_parse_dt(struct device *dev, + struct sgm37603a_data *pdata, struct device_node *np) +{ + u32 regaddr; + int ret; + + ret = of_property_read_u32(np, "reg", ®addr); + if(ret){ + printk(KERN_ERR "parse backlight_i2c dtsi node failed"); + return -EINVAL; + } + + return 0; +} + +static int getChipId(struct device *dev){ + int ret; + unsigned char value = 0; + struct sgm37603a_data *i2c_data = sgmdata; + if(i2c_data == NULL){ + pr_err("%s: i2c_data is NULL\n"); + return 1; + } + + ret = backlight_i2c_read(i2c_data,BACKLIGHT_CHIP_ID_REG,&value); + if(ret < 0){ + pr_err("%s: get 0x10 register for compatibility error\n"); + return 1; + } + printk(KERN_ERR "%s:read chip id reg:0x%x, value=0x%x\n",__func__,BACKLIGHT_CHIP_ID_REG,value); + return (value&BACKLIGHT_CHIP_ID_REG_MASK)>>4; +} + + +static int sgm37603a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct sgm37603a_data *data; + struct device_node *np=client->dev.of_node; + + pr_err("%s: enter\n",__func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_info(KERN_ERR "i2c_check_functionality error\n"); + return -EIO; + } + + data = devm_kzalloc(&client->dev,sizeof(struct sgm37603a_data), GFP_KERNEL); + if (!data) { + pr_err("%s: kzalloc error\n",__func__); + return -ENOMEM; + } + + data->bk_i2c_client = client; + mutex_init(&data->lock); + data->mode = 0; + i2c_set_clientdata(client, data); + sgmdata=data; + + if (np) { + ret = sgm37603a_parse_dt(&client->dev, data, np); + if (ret) { + dev_err(&client->dev,"Unable to parse platfrom data err=%d\n", ret); + goto kfree_exit; + } + }else{ + dev_err(&client->dev,"backlight_i2c dtsi node not exists\n"); + ret = -ENODEV; + goto kfree_exit; + } + + chipid=getChipId(&client->dev); + printk(KERN_ERR "%s: chipid=%d\n", __func__,chipid); + + if(1==chipid){ + printk(KERN_ERR "sgm37603 chip\n"); + mutex_lock(&data->lock); + data->name="sgm37603\0"; + ret = backlight_i2c_write_bits(data,sgm_nr_data[0][0],SGM_LSB_MASK,sgm_nr_data[0][1]); + if(ret < 0){ + pr_err("%s:NR mode:write sgm chip LSB bit error\n",__func__); + } + //backlight_i2c_write(data,sgm_nr_data[0][0],sgm_nr_data[0][1]); //write LSB + ret = backlight_i2c_write(data,sgm_nr_data[1][0],sgm_nr_data[1][1]); //write MSB + if(ret < 0){ + pr_err("%s:NR mode:write sgm chip MSB error\n",__func__); + } + mutex_unlock(&data->lock); + } + else{ + dev_err(&client->dev,"wrong chipid\n"); + ret = -1; + goto kfree_exit; + } + + bd = backlight_device_register("hbm", NULL, NULL, NULL, NULL); + if (IS_ERR(bd)){ + pr_err("sgm failed to register backlight device!\n"); + ret= -1; + goto kfree_node; + } + + ret = sysfs_create_group(&bd->dev.kobj, &sgm37603a_attribute_group); + if(ret < 0){ + dev_err(&bd->dev,"Unable to create backlight_i2c_attribute\n"); + goto kfree_sysfs; + } + return 0; + +kfree_sysfs: + sysfs_remove_group(&bd->dev.kobj, &sgm37603a_attribute_group); +kfree_node: + backlight_device_unregister(bd); +kfree_exit: + mutex_destroy(&data->lock); + return ret; +} + +static int sgm37603a_remove(struct i2c_client *client) +{ + struct sgm37603a_data *data = sgmdata; + if(sgmdata != NULL) + mutex_destroy(&data->lock); + sysfs_remove_group(&bd->dev.kobj, &sgm37603a_attribute_group); + backlight_device_unregister(bd); + return 0; +} + +static const struct i2c_device_id sgm37603a_id[] = { + { SGM_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sgm37603a_id); + +static struct of_device_id sgm37603a_match_table[] = { + { .compatible = "backlight_i2c", }, + { }, +}; + +static struct i2c_driver sgm37603a_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SGM_I2C_NAME, + .of_match_table = sgm37603a_match_table, + }, + .id_table = sgm37603a_id, + .probe = sgm37603a_probe, + .remove = sgm37603a_remove, + +}; + +static int __init sgm37603a_init(void) +{ + int ret=0; + pr_info("sgm37603a_init\n"); + + ret = i2c_add_driver(&sgm37603a_driver); + if(ret){ + pr_err("fail to add sgm37603 driver\n"); + return ret; + } + + return 0; +} + +static void __exit sgm37603a_exit(void) +{ + pr_info("sgm37603a_exit\n"); + i2c_del_driver(&sgm37603a_driver); +} + +MODULE_DESCRIPTION("LCD_BACKLIGHT davicom ic driver"); +MODULE_LICENSE("GPL"); + +module_init(sgm37603a_init); +module_exit(sgm37603a_exit); \ No newline at end of file diff --git a/drivers/video/backlight/sgm37603a.h b/drivers/video/backlight/sgm37603a.h new file mode 100755 index 000000000000..2c4acf301058 --- /dev/null +++ b/drivers/video/backlight/sgm37603a.h @@ -0,0 +1,114 @@ +#ifndef _SGM37603A_H_ +#define _SGM37603A_H_ + +#include +#include + +#define BK_I2C_RETRIES 1 //times for try i2c write/read operation +#define BK_I2C_RETRY_DELAY 1 //time between the current and the last try + +//reg addr used for compatibility +#define BACKLIGHT_CHIP_ID_REG 0x10 //chip id +#define BACKLIGHT_CHIP_ID_REG_MASK 0x10 +#define SGM_LSB_MASK 0x0F + +//sgm +#define SGM_REG_NUM 7 +#define SGM_SFRESET_REG 0x01 +#define SGM_ENABLE_REG 0x10 +#define SGM_BRCTL_REG 0x11 +#define SGM_BR_LSB_REG 0x1A +#define SGM_BR_MSB_REG 0x19 +#define SGM_FLTFLAG_REG 0x1F +#define SGM_MAXLEDCURR_REG 0x1B + +unsigned char sgm_reg[SGM_REG_NUM]={ + SGM_SFRESET_REG, + SGM_ENABLE_REG, + SGM_BRCTL_REG, + SGM_BR_LSB_REG, + SGM_BR_MSB_REG, + SGM_FLTFLAG_REG, + SGM_MAXLEDCURR_REG +}; + +struct sgm37603a_data { + struct i2c_client *bk_i2c_client; + struct mutex lock; + unsigned char mode; + char* name; +}; + +unsigned char sgm_nr_data[][2]= +{ + {0x1A, 0x0C}, + {0x19, 0xCC}, +}; + +unsigned char sgm_hl_data[][2]= +{ + {0x1A, 0x0F}, + {0x19, 0xFF}, +}; + +static int backlight_i2c_write(struct sgm37603a_data *i2c_data, + unsigned char reg_addr, unsigned char reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + + while(cnt < BK_I2C_RETRIES) { + ret = i2c_smbus_write_byte_data(i2c_data->bk_i2c_client, reg_addr, reg_data); + if(ret < 0) { + pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt, ret); + }else { + break; + } + cnt ++; + msleep(BK_I2C_RETRY_DELAY); + } + + return ret; +} + +static int backlight_i2c_read(struct sgm37603a_data *i2c_data, + unsigned char reg_addr, unsigned char *reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + + while(cnt < BK_I2C_RETRIES) { + ret = i2c_smbus_read_byte_data(i2c_data->bk_i2c_client, reg_addr); + if(ret < 0) { + pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt, ret); + }else { + *reg_data = ret; + break; + } + cnt ++; + msleep(BK_I2C_RETRY_DELAY); + } + + return ret; +} + +static int backlight_i2c_write_bits(struct sgm37603a_data *i2c_data, + unsigned char reg_addr, unsigned char mask, unsigned char reg_data) +{ + int ret = -1; + unsigned char reg_val = 0; + + ret = backlight_i2c_read(i2c_data, reg_addr, ®_val); + if(ret < 0) { + pr_err("%s: read reg[0x%x] last value error\n", __func__, reg_addr); + } + reg_val &= (~mask); + reg_val |= (reg_data&mask); + msleep(1); + ret = backlight_i2c_write(i2c_data, reg_addr, reg_val); + if(ret < 0) { + pr_err("%s: write new value[0x%x] to reg[0x%x] error\n", __func__, reg_val ,reg_addr); + } + return ret; +} +#endif \ No newline at end of file -- 2.20.1