};
};
};
+
+&hsi2c_3 {
+ status = "okay";
+ samsung,reset-before-trans;
+ clock-frequency = <400000>;
+
+ backlight_i2c@36 {
+ compatible = "backlight_i2c";
+ reg = <0x36>;
+ };
+};
CONFIG_MOT_UTAG=y
CONFIG_HWMON=y
CONFIG_SENSORS_NTC_THERMISTOR=y
+CONFIG_BACKLIGHT_SGM37603=y
+CONFIG_BACKLIGHT_LM36923=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
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
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
--- /dev/null
+/* 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", ®, &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", ®addr);\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
--- /dev/null
+#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, ®_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
--- /dev/null
+/* 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", ®, &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", ®addr);\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
--- /dev/null
+#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, ®_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