Add LM3643 new flash driver using LED subsystem v0.8.LM3643.LED.V0
authorDaniel jeong <daniel.jeong@ti.com>
Tue, 8 Jul 2014 01:46:04 +0000 (10:46 +0900)
committerDaniel jeong <daniel.jeong@ti.com>
Tue, 8 Jul 2014 01:46:04 +0000 (10:46 +0900)
Signed-off-by: Daniel jeong <daniel.jeong@ti.com>
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-lm3643.c [new file with mode: 0644]
include/linux/platform_data/leds-lm3643.h [new file with mode: 0644]

index 8dc4932c45f800dcf755272cecc7302b17d9b79f..4d9cf388fefe26fda78a7639ec3625912d0465d8 100644 (file)
@@ -73,6 +73,13 @@ config LEDS_LM3642
          converter plus 1.5A constant current driver for a high-current
          white LED.
 
+config LEDS_LM3643
+       tristate "LED support for LM3643 Chip"
+       depends on LEDS_CLASS && I2C
+       select REGMAP_I2C
+       help
+         This option enables support for LEDs connected to LM3643.
+         The LM3642 is a dual led flash driver.
 
 config LEDS_LOCOMO
        tristate "LED Support for Locomo device"
index 4b61b5c4540b57b475fbf541cc11ecc7b5ebb364..9bfa0819f1d6f038dcfec8db7358c71dfaa705c8 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_LEDS_LOCOMO)             += leds-locomo.o
 obj-$(CONFIG_LEDS_LM3530)              += leds-lm3530.o
 obj-$(CONFIG_LEDS_LM3533)              += leds-lm3533.o
 obj-$(CONFIG_LEDS_LM3642)              += leds-lm3642.o
+obj-$(CONFIG_LEDS_LM3643)              += leds-lm3643.o
 obj-$(CONFIG_LEDS_MIKROTIK_RB532)      += leds-rb532.o
 obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
