leds: tps61310_flashlight: Add TI TPS61310 flashlight driver
HTC kernel version: villeu-jb-crc-3.4.10-ae8b65e
Change-Id: I53b57e105643a7ace9f73d36261e2b7b5f9dcd7a
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 26e8496..19b18ac 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -585,4 +585,11 @@
comment "iptables trigger is under Netfilter config (LED target)"
depends on LEDS_TRIGGERS
+comment "LED Flashlights"
+
+config FLASHLIGHT_TPS61310
+ tristate "TI TPS61310 flashlight"
+ help
+ Say Y here to enable the TI TPS61310 flashlight.
+
endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 3fe422e..430e0b0 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -70,3 +70,6 @@
obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
obj-$(CONFIG_LEDS_TRIGGER_SLEEP) += ledtrig-sleep.o
+
+# Flashlight Drivers
+obj-$(CONFIG_FLASHLIGHT_TPS61310) += tps61310_flashlight.o
diff --git a/drivers/leds/tps61310_flashlight.c b/drivers/leds/tps61310_flashlight.c
new file mode 100644
index 0000000..4e6b40a
--- /dev/null
+++ b/drivers/leds/tps61310_flashlight.c
@@ -0,0 +1,604 @@
+/* drivers/i2c/chips/tps61310_flashlight.c
+ *
+ * Copyright (C) 2008-2009 HTC Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <mach/msm_iomap.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/htc_flashlight.h>
+#include <linux/module.h>
+
+#define FLT_DBG_LOG(fmt, ...) \
+ printk(KERN_DEBUG "[FLT]TPS " fmt, ##__VA_ARGS__)
+#define FLT_INFO_LOG(fmt, ...) \
+ printk(KERN_INFO "[FLT]TPS " fmt, ##__VA_ARGS__)
+#define FLT_ERR_LOG(fmt, ...) \
+ printk(KERN_ERR "[FLT][ERR]TPS " fmt, ##__VA_ARGS__)
+
+#define TPS61310_RETRY_COUNT 10
+
+struct tps61310_data {
+ struct led_classdev fl_lcdev;
+ struct early_suspend fl_early_suspend;
+ enum flashlight_mode_flags mode_status;
+ uint32_t flash_sw_timeout;
+ struct mutex tps61310_data_mutex;
+ uint32_t strb0;
+ uint32_t strb1;
+ uint8_t led_count;
+ uint8_t mode_pin_suspend_state_low;
+};
+
+static struct i2c_client *this_client;
+static struct tps61310_data *this_tps61310;
+struct delayed_work tps61310_delayed_work;
+static struct workqueue_struct *tps61310_work_queue;
+static struct mutex tps61310_mutex;
+
+static int switch_state = 1;
+
+static ssize_t switch_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "switch status:%d \n", switch_state);
+}
+
+static ssize_t switch_store(
+ struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int switch_status;
+ switch_status = -1;
+ sscanf(buf, "%d ",&switch_status);
+ FLT_INFO_LOG("%s: %d\n",__func__,switch_status);
+ switch_state = switch_status;
+ return size;
+}
+
+static DEVICE_ATTR(function_switch, S_IRUGO | S_IWUSR, switch_show, switch_store);
+
+static int TPS61310_I2C_TxData(char *txData, int length)
+{
+ uint8_t loop_i;
+ struct i2c_msg msg[] = {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = length,
+ .buf = txData,
+ },
+ };
+
+ for (loop_i = 0; loop_i < TPS61310_RETRY_COUNT; loop_i++) {
+ if (i2c_transfer(this_client->adapter, msg, 1) > 0)
+ break;
+
+ mdelay(10);
+ }
+
+ if (loop_i >= TPS61310_RETRY_COUNT) {
+ FLT_ERR_LOG("%s retry over %d\n", __func__,
+ TPS61310_RETRY_COUNT);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int tps61310_i2c_command(uint8_t address, uint8_t data)
+{
+ uint8_t buffer[2];
+ int ret;
+
+ buffer[0] = address;
+ buffer[1] = data;
+ ret = TPS61310_I2C_TxData(buffer, 2);
+ if (ret < 0) {
+ FLT_ERR_LOG("%s error\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+
+static int flashlight_turn_off(void)
+{
+ FLT_INFO_LOG("%s\n", __func__);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x00);
+ this_tps61310->mode_status = FL_MODE_OFF;
+ return 0;
+}
+
+int tps61310_flashlight_control(int mode)
+{
+ int ret = 0;
+
+ mutex_lock(&tps61310_mutex);
+ if (this_tps61310->led_count == 1) {
+ switch (mode) {
+ case FL_MODE_OFF:
+ flashlight_turn_off();
+ break;
+ case FL_MODE_FLASH:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x01, 0x9E);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL1:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x01, 0x86);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL2:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x01, 0x88);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL3:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x01, 0x8C);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL4:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x01, 0x90);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL5:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x01, 0x94);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL6:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x01, 0x98);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL7:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x01, 0x9C);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_PRE_FLASH:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x04);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ case FL_MODE_TORCH:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x05);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ case FL_MODE_TORCH_LEVEL_1:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x01);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ case FL_MODE_TORCH_LEVEL_2:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x03);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ default:
+ FLT_ERR_LOG("%s: unknown flash_light flags: %d\n",
+ __func__, mode);
+ ret = -EINVAL;
+ break;
+ }
+ } else if (this_tps61310->led_count == 2) {
+ switch (mode) {
+ case FL_MODE_OFF:
+ flashlight_turn_off();
+ break;
+ case FL_MODE_FLASH:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x02, 0x90);
+ tps61310_i2c_command(0x01, 0x90);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL1:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x02, 0x83);
+ tps61310_i2c_command(0x01, 0x83);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL2:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x02, 0x84);
+ tps61310_i2c_command(0x01, 0x84);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL3:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x02, 0x86);
+ tps61310_i2c_command(0x01, 0x86);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL4:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x02, 0x88);
+ tps61310_i2c_command(0x01, 0x88);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL5:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x02, 0x8A);
+ tps61310_i2c_command(0x01, 0x8A);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL6:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x02, 0x8C);
+ tps61310_i2c_command(0x01, 0x8C);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_FLASH_LEVEL7:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x00);
+ tps61310_i2c_command(0x02, 0x8E);
+ tps61310_i2c_command(0x01, 0x8E);
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+ gpio_set_value_cansleep(this_tps61310->strb0, 1);
+ queue_delayed_work(tps61310_work_queue, &tps61310_delayed_work,
+ msecs_to_jiffies(this_tps61310->flash_sw_timeout));
+ break;
+ case FL_MODE_PRE_FLASH:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x12);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ case FL_MODE_TORCH:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x1B);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ case FL_MODE_TORCH_LEVEL_1:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x09);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ case FL_MODE_TORCH_LEVEL_2:
+ tps61310_i2c_command(0x05, 0x6B);
+ tps61310_i2c_command(0x00, 0x12);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ case FL_MODE_TORCH_LED_A:
+ tps61310_i2c_command(0x05, 0x69);
+ tps61310_i2c_command(0x00, 0x09);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+ case FL_MODE_TORCH_LED_B:
+ tps61310_i2c_command(0x05, 0x6A);
+ tps61310_i2c_command(0x00, 0x09);
+ gpio_set_value_cansleep(this_tps61310->strb0, 0);
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ tps61310_i2c_command(0x01, 0x40);
+ break;
+
+ default:
+ FLT_ERR_LOG("%s: unknown flash_light flags: %d\n",
+ __func__, mode);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ FLT_INFO_LOG("%s: mode: %d\n", __func__, mode);
+ this_tps61310->mode_status = mode;
+ mutex_unlock(&tps61310_mutex);
+
+ return ret;
+}
+
+static void fl_lcdev_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ enum flashlight_mode_flags mode;
+ int ret = -1;
+
+
+ if (brightness > 0 && brightness <= LED_HALF) {
+ if (brightness == (LED_HALF - 2))
+ mode = FL_MODE_TORCH_LEVEL_1;
+ else if (brightness == (LED_HALF - 1))
+ mode = FL_MODE_TORCH_LEVEL_2;
+ else if (brightness == 1 && this_tps61310->led_count ==2)
+ mode = FL_MODE_TORCH_LED_A;
+ else if (brightness == 2 && this_tps61310->led_count ==2)
+ mode = FL_MODE_TORCH_LED_B;
+ else
+ mode = FL_MODE_TORCH;
+ } else if (brightness > LED_HALF && brightness <= LED_FULL) {
+ if (brightness == (LED_HALF + 1))
+ mode = FL_MODE_PRE_FLASH;
+ else if (brightness == (LED_HALF + 3))
+ mode = FL_MODE_FLASH_LEVEL1;
+ else if (brightness == (LED_HALF + 4))
+ mode = FL_MODE_FLASH_LEVEL2;
+ else if (brightness == (LED_HALF + 5))
+ mode = FL_MODE_FLASH_LEVEL3;
+ else if (brightness == (LED_HALF + 6))
+ mode = FL_MODE_FLASH_LEVEL4;
+ else if (brightness == (LED_HALF + 7))
+ mode = FL_MODE_FLASH_LEVEL5;
+ else if (brightness == (LED_HALF + 8))
+ mode = FL_MODE_FLASH_LEVEL6;
+ else if (brightness == (LED_HALF + 9))
+ mode = FL_MODE_FLASH_LEVEL7;
+ else
+ mode = FL_MODE_FLASH;
+ } else
+
+ mode = FL_MODE_OFF;
+
+ if ((mode != FL_MODE_OFF) && switch_state == 0){
+ FLT_INFO_LOG("%s flashlight is disabled by switch, mode = %d\n",__func__, mode);
+ return;
+ }
+
+
+ ret = tps61310_flashlight_control(mode);
+ if (ret) {
+ FLT_ERR_LOG("%s: control failure rc:%d\n", __func__, ret);
+ return;
+ }
+}
+
+static void flashlight_early_suspend(struct early_suspend *handler)
+{
+ FLT_INFO_LOG("%s\n", __func__);
+ if (this_tps61310 != NULL && this_tps61310->mode_status)
+ flashlight_turn_off();
+}
+
+static void flashlight_late_resume(struct early_suspend *handler)
+{
+}
+
+static void flashlight_turn_off_work(struct work_struct *work)
+{
+ FLT_INFO_LOG("%s\n", __func__);
+ flashlight_turn_off();
+}
+
+static int tps61310_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tps61310_data *tps61310;
+ struct TPS61310_flashlight_platform_data *pdata;
+ int err = 0;
+
+ FLT_INFO_LOG("%s +\n", __func__);
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ FLT_ERR_LOG("%s: Assign platform_data error!!\n", __func__);
+ return -EINVAL;
+ }
+
+ if (pdata->gpio_init)
+ pdata->gpio_init();
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ err = -ENODEV;
+ goto check_functionality_failed;
+ }
+
+ tps61310 = kzalloc(sizeof(struct tps61310_data), GFP_KERNEL);
+ if (!tps61310) {
+ FLT_ERR_LOG("%s: kzalloc fail !!!\n", __func__);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, tps61310);
+ this_client = client;
+
+ INIT_DELAYED_WORK(&tps61310_delayed_work, flashlight_turn_off_work);
+ tps61310_work_queue = create_singlethread_workqueue("tps61310_wq");
+ if (!tps61310_work_queue)
+ goto err_create_tps61310_work_queue;
+
+
+ tps61310->fl_lcdev.name = FLASHLIGHT_NAME;
+ tps61310->fl_lcdev.brightness_set = fl_lcdev_brightness_set;
+ tps61310->strb0 = pdata->tps61310_strb0;
+ tps61310->strb1 = pdata->tps61310_strb1;
+ tps61310->flash_sw_timeout = pdata->flash_duration_ms;
+ tps61310->led_count = (pdata->led_count) ? pdata->led_count : 1;
+ tps61310->mode_pin_suspend_state_low = pdata->mode_pin_suspend_state_low;
+
+ if (tps61310->flash_sw_timeout <= 0)
+ tps61310->flash_sw_timeout = 600;
+
+ mutex_init(&tps61310_mutex);
+ err = led_classdev_register(&client->dev, &tps61310->fl_lcdev);
+ if (err < 0) {
+ FLT_ERR_LOG("%s: failed on led_classdev_register\n", __func__);
+ goto platform_data_null;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ tps61310->fl_early_suspend.suspend = flashlight_early_suspend;
+ tps61310->fl_early_suspend.resume = flashlight_late_resume;
+ register_early_suspend(&tps61310->fl_early_suspend);
+#endif
+ this_tps61310 = tps61310;
+
+ err = device_create_file(tps61310->fl_lcdev.dev, &dev_attr_function_switch);
+ if (err < 0) {
+ FLT_ERR_LOG("%s, create function_switch sysfs fail\n", __func__);
+ }
+
+ tps61310_i2c_command(0x01, 0x00);
+
+ tps61310_i2c_command(0x07, 0xF6);
+
+ FLT_INFO_LOG("%s -\n", __func__);
+ return 0;
+
+
+platform_data_null:
+ destroy_workqueue(tps61310_work_queue);
+ mutex_destroy(&tps61310_mutex);
+err_create_tps61310_work_queue:
+ kfree(tps61310);
+check_functionality_failed:
+ return err;
+}
+
+static int tps61310_remove(struct i2c_client *client)
+{
+ struct tps61310_data *tps61310 = i2c_get_clientdata(client);
+
+ led_classdev_unregister(&tps61310->fl_lcdev);
+ destroy_workqueue(tps61310_work_queue);
+ mutex_destroy(&tps61310_mutex);
+ unregister_early_suspend(&tps61310->fl_early_suspend);
+ kfree(tps61310);
+
+ FLT_INFO_LOG("%s:\n", __func__);
+ return 0;
+}
+
+static const struct i2c_device_id tps61310_id[] = {
+ { "TPS61310_FLASHLIGHT", 0 },
+ { }
+};
+static int tps61310_resume(struct i2c_client *client)
+{
+
+ FLT_INFO_LOG("%s:\n", __func__);
+ if (this_tps61310->mode_pin_suspend_state_low)
+ gpio_set_value_cansleep(this_tps61310->strb1, 1);
+ return 0;
+}
+static int tps61310_suspend(struct i2c_client *client, pm_message_t state)
+{
+
+ FLT_INFO_LOG("%s:\n", __func__);
+ if (this_tps61310->mode_pin_suspend_state_low)
+ gpio_set_value_cansleep(this_tps61310->strb1, 0);
+
+ return 0;
+}
+
+static struct i2c_driver tps61310_driver = {
+ .probe = tps61310_probe,
+ .remove = tps61310_remove,
+ .suspend = tps61310_suspend,
+ .resume = tps61310_resume,
+ .id_table = tps61310_id,
+ .driver = {
+ .name = "TPS61310_FLASHLIGHT",
+ },
+};
+
+static int __init tps61310_init(void)
+{
+ FLT_INFO_LOG("tps61310 Led Flash driver: init\n");
+ return i2c_add_driver(&tps61310_driver);
+}
+
+static void __exit tps61310_exit(void)
+{
+ i2c_del_driver(&tps61310_driver);
+}
+
+module_init(tps61310_init);
+module_exit(tps61310_exit);
+
+MODULE_DESCRIPTION("TPS61310 Led Flash driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/htc_flashlight.h b/include/linux/htc_flashlight.h
new file mode 100644
index 0000000..15be786
--- /dev/null
+++ b/include/linux/htc_flashlight.h
@@ -0,0 +1,92 @@
+/*
+ * arch/arm/mach-msm/include/mach/msm_flashlight.h - The flashlight header
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __HTC_FLASHLIGHT_H
+#define __HTC_FLASHLIGHT_H
+#include <linux/earlysuspend.h>
+
+#define FLASHLIGHT_NAME "flashlight"
+
+#define FLASHLIGHT_OFF 0
+#define FLASHLIGHT_TORCH 1
+#define FLASHLIGHT_FLASH 2
+#define FLASHLIGHT_NUM 3
+
+
+enum flashlight_mode_flags {
+ FL_MODE_OFF = 0,
+ FL_MODE_TORCH,
+ FL_MODE_FLASH,
+ FL_MODE_PRE_FLASH,
+ FL_MODE_TORCH_LED_A,
+ FL_MODE_TORCH_LED_B,
+ FL_MODE_TORCH_LEVEL_1,
+ FL_MODE_TORCH_LEVEL_2,
+ FL_MODE_CAMERA_EFFECT_FLASH,
+ FL_MODE_CAMERA_EFFECT_PRE_FLASH,
+ FL_MODE_FLASH_LEVEL1,
+ FL_MODE_FLASH_LEVEL2,
+ FL_MODE_FLASH_LEVEL3,
+ FL_MODE_FLASH_LEVEL4,
+ FL_MODE_FLASH_LEVEL5,
+ FL_MODE_FLASH_LEVEL6,
+ FL_MODE_FLASH_LEVEL7,
+
+};
+
+#ifdef CONFIG_FLASHLIGHT_AAT
+struct flashlight_platform_data {
+ void (*gpio_init) (void);
+ uint32_t torch;
+ uint32_t flash;
+ uint32_t flash_adj;
+ uint32_t torch_set1;
+ uint32_t torch_set2;
+ uint32_t flash_duration_ms;
+ uint8_t led_count;
+ uint32_t chip_model;
+};
+
+enum flashlight_chip{
+ AAT1271 = 0,
+ AAT3177,
+ AAT1277,
+};
+#endif
+
+#ifdef CONFIG_FLASHLIGHT_TPS61310
+struct TPS61310_flashlight_platform_data {
+ void (*gpio_init) (void);
+ uint32_t flash_duration_ms;
+ uint8_t led_count;
+ uint32_t tps61310_strb0;
+ uint32_t tps61310_strb1;
+ uint8_t mode_pin_suspend_state_low;
+};
+
+int aat1271_flashlight_control(int mode);
+int adp1650_flashlight_control(int mode);
+int aat3177_flashlight_control(int mode);
+int aat1277_flashlight_control(int mode);
+int tps61310_flashlight_control(int mode);
+int htc_flashlight_control(int flashlight_mode);
+#endif
+
+#undef __HTC_FLASHLIGHT_H
+#endif