aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig17
-rw-r--r--drivers/leds/leds-aat1290a.c32
-rw-r--r--drivers/leds/leds-an30259a.c62
-rw-r--r--drivers/leds/leds-lp5521.c520
-rw-r--r--drivers/leds/leds-max77693.c101
-rw-r--r--drivers/leds/leds-max8997.c6
6 files changed, 409 insertions, 329 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index d63605c..7cdcd46 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -331,6 +331,14 @@ config LEDS_REGULATOR
help
This option enables support for regulator driven LEDs.
+config LEDS_MAX8997
+ tristate "MAX8997 LED support"
+ default n
+ help
+ This option
+ enables support
+ for LEDs
+ of MAX8997.
config LEDS_BD2802
tristate "LED driver for BD2802 RGB LED"
depends on LEDS_CLASS
@@ -415,11 +423,18 @@ config LEDS_ASIC3
cannot be used. This driver supports hardware blinking with an on+off
period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.
+config LEDS_SWITCH
+ bool "LED control switch support"
+ depends on LEDS_CLASS
+ default n
+ help
+ This option enables support for the LED SWITCH.
+
config LEDS_MAX77693
bool "LED support for the MAX77693"
depends on LEDS_CLASS
depends on MFD_MAX77693
- default y
+ default n
help
This option enables support for the LEDs on the MAX77693.
diff --git a/drivers/leds/leds-aat1290a.c b/drivers/leds/leds-aat1290a.c
index 493f422..cf916ee 100644
--- a/drivers/leds/leds-aat1290a.c
+++ b/drivers/leds/leds-aat1290a.c
@@ -12,7 +12,7 @@
int *aat1290a_ctrl;
struct aat1290a_led_platform_data *led_pdata;
-struct class *flash_class;
+extern struct class *camera_class; /*sys/class/camera*/
struct device *aat1290a_dev;
static int aat1290a_setPower(int onoff, int level)
@@ -165,8 +165,15 @@ ssize_t aat1290a_power(struct device *dev,
return count;
}
-static DEVICE_ATTR(flash_power, S_IWUSR|S_IWGRP|S_IROTH,
- NULL, aat1290a_power);
+ssize_t aat1290a_get_max_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf,
+ sizeof(led_pdata->brightness), "%d", TORCH_BRIGHTNESS_100);
+}
+
+static DEVICE_ATTR(rear_flash, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH,
+ aat1290a_get_max_brightness, aat1290a_power);
static const struct file_operations aat1290a_fops = {
.owner = THIS_MODULE,
@@ -192,18 +199,17 @@ static int aat1290a_led_probe(struct platform_device *pdev)
return -ENODEV;
}
- flash_class = class_create(THIS_MODULE, "flash");
- if (IS_ERR(flash_class))
- LED_ERROR("Failed to create class(flash)!\n");
- aat1290a_dev = device_create(flash_class, NULL, 0, NULL, "flash");
+ aat1290a_dev = device_create(camera_class, NULL, 0, NULL, "flash");
if (IS_ERR(aat1290a_dev))
LED_ERROR("Failed to create device(flash)!\n");
- if (device_create_file(aat1290a_dev, &dev_attr_flash_power) < 0) {
+ if (device_create_file(aat1290a_dev, &dev_attr_rear_flash) < 0) {
LED_ERROR("failed to create device file, %s\n",
- dev_attr_flash_power.attr.name);
+ dev_attr_rear_flash.attr.name);
}
- led_pdata->initGpio();
+
+ if (led_pdata)
+ led_pdata->initGpio();
aat1290a_setGpio();
return 0;
}
@@ -213,9 +219,9 @@ static int __devexit aat1290a_led_remove(struct platform_device *pdev)
led_pdata->freeGpio();
misc_deregister(&aat1290a_miscdev);
- device_remove_file(aat1290a_dev, &dev_attr_flash_power);
- device_destroy(flash_class, 0);
- class_destroy(flash_class);
+ device_remove_file(aat1290a_dev, &dev_attr_rear_flash);
+ device_destroy(camera_class, 0);
+ class_destroy(camera_class);
return 0;
}
diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c
index 5d351c4..965ef3e 100644
--- a/drivers/leds/leds-an30259a.c
+++ b/drivers/leds/leds-an30259a.c
@@ -82,6 +82,9 @@
#define MAX_NUM_LEDS 3
+u8 LED_DYNAMIC_CURRENT = 0x8;
+u8 LED_LOWPOWER_MODE = 0x0;
+
static struct an30259_led_conf led_conf[] = {
{
.name = "led_r",
@@ -317,7 +320,6 @@ static void an30259a_reset_register_work(struct work_struct *work)
static void an30259a_start_led_pattern(int mode)
{
int retval;
-
struct i2c_client *client;
struct work_struct *reset = 0;
client = b_client;
@@ -329,6 +331,12 @@ static void an30259a_start_led_pattern(int mode)
if (mode == LED_OFF)
return;
+ /* Set to low power consumption mode */
+ if (LED_LOWPOWER_MODE == 1)
+ LED_DYNAMIC_CURRENT = 0x8;
+ else
+ LED_DYNAMIC_CURRENT = 0x1;
+
switch (mode) {
/* leds_set_slope_mode(client, LED_SEL, DELAY, MAX, MID, MIN,
SLPTT1, SLPTT2, DT1, DT2, DT3, DT4) */
@@ -437,6 +445,27 @@ static void an30259a_set_led_blink(enum an30259a_led_enum led,
}
}
+static ssize_t store_an30259a_led_lowpower(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int retval;
+ u8 led_lowpower;
+ struct an30259a_data *data = dev_get_drvdata(dev);
+
+ retval = kstrtou8(buf, 0, &led_lowpower);
+ if (retval != 0) {
+ dev_err(&data->client->dev, "fail to get led_lowpower.\n");
+ return count;
+ }
+
+ LED_LOWPOWER_MODE = led_lowpower;
+
+ printk(KERN_DEBUG "led_lowpower mode set to %i\n", led_lowpower);
+
+ return count;
+}
+
static ssize_t store_an30259a_led_br_lev(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
@@ -449,7 +478,7 @@ static ssize_t store_an30259a_led_br_lev(struct device *dev,
retval = strict_strtoul(buf, 16, &brightness_lev);
if (retval != 0) {
- dev_err(&data->client->dev, "fail to get led_pattern mode.\n");
+ dev_err(&data->client->dev, "fail to get led_br_lev.\n");
return count;
}
@@ -517,7 +546,8 @@ static ssize_t store_an30259a_led_blink(struct device *dev,
leds_i2c_write_all(data->client);
- printk(KERN_DEBUG "led_blink is called\n");
+ printk(KERN_DEBUG "led_blink is called, Color:0x%X Brightness:%i\n",
+ led_brightness, LED_DYNAMIC_CURRENT);
return count;
}
@@ -739,6 +769,9 @@ static DEVICE_ATTR(led_fade, 0664, show_an30259a_led_fade, \
store_an30259a_led_fade);
static DEVICE_ATTR(led_br_lev, 0664, NULL, \
store_an30259a_led_br_lev);
+static DEVICE_ATTR(led_lowpower, 0664, NULL, \
+ store_an30259a_led_lowpower);
+
#endif
static struct attribute *led_class_attrs[] = {
@@ -761,6 +794,7 @@ static struct attribute *sec_led_attributes[] = {
&dev_attr_led_blink.attr,
&dev_attr_led_fade.attr,
&dev_attr_led_br_lev.attr,
+ &dev_attr_led_lowpower.attr,
NULL,
};
@@ -867,11 +901,14 @@ static int __devinit an30259a_probe(struct i2c_client *client,
dev_err(&client->dev,
"Failed to create device for samsung specific led\n");
ret = -ENODEV;
+ goto exit;
}
ret = sysfs_create_group(&led_dev->kobj, &sec_led_attr_group);
- if (ret)
+ if (ret) {
dev_err(&client->dev,
"Failed to create sysfs group for samsung specific led\n");
+ goto exit;
+ }
#endif
return ret;
exit:
@@ -885,22 +922,6 @@ static int __devexit an30259a_remove(struct i2c_client *client)
struct an30259a_data *data = i2c_get_clientdata(client);
int i;
dev_dbg(&client->adapter->dev, "%s\n", __func__);
-
- // this is not an ugly hack to shutdown led.
- data->shadow_reg[AN30259A_REG_LEDON] &= ~(LED_ON << 0);
- data->shadow_reg[AN30259A_REG_LEDON] &= ~(LED_ON << 1);
- data->shadow_reg[AN30259A_REG_LEDON] &= ~(LED_ON << 2);
- data->shadow_reg[AN30259A_REG_LED1CNT2 + 0 * 4] &= ~AN30259A_MASK_DELAY;
- data->shadow_reg[AN30259A_REG_LED1CNT2 + 1 * 4] &= ~AN30259A_MASK_DELAY;
- data->shadow_reg[AN30259A_REG_LED1CNT2 + 2 * 4] &= ~AN30259A_MASK_DELAY;
- data->shadow_reg[AN30259A_REG_LEDON] &= ~(LED_SLOPE_MODE << 0);
- data->shadow_reg[AN30259A_REG_LEDON] &= ~(LED_SLOPE_MODE << 1);
- data->shadow_reg[AN30259A_REG_LEDON] &= ~(LED_SLOPE_MODE << 2);
- data->shadow_reg[AN30259A_REG_LED1CC + 0] = 0;
- data->shadow_reg[AN30259A_REG_LED1CC + 1] = 0;
- data->shadow_reg[AN30259A_REG_LED1CC + 2] = 0;
- msleep(200);
-
#ifdef SEC_LED_SPECIFIC
sysfs_remove_group(&led_dev->kobj, &sec_led_attr_group);
#endif
@@ -910,7 +931,6 @@ static int __devexit an30259a_remove(struct i2c_client *client)
led_classdev_unregister(&data->leds[i].cdev);
cancel_work_sync(&data->leds[i].brightness_work);
}
-
mutex_destroy(&data->mutex);
kfree(data);
return 0;
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index 58a5dee..b33dc63 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -5,8 +5,6 @@
*
* Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
*
- * Updated: Milo(Woogyom) Kim <milo.kim@ti.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.
@@ -37,11 +35,6 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#endif
-
#define LP5521_PROGRAM_LENGTH 32 /* in bytes */
#define LP5521_MAX_LEDS 3 /* Maximum number of LEDs */
@@ -88,13 +81,28 @@
#define LP5521_MASTER_ENABLE 0x40 /* Chip master enable */
#define LP5521_LOGARITHMIC_PWM 0x80 /* Logarithmic PWM adjustment */
#define LP5521_EXEC_RUN 0x2A
+#define LP5521_ENABLE_DEFAULT \
+ (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM)
+#define LP5521_ENABLE_RUN_PROGRAM \
+ (LP5521_ENABLE_DEFAULT | LP5521_EXEC_RUN)
/* Status */
#define LP5521_EXT_CLK_USED 0x08
-#define LED_DEBUG 1
+/* default R channel current register value */
+#define LP5521_REG_R_CURR_DEFAULT 0xAF
-extern struct class *sec_class;
+/* Pattern Mode */
+#define PATTERN_OFF 0
+
+/* Blink time unit */
+#define MAX_BLINK_TIME 7500
+
+/* Program Commands */
+#define CMD_SET_PWM 0x40
+#define CMD_WAIT_MSB 0x60 /* 500ms unit */
+#define CMD_WAIT_LSB 0x00
+#define WAIT_UNIT 500
struct lp5521_engine {
int id;
@@ -113,13 +121,6 @@ struct lp5521_led {
u8 brightness;
};
-#ifdef CONFIG_DEBUG_FS
-struct dbg_dentry {
- struct dentry *dir;
- struct dentry *reg;
-};
-#endif
-
struct lp5521_chip {
struct lp5521_platform_data *pdata;
struct mutex lock; /* Serialize control */
@@ -128,17 +129,16 @@ struct lp5521_chip {
struct lp5521_led leds[LP5521_MAX_LEDS];
u8 num_channels;
u8 num_leds;
-#ifdef CONFIG_DEBUG_FS
- struct dbg_dentry dd;
-#endif
- struct device *led_dev;
};
-static struct lp5521_chip *g_chip;
-
-#ifdef LED_DEBUG
-static struct i2c_client *g_client;
-#endif
+struct lp5521_pattern_cmd {
+ u8 r[LP5521_PROGRAM_LENGTH];
+ u8 g[LP5521_PROGRAM_LENGTH];
+ u8 b[LP5521_PROGRAM_LENGTH];
+ int pc_r;
+ int pc_g;
+ int pc_b;
+};
static inline struct lp5521_led *cdev_to_led(struct led_classdev *cdev)
{
@@ -157,8 +157,6 @@ static inline struct lp5521_chip *led_to_lp5521(struct lp5521_led *led)
leds[led->id]);
}
-void lp5521_led_brightness(u8 channel, u8 brightness);
-
static void lp5521_led_brightness_work(struct work_struct *work);
static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value)
@@ -193,14 +191,14 @@ static int lp5521_set_engine_mode(struct lp5521_engine *engine, u8 mode)
mode = LP5521_CMD_DIRECT;
ret = lp5521_read(client, LP5521_REG_OP_MODE, &engine_state);
+ if (ret < 0)
+ return ret;
/* set mode only for this engine */
engine_state &= ~(engine->engine_mask);
mode &= engine->engine_mask;
engine_state |= mode;
- ret |= lp5521_write(client, LP5521_REG_OP_MODE, engine_state);
-
- return ret;
+ return lp5521_write(client, LP5521_REG_OP_MODE, engine_state);
}
static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
@@ -213,9 +211,14 @@ static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
/* move current engine to direct mode and remember the state */
ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT);
+ if (ret)
+ return ret;
+
/* Mode change requires min 500 us delay. 1 - 2 ms with margin */
usleep_range(1000, 2000);
- ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode);
+ ret = lp5521_read(client, LP5521_REG_OP_MODE, &mode);
+ if (ret)
+ return ret;
/* For loading, all the engines to load mode */
lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
@@ -231,8 +234,7 @@ static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
LP5521_PROG_MEM_SIZE,
pattern);
- ret |= lp5521_write(client, LP5521_REG_OP_MODE, mode);
- return ret;
+ return lp5521_write(client, LP5521_REG_OP_MODE, mode);
}
static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr)
@@ -255,16 +257,17 @@ static void lp5521_init_engine(struct lp5521_chip *chip)
static int lp5521_configure(struct i2c_client *client)
{
struct lp5521_chip *chip = i2c_get_clientdata(client);
- u8 cfg = chip->pdata->update_config;
int ret;
+ u8 cfg;
lp5521_init_engine(chip);
/* Set all PWMs to direct control mode */
- ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+ ret = lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
- if (cfg)
- ret |= lp5521_write(client, LP5521_REG_CONFIG, cfg);
+ cfg = chip->pdata->update_config ?
+ : (LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+ ret |= lp5521_write(client, LP5521_REG_CONFIG, cfg);
/* Initialize all channels PWM to zero -> leds off */
ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
@@ -273,8 +276,7 @@ static int lp5521_configure(struct i2c_client *client)
/* Set engines are set to run state when OP_MODE enables engines */
ret |= lp5521_write(client, LP5521_REG_ENABLE,
- LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
- LP5521_EXEC_RUN);
+ LP5521_ENABLE_RUN_PROGRAM);
/* enable takes 500us. 1 - 2 ms leaves some margin */
usleep_range(1000, 2000);
@@ -325,8 +327,7 @@ static int lp5521_detect(struct i2c_client *client)
int ret;
u8 buf;
- ret = lp5521_write(client, LP5521_REG_ENABLE,
- LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
+ ret = lp5521_write(client, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
if (ret)
return ret;
/* enable takes 500us. 1 - 2 ms leaves some margin */
@@ -334,7 +335,7 @@ static int lp5521_detect(struct i2c_client *client)
ret = lp5521_read(client, LP5521_REG_ENABLE, &buf);
if (ret)
return ret;
- if (buf != (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM))
+ if (buf != LP5521_ENABLE_DEFAULT)
return -ENODEV;
return 0;
@@ -519,7 +520,7 @@ static ssize_t store_current(struct device *dev,
ssize_t ret;
unsigned long curr;
- if (strict_strtoul(buf, 0, &curr))
+ if (kstrtoul(buf, 0, &curr))
return -EINVAL;
if (curr > led->max_current)
@@ -551,229 +552,93 @@ static ssize_t lp5521_selftest(struct device *dev,
return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
}
-/* led class device attributes */
-static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
-static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
-
-static struct attribute *lp5521_led_attributes[] = {
- &dev_attr_led_current.attr,
- &dev_attr_max_current.attr,
- NULL,
-};
-
-static struct attribute_group lp5521_led_attribute_group = {
- .attrs = lp5521_led_attributes
-};
-
-/* device attributes */
-static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR,
- show_engine1_mode, store_engine1_mode);
-static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR,
- show_engine2_mode, store_engine2_mode);
-static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR,
- show_engine3_mode, store_engine3_mode);
-static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load);
-static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
-static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
-static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
-
-static struct attribute *lp5521_attributes[] = {
- &dev_attr_engine1_mode.attr,
- &dev_attr_engine2_mode.attr,
- &dev_attr_engine3_mode.attr,
- &dev_attr_selftest.attr,
- &dev_attr_engine1_load.attr,
- &dev_attr_engine2_load.attr,
- &dev_attr_engine3_load.attr,
- NULL
-};
-
-static const struct attribute_group lp5521_group = {
- .attrs = lp5521_attributes,
-};
-
-#ifdef CONFIG_DEBUG_FS
-static int lp5521_dbg_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t lp5521_help_register(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
+static void lp5521_clear_program_memory(struct i2c_client *cl)
{
- char buf[320];
- unsigned int len;
- const char *help = "\n How to read/write LP5521 registers\n\n";
-/* (example) To read 0x00 register,\n \
- echo 0x00 r > /sys/kernel/debug/lp5521/registers\n \
- To write 0xff into 0x1 address,\n \
- echo 0x00 0xff w > /sys/kernel/debug/lp5521/registers \n \
- To dump values from 0x00 to 0x0a address,\n \
- echo 0x00 0x0a d > /sys/kernel/debug/lp5521/registers\n";
-*/
- len = snprintf(buf, sizeof(buf), "%s\n", help);
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+ int i;
+ u8 rgb_mem[] = {
+ LP5521_REG_R_PROG_MEM,
+ LP5521_REG_G_PROG_MEM,
+ LP5521_REG_B_PROG_MEM,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(rgb_mem); i++) {
+ lp5521_write(cl, rgb_mem[i], 0);
+ lp5521_write(cl, rgb_mem[i] + 1, 0);
+ }
}
-static char *lp5521_parse_register_cmd(const char *cmd, u8 *byte)
+static void lp5521_write_program_memory(struct i2c_client *cl,
+ u8 base, u8 *rgb, int size)
{
- char tmp[10];
- char *blank;
- unsigned long arg;
+ int i;
- blank = strchr(cmd, ' ');
- memset(tmp, 0x0, sizeof(tmp));
- memcpy(tmp, cmd, blank - cmd);
+ if (!rgb || size <= 0)
+ return;
- if (strict_strtol(tmp, 16, &arg) < 0)
- return NULL;
+ for (i = 0; i < size; i++)
+ lp5521_write(cl, base + i, *(rgb + i));
- *byte = arg;
- return blank;
+ lp5521_write(cl, base + i, 0);
+ lp5521_write(cl, base + i + 1, 0);
}
-static ssize_t lp5521_ctrl_register(struct file *file,
- const char __user *userbuf, size_t count,
- loff_t *ppos)
+static inline struct lp5521_led_pattern *lp5521_get_pattern
+ (struct lp5521_chip *chip, u8 offset)
{
- char mode, buf[20];
- char *pos, *pos2;
- u8 i, arg1, arg2, val = 0;
- struct lp5521_chip *chip = file->private_data;
- struct i2c_client *cl = chip->client;
-
- if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
- return -EFAULT;
-
- mode = buf[count - 2];
- switch (mode) {
- case 'r':
- if (!lp5521_parse_register_cmd(buf, &arg1))
- return -EINVAL;
-
- lp5521_read(cl, arg1, &val);
- dev_info(&cl->dev, "Read [0x%.2x] = 0x%.2x\n", arg1, val);
- break;
- case 'w':
- pos = lp5521_parse_register_cmd(buf, &arg1);
- if (!pos)
- return -EINVAL;
- pos2 = lp5521_parse_register_cmd(pos + 1, &arg2);
- if (!pos2)
- return -EINVAL;
-
- lp5521_write(cl, arg1, arg2);
- dev_info(&cl->dev, "Written [0x%.2x] = 0x%.2x\n", arg1, arg2);
- break;
- case 'd':
- pos = lp5521_parse_register_cmd(buf, &arg1);
- if (!pos)
- return -EINVAL;
- pos2 = lp5521_parse_register_cmd(pos + 1, &arg2);
- if (!pos2)
- return -EINVAL;
-
- for (i = arg1; i <= arg2; i++) {
- lp5521_read(cl, i, &val);
- dev_info(&cl->dev, "Read [0x%.2x] = 0x%.2x\n", i, val);
- }
- break;
- default:
- break;
- }
-
- return count;
+ struct lp5521_led_pattern *ptn;
+ ptn = chip->pdata->patterns + (offset - 1);
+ return ptn;
}
-static const struct file_operations fops_registers = {
- .open = lp5521_dbg_open,
- .read = lp5521_help_register,
- .write = lp5521_ctrl_register,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static void lp5521_create_debugfs(struct lp5521_chip *chip)
+static void _run_led_pattern(struct lp5521_chip *chip,
+ struct lp5521_led_pattern *ptn)
{
- struct dbg_dentry *dd = &chip->dd;
+ struct i2c_client *cl = chip->client;
- dd->dir = debugfs_create_dir("lp5521", NULL);
- dd->reg = debugfs_create_file("registers", S_IWUSR | S_IRUGO,
- dd->dir, chip, &fops_registers);
-}
+ lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
+ usleep_range(1000, 2000);
-static void lp5521_remove_debugfs(struct lp5521_chip *chip)
-{
- struct dbg_dentry *dd = &chip->dd;
+ lp5521_clear_program_memory(cl);
- debugfs_remove(dd->reg);
- debugfs_remove(dd->dir);
-}
-#else
-static inline void lp5521_create_debugfs(struct lp5521_chip *chip)
-{
- return;
-}
+ lp5521_write_program_memory(cl, LP5521_REG_R_PROG_MEM,
+ ptn->r, ptn->size_r);
+ lp5521_write_program_memory(cl, LP5521_REG_G_PROG_MEM,
+ ptn->g, ptn->size_g);
+ lp5521_write_program_memory(cl, LP5521_REG_B_PROG_MEM,
+ ptn->b, ptn->size_b);
-static inline void lp5521_remove_debugfs(struct lp5521_chip *chip)
-{
- return;
+ lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_RUN);
+ usleep_range(1000, 2000);
+ lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_RUN_PROGRAM);
}
-#endif
-#define LP5521_ENABLE_DEFAULT \
- (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM)
-#define LP5521_ENABLE_RUN_PROGRAM \
- (LP5521_ENABLE_DEFAULT | LP5521_EXEC_RUN)
-
-static void lp5521_program_pattern(int mode, struct lp5521_chip *chip)
+static void lp5521_run_led_pattern(int mode, struct lp5521_chip *chip)
{
+ struct lp5521_led_pattern *ptn;
struct i2c_client *cl = chip->client;
- int i;
- u8 mode1_red[] = {
- 0x40, 0xED, 0x41, 0x00, /* 15.6ms on with red 0xff */
- 0x40, 0x00, 0x46, 0x00, /* 100ms off */
- 0x40, 0xED, 0x41, 0x00, /* 15.6ms on with red 0xff */
- 0x40, 0x00, 0x60, 0x00, /* 500ms off */
- 0xa4, 0x87, /* 4500ms off = 500ms off x 9 times */
- };
-
- u8 mode1_green[] = {
- 0x40, 0x59, 0x41, 0x00, /* 15.6ms on with green 0x25 */
- 0x40, 0x00, 0x46, 0x00, /* 100ms off */
- 0x40, 0x59, 0x41, 0x00, /* 15.6ms on with green 0x25 */
- 0x40, 0x00, 0x60, 0x00, /* 500ms off */
- 0xa4, 0x87, /* 4500ms off = 500ms off x 9 times */
- };
-
- if (mode == 0) {
- lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
- lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
- } else if (mode == 1) {
- lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
+ int num_patterns = chip->pdata->num_patterns;
- for (i = 0 ; i < ARRAY_SIZE(mode1_red) ; i++)
- lp5521_write(cl, LP5521_REG_R_PROG_MEM + i,
- mode1_red[i]);
+ if (mode > num_patterns || !(chip->pdata->patterns))
+ return;
- for (i = 0 ; i < ARRAY_SIZE(mode1_green) ; i++)
- lp5521_write(cl, LP5521_REG_G_PROG_MEM + i,
- mode1_green[i]);
+ if (mode == PATTERN_OFF) {
+ lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
+ usleep_range(1000, 2000);
+ lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
+ } else {
+ ptn = lp5521_get_pattern(chip, mode);
+ if (!ptn)
+ return;
- lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_RUN);
- lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_RUN_PROGRAM);
+ _run_led_pattern(chip, ptn);
}
}
-static ssize_t lp5521_store_pattern(struct device *dev,
+static ssize_t store_led_pattern(struct device *dev,
struct device_attribute *attr,
- const char *buf,
- size_t count)
+ const char *buf, size_t len)
{
+ struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
unsigned long val;
int ret;
@@ -781,29 +646,141 @@ static ssize_t lp5521_store_pattern(struct device *dev,
if (ret)
return ret;
- lp5521_program_pattern(val, g_chip);
+ lp5521_run_led_pattern(val, chip);
- return count;
+ return len;
}
-static struct device_attribute lp5521_pattern_attr = {
- .attr = {
- .name = "led-pattern",
- .mode = 0644,
- },
- .store = lp5521_store_pattern,
-};
+static void _set_pwm_cmd(struct lp5521_pattern_cmd *cmd, unsigned int color)
+{
+ u8 r = (color >> 16) & 0xFF;
+ u8 g = (color >> 8) & 0xFF;
+ u8 b = color & 0xFF;
+
+ cmd->r[cmd->pc_r++] = CMD_SET_PWM;
+ cmd->r[cmd->pc_r++] = r;
+ cmd->g[cmd->pc_g++] = CMD_SET_PWM;
+ cmd->g[cmd->pc_g++] = g;
+ cmd->b[cmd->pc_b++] = CMD_SET_PWM;
+ cmd->b[cmd->pc_b++] = b;
+}
-static int lp5521_create_pattern_nodes(struct lp5521_chip *chip)
+static void _set_wait_cmd(struct lp5521_pattern_cmd *cmd,
+ unsigned int ms, u8 jump)
{
- return device_create_file(chip->led_dev, &lp5521_pattern_attr);
+ u8 msb, lsb;
+ u16 branch;
+ int loop = ms / WAIT_UNIT;
+
+ /* wait command */
+ cmd->r[cmd->pc_r++] = CMD_WAIT_MSB;
+ cmd->r[cmd->pc_r++] = CMD_WAIT_LSB;
+ cmd->g[cmd->pc_g++] = CMD_WAIT_MSB;
+ cmd->g[cmd->pc_g++] = CMD_WAIT_LSB;
+ cmd->b[cmd->pc_b++] = CMD_WAIT_MSB;
+ cmd->b[cmd->pc_b++] = CMD_WAIT_LSB;
+
+ /* branch command : if wait time is bigger than 980ms,
+ branch is used for command looping */
+ if (loop > 1) {
+ branch = (5 << 13) | ((loop - 1) << 7) | jump;
+ msb = (branch >> 8) & 0xFF;
+ lsb = branch & 0xFF;
+
+ cmd->r[cmd->pc_r++] = msb;
+ cmd->r[cmd->pc_r++] = lsb;
+ cmd->g[cmd->pc_g++] = msb;
+ cmd->g[cmd->pc_g++] = lsb;
+ cmd->b[cmd->pc_b++] = msb;
+ cmd->b[cmd->pc_b++] = lsb;
+ }
}
-static void lp5521_remove_pattern_nodes(struct lp5521_chip *chip)
+static ssize_t store_led_blink(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
- device_remove_file(chip->led_dev, &lp5521_pattern_attr);
+ struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
+ unsigned int rgb = 0, on = 0, off = 0;
+ struct lp5521_led_pattern ptn = { };
+ struct lp5521_pattern_cmd cmd = { };
+ u8 jump_pc;
+
+ sscanf(buf, "0x%06x %d %d", &rgb, &on, &off);
+
+ if (on > MAX_BLINK_TIME || off > MAX_BLINK_TIME)
+ return len;
+
+ lp5521_run_led_pattern(PATTERN_OFF, chip);
+
+ if (on == 0 && off == 0) {
+ _set_pwm_cmd(&cmd, rgb);
+ } else {
+ jump_pc = 0;
+ _set_pwm_cmd(&cmd, rgb);
+ _set_wait_cmd(&cmd, on, jump_pc);
+ jump_pc = cmd.pc_r / 2; /* 16bit size program counter */
+ _set_pwm_cmd(&cmd, 0);
+ _set_wait_cmd(&cmd, off, jump_pc);
+ }
+
+ ptn.r = cmd.r;
+ ptn.size_r = cmd.pc_r;
+ ptn.g = cmd.g;
+ ptn.size_g = cmd.pc_g;
+ ptn.b = cmd.b;
+ ptn.size_b = cmd.pc_b;
+
+ _run_led_pattern(chip, &ptn);
+
+ return len;
}
+/* led class device attributes */
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
+static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
+
+static struct attribute *lp5521_led_attributes[] = {
+ &dev_attr_led_current.attr,
+ &dev_attr_max_current.attr,
+ NULL,
+};
+
+static struct attribute_group lp5521_led_attribute_group = {
+ .attrs = lp5521_led_attributes
+};
+
+/* device attributes */
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR,
+ show_engine1_mode, store_engine1_mode);
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR,
+ show_engine2_mode, store_engine2_mode);
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR,
+ show_engine3_mode, store_engine3_mode);
+static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
+static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
+static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, store_led_pattern);
+static DEVICE_ATTR(led_blink, S_IWUSR, NULL, store_led_blink);
+
+static struct attribute *lp5521_attributes[] = {
+ &dev_attr_engine1_mode.attr,
+ &dev_attr_engine2_mode.attr,
+ &dev_attr_engine3_mode.attr,
+ &dev_attr_selftest.attr,
+ &dev_attr_engine1_load.attr,
+ &dev_attr_engine2_load.attr,
+ &dev_attr_engine3_load.attr,
+ &dev_attr_led_pattern.attr,
+ &dev_attr_led_blink.attr,
+ NULL
+};
+
+static const struct attribute_group lp5521_group = {
+ .attrs = lp5521_attributes,
+};
+
static int lp5521_register_sysfs(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -848,7 +825,6 @@ static int __devinit lp5521_init_led(struct lp5521_led *led,
}
led->cdev.brightness_set = lp5521_set_brightness;
-
if (pdata->led_config[chan].name) {
led->cdev.name = pdata->led_config[chan].name;
} else {
@@ -879,6 +855,7 @@ static int __devinit lp5521_probe(struct i2c_client *client,
struct lp5521_chip *chip;
struct lp5521_platform_data *pdata;
int ret, i, led;
+ u8 buf;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -886,11 +863,7 @@ static int __devinit lp5521_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip);
chip->client = client;
- g_chip = chip;
-#ifdef LED_DEBUG
- g_client = client;
-#endif
pdata = client->dev.platform_data;
if (!pdata) {
@@ -921,6 +894,20 @@ static int __devinit lp5521_probe(struct i2c_client *client,
* Exact value is not available. 10 - 20ms
* appears to be enough for reset.
*/
+
+ /*
+ * Make sure that the chip is reset by reading back the r channel
+ * current reg. This is dummy read is required on some platforms -
+ * otherwise further access to the R G B channels in the
+ * LP5521_REG_ENABLE register will not have any effect - strange!
+ */
+ ret = lp5521_read(client, LP5521_REG_R_CURRENT, &buf);
+ if (ret || buf != LP5521_REG_R_CURR_DEFAULT) {
+ dev_err(&client->dev, "error in resetting chip\n");
+ goto fail2;
+ }
+ usleep_range(10000, 20000);
+
ret = lp5521_detect(client);
if (ret) {
@@ -940,7 +927,6 @@ static int __devinit lp5521_probe(struct i2c_client *client,
chip->num_channels = pdata->num_channels;
chip->num_leds = 0;
led = 0;
- chip->led_dev = device_create(sec_class, NULL, 0, NULL, "leds");
for (i = 0; i < pdata->num_channels; i++) {
/* Do not initialize channels that are not connected */
if (pdata->led_config[i].led_current == 0)
@@ -969,10 +955,6 @@ static int __devinit lp5521_probe(struct i2c_client *client,
dev_err(&client->dev, "registering sysfs failed\n");
goto fail3;
}
-
- lp5521_create_pattern_nodes(chip);
- lp5521_create_debugfs(chip);
-
return ret;
fail3:
for (i = 0; i < chip->num_leds; i++) {
@@ -989,24 +971,12 @@ fail1:
return ret;
}
-#ifdef LED_DEBUG
-void lp5521_led_brightness(u8 channel, u8 brightness)
-{
-
- lp5521_write(g_client, LP5521_REG_LED_PWM_BASE + channel,
- brightness);
-}
-EXPORT_SYMBOL(lp5521_led_brightness);
-#endif
-
-static int lp5521_remove(struct i2c_client *client)
+static int __devexit lp5521_remove(struct i2c_client *client)
{
struct lp5521_chip *chip = i2c_get_clientdata(client);
int i;
- lp5521_program_pattern(0, chip);
- lp5521_remove_pattern_nodes(chip);
- lp5521_remove_debugfs(chip);
+ lp5521_run_led_pattern(PATTERN_OFF, chip);
lp5521_unregister_sysfs(client);
for (i = 0; i < chip->num_leds; i++) {
@@ -1033,7 +1003,7 @@ static struct i2c_driver lp5521_driver = {
.name = "lp5521",
},
.probe = lp5521_probe,
- .remove = lp5521_remove,
+ .remove = __devexit_p(lp5521_remove),
.id_table = lp5521_id,
};
diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
index bdbb953..05499b8 100644
--- a/drivers/leds/leds-max77693.c
+++ b/drivers/leds/leds-max77693.c
@@ -18,6 +18,12 @@
#include <linux/mfd/max77693.h>
#include <linux/mfd/max77693-private.h>
#include <linux/leds-max77693.h>
+#include <linux/ctype.h>
+
+#ifdef CONFIG_LEDS_SWITCH
+#include <linux/gpio.h>
+#define FLASH_SWITCH_REMOVED_REVISION 0x05
+#endif
struct max77693_led_data {
struct led_classdev led;
@@ -73,6 +79,9 @@ static u8 led_current_shift[MAX77693_LED_MAX] = {
4,
};
+extern struct class *camera_class; /*sys/class/camera*/
+struct device *flash_dev;
+
static int max77693_set_bits(struct i2c_client *client, const u8 reg,
const u8 mask, const u8 inval)
{
@@ -104,14 +113,17 @@ static void print_all_reg_value(struct i2c_client *client)
static int max77693_led_get_en_value(struct max77693_led_data *led_data, int on)
{
if (on)
- return 0x03;
+ return 0x03; /*triggered via serial interface*/
+#if 0
if (led_data->data->cntrl_mode == MAX77693_LED_CTRL_BY_I2C)
return 0x00;
- else if (led_data->data->id < 2)
- return 0x01;
+#endif
+
+ if (led_data->data->id < 2)
+ return 0x01; /*Flash triggered via FLASHEN*/
else
- return 0x02;
+ return 0x02; /*Torch triggered via TORCHEN*/
}
static void max77693_led_set(struct led_classdev *led_cdev, enum led_brightness value)
@@ -163,8 +175,8 @@ static void led_set(struct max77693_led_data *led_data)
if (unlikely(ret))
goto error_set_bits;
- /* Turn off LED */
- value = max77693_led_get_en_value(led_data, 0);
+ /* Turn on LED */
+ value = max77693_led_get_en_value(led_data, 1);
ret = max77693_set_bits(led_data->i2c, MAX77693_LED_REG_FLASH_EN,
led_en_mask[id],
value << led_en_shift[id]);
@@ -172,13 +184,6 @@ static void led_set(struct max77693_led_data *led_data)
if (unlikely(ret))
goto error_set_bits;
- /* Turn on LED */
- ret = max77693_set_bits(led_data->i2c, MAX77693_LED_REG_FLASH_EN,
- led_en_mask[id], led_en_mask[id]);
-
- if (unlikely(ret))
- goto error_set_bits;
-
return;
error_set_bits:
@@ -211,7 +216,7 @@ static int max77693_led_setup(struct max77693_led_data *led_data)
ret |= max77693_write_reg(led_data->i2c, MAX77693_LED_REG_VOUT_FLASH1,
MAX77693_BOOST_VOUT_FLASH_FROM_VOLT(5000));
ret |= max77693_write_reg(led_data->i2c,
- MAX77693_LED_REG_MAX_FLASH1, 0xEC);
+ MAX77693_LED_REG_MAX_FLASH1, 0x80);
ret |= max77693_write_reg(led_data->i2c,
MAX77693_LED_REG_MAX_FLASH2, 0x00);
@@ -227,7 +232,7 @@ static int max77693_led_setup(struct max77693_led_data *led_data)
(data->timer | data->timer_mode << 7));
} else {
ret |= max77693_write_reg(led_data->i2c, reg_led_timer[id],
- 0xC0);
+ 0x40);
}
/* Set current */
@@ -238,6 +243,34 @@ static int max77693_led_setup(struct max77693_led_data *led_data)
return ret;
}
+static ssize_t max77693_flash(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ ssize_t ret = -EINVAL;
+ char *after;
+ unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ if (isspace(*after))
+ count++;
+
+ if (count == size) {
+ ret = count;
+
+ if (state > led_cdev->max_brightness)
+ state = led_cdev->max_brightness;
+ led_cdev->brightness = state;
+ if (!(led_cdev->flags & LED_SUSPENDED))
+ led_cdev->brightness_set(led_cdev, state);
+ }
+
+ return ret;
+}
+
+static DEVICE_ATTR(rear_flash, S_IWUSR|S_IWGRP|S_IROTH,
+ NULL, max77693_flash);
+
static int max77693_led_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -284,7 +317,7 @@ static int max77693_led_probe(struct platform_device *pdev)
led_data->led.brightness_set = max77693_led_set;
led_data->led.brightness = LED_OFF;
led_data->brightness = data->brightness;
- led_data->led.flags = LED_CORE_SUSPENDRESUME;
+ led_data->led.flags = 0;
led_data->led.max_brightness = data->id < 2
? MAX_FLASH_DRV_LEVEL : MAX_TORCH_DRV_LEVEL;
@@ -303,12 +336,32 @@ static int max77693_led_probe(struct platform_device *pdev)
ret = max77693_led_setup(led_data);
if (unlikely(ret)) {
pr_err("unable to register LED\n");
+ mutex_destroy(&led_data->lock);
led_classdev_unregister(&led_data->led);
kfree(led_data);
ret = -EFAULT;
}
}
/* print_all_reg_value(max77693->i2c); */
+
+ flash_dev = device_create(camera_class, NULL, 0, led_datas[2], "flash");
+ if (flash_dev < 0)
+ pr_err("Failed to create device(flash)!\n");
+
+ if (device_create_file(flash_dev, &dev_attr_rear_flash) < 0) {
+ pr_err("failed to create device file, %s\n",
+ dev_attr_rear_flash.attr.name);
+ }
+
+#ifdef CONFIG_LEDS_SWITCH
+ if (system_rev < FLASH_SWITCH_REMOVED_REVISION) {
+ if (gpio_request(GPIO_CAM_SW_EN, "CAM_SW_EN"))
+ pr_err("failed to request CAM_SW_EN\n");
+ else
+ gpio_direction_output(GPIO_CAM_SW_EN, 1);
+ }
+#endif
+
return ret;
}
@@ -328,9 +381,24 @@ static int __devexit max77693_led_remove(struct platform_device *pdev)
}
kfree(led_datas);
+ device_remove_file(flash_dev, &dev_attr_rear_flash);
+ device_destroy(camera_class, 0);
+ class_destroy(camera_class);
+
return 0;
}
+void max77693_led_shutdown(struct device *dev)
+{
+ struct max77693_led_data **led_datas = dev_get_drvdata(dev);
+
+ /* Turn off LED */
+ max77693_set_bits(led_datas[2]->i2c,
+ MAX77693_LED_REG_FLASH_EN,
+ led_en_mask[2],
+ 0x02 << led_en_shift[2]);
+}
+
static struct platform_driver max77693_led_driver =
{
.probe = max77693_led_probe,
@@ -339,6 +407,7 @@ static struct platform_driver max77693_led_driver =
{
.name = "max77693-led",
.owner = THIS_MODULE,
+ .shutdown = max77693_led_shutdown,
},
};
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
index 54c4a04..2b7a8c7 100644
--- a/drivers/leds/leds-max8997.c
+++ b/drivers/leds/leds-max8997.c
@@ -39,7 +39,7 @@ static inline int led_regulator_get_max_brightness(struct regulator *supply)
int voltage = regulator_list_voltage(supply, 0);
/*TODO*/
-#if defined(CONFIG_MACH_Q1_BD)
+#if defined(CONFIG_MACH_Q1_BD) || defined(CONFIG_MACH_U1_NA_USCC)
return LED_BRIGHTNESS_MAX_LEVEL;
#else
return 1;
@@ -126,7 +126,7 @@ static void regulator_led_set_value(struct regulator_led *led)
/* Q1 has torch light widget, and it changes */
/* its brightness level without disabling rerulator */
/* So, remove the below code for Q1 */
-#if !defined(CONFIG_MACH_Q1_BD)
+#if !defined(CONFIG_MACH_Q1_BD) && !defined(CONFIG_MACH_U1_NA_USCC)
if (regulator_is_enabled(movie) > 0) {
pr_info("%s: led_movie is enabled.\n", __func__);
goto end;
@@ -146,7 +146,7 @@ static void regulator_led_set_value(struct regulator_led *led)
}
#endif
-#if defined(CONFIG_MACH_Q1_BD)
+#if defined(CONFIG_MACH_Q1_BD) || defined(CONFIG_MACH_U1_NA_USCC)
switch (led->value) {
case LED_BRIGHTNESS_LEVEL1:
regulator_set_current_limit(led->vcc, 10000, 20000);