mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 21:07:02 +09:00
leds : add support att1272 white led driver for camera flash led
This commit is contained in:
@@ -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
|
||||
|
||||
7
drivers/leds/Kconfig
Normal file → Executable file
7
drivers/leds/Kconfig
Normal file → Executable file
@@ -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
|
||||
|
||||
1
drivers/leds/Makefile
Normal file → Executable file
1
drivers/leds/Makefile
Normal file → Executable file
@@ -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
|
||||
|
||||
346
drivers/leds/leds-att1272.c
Executable file
346
drivers/leds/leds-att1272.c
Executable file
@@ -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");
|
||||
|
||||
23
include/linux/leds-att1272.h
Executable file
23
include/linux/leds-att1272.h
Executable file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#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_ */
|
||||
Reference in New Issue
Block a user