(CR):[Kane]:add backlight i2c device for high light mode
authorxingbin <xingbin@huaqin.com>
Mon, 12 Nov 2018 13:24:03 +0000 (21:24 +0800)
committerxiest1 <xiest1@lenovo.com>
Tue, 5 Nov 2019 09:29:55 +0000 (17:29 +0800)
Change-Id: I9b5e8171f4446ce26a823b66908917876e6b11a1
Signed-off-by: xingbin <xingbin@huaqin.com>
arch/arm64/boot/dts/exynos/exynos9610-display-lcd.dtsi
arch/arm64/configs/robusta2_evb_defconfig
arch/arm64/configs/wing_defconfig
drivers/video/backlight/Kconfig [changed mode: 0644->0755]
drivers/video/backlight/Makefile [changed mode: 0644->0755]
drivers/video/backlight/lm36923.c [new file with mode: 0755]
drivers/video/backlight/lm36923.h [new file with mode: 0755]
drivers/video/backlight/sgm37603a.c [new file with mode: 0755]
drivers/video/backlight/sgm37603a.h [new file with mode: 0755]

index 1c174883d03254c4ff5fb81b6e60c9ea3321993e..87d8a81ac890cf7b828b739057f2fbe2c2f02b5a 100755 (executable)
                };
        };
 };
