| /* 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"); |