diff --git a/drivers/leds/leds-lm3643.c b/drivers/leds/leds-lm3643.c
new file mode 100644 (file)
index 0000000..9395cb7
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ * drivers/leds/leds-lm3643.c
+ * General device driver for TI LM3643, FLASH LED Driver
+ *
+ * Copyright (C) 2014 Texas Instruments
+ *
+ * Contact: Daniel Jeong <gshark.jeong@gmail.com>
+ *                     Ldd-Mlp <ldd-mlp@list.ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/platform_data/leds-lm3643.h>
+
+/* registers definitions */
+#define REG_ENABLE             0x01
+#define REG_FLASH_LED0_BR      0x03
+#define REG_FLASH_LED1_BR      0x04
+#define REG_TORCH_LED0_BR      0x05
+#define REG_TORCH_LED1_BR      0x06
+#define REG_FLASH_TOUT         0x08
+#define REG_FLAG0              0x0a
+#define REG_FLAG1              0x0b
+
+enum lm3643_devid {
+       ID_FLASH0 = 0x0,
+       ID_FLASH1,
+       ID_TORCH0,
+       ID_TORCH1,
+       ID_MAX
+};
+
+enum lm3643_mode {
+       MODE_STDBY = 0x0,
+       MODE_IR,
+       MODE_TORCH,
+       MODE_FLASH,
+       MODE_MAX
+};
+
+enum lm3643_devfile {
+       DFILE_FLASH0_ENABLE = 0,
+       DFILE_FLASH0_ONOFF,
+       DFILE_FLASH0_SOURCE,
+       DFILE_FLASH0_TIMEOUT,
+       DFILE_FLASH1_ENABLE,
+       DFILE_FLASH1_ONOFF,
+       DFILE_TORCH0_ENABLE,
+       DFILE_TORCH0_ONOFF,
+       DFILE_TORCH0_SOURCE,
+       DFILE_TORCH1_ENABLE,
+       DFILE_TORCH1_ONOFF,
+       DFILE_MAX
+};
+
+#define to_lm3643(_ctrl, _no) container_of(_ctrl, struct lm3643, cdev[_no])
+
+struct lm3643 {
+       struct device *dev;
+
+       u8 brightness[ID_MAX];
+       struct work_struct work[ID_MAX];
+       struct led_classdev cdev[ID_MAX];
+
+       struct lm3643_platform_data *pdata;
+       struct regmap *regmap;
+       struct mutex lock;
+};
+
+static void lm3643_read_flag(struct lm3643 *pchip){
+
+       int rval;
+       unsigned int flag0, flag1;
+
+       rval = regmap_read(pchip->regmap,REG_FLAG0, &flag0);
+       rval |= regmap_read(pchip->regmap,REG_FLAG1, &flag1);
+
+       if(rval < 0)
+               dev_err(pchip->dev, "i2c access fail.\n");
+
+       dev_info(pchip->dev, "[flag1] 0x%x, [flag0] 0x%x\n", flag1 & 0x1f, flag0);
+}
+
+/* torch0 brightness control */
+static void lm3643_deferred_torch0_brightness_set(struct work_struct *work)
+{
+       struct lm3643 *pchip = container_of(work,
+                                                       struct lm3643, work[ID_TORCH0]);
+
+       if(regmap_update_bits(pchip->regmap, 
+                                                               REG_TORCH_LED0_BR, 0x7f,
+                                                               pchip->brightness[ID_TORCH0]))
+               dev_err(pchip->dev, "i2c access fail.\n");
+       lm3643_read_flag(pchip);
+}
+
+static void lm3643_torch0_brightness_set(struct led_classdev *cdev,
+                                       enum led_brightness brightness)
+{
+       struct lm3643 *pchip = container_of(cdev, struct lm3643, cdev[ID_TORCH0]);
+
+       pchip->brightness[ID_TORCH0] = brightness;
+       schedule_work(&pchip->work[ID_TORCH0]);
+}
+
+/* torch1 brightness control */
+static void lm3643_deferred_torch1_brightness_set(struct work_struct *work)
+{
+       struct lm3643 *pchip = container_of(work,
+                                                       struct lm3643, work[ID_TORCH1]);
+
+       if(regmap_update_bits(pchip->regmap, 
+                                                               REG_TORCH_LED1_BR, 0x7f,
+                                                               pchip->brightness[ID_TORCH1]))
+               dev_err(pchip->dev, "i2c access fail.\n");
+       lm3643_read_flag(pchip);
+}
+
+static void lm3643_torch1_brightness_set(struct led_classdev *cdev,
+                                       enum led_brightness brightness)
+{
+       struct lm3643 *pchip = container_of(cdev, struct lm3643, cdev[ID_TORCH1]);
+
+       pchip->brightness[ID_TORCH1] = brightness;
+       schedule_work(&pchip->work[ID_TORCH1]);
+}
+
+/* flash0 brightness control */
+static void lm3643_deferred_flash0_brightness_set(struct work_struct *work)
+{
+       struct lm3643 *pchip = container_of(work,
+                                                       struct lm3643, work[ID_FLASH0]);
+
+       if(regmap_update_bits(pchip->regmap, 
+                                                               REG_FLASH_LED0_BR, 0x7f,
+                                                               pchip->brightness[ID_FLASH0]))
+               dev_err(pchip->dev, "i2c access fail.\n");
+       lm3643_read_flag(pchip);
+}
+
+static void lm3643_flash0_brightness_set(struct led_classdev *cdev,
+                                       enum led_brightness brightness)
+{
+       struct lm3643 *pchip = container_of(cdev, struct lm3643, cdev[ID_FLASH0]);
+
+       pchip->brightness[ID_FLASH0] = brightness;
+       schedule_work(&pchip->work[ID_FLASH0]);
+}
+
+/* flash1 brightness control */
+static void lm3643_deferred_flash1_brightness_set(struct work_struct *work)
+{
+       struct lm3643 *pchip = container_of(work,
+                                                       struct lm3643, work[ID_FLASH1]);
+
+       if(regmap_update_bits(pchip->regmap, 
+                                                               REG_FLASH_LED1_BR, 0x7f,
+                                                               pchip->brightness[ID_FLASH1]))
+               dev_err(pchip->dev, "i2c access fail.\n");
+       lm3643_read_flag(pchip);
+}
+
+static void lm3643_flash1_brightness_set(struct led_classdev *cdev,
+                                       enum led_brightness brightness)
+{
+       struct lm3643 *pchip = container_of(cdev, struct lm3643, cdev[ID_FLASH1]);
+
+       pchip->brightness[ID_FLASH1] = brightness;
+       schedule_work(&pchip->work[ID_FLASH1]);
+}
+
+struct lm3643_devices {
+       struct led_classdev cdev;
+       work_func_t func;
+};
+
+static struct lm3643_devices lm3643_leds[ID_MAX] = {
+       [ID_FLASH0] = {
+               .cdev.name = "flash0",
+               .cdev.brightness = 0,
+               .cdev.max_brightness = 0x7f,
+               .cdev.brightness_set = lm3643_flash0_brightness_set,
+               .cdev.default_trigger = "flash0",
+               .func = lm3643_deferred_flash0_brightness_set
+               },
+       [ID_FLASH1] = {
+               .cdev.name = "flash1",
+               .cdev.brightness = 0,
+               .cdev.max_brightness = 0x7f,
+               .cdev.brightness_set = lm3643_flash1_brightness_set,
+               .cdev.default_trigger = "flash1",
+               .func = lm3643_deferred_flash1_brightness_set
+               },
+       [ID_TORCH0] = {
+               .cdev.name = "torch0",
+               .cdev.brightness = 0,
+               .cdev.max_brightness = 0x7f,
+               .cdev.brightness_set = lm3643_torch0_brightness_set,
+               .cdev.default_trigger = "torch0",
+               .func = lm3643_deferred_torch0_brightness_set
+               },
+       [ID_TORCH1] = {
+               .cdev.name = "torch1",
+               .cdev.brightness = 0,
+               .cdev.max_brightness = 0x7f,
+               .cdev.brightness_set = lm3643_torch1_brightness_set,
+               .cdev.default_trigger = "torch1",
+               .func = lm3643_deferred_torch1_brightness_set
+               },
+};
+
+static void lm3643_led_unregister(struct lm3643 *pchip, enum lm3643_devid id)
+{
+       int icnt;
+
+       for(icnt = id; icnt > 0 ; icnt--)
+               led_classdev_unregister(&pchip->cdev[icnt-1]);
+}
+
+static int lm3643_led_register(struct lm3643 *pchip)
+{
+       int icnt, rval; 
+
+       for(icnt = 0 ; icnt < ID_MAX; icnt++){
+               INIT_WORK(&pchip->work[icnt], lm3643_leds[icnt].func);
+               pchip->cdev[icnt].name = lm3643_leds[icnt].cdev.name;
+               pchip->cdev[icnt].max_brightness = lm3643_leds[icnt].cdev.max_brightness;
+               pchip->cdev[icnt].brightness = lm3643_leds[icnt].cdev.brightness;
+               pchip->cdev[icnt].brightness_set = lm3643_leds[icnt].cdev.brightness_set;
+               pchip->cdev[icnt].default_trigger = lm3643_leds[icnt].cdev.default_trigger;
+               rval = led_classdev_register((struct device *)
+                                   pchip->dev, &pchip->cdev[icnt]);
+               if(rval < 0){
+                       lm3643_led_unregister(pchip, icnt);
+                       return rval;
+               }       
+       }
+       return 0;
+}
+
+/* device files to control registers */
+struct lm3643_commands {
+       char *str;
+       int size;
+};
+
+enum lm3643_cmd_id {
+       CMD_ENABLE = 0,
+       CMD_DISABLE,
+       CMD_ON,
+       CMD_OFF,
+       CMD_IRMODE,
+       CMD_OVERRIDE,
+       CMD_MAX
+};
+
+struct lm3643_commands cmds[CMD_MAX] = {
+       [CMD_ENABLE] = {"enable", 6},
+       [CMD_DISABLE] = {"disable", 7},
+       [CMD_ON] = {"on", 2},
+       [CMD_OFF] = {"off", 3},
+       [CMD_IRMODE] = {"irmode", 6},
+       [CMD_OVERRIDE] = {"override", 8},
+};
+
+struct lm3643_files {
+       enum lm3643_devid id;
+       struct device_attribute attr;
+};
+
+static size_t lm3643_ctrl(struct device *dev,
+                                          const char *buf, enum lm3643_devid id,
+                                          enum lm3643_devfile dfid, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lm3643 *pchip = to_lm3643(led_cdev, id);
+       enum lm3643_cmd_id icnt;
+       int tout, rval;
+
+       mutex_lock(&pchip->lock);
+       for(icnt=0; icnt < CMD_MAX ; icnt++){
+               if (strncmp(buf, cmds[icnt].str, cmds[icnt].size) == 0)
+                       break;
+       }
+
+       switch(dfid){
+       /* led 0 enable */
+       case DFILE_FLASH0_ENABLE:
+       case DFILE_TORCH0_ENABLE:
+               if(icnt == CMD_ENABLE)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x1, 0x1);
+               else if(icnt == CMD_DISABLE)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x1, 0x0);
+       break;
+       /* led 1 enable, flash override */
+       case DFILE_FLASH1_ENABLE:
+               if(icnt == CMD_ENABLE){
+                       rval = regmap_update_bits(pchip->regmap, 
+                                                       REG_FLASH_LED0_BR, 0x80, 0x0);
+                       rval |= regmap_update_bits(pchip->regmap, REG_ENABLE, 0x2, 0x2);
+               }else if(icnt == CMD_DISABLE){
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x2, 0x0);
+               }else if(icnt == CMD_OVERRIDE){
+                       rval = regmap_update_bits(pchip->regmap, 
+                                                       REG_FLASH_LED0_BR, 0x80, 0x80);
+                       rval |= regmap_update_bits(pchip->regmap, REG_ENABLE, 0x2, 0x2);
+               }
+       break;
+       /* led 1 enable, torch override */
+       case DFILE_TORCH1_ENABLE:
+               if(icnt == CMD_ENABLE){
+                       rval = regmap_update_bits(pchip->regmap, 
+                                                       REG_TORCH_LED0_BR, 0x80, 0x0);
+                       rval |= regmap_update_bits(pchip->regmap, REG_ENABLE, 0x2, 0x2);
+               }else if(icnt == CMD_DISABLE){
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x2, 0x0);
+               }else if(icnt == CMD_OVERRIDE){
+                       rval = regmap_update_bits(pchip->regmap, 
+                                                       REG_TORCH_LED0_BR, 0x80, 0x80);
+                       rval |= regmap_update_bits(pchip->regmap, REG_ENABLE, 0x2, 0x2);
+               }
+       break;
+       /* mode control flash/ir */
+       case DFILE_FLASH0_ONOFF:
+       case DFILE_FLASH1_ONOFF:
+               if(icnt == CMD_ON)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0xc, 0xc);
+               else if(icnt == CMD_OFF)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0xc, 0x0);
+               else if(icnt == CMD_IRMODE)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0xc, 0x4);
+       break;
+       /* mode control torch */        
+       case DFILE_TORCH0_ONOFF:
+       case DFILE_TORCH1_ONOFF:
+               if(icnt == CMD_ON)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0xc, 0x8);
+               else if(icnt == CMD_OFF)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0xc, 0x0);
+       break;
+       /* strobe pin control */
+       case DFILE_FLASH0_SOURCE:
+               if(icnt == CMD_ON)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x20, 0x20);
+               else if(icnt == CMD_OFF)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x20, 0x0);
+       break;
+       case DFILE_TORCH0_SOURCE:
+               if(icnt == CMD_ON)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x10, 0x10);
+               else if(icnt == CMD_OFF)
+                       rval = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x10, 0x0);
+       break;
+       /* flash time out */
+       case DFILE_FLASH0_TIMEOUT:
+               rval = kstrtouint((const char *)buf, 10, &tout);
+               if(rval < 0)
+                       break;
+               rval = regmap_update_bits(pchip->regmap,
+                                                                       REG_FLASH_TOUT, 0x0f, tout);
+       break;
+       default:
+               dev_err(pchip->dev, "error : undefined dev file\n");
+       break;
+       }
+       lm3643_read_flag(pchip);
+       mutex_unlock(&pchip->lock);
+       return size;
+}
+
+/* flash enable control */
+static ssize_t lm3643_flash0_enable_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_FLASH0, DFILE_FLASH0_ENABLE, size);
+}
+
+static ssize_t lm3643_flash1_enable_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_FLASH1, DFILE_FLASH1_ENABLE, size);
+}
+
+/* flash onoff control */
+static ssize_t lm3643_flash0_onoff_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_FLASH0, DFILE_FLASH0_ONOFF, size);
+}
+
+static ssize_t lm3643_flash1_onoff_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_FLASH1, DFILE_FLASH1_ONOFF, size);
+}
+
+/* flash timeout control */
+static ssize_t lm3643_flash0_timeout_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_FLASH0, DFILE_FLASH0_TIMEOUT, size);
+}
+
+/* flash source control */
+static ssize_t lm3643_flash0_source_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_FLASH0, DFILE_FLASH0_SOURCE, size);
+}
+
+/* torch enable control */
+static ssize_t lm3643_torch0_enable_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_FLASH0, DFILE_TORCH0_ENABLE, size);
+}
+
+static ssize_t lm3643_torch1_enable_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_TORCH1, DFILE_TORCH1_ENABLE, size);
+}
+
+/* torch onoff control */
+static ssize_t lm3643_torch0_onoff_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_TORCH0, DFILE_TORCH0_ONOFF, size);
+}
+
+static ssize_t lm3643_torch1_onoff_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_TORCH1, DFILE_TORCH1_ONOFF, size);
+}
+
+/* torch source control */
+static ssize_t lm3643_torch0_source_store(struct device *dev,
+                                          struct device_attribute *devAttr,
+                                          const char *buf, size_t size)
+{
+       return lm3643_ctrl(dev, buf, ID_TORCH0, DFILE_TORCH0_SOURCE, size);
+}
+
+#define lm3643_attr(_name, _show, _store)\
+{\
+       .attr = {\
+               .name = _name,\
+               .mode = 0644,\
+       },\
+       .show = _show,\
+       .store = _store,\
+}
+
+static struct lm3643_files lm3643_devfiles[DFILE_MAX] = {
+       [DFILE_FLASH0_ENABLE] = {
+               .id = ID_FLASH0,
+               .attr = lm3643_attr("enable", NULL, lm3643_flash0_enable_store),
+       },
+       [DFILE_FLASH0_ONOFF] = {
+               .id = ID_FLASH0,
+               .attr = lm3643_attr("onoff", NULL, lm3643_flash0_onoff_store),
+       },
+       [DFILE_FLASH0_SOURCE] = {
+               .id = ID_FLASH0,
+               .attr = lm3643_attr("source", NULL, lm3643_flash0_source_store),
+       },
+       [DFILE_FLASH0_TIMEOUT] = {
+               .id = ID_FLASH0,
+               .attr = lm3643_attr("timeout", NULL, lm3643_flash0_timeout_store),
+       },
+       [DFILE_FLASH1_ENABLE] = {
+               .id = ID_FLASH1,
+               .attr = lm3643_attr("enable", NULL, lm3643_flash1_enable_store),
+       },
+       [DFILE_FLASH1_ONOFF] = {
+               .id = ID_FLASH1,
+               .attr = lm3643_attr("onoff", NULL, lm3643_flash1_onoff_store),
+       },
+       [DFILE_TORCH0_ENABLE] = {
+               .id = ID_TORCH0,
+               .attr = lm3643_attr("enable", NULL, lm3643_torch0_enable_store),
+       },
+       [DFILE_TORCH0_ONOFF] = {
+               .id = ID_TORCH0,
+               .attr = lm3643_attr("onoff", NULL, lm3643_torch0_onoff_store),
+       },
+       [DFILE_TORCH0_SOURCE] = {
+               .id = ID_TORCH0,
+               .attr = lm3643_attr("source", NULL, lm3643_torch0_source_store),
+       },
+       [DFILE_TORCH1_ENABLE] = {
+               .id = ID_TORCH1,
+               .attr = lm3643_attr("enable", NULL, lm3643_torch1_enable_store),
+       },
+       [DFILE_TORCH1_ONOFF] = {
+               .id = ID_TORCH1,
+               .attr = lm3643_attr("onoff", NULL, lm3643_torch1_onoff_store),
+       }
+};
+
+static void lm3643_df_remove(struct lm3643 *pchip, enum lm3643_devfile dfid)
+{
+       enum lm3643_devfile icnt;
+       
+       for( icnt = dfid; icnt > 0; icnt--)
+               device_remove_file(pchip->cdev[lm3643_devfiles[icnt-1].id].dev,
+                                                                       &lm3643_devfiles[icnt-1].attr);
+}
+
+static int lm3643_df_create(struct lm3643 *pchip)
+{      
+       enum lm3643_devfile icnt;
+       int rval; 
+
+       for(icnt = 0; icnt < DFILE_MAX; icnt++){
+               rval = device_create_file(pchip->cdev[lm3643_devfiles[icnt].id].dev,
+                                                                       &lm3643_devfiles[icnt].attr);
+               if (rval < 0){
+                       lm3643_df_remove(pchip, icnt);
+                       return rval;
+               }
+       }
+       return 0;
+}
+
+static const struct regmap_config lm3643_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xff,
+};
+
+static int lm3643_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct lm3643 *pchip;
+       int rval;
+
+       /* i2c check */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "i2c functionality check fail.\n");
+               return -EOPNOTSUPP;
+       }
+
+       pchip = devm_kzalloc(&client->dev, sizeof(struct lm3643), GFP_KERNEL);
+       if (!pchip)
+               return -ENOMEM;
+
+       pchip->dev = &client->dev;
+       pchip->regmap = devm_regmap_init_i2c(client, &lm3643_regmap);
+       if (IS_ERR(pchip->regmap)) {
+               rval = PTR_ERR(pchip->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       rval);
+               return rval;
+       }
+       mutex_init(&pchip->lock);
+       i2c_set_clientdata(client, pchip);
+
+       /* led class register */
+       rval = lm3643_led_register(pchip);
+       if (rval < 0)
+               return rval;
+
+       /* create dev files*/
+       rval =  lm3643_df_create(pchip);
+       if (rval < 0){
+               lm3643_led_unregister(pchip, ID_MAX);
+               return rval;
+       }
+
+       dev_info(pchip->dev, "lm3643 leds initialized\n");
+       return 0;
+}
+
+static int lm3643_remove(struct i2c_client *client)
+{
+       struct lm3643 *pchip = i2c_get_clientdata(client);
+
+       lm3643_df_remove(pchip, DFILE_MAX);
+       lm3643_led_unregister(pchip, ID_MAX);
+
+       return 0;
+}
+
+static const struct i2c_device_id lm3643_id[] = {
+       {LM3643_NAME, 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3643_id);
+
+static struct i2c_driver lm3643_i2c_driver = {
+       .driver = {
+                  .name = LM3643_NAME,
+                  .owner = THIS_MODULE,
+                  .pm = NULL,
+                  },
+       .probe = lm3643_probe,
+       .remove = lm3643_remove,
+       .id_table = lm3643_id,
+};
+
+module_i2c_driver(lm3643_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3643");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/leds-lm3643.h b/include/linux/platform_data/leds-lm3643.h
new file mode 100644 (file)
index 0000000..9782cd0
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Simple driver for Texas Instruments LM3643 LED Flash driver chip
+ * Copyright (C) 2014 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __LM3643_H
+#define __LM3643_H
+
+#define LM3643_NAME "leds-lm3643"
+#define LM3643_ADDR 0x63
+
+#endif /* __LM3643_H */