From: ddl Date: Fri, 11 Mar 2011 15:52:26 +0000 (+0800) Subject: leds : add support att1272 white led driver for camera flash led X-Git-Tag: firefly_0821_release~10650^2~7 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=63415cbc223d11e56b9431fa3ece38dd87d0f60f;p=firefly-linux-kernel-4.4.55.git leds : add support att1272 white led driver for camera flash led --- diff --git a/arch/arm/mach-rk29/board-rk29-fih.c b/arch/arm/mach-rk29/board-rk29-fih.c index 567279307605..add2475d083f 100755 --- a/arch/arm/mach-rk29/board-rk29-fih.c +++ b/arch/arm/mach-rk29/board-rk29-fih.c @@ -43,6 +43,7 @@ #include #include /* ddl@rock-chips.com : camera support */ #include /* ddl@rock-chips.com : camera support */ +#include /* ddl@rock-chips.com: camera flash led support */ #include #include @@ -67,7 +68,7 @@ #define PMEM_VPU_SIZE SZ_64M #define PMEM_CAM_SIZE 0x01300000 #ifdef CONFIG_VIDEO_RK29_WORK_IPP -#define MEM_CAMIPP_SIZE SZ_4M +#define MEM_CAMIPP_SIZE SZ_8M #else #define MEM_CAMIPP_SIZE 0 #endif @@ -805,7 +806,14 @@ struct tps65910_platform_data rk29_tps65910_data = { }; #endif /* CONFIG_TPS65910_CORE */ - +/* ddl@rock-chips.com: camera flash led support */ +#if CONFIG_LEDS_ATT1272 +struct att1272_led_platform_data rk29_att1272_led_data = { + .name = "camera_flash_led", + .en_gpio = RK29_PIN1_PB0, + .flen_gpio = RK29_PIN1_PB1, +}; +#endif /***************************************************************************************** * i2c devices * author: kfx@rock-chips.com @@ -983,6 +991,15 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = { //.platform_data = &p1003_info, }, #endif + +#if defined (CONFIG_LEDS_ATT1272) + { + .type = "att1272", + .addr = 0x37, + .flags = 0, + .platform_data = &rk29_att1272_led_data, + }, +#endif }; #endif @@ -1029,7 +1046,7 @@ static struct i2c_board_info __initdata board_i2c3_devices[] = { *****************************************************************************************/ #ifdef CONFIG_VIDEO_RK29 #define SENSOR_NAME_0 RK29_CAM_SENSOR_NAME_MT9P111 /* back camera sensor */ -#define SENSOR_IIC_ADDR_0 0x00 +#define SENSOR_IIC_ADDR_0 0x78 #define SENSOR_IIC_ADAPTER_ID_0 1 #define SENSOR_POWER_PIN_0 RK29_PIN5_PD7 #define SENSOR_RESET_PIN_0 INVALID_GPIO @@ -1041,7 +1058,7 @@ static struct i2c_board_info __initdata board_i2c3_devices[] = { #define SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L #define SENSOR_NAME_1 RK29_CAM_SENSOR_NAME_S5K6AA /* front camera sensor */ -#define SENSOR_IIC_ADDR_1 0x78 +#define SENSOR_IIC_ADDR_1 0x00 #define SENSOR_IIC_ADAPTER_ID_1 1 #define SENSOR_POWER_PIN_1 INVALID_GPIO #define SENSOR_RESET_PIN_1 RK29_PIN1_PB3 diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig old mode 100644 new mode 100755 index d16677f77a5d..dab9a1bdb4c1 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -236,6 +236,13 @@ config LEDS_BD2802 This option enables support for BD2802GU RGB LED driver chips accessed via the I2C bus. +config LEDS_ATT1272 + tristate "LED driver for ATT1272 LED" + depends on LEDS_CLASS && I2C + help + This option enables support for ATT1272 LED driver chips + accessed via the I2C bus. + comment "LED Triggers" config LEDS_TRIGGERS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile old mode 100644 new mode 100755 index 4ef1e3eab790..0263ff237ea2 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o obj-$(CONFIG_LEDS_PWM) += leds-pwm.o +obj-$(CONFIG_LEDS_ATT1272) += leds-att1272.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-att1272.c b/drivers/leds/leds-att1272.c new file mode 100755 index 000000000000..47fdaa0466b2 --- /dev/null +++ b/drivers/leds/leds-att1272.c @@ -0,0 +1,346 @@ +/* + * leds-att1272.c - LED Driver + * + * Copyright (C) 2011 Rockchips + * deng dalong + * + * 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. + * + * Datasheet: http://www.rohm.com/products/databook/driver/pdf/att1272gu-e.pdf + * + */ + +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING"leds-att1272: " fmt , ## arg); } while (0) + +#define LEDS_ATT1272_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define LEDS_ATT1272_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) + + +struct att1272_led { + struct att1272_led_platform_data *pdata; + struct i2c_client *client; + struct rw_semaphore rwsem; + struct work_struct work; + + /* + * Making led_classdev as array is not recommended, because array + * members prevent using 'container_of' macro. So repetitive works + * are needed. + */ + struct led_classdev cdev_led; + + /* General attributes of LEDs */ + int flash_safety_timeout; + int flash_safety_timeout_offset; + int movie_mode_current; + int movie_mode_current_offset; + int flash_to_movie_mode_ratio; + int flash_to_movie_mode_ratio_offset; + int flout_config; + int flout_config_offset; +}; + +static int att1272_write_byte(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + struct att1272_led *led = i2c_get_clientdata(client); + u8 buf[2]; + struct i2c_msg msg[1]; + + gpio_set_value(led->pdata->en_gpio, 0); + buf[0] = reg & 0xFF; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = 100000; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 1; + err = -EAGAIN; + gpio_set_value(led->pdata->en_gpio, 1); + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + err = 0; + goto att1272_write_byte_end; + } else { + LEDS_ATT1272_TR("\n write reg(0x%x, val:0x%x) failed, try to write again!\n",reg, val); + udelay(10); + } + } + +att1272_write_byte_end: + gpio_set_value(led->pdata->en_gpio, 0); + return err; +} + +#define att1272_CONTROL_ATTR(attr_name, name_str,reg_addr, attr_together) \ +static ssize_t att1272_show_##attr_name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct att1272_led *led = i2c_get_clientdata(to_i2c_client(dev));\ + ssize_t ret; \ + LEDS_ATT1272_DG("%s enter\n",__FUNCTION__); \ + down_read(&led->rwsem); \ + ret = sprintf(buf, "0x%02x\n", led->attr_name); \ + up_read(&led->rwsem); \ + return ret; \ +} \ +static ssize_t att1272_store_##attr_name(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct att1272_led *led = i2c_get_clientdata(to_i2c_client(dev));\ + unsigned long val,val_w; \ + int ret; \ + if (!count) \ + return -EINVAL; \ + ret = strict_strtoul(buf, 16, &val); \ + if (ret) \ + return ret; \ + down_write(&led->rwsem); \ + val_w = (val<attr_name##_offset); \ + val_w |= (led->attr_together<attr_together##_offset);\ + LEDS_ATT1272_DG("%s enter, val:0x%x\n",__FUNCTION__,val_w); \ + if (att1272_write_byte(led->client, reg_addr, (u8) val) == 0) { \ + led->attr_name = val; \ + } \ + up_write(&led->rwsem); \ + return count; \ +} \ +static struct device_attribute att1272_##attr_name##_attr = { \ + .attr = { \ + .name = name_str, \ + .mode = 0644, \ + .owner = THIS_MODULE \ + }, \ + .show = att1272_show_##attr_name, \ + .store = att1272_store_##attr_name, \ +}; + +att1272_CONTROL_ATTR(flash_safety_timeout, "flash_safety_timeout",0x00,movie_mode_current); +att1272_CONTROL_ATTR(flash_to_movie_mode_ratio, "flash_to_movie_mode_ratio",0x01,flout_config); +att1272_CONTROL_ATTR(flout_config, "flout_config",0x01,flash_to_movie_mode_ratio); + +static struct device_attribute *att1272_attributes[] = { + &att1272_flash_safety_timeout_attr, + &att1272_flash_to_movie_mode_ratio_attr, + &att1272_flout_config_attr, +}; + +static void att1272_led_work(struct work_struct *work) +{ + struct att1272_led *led = container_of(work, struct att1272_led, work); + + att1272_write_byte(led->client, 0x00, (u8)(led->movie_mode_current<movie_mode_current_offset)); + LEDS_ATT1272_DG(); +} + +static void att1272_set_led_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct att1272_led *led = + container_of(led_cdev, struct att1272_led, cdev_led); + + led->movie_mode_current = led->cdev_led.max_brightness - (value>led->cdev_led.max_brightness)?led->cdev_led.max_brightness:value; + schedule_work(&led->work); +} +static int att1272_set_led_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, unsigned long *delay_off) +{ + struct att1272_led *led = + container_of(led_cdev, struct att1272_led, cdev_led); + if (*delay_on == 0 || *delay_off == 0) + return -EINVAL; + + schedule_work(&led->work); + return 0; +} + +static int att1272_register_led_classdev(struct att1272_led *led) +{ + int ret; + struct att1272_led_platform_data *pdata = led->client->dev.platform_data; + + INIT_WORK(&led->work, att1272_led_work); + + led->cdev_led.name = pdata->name; + led->cdev_led.brightness = LED_OFF; + led->cdev_led.max_brightness = 15; + led->cdev_led.brightness_set = att1272_set_led_brightness; + led->cdev_led.blink_set = att1272_set_led_blink; + + ret = led_classdev_register(&led->client->dev, &led->cdev_led); + if (ret < 0) { + LEDS_ATT1272_TR("couldn't register LED %s\n", + led->cdev_led.name); + goto failed_unregister_led; + } + + + return 0; + +failed_unregister_led: + + return ret; +} + +static void att1272_unregister_led_classdev(struct att1272_led *led) +{ + cancel_work_sync(&led->work); + led_classdev_unregister(&led->cdev_led); +} + +static int __devinit att1272_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct att1272_led *led; + struct att1272_led_platform_data *pdata; + int ret, i; + + LEDS_ATT1272_DG("%s enter: client->addr:0x%x\n",__FUNCTION__,client->addr); + + led = kzalloc(sizeof(struct att1272_led), GFP_KERNEL); + if (!led) { + LEDS_ATT1272_TR("failed to allocate driver data\n"); + return -ENOMEM; + } + + led->client = client; + pdata = led->pdata = client->dev.platform_data; + i2c_set_clientdata(client, led); + + /* Configure EN GPIO */ + if (gpio_request(pdata->en_gpio, "ATT1272_EN") < 0) { + LEDS_ATT1272_TR("request en_gpio(%d) is failed!\n",pdata->en_gpio); + goto failed_free; + } + gpio_direction_output(pdata->en_gpio, 0); + + /* Detect att1272 */ + printk("att1272 i2c write.....\n"); + ret = att1272_write_byte(client, 0x01, 0x30); + ret |= att1272_write_byte(client, 0x00, 0x00); + if (ret < 0) { + LEDS_ATT1272_TR("failed to detect device\n"); + goto failed_free; + } + + /* Default attributes */ + led->flash_safety_timeout = 0x00; + led->flash_safety_timeout_offset = 0x00; + led->movie_mode_current = 0x00; + led->movie_mode_current_offset = 0x04; + led->flash_to_movie_mode_ratio = 0x03; + led->flash_to_movie_mode_ratio_offset = 0x03; + led->flout_config = 0x00; + led->flout_config_offset = 0x04; + + init_rwsem(&led->rwsem); + + for (i = 0; i < ARRAY_SIZE(att1272_attributes); i++) { + ret = device_create_file(&led->client->dev, + att1272_attributes[i]); + if (ret) { + LEDS_ATT1272_TR("failed: sysfs file %s\n", + att1272_attributes[i]->attr.name); + goto failed_unregister_dev_file; + } + } + + ret = att1272_register_led_classdev(led); + if (ret < 0) + goto failed_unregister_dev_file; + + return 0; + +failed_unregister_dev_file: + for (i--; i >= 0; i--) + device_remove_file(&led->client->dev, att1272_attributes[i]); +failed_free: + i2c_set_clientdata(client, NULL); + kfree(led); + + return ret; +} + +static int __exit att1272_remove(struct i2c_client *client) +{ + struct att1272_led *led = i2c_get_clientdata(client); + int i; + + gpio_set_value(led->pdata->en_gpio, 0); + att1272_unregister_led_classdev(led); + + for (i = 0; i < ARRAY_SIZE(att1272_attributes); i++) + device_remove_file(&led->client->dev, att1272_attributes[i]); + i2c_set_clientdata(client, NULL); + kfree(led); + + return 0; +} + +static int att1272_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct att1272_led *led = i2c_get_clientdata(client); + + return 0; +} + +static int att1272_resume(struct i2c_client *client) +{ + struct att1272_led *led = i2c_get_clientdata(client); + + return 0; +} + +static const struct i2c_device_id att1272_id[] = { + { "att1272", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, att1272_id); + +static struct i2c_driver att1272_i2c_driver = { + .driver = { + .name = "att1272", + }, + .probe = att1272_probe, + .remove = __exit_p(att1272_remove), + .suspend = att1272_suspend, + .resume = att1272_resume, + .id_table = att1272_id, +}; + +static int __init att1272_init(void) +{ + return i2c_add_driver(&att1272_i2c_driver); +} +module_init(att1272_init); + +static void __exit att1272_exit(void) +{ + i2c_del_driver(&att1272_i2c_driver); +} +module_exit(att1272_exit); + +MODULE_AUTHOR("deng dalong "); +MODULE_DESCRIPTION("att1272 LED driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/include/linux/leds-att1272.h b/include/linux/leds-att1272.h new file mode 100755 index 000000000000..19aa1ddb31f5 --- /dev/null +++ b/include/linux/leds-att1272.h @@ -0,0 +1,23 @@ +/* + * leds-att1272.c - LED Driver + * + * Copyright (C) 2011 Rockchips + * deng dalong + * + * 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. + * + * Datasheet: http://www.rohm.com/products/databook/driver/pdf/att1272gu-e.pdf + * + */ +#ifndef _LEDS_ATT1272_H_ +#define _LEDS_ATT1272_H_ + +struct att1272_led_platform_data { + const char *name; + int en_gpio; + int flen_gpio; +}; + +#endif /* _LEDS_ATT1272_H_ */