+
+&hsi2c_3 {
+       status = "okay";
+       samsung,reset-before-trans;
+       clock-frequency = <400000>;
+
+       backlight_i2c@36 {
+               compatible = "backlight_i2c";
+               reg = <0x36>;
+       };
+};
index ac176d8515a586afdb579d7af624c260bb3e03f2..a63a8eb0f1cf93f8ef80c90edc834b9aec67b5f5 100755 (executable)
@@ -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
index ea1f260b25fcd0474bb649e7a3bfb98093e024ae..945c12328aa33fec7513817b368e1123fa6eeae0 100755 (executable)
@@ -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
old mode 100644 (file)
new mode 100755 (executable)
index 4e1d2ad..094b640
@@ -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
old mode 100644 (file)
new mode 100755 (executable)
index 5e28f01..fd65ffe
@@ -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 (executable)
index 0000000..0774708
--- /dev/null
@@ -0,0 +1,379 @@
+/*  Date: 2018/11/9 10:00:00\r
+ *  Revision: 1.0\r
+ */\r
+\r
+/*\r
+ * This software program is licensed subject to the GNU General Public License\r
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html\r
+\r
+ * (C) Copyright 2011 Bosch Sensortec GmbH\r
+ * All Rights Reserved\r
+ */\r
+\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/input.h>\r
+#include <linux/workqueue.h>\r
+#include <linux/mutex.h>\r
+#include <linux/slab.h>\r
+#include <linux/mutex.h>\r
+#include <linux/interrupt.h>\r
+#ifdef CONFIG_OF\r
+#include <linux/of_gpio.h>\r
+#endif\r
+#include <linux/backlight.h>\r
+#include "lm36923.h"\r
+\r
+#define LM_I2C_NAME "lm"\r
+\r
+static int chipid=-1;   //used for compatibility\r
+static unsigned char lm_data[LM_REG_NUM];\r
+\r
+static struct lm36923_data* lmdata;\r
+static struct backlight_device *bd;\r
+//LM36923\r
+static void lm_get_reg_val(struct lm36923_data *i2c_data){\r
+    int i;\r
+    for(i=0; i<LM_REG_NUM; i++){\r
+        backlight_i2c_read(i2c_data,lm_reg[i],&lm_data[i]);\r
+        pr_err("%s: lm_data[%d]=0x%x\n", __func__, i, lm_data[i]);\r
+        mdelay(2);\r
+    }\r
+}\r
+\r
+/************************************************************\r
+*\r
+*   backlight i2c device attributes\r
+*\r
+*\r
+*************************************************************/\r
+static ssize_t lm36923_chip_name_show(struct device *dev, struct device_attribute *attr,\r
+        char *buf)\r
+{\r
+    struct lm36923_data *i2c_data = lmdata;\r
+    if(i2c_data != NULL)\r
+        return scnprintf(buf, PAGE_SIZE, "%s\n", i2c_data->name);\r
+    else\r
+        return scnprintf(buf, PAGE_SIZE, "NULL\n");\r
+}\r
+\r
+static ssize_t lm36923_mode_show(struct device *dev, struct device_attribute *attr,\r
+        char *buf)\r
+{\r
+    struct lm36923_data *i2c_data = lmdata;\r
+    if(i2c_data != NULL)\r
+        return scnprintf(buf, PAGE_SIZE, "%d\n", i2c_data->mode);\r
+    else\r
+        return scnprintf(buf, PAGE_SIZE, "NULL\n");\r
+}\r
+\r
+static ssize_t lm36923_mode_store(struct device *dev, struct device_attribute *attr,\r
+        const char *buf, size_t count)\r
+{\r
+    int ret;\r
+    unsigned int value = 0;\r
+    struct lm36923_data *i2c_data = lmdata;\r
+\r
+    if(!count || i2c_data==NULL){\r
+        pr_err("count=0 or i2c_data is NULL pointer\n");\r
+        return -EINVAL;\r
+    }\r
+\r
+    ret = kstrtouint(buf, 0, &value);\r
+    if (ret < 0 || (value!=0&&value!=1)){\r
+        pr_err("wrong params. should be 0 or 1\n");\r
+        return ret;\r
+    }\r
+\r
+    pr_err("%s: current mode=%d, now write to %d\n", __func__, i2c_data->mode, value);\r
+\r
+    if(1 == value){\r
+        mutex_lock(&i2c_data->lock);\r
+        ret = backlight_i2c_write_bits(i2c_data,lm_hl_data[0][0],LM_LSB_MASK,lm_hl_data[0][1]);  //write LSB\r
+        if(ret < 0){\r
+            pr_err("HL mode:write lm chip LSB bit error\n");\r
+            mutex_unlock(&i2c_data->lock);\r
+            goto exit;\r
+        }\r
+\r
+        ret = backlight_i2c_write(i2c_data,lm_hl_data[1][0],lm_hl_data[1][1]); //write MSB\r
+        if(ret < 0){\r
+            pr_err("HL mode:write lm chip MSB error\n");\r
+            mutex_unlock(&i2c_data->lock);\r
+            goto exit;\r
+        }\r
+        i2c_data->mode = value;\r
+        mutex_unlock(&i2c_data->lock);\r
+    }\r
+    else if(0 == value){\r
+        mutex_lock(&i2c_data->lock);\r
+        ret = backlight_i2c_write_bits(i2c_data,lm_nr_data[0][0],LM_LSB_MASK,lm_nr_data[0][1]);  //write LSB\r
+        if(ret < 0){\r
+            pr_err("NR mode:write lm chip LSB bit error\n");\r
+            mutex_unlock(&i2c_data->lock);\r
+            goto exit;\r
+        }\r
+\r
+        ret = backlight_i2c_write(i2c_data,lm_nr_data[1][0],lm_nr_data[1][1]); //write MSB\r
+        if(ret < 0){\r
+            pr_err("NR mode:write lm chip MSB error\n");\r
+            mutex_unlock(&i2c_data->lock);\r
+            goto exit;\r
+        }\r
+        i2c_data->mode = value;\r
+        mutex_unlock(&i2c_data->lock);\r
+    }\r
+    else{\r
+        pr_err("the error echo value, 0 or 1 is allowed only\n");\r
+    }\r
+exit:\r
+    return count;\r
+}\r
+\r
+static ssize_t lm36923_chip_reg_show(struct device *dev,\r
+        struct device_attribute *attr,char *buf)\r
+{\r
+    int i;\r
+    char reg_data_show[180]="";\r
+    char reg_tmp[13];\r
+    struct lm36923_data *i2c_data = lmdata;\r
+\r
+    if(i2c_data == NULL)\r
+        return scnprintf(buf, PAGE_SIZE, "NULL\n");\r
+    lm_get_reg_val(i2c_data);\r
+    for(i=0; i<LM_REG_NUM; i++){\r
+        snprintf(reg_tmp, sizeof(reg_tmp), "[0x%2x]=0x%2x\n", lm_reg[i],lm_data[i]);\r
+        //pr_err("reg_tmp=%s\0",reg_tmp);\r
+        strncat(reg_data_show,reg_tmp,strlen(reg_tmp));\r
+    }\r
+\r
+    return scnprintf(buf, PAGE_SIZE, "%s\n", reg_data_show);\r
+}\r
+\r
+static ssize_t lm36923_chip_reg_store(struct device *dev,\r
+        struct device_attribute *attr,const char *buf, size_t count)\r
+{\r
+    int ret = -1;\r
+    unsigned char reg;\r
+    unsigned char val;\r
+    struct lm36923_data *i2c_data = lmdata;\r
+    if(!count || i2c_data==NULL){\r
+        pr_err("%s:count=0 or i2c_data is NULL pointer\n",__func__);\r
+        return -EINVAL;\r
+    }\r
+\r
+    if (sscanf(buf, "%x %x", &reg, &val) == 2)\r
+    {\r
+        pr_err("Notice chip id and write the corrent reg\n");\r
+        pr_err("%s,reg = 0x%02x, val = 0x%02x\n", __func__, reg, val);\r
+        ret = backlight_i2c_write(i2c_data,reg,val);\r
+        if(ret < 0)\r
+            pr_err("write chip reg[0x%x] error\n",reg);\r
+    }\r
+    else{\r
+        pr_err("write echo command error; like this: echo 0x19 0xFF > chip_reg\n");\r
+    }\r
+    return count;\r
+}\r
+\r
+static DEVICE_ATTR(chip_reg, 0644, lm36923_chip_reg_show, lm36923_chip_reg_store);\r
+static DEVICE_ATTR(hbm_mode, 0644, lm36923_mode_show, lm36923_mode_store);\r
+static DEVICE_ATTR(chip_name, 0444, lm36923_chip_name_show, NULL);\r
+\r
+static struct attribute *lm36923_attributes[] = {\r
+    &dev_attr_hbm_mode.attr,\r
+    &dev_attr_chip_name.attr,\r
+    &dev_attr_chip_reg.attr,\r
+    NULL\r
+};\r
+\r
+static struct attribute_group lm36923_attribute_group = {\r
+    .attrs = lm36923_attributes\r
+};\r
+\r
+/************************************************************\r
+*\r
+*   backlight i2c device init\r
+*\r
+*\r
+*************************************************************/\r
+static int lm36923_parse_dt(struct device *dev,\r
+                struct lm36923_data *pdata, struct device_node *np)\r
+{\r
+    u32 regaddr;\r
+    int ret;\r
+\r
+    ret = of_property_read_u32(np, "reg", &regaddr);\r
+    if(ret){\r
+        printk(KERN_ERR "parse backlight_i2c dtsi node failed");\r
+        return -EINVAL;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+static int getChipId(struct device *dev){\r
+    int ret;\r
+    unsigned char value = 0;\r
+    struct lm36923_data *i2c_data = lmdata;\r
+\r
+    if(i2c_data == NULL){\r
+        pr_err("%s: i2c_data is NULL\n");\r
+        return 1;\r
+    }\r
+\r
+    ret = backlight_i2c_read(i2c_data,BACKLIGHT_CHIP_ID_REG,&value);\r
+    if(ret < 0){\r
+        pr_err("%s: get 0x10 register for compatibility error\n");\r
+        return 1;\r
+    }\r
+    printk(KERN_ERR "%s:read chip id reg:0x%x, value=0x%x\n",__func__,BACKLIGHT_CHIP_ID_REG,value);\r
+    return (value&BACKLIGHT_CHIP_ID_REG_MASK)>>4;\r
+}\r
+\r
+\r
+static int lm36923_probe(struct i2c_client *client,\r
+        const struct i2c_device_id *id)\r
+{\r
+    int ret = 0;\r
+    struct lm36923_data *data;\r
+    struct device_node *np=client->dev.of_node;\r
+\r
+    pr_err("%s: enter\n",__func__);\r
+    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {\r
+        pr_info(KERN_ERR "i2c_check_functionality error\n");\r
+        return -EIO;\r
+    }\r
+\r
+    data = devm_kzalloc(&client->dev,sizeof(struct lm36923_data), GFP_KERNEL);\r
+    if (!data) {\r
+        pr_err("%s: kzalloc error\n",__func__);\r
+        return -ENOMEM;\r
+    }\r
+\r
+    data->bk_i2c_client = client;\r
+    mutex_init(&data->lock);\r
+    data->mode = 0;\r
+\r
+    i2c_set_clientdata(client, data);\r
+    lmdata=data;\r
+\r
+    if (np) {\r
+        ret = lm36923_parse_dt(&client->dev, data, np);\r
+        if (ret) {\r
+            dev_err(&client->dev,"Unable to parse platfrom data err=%d\n", ret);\r
+            goto kfree_exit;\r
+        }\r
+    }else{\r
+        dev_err(&client->dev,"backlight_i2c dtsi node not exists\n");\r
+        ret = -ENODEV;\r
+        goto kfree_exit;\r
+\r
+    }\r
+\r
+    chipid=getChipId(&client->dev);\r
+    printk(KERN_ERR "%s: chipid=%d\n", __func__,chipid);\r
+\r
+    if(0==chipid){\r
+        printk(KERN_ERR "lm36923 chip\n");\r
+        mutex_lock(&data->lock);\r
+        data->name="lm36923\0";\r
+        ret = backlight_i2c_write_bits(data,lm_nr_data[0][0],LM_LSB_MASK,lm_nr_data[0][1]);\r
+        if(ret < 0){\r
+            pr_err("%s:NR mode:write lm chip LSB bit error\n",__func__);\r
+        }\r
+\r
+        ret = backlight_i2c_write(data,lm_nr_data[1][0],lm_nr_data[1][1]); //write MSB\r
+        if(ret < 0){\r
+            pr_err("%s:NR mode:write lm chip MSB error\n",__func__);\r
+        }\r
+        mutex_unlock(&data->lock);\r
+    }\r
+    else{\r
+        dev_err(&client->dev,"wrong chipid\n");\r
+        ret = -1;\r
+        goto kfree_exit;\r
+    }\r
+\r
+    bd = backlight_device_register("hbm", NULL, NULL, NULL, NULL);\r
+    if (IS_ERR(bd)){\r
+        pr_err("sgm failed to register backlight device!\n");\r
+        ret= -1;\r
+        goto kfree_node;\r
+    }\r
+\r
+    ret = sysfs_create_group(&bd->dev.kobj, &lm36923_attribute_group);\r
+    if(ret < 0){\r
+        dev_err(&bd->dev,"Unable to create backlight_i2c_attribute\n");\r
+        goto kfree_sysfs;\r
+    }\r
+    return 0;\r
+\r
+kfree_sysfs:\r
+    sysfs_remove_group(&bd->dev.kobj, &lm36923_attribute_group);\r
+kfree_node:\r
+    backlight_device_unregister(bd);\r
+kfree_exit:\r
+    mutex_destroy(&data->lock);\r
+    return ret;\r
+}\r
+\r
+static int lm36923_remove(struct i2c_client *client)\r
+{\r
+    struct lm36923_data *data = lmdata;\r
+    if(lmdata != NULL)\r
+        mutex_destroy(&data->lock);\r
+    sysfs_remove_group(&bd->dev.kobj, &lm36923_attribute_group);\r
+    backlight_device_unregister(bd);\r
+    return 0;\r
+}\r
+\r
+static const struct i2c_device_id lm36923_id[] = {\r
+    { LM_I2C_NAME, 0 },\r
+    { }\r
+};\r
+MODULE_DEVICE_TABLE(i2c, lm36923_id);\r
+\r
+static struct of_device_id lm36923_match_table[] = {\r
+    { .compatible = "backlight_i2c", },\r
+    { },\r
+};\r
+\r
+static struct i2c_driver lm36923_driver = {\r
+    .driver = {\r
+        .owner  = THIS_MODULE,\r
+        .name   = LM_I2C_NAME,\r
+        .of_match_table = lm36923_match_table,\r
+    },\r
+    .id_table   = lm36923_id,\r
+    .probe      = lm36923_probe,\r
+    .remove     = lm36923_remove,\r
+\r
+};\r
+\r
+static int __init lm36923_init(void)\r
+{\r
+    int ret=0;\r
+    pr_info("lm36923_init\n");\r
+\r
+    ret = i2c_add_driver(&lm36923_driver);\r
+    pr_info("lm36923_init ret=%d\n",ret);\r
+    if(ret){\r
+        pr_err("fail to add lm36923_driver\n");\r
+        return ret;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+static void __exit lm36923_exit(void)\r
+{\r
+    pr_info("lm36923_exit\n");\r
+    i2c_del_driver(&lm36923_driver);\r
+}\r
+\r
+MODULE_DESCRIPTION("LCD_BACKLIGHT davicom ic driver");\r
+MODULE_LICENSE("GPL");\r
+\r
+module_init(lm36923_init);\r
+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 (executable)
index 0000000..1f0905c
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef _LM36923_H_\r
+#define _LM36923_H_\r
+\r
+#include <linux/delay.h>\r
+#include <linux/i2c.h>\r
+\r
+#define BK_I2C_RETRIES 1   //times for try i2c write/read operation\r
+#define BK_I2C_RETRY_DELAY 1  //time between the current and the last try\r
+\r
+//reg addr used for compatibility\r
+#define BACKLIGHT_CHIP_ID_REG       0x10 //chip id\r
+#define BACKLIGHT_CHIP_ID_REG_MASK  0x10\r
+#define LM_LSB_MASK 0x07\r
+\r
+//lm\r
+#define LM_REG_NUM 13\r
+#define LM_REV_REG 0x00\r
+#define LM_SFRESET_REG 0x01\r
+#define LM_ENABLE_REG 0x10\r
+#define LM_BRCTL_REG 0x11\r
+#define LM_PWMCTL_REG 0x12\r
+#define LM_BSTCTL_REG 0x13\r
+#define LM_AUTOFRQ_HIGH_TH 0x15\r
+#define LM_AUTOFRQ_LOW_TH 0x16\r
+#define LM_BK_AD_TRH 0x17\r
+#define LM_BR_LSB_REG 0x18\r
+#define LM_BR_MSB_REG 0x19\r
+#define LM_FLTCTL_REG 0x1E\r
+#define LM_FLTFLAG_REG 0x1F\r
+\r
+unsigned char lm_reg[LM_REG_NUM]={\r
+       LM_REV_REG,\r
+       LM_SFRESET_REG,\r
+       LM_ENABLE_REG,\r
+       LM_BRCTL_REG,\r
+       LM_PWMCTL_REG,\r
+       LM_BSTCTL_REG,\r
+       LM_AUTOFRQ_HIGH_TH,\r
+       LM_AUTOFRQ_LOW_TH,\r
+       LM_BK_AD_TRH,\r
+       LM_BR_LSB_REG,\r
+       LM_BR_MSB_REG,\r
+       LM_FLTCTL_REG,\r
+       LM_FLTFLAG_REG\r
+};\r
+\r
+struct lm36923_data {\r
+       struct i2c_client *bk_i2c_client;\r
+       struct mutex lock;\r
+       unsigned char mode;\r
+       char* name;\r
+};\r
+\r
+//lm 36923\r
+unsigned char lm_nr_data[][2]=\r
+{\r
+    {0x18, 0x06},\r
+    {0x19, 0xCC},\r
+};\r
+\r
+unsigned char lm_hl_data[][2]=\r
+{\r
+    {0x18, 0x07},\r
+    {0x19, 0xFF},\r
+};\r
+static int backlight_i2c_write(struct lm36923_data *i2c_data,\r
+         unsigned char reg_addr, unsigned char reg_data)\r
+{\r
+    int ret = -1;\r
+    unsigned char cnt = 0;\r
+\r
+    while(cnt < BK_I2C_RETRIES) {\r
+        ret = i2c_smbus_write_byte_data(i2c_data->bk_i2c_client, reg_addr, reg_data);\r
+        if(ret < 0) {\r
+            pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt, ret);\r
+        }else {\r
+            break;\r
+        }\r
+        cnt ++;\r
+        msleep(BK_I2C_RETRY_DELAY);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+static int backlight_i2c_read(struct lm36923_data *i2c_data,\r
+        unsigned char reg_addr, unsigned char *reg_data)\r
+{\r
+    int ret = -1;\r
+    unsigned char cnt = 0;\r
+\r
+    while(cnt < BK_I2C_RETRIES) {\r
+        ret = i2c_smbus_read_byte_data(i2c_data->bk_i2c_client, reg_addr);\r
+        if(ret < 0) {\r
+            pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt, ret);\r
+        }else {\r
+            *reg_data = ret;\r
+            break;\r
+        }\r
+        cnt ++;\r
+        msleep(BK_I2C_RETRY_DELAY);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+static int backlight_i2c_write_bits(struct lm36923_data *i2c_data,\r
+         unsigned char reg_addr, unsigned char mask, unsigned char reg_data)\r
+{\r
+    int ret = -1;\r
+    unsigned char reg_val = 0;\r
+\r
+    ret = backlight_i2c_read(i2c_data, reg_addr, &reg_val);\r
+    if(ret < 0) {\r
+        pr_err("%s: read reg[0x%x] last value error\n", __func__, reg_addr);\r
+    }\r
+    reg_val &= (~mask);\r
+    reg_val |= (reg_data&mask);\r
+    msleep(1);\r
+    ret = backlight_i2c_write(i2c_data, reg_addr, reg_val);\r
+    if(ret < 0) {\r
+        pr_err("%s: write new value[0x%x] to reg[0x%x] error\n", __func__, reg_val ,reg_addr);\r
+    }\r
+    return ret;\r
+}\r
+#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 (executable)
index 0000000..36d1d53
--- /dev/null
@@ -0,0 +1,379 @@
+/*  Date: 2018/11/9 10:00:00\r
+ *  Revision: 1.0\r
+ */\r
+\r
+/*\r
+ * This software program is licensed subject to the GNU General Public License\r
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html\r
+\r
+ * (C) Copyright 2011 Bosch Sensortec GmbH\r
+ * All Rights Reserved\r
+ */\r
+\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/input.h>\r
+#include <linux/workqueue.h>\r
+#include <linux/mutex.h>\r
+#include <linux/slab.h>\r
+#include <linux/mutex.h>\r
+#include <linux/interrupt.h>\r
+#ifdef CONFIG_OF\r
+#include <linux/of_gpio.h>\r
+#endif\r
+#include <linux/backlight.h>\r
+#include "sgm37603a.h"\r
+\r
+#define SGM_I2C_NAME "sgm"\r
+\r
+static int chipid=-1;   //used for compatibility\r
+static unsigned char sgm_data[SGM_REG_NUM];\r
+\r
+static struct sgm37603a_data* sgmdata;\r
+static struct backlight_device *bd;\r
+\r
+//SGM37603A\r
+static void sgm_get_reg_val(struct sgm37603a_data *i2c_data){\r
+    int i;\r
+    for(i=0; i<SGM_REG_NUM; i++){\r
+        backlight_i2c_read(i2c_data,sgm_reg[i],&sgm_data[i]);\r
+        pr_err("%s: sgm_data[%d]=0x%x\n", __func__, i, sgm_data[i]);\r
+        mdelay(2);\r
+    }\r
+}\r
+\r
+/************************************************************\r
+*\r
+*   backlight i2c device attributes\r
+*\r
+*\r
+*************************************************************/\r
+static ssize_t sgm37603a_chip_name_show(struct device *dev, struct device_attribute *attr,\r
+        char *buf)\r
+{\r
+    struct sgm37603a_data *i2c_data = sgmdata;\r
+    if(i2c_data != NULL)\r
+        return scnprintf(buf, PAGE_SIZE, "%s\n", i2c_data->name);\r
+    else\r
+        return scnprintf(buf, PAGE_SIZE, "NULL\n");\r
+}\r
+\r
+static ssize_t sgm37603a_mode_show(struct device *dev, struct device_attribute *attr,\r
+        char *buf)\r
+{\r
+    struct sgm37603a_data *i2c_data = sgmdata;\r
+    if(i2c_data != NULL)\r
+        return scnprintf(buf, PAGE_SIZE, "%d\n", i2c_data->mode);\r
+    else\r
+        return scnprintf(buf, PAGE_SIZE, "NULL\n");\r
+}\r
+\r
+static ssize_t sgm37603a_mode_store(struct device *dev, struct device_attribute *attr,\r
+        const char *buf, size_t count)\r
+{\r
+    int ret;\r
+    unsigned int value = 0;\r
+    struct sgm37603a_data *i2c_data = sgmdata;\r
+\r
+    if(!count || i2c_data==NULL){\r
+        pr_err("count=0 or i2c_data is NULL pointer\n");\r
+        return -EINVAL;\r
+    }\r
+\r
+    ret = kstrtouint(buf, 0, &value);\r
+    if (ret < 0 || (value!=0&&value!=1)){\r
+        pr_err("wrong params. should be 0 or 1\n");\r
+        return ret;\r
+    }\r
+\r
+    pr_err("%s: current mode=%d, now write to %d\n", __func__, i2c_data->mode, value);\r
+\r
+    if(1 == value){\r
+        mutex_lock(&i2c_data->lock);\r
+        ret = backlight_i2c_write_bits(i2c_data,sgm_hl_data[0][0],SGM_LSB_MASK,sgm_hl_data[0][1]);  //write LSB\r
+        if(ret < 0){\r
+            pr_err("HL mode:write sgm chip LSB bit error\n");\r
+            mutex_unlock(&i2c_data->lock);\r
+            goto exit;\r
+        }\r
+\r
+        ret = backlight_i2c_write(i2c_data,sgm_hl_data[1][0],sgm_hl_data[1][1]); //write MSB\r
+        if(ret < 0){\r
+            pr_err("HL mode:write sgm chip MSB error\n");\r
+            mutex_unlock(&i2c_data->lock);\r
+            goto exit;\r
+        }\r
+        i2c_data->mode = value;\r
+        mutex_unlock(&i2c_data->lock);\r
+    }\r
+    else if(0 == value){\r
+        mutex_lock(&i2c_data->lock);\r
+        ret = backlight_i2c_write_bits(i2c_data,sgm_nr_data[0][0],SGM_LSB_MASK,sgm_nr_data[0][1]);  //write LSB\r
+        if(ret < 0){\r
+            pr_err("NR mode:write sgm chip LSB bit error\n");\r
+            mutex_unlock(&i2c_data->lock);\r
+            goto exit;\r
+        }\r
+\r
+        ret = backlight_i2c_write(i2c_data,sgm_nr_data[1][0],sgm_nr_data[1][1]); //write MSB\r
+        if(ret < 0){\r
+            pr_err("NR mode:write sgm chip MSB error\n");\r
+            mutex_unlock(&i2c_data->lock);\r
+            goto exit;\r
+        }\r
+        i2c_data->mode = value;\r
+        mutex_unlock(&i2c_data->lock);\r
+    }\r
+    else{\r
+        pr_err("the error echo value, 0 or 1 is allowed only\n");\r
+    }\r
+exit:\r
+    return count;\r
+}\r
+\r
+static ssize_t sgm37603a_chip_reg_show(struct device *dev,\r
+        struct device_attribute *attr,char *buf)\r
+{\r
+    int i;\r
+    char reg_data_show[180]="";\r
+    char reg_tmp[13];\r
+    struct sgm37603a_data *i2c_data = sgmdata;\r
+\r
+    if(i2c_data == NULL)\r
+        return scnprintf(buf, PAGE_SIZE, "NULL\n");\r
+\r
+    sgm_get_reg_val(i2c_data);\r
+    for(i=0; i<SGM_REG_NUM; i++){\r
+        snprintf(reg_tmp, sizeof(reg_tmp), "[0x%2x]=0x%2x\n", sgm_reg[i],sgm_data[i]);\r
+        //pr_err("reg_tmp=%s\0",reg_tmp);\r
+        strncat(reg_data_show,reg_tmp,strlen(reg_tmp));\r
+    }\r
+\r
+    return scnprintf(buf, PAGE_SIZE, "%s\n", reg_data_show);\r
+}\r
+\r
+static ssize_t sgm37603a_chip_reg_store(struct device *dev,\r
+        struct device_attribute *attr,const char *buf, size_t count)\r
+{\r
+    int ret = -1;\r
+    unsigned char reg;\r
+    unsigned char val;\r
+    struct sgm37603a_data *i2c_data = sgmdata;\r
+    \r
+    if(!count || i2c_data==NULL){\r
+        pr_err("%s:count=0 or i2c_data is NULL pointer\n",__func__);\r
+        return -EINVAL;\r
+    }\r
+\r
+    if (sscanf(buf, "%x %x", &reg, &val) == 2)\r
+    {\r
+        pr_err("Notice chip id and write the corrent reg\n");\r
+        pr_err("%s,reg = 0x%02x, val = 0x%02x\n", __func__, reg, val);\r
+        ret = backlight_i2c_write(i2c_data,reg,val);\r
+        if(ret < 0)\r
+            pr_err("write chip reg[0x%x] error\n",reg);\r
+    }\r
+    else{\r
+        pr_err("write echo command error; like this: echo 0x19 0xFF > chip_reg\n");\r
+    }\r
+    return count;\r
+}\r
+\r
+static DEVICE_ATTR(chip_reg, 0644, sgm37603a_chip_reg_show, sgm37603a_chip_reg_store);\r
+static DEVICE_ATTR(hbm_mode, 0644, sgm37603a_mode_show, sgm37603a_mode_store);\r
+static DEVICE_ATTR(chip_name, 0444, sgm37603a_chip_name_show, NULL);\r
+\r
+static struct attribute *sgm37603a_attributes[] = {\r
+    &dev_attr_hbm_mode.attr,\r
+    &dev_attr_chip_name.attr,\r
+    &dev_attr_chip_reg.attr,\r
+    NULL\r
+};\r
+\r
+static struct attribute_group sgm37603a_attribute_group = {\r
+    .attrs = sgm37603a_attributes\r
+};\r
+\r
+/************************************************************\r
+*\r
+*   backlight i2c device init\r
+*\r
+*\r
+*************************************************************/\r
+static int sgm37603a_parse_dt(struct device *dev,\r
+                struct sgm37603a_data *pdata, struct device_node *np)\r
+{\r
+    u32 regaddr;\r
+    int ret;\r
+\r
+    ret = of_property_read_u32(np, "reg", &regaddr);\r
+    if(ret){\r
+        printk(KERN_ERR "parse backlight_i2c dtsi node failed");\r
+        return -EINVAL;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+static int getChipId(struct device *dev){\r
+    int ret;\r
+    unsigned char value = 0;\r
+    struct sgm37603a_data *i2c_data = sgmdata;\r
+    if(i2c_data == NULL){\r
+        pr_err("%s: i2c_data is NULL\n");\r
+        return 1;\r
+    }\r
+\r
+    ret = backlight_i2c_read(i2c_data,BACKLIGHT_CHIP_ID_REG,&value);\r
+    if(ret < 0){\r
+        pr_err("%s: get 0x10 register for compatibility error\n");\r
+        return 1;\r
+    }\r
+    printk(KERN_ERR "%s:read chip id reg:0x%x, value=0x%x\n",__func__,BACKLIGHT_CHIP_ID_REG,value);\r
+    return (value&BACKLIGHT_CHIP_ID_REG_MASK)>>4;\r
+}\r
+\r
+\r
+static int sgm37603a_probe(struct i2c_client *client,\r
+        const struct i2c_device_id *id)\r
+{\r
+    int ret = 0;\r
+    struct sgm37603a_data *data;\r
+    struct device_node *np=client->dev.of_node;\r
+\r
+    pr_err("%s: enter\n",__func__);\r
+    \r
+    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {\r
+        pr_info(KERN_ERR "i2c_check_functionality error\n");\r
+        return -EIO;\r
+    }\r
+\r
+    data = devm_kzalloc(&client->dev,sizeof(struct sgm37603a_data), GFP_KERNEL);\r
+    if (!data) {\r
+        pr_err("%s: kzalloc error\n",__func__);\r
+        return -ENOMEM;\r
+    }\r
+\r
+    data->bk_i2c_client = client;\r
+    mutex_init(&data->lock);\r
+    data->mode = 0;\r
+    i2c_set_clientdata(client, data);\r
+    sgmdata=data;\r
+\r
+    if (np) {\r
+        ret = sgm37603a_parse_dt(&client->dev, data, np);\r
+        if (ret) {\r
+            dev_err(&client->dev,"Unable to parse platfrom data err=%d\n", ret);\r
+            goto kfree_exit;\r
+        }\r
+    }else{\r
+        dev_err(&client->dev,"backlight_i2c dtsi node not exists\n");\r
+        ret = -ENODEV;\r
+        goto kfree_exit;\r
+    }\r
+\r
+    chipid=getChipId(&client->dev);\r
+    printk(KERN_ERR "%s: chipid=%d\n", __func__,chipid);\r
+\r
+    if(1==chipid){\r
+        printk(KERN_ERR "sgm37603 chip\n");\r
+        mutex_lock(&data->lock);\r
+        data->name="sgm37603\0";\r
+        ret = backlight_i2c_write_bits(data,sgm_nr_data[0][0],SGM_LSB_MASK,sgm_nr_data[0][1]);\r
+        if(ret < 0){\r
+            pr_err("%s:NR mode:write sgm chip LSB bit error\n",__func__);\r
+        }\r
+        //backlight_i2c_write(data,sgm_nr_data[0][0],sgm_nr_data[0][1]); //write LSB\r
+        ret = backlight_i2c_write(data,sgm_nr_data[1][0],sgm_nr_data[1][1]); //write MSB\r
+        if(ret < 0){\r
+            pr_err("%s:NR mode:write sgm chip MSB error\n",__func__);\r
+        }\r
+        mutex_unlock(&data->lock);\r
+    }\r
+    else{\r
+        dev_err(&client->dev,"wrong chipid\n");\r
+        ret = -1;\r
+        goto kfree_exit;\r
+    }\r
+\r
+    bd = backlight_device_register("hbm", NULL, NULL, NULL, NULL);\r
+    if (IS_ERR(bd)){\r
+        pr_err("sgm failed to register backlight device!\n");\r
+        ret= -1;\r
+        goto kfree_node;\r
+    }\r
+\r
+    ret = sysfs_create_group(&bd->dev.kobj, &sgm37603a_attribute_group);\r
+    if(ret < 0){\r
+        dev_err(&bd->dev,"Unable to create backlight_i2c_attribute\n");\r
+        goto kfree_sysfs;\r
+    }\r
+    return 0;\r
+    \r
+kfree_sysfs:\r
+    sysfs_remove_group(&bd->dev.kobj, &sgm37603a_attribute_group);\r
+kfree_node:\r
+    backlight_device_unregister(bd);\r
+kfree_exit:\r
+    mutex_destroy(&data->lock);\r
+    return ret;\r
+}\r
+\r
+static int sgm37603a_remove(struct i2c_client *client)\r
+{\r
+    struct sgm37603a_data *data = sgmdata;\r
+    if(sgmdata != NULL)\r
+        mutex_destroy(&data->lock);\r
+    sysfs_remove_group(&bd->dev.kobj, &sgm37603a_attribute_group);\r
+    backlight_device_unregister(bd);\r
+    return 0;\r
+}\r
+\r
+static const struct i2c_device_id sgm37603a_id[] = {\r
+    { SGM_I2C_NAME, 0 },\r
+    { }\r
+};\r
+MODULE_DEVICE_TABLE(i2c, sgm37603a_id);\r
+\r
+static struct of_device_id sgm37603a_match_table[] = {\r
+    { .compatible = "backlight_i2c", },\r
+    { },\r
+};\r
+\r
+static struct i2c_driver sgm37603a_driver = {\r
+    .driver = {\r
+        .owner  = THIS_MODULE,\r
+        .name   = SGM_I2C_NAME,\r
+        .of_match_table = sgm37603a_match_table,\r
+    },\r
+    .id_table   = sgm37603a_id,\r
+    .probe      = sgm37603a_probe,\r
+    .remove     = sgm37603a_remove,\r
+\r
+};\r
+\r
+static int __init sgm37603a_init(void)\r
+{\r
+    int ret=0;\r
+    pr_info("sgm37603a_init\n");\r
+\r
+    ret = i2c_add_driver(&sgm37603a_driver);\r
+    if(ret){\r
+        pr_err("fail to add sgm37603 driver\n");\r
+        return ret;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+static void __exit sgm37603a_exit(void)\r
+{\r
+    pr_info("sgm37603a_exit\n");\r
+    i2c_del_driver(&sgm37603a_driver);\r
+}\r
+\r
+MODULE_DESCRIPTION("LCD_BACKLIGHT davicom ic driver");\r
+MODULE_LICENSE("GPL");\r
+\r
+module_init(sgm37603a_init);\r
+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 (executable)
index 0000000..2c4acf3
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef _SGM37603A_H_\r
+#define _SGM37603A_H_\r
+\r
+#include <linux/delay.h>\r
+#include <linux/i2c.h>\r
+\r
+#define BK_I2C_RETRIES 1   //times for try i2c write/read operation\r
+#define BK_I2C_RETRY_DELAY 1  //time between the current and the last try\r
+\r
+//reg addr used for compatibility\r
+#define BACKLIGHT_CHIP_ID_REG       0x10 //chip id\r
+#define BACKLIGHT_CHIP_ID_REG_MASK  0x10\r
+#define SGM_LSB_MASK 0x0F\r
+\r
+//sgm\r
+#define SGM_REG_NUM 7\r
+#define SGM_SFRESET_REG 0x01\r
+#define SGM_ENABLE_REG 0x10\r
+#define SGM_BRCTL_REG 0x11\r
+#define SGM_BR_LSB_REG 0x1A\r
+#define SGM_BR_MSB_REG 0x19\r
+#define SGM_FLTFLAG_REG 0x1F\r
+#define SGM_MAXLEDCURR_REG 0x1B\r
+\r
+unsigned char sgm_reg[SGM_REG_NUM]={\r
+       SGM_SFRESET_REG,\r
+       SGM_ENABLE_REG,\r
+       SGM_BRCTL_REG,\r
+       SGM_BR_LSB_REG,\r
+       SGM_BR_MSB_REG,\r
+       SGM_FLTFLAG_REG,\r
+       SGM_MAXLEDCURR_REG\r
+};\r
+\r
+struct sgm37603a_data {\r
+       struct i2c_client *bk_i2c_client;\r
+       struct mutex lock;\r
+       unsigned char mode;\r
+       char* name;\r
+};\r
+\r
+unsigned char sgm_nr_data[][2]=\r
+{\r
+    {0x1A, 0x0C},\r
+    {0x19, 0xCC},\r
+};\r
+\r
+unsigned char sgm_hl_data[][2]=\r
+{\r
+    {0x1A, 0x0F},\r
+    {0x19, 0xFF},\r
+};\r
+\r
+static int backlight_i2c_write(struct sgm37603a_data *i2c_data,\r
+         unsigned char reg_addr, unsigned char reg_data)\r
+{\r
+    int ret = -1;\r
+    unsigned char cnt = 0;\r
+\r
+    while(cnt < BK_I2C_RETRIES) {\r
+        ret = i2c_smbus_write_byte_data(i2c_data->bk_i2c_client, reg_addr, reg_data);\r
+        if(ret < 0) {\r
+            pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt, ret);\r
+        }else {\r
+            break;\r
+        }\r
+        cnt ++;\r
+        msleep(BK_I2C_RETRY_DELAY);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+static int backlight_i2c_read(struct sgm37603a_data *i2c_data,\r
+        unsigned char reg_addr, unsigned char *reg_data)\r
+{\r
+    int ret = -1;\r
+    unsigned char cnt = 0;\r
+\r
+    while(cnt < BK_I2C_RETRIES) {\r
+        ret = i2c_smbus_read_byte_data(i2c_data->bk_i2c_client, reg_addr);\r
+        if(ret < 0) {\r
+            pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt, ret);\r
+        }else {\r
+            *reg_data = ret;\r
+            break;\r
+        }\r
+        cnt ++;\r
+        msleep(BK_I2C_RETRY_DELAY);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+static int backlight_i2c_write_bits(struct sgm37603a_data *i2c_data,\r
+         unsigned char reg_addr, unsigned char mask, unsigned char reg_data)\r
+{\r
+    int ret = -1;\r
+    unsigned char reg_val = 0;\r
+\r
+    ret = backlight_i2c_read(i2c_data, reg_addr, &reg_val);\r
+    if(ret < 0) {\r
+        pr_err("%s: read reg[0x%x] last value error\n", __func__, reg_addr);\r
+    }\r
+    reg_val &= (~mask);\r
+    reg_val |= (reg_data&mask);\r
+    msleep(1);\r
+    ret = backlight_i2c_write(i2c_data, reg_addr, reg_val);\r
+    if(ret < 0) {\r
+        pr_err("%s: write new value[0x%x] to reg[0x%x] error\n", __func__, reg_val ,reg_addr);\r
+    }\r
+    return ret;\r
+}\r
+#endif
\ No newline at end of file