leds : add support att1272 white led driver for camera flash led
authorddl <ddl@rockchip.com>
Fri, 11 Mar 2011 15:52:26 +0000 (23:52 +0800)
committerddl <ddl@rockchip.com>
Fri, 11 Mar 2011 16:25:16 +0000 (00:25 +0800)
arch/arm/mach-rk29/board-rk29-fih.c
drivers/leds/Kconfig [changed mode: 0644->0755]
drivers/leds/Makefile [changed mode: 0644->0755]
drivers/leds/leds-att1272.c [new file with mode: 0755]
include/linux/leds-att1272.h [new file with mode: 0755]

index 567279307605bd9836660273d99a8872879f6a7d..add2475d083fdc20aef80241270976cdf843113b 100755 (executable)
@@ -43,6 +43,7 @@
 #include <mach/rk29_nand.h>
 #include <mach/rk29_camera.h>                          /* ddl@rock-chips.com : camera support */
 #include <media/soc_camera.h>                               /* ddl@rock-chips.com : camera support */
+#include <linux/leds-att1272.h>                                                        /* ddl@rock-chips.com: camera flash led support */
 #include <mach/vpu_mem.h>
 #include <mach/sram.h>
 
@@ -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
old mode 100644 (file)
new mode 100755 (executable)
index d16677f..dab9a1b
@@ -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
old mode 100644 (file)
new mode 100755 (executable)
index 4ef1e3e..0263ff2
@@ -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 (executable)
index 0000000..47fdaa0
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * leds-att1272.c -  LED Driver
+ *
+ * Copyright (C) 2011 Rockchips
+ * deng dalong <ddl@rock-chips.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.
+ *
+ * Datasheet: http://www.rohm.com/products/databook/driver/pdf/att1272gu-e.pdf
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/leds-att1272.h>
+
+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<<led->attr_name##_offset);                 \
+       val_w |= (led->attr_together<<led->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<<led->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 <ddl@rock-chips.com>");
+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 (executable)
index 0000000..19aa1dd
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * leds-att1272.c -  LED Driver\r
+ *
+ * Copyright (C) 2011 Rockchips\r
+ * deng dalong <ddl@rock-chips.com>\r
+ *
+ * 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\r
+ *
+ */\r
+#ifndef _LEDS_ATT1272_H_\r
+#define _LEDS_ATT1272_H_\r
+
+struct att1272_led_platform_data {\r
+       const char              *name;\r
+       int     en_gpio;\r
+       int flen_gpio;\r
+};\r
+
+#endif /* _LEDS_ATT1272_H_ */\r