summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 2360dfb)
raw | patch | inline | side by side (parent: 2360dfb)
author | Daniel jeong <daniel.jeong@ti.com> | |
Tue, 8 Jul 2014 11:03:04 +0000 (20:03 +0900) | ||
committer | Daniel jeong <daniel.jeong@ti.com> | |
Tue, 8 Jul 2014 11:03:04 +0000 (20:03 +0900) |
Signed-off-by: Daniel jeong <daniel.jeong@ti.com>
drivers/leds/Kconfig | patch | blob | history | |
drivers/leds/Makefile | patch | blob | history | |
drivers/leds/leds-lm3643.c | [new file with mode: 0644] | patch | blob |
include/linux/platform_data/leds-lm3643.h | [new file with mode: 0644] | patch | blob |
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 288d39db3135bdcd93fe38531f512d16a5984b16..b5609c0dcb946121a45244068970bf6544a3c078 100644 (file)
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
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 LM3643 is a 2/4MHz fixed-frequency synchronous boost
+ converter with 1.5A constant current LED driver.
+
config LEDS_LOCOMO
tristate "LED Support for Locomo device"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 4b61b5c4540b57b475fbf541cc11ecc7b5ebb364..9bfa0819f1d6f038dcfec8db7358c71dfaa705c8 100644 (file)
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
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
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * 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
--- /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 */