* [PATCH 0/8] updates to two nokia drivers @ 2009-02-10 12:15 Felipe Balbi 2009-02-10 12:15 ` [PATCH 1/8] i2c: lp5521: remove dead code Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:15 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi Hi Tony, all, I'd like to get these integrated so afterwards I can send the drivers to mainline. At least lp5521 is in pretty good shape for mainline, I'd say, but maybe lm8323 will get some comments. Anyways, these were tested on n810. Felipe Balbi (8): i2c: lp5521: remove dead code i2c: lp5521: cosmetic fixes i2c: lp5521: simplify mode setting i2c: lp5521: move to LED framework leds: lp5521: move to drivers/leds input: lm8323: get rid of global pdata pointer input: lm8323: get rid of useless debug macro input: lm8323: general clean up arch/arm/mach-omap2/board-n800.c | 14 +- drivers/i2c/chips/Kconfig | 7 - drivers/i2c/chips/Makefile | 1 - drivers/input/keyboard/lm8323.c | 113 +++---- drivers/leds/Kconfig | 10 + drivers/leds/Makefile | 1 + drivers/{i2c/chips/lp5521.c => leds/leds-lp5521.c} | 379 +++++++++++++------- 7 files changed, 321 insertions(+), 204 deletions(-) rename drivers/{i2c/chips/lp5521.c => leds/leds-lp5521.c} (62%) ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 1/8] i2c: lp5521: remove dead code 2009-02-10 12:15 [PATCH 0/8] updates to two nokia drivers Felipe Balbi @ 2009-02-10 12:15 ` Felipe Balbi 2009-02-10 12:15 ` [PATCH 2/8] i2c: lp5521: cosmetic fixes Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:15 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi That LED_CONNECTED_WRONG was never defined so removing. If someone needs those hooks, add back via proper platform_data instead of nasty ifdefery. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/lp5521.c | 22 ---------------------- 1 files changed, 0 insertions(+), 22 deletions(-) diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index c0862d9..7fb8091 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -28,13 +28,8 @@ #define LP5521_DRIVER_NAME "lp5521" -#ifdef LED_CONNECTED_WRONG -#define LP5521_REG_R_PWM 0x04 -#define LP5521_REG_B_PWM 0x02 -#else #define LP5521_REG_R_PWM 0x02 #define LP5521_REG_B_PWM 0x04 -#endif #define LP5521_REG_ENABLE 0x00 #define LP5521_REG_OP_MODE 0x01 #define LP5521_REG_G_PWM 0x03 @@ -200,22 +195,12 @@ static ssize_t show_active_channels(struct device *dev, char channels[4]; int pos = 0; -#ifdef LED_CONNECTED_WRONG - if (chip->blue) - pos += sprintf(channels + pos, "r"); - if (chip->green) - pos += sprintf(channels + pos, "g"); - if (chip->red) - pos += sprintf(channels + pos, "b"); - -#else if (chip->red) pos += sprintf(channels + pos, "r"); if (chip->green) pos += sprintf(channels + pos, "g"); if (chip->blue) pos += sprintf(channels + pos, "b"); -#endif channels[pos] = '\0'; @@ -232,17 +217,10 @@ static ssize_t store_active_channels(struct device *dev, chip->green = 0; chip->blue = 0; -#ifdef LED_CONNECTED_WRONG - if (strchr(buf, 'r') != NULL) - chip->blue = 1; - if (strchr(buf, 'b') != NULL) - chip->red = 1; -#else if (strchr(buf, 'r') != NULL) chip->red = 1; if (strchr(buf, 'b') != NULL) chip->blue = 1; -#endif if (strchr(buf, 'g') != NULL) chip->green = 1; -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 2/8] i2c: lp5521: cosmetic fixes 2009-02-10 12:15 ` [PATCH 1/8] i2c: lp5521: remove dead code Felipe Balbi @ 2009-02-10 12:15 ` Felipe Balbi 2009-02-10 12:16 ` [PATCH 3/8] i2c: lp5521: simplify mode setting Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:15 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi General cleanup to the code. Preparing to send it to mainline. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/lp5521.c | 159 ++++++++++++++++++++------------------------ 1 files changed, 73 insertions(+), 86 deletions(-) diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index 7fb8091..e040c4d 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -1,5 +1,5 @@ /* - * drivers/i2c/chips/lp5521.c + * lp5521.c - LP5521 LED Driver * * Copyright (C) 2007 Nokia Corporation * @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/mutex.h> -#include <mach/gpio.h> #define LP5521_DRIVER_NAME "lp5521" @@ -71,6 +70,7 @@ #define LP5521_PROGRAM_LENGTH 32 /* in bytes */ struct lp5521_chip { + /* device lock */ struct mutex lock; struct i2c_client *client; char *mode; @@ -81,20 +81,14 @@ struct lp5521_chip { static int lp5521_set_mode(struct lp5521_chip *chip, char *mode); -static int lp5521_write(struct i2c_client *client, u8 reg, u8 value) +static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } -static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf) +static inline int lp5521_read(struct i2c_client *client, u8 reg) { - s32 ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) - return -EIO; - - *buf = ret; - return 0; + return i2c_smbus_read_byte_data(client, reg); } static int lp5521_configure(struct i2c_client *client) @@ -136,19 +130,19 @@ static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) if (chip->red) ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_R_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); + LP5521_REG_R_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); if (chip->green) ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_G_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); + LP5521_REG_G_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); if (chip->blue) ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_B_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); + LP5521_REG_B_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); return ret; } @@ -156,31 +150,33 @@ static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) static int lp5521_run_program(struct lp5521_chip *chip) { struct i2c_client *client = chip->client; - int ret; + int reg; u8 mask = 0xc0; u8 exec_state = 0; - u8 enable_reg; - ret = lp5521_read(client, LP5521_REG_ENABLE, &enable_reg); - if (ret) - goto fail; + reg = lp5521_read(client, LP5521_REG_ENABLE); + if (reg < 0) + return reg; - enable_reg &= mask; + reg &= mask; /* set all active channels exec state to countinous run*/ - exec_state |= (chip->red << 5); + exec_state |= (chip->red << 5); exec_state |= (chip->green << 3); - exec_state |= (chip->blue << 1); + exec_state |= (chip->blue << 1); - enable_reg |= exec_state; + reg |= exec_state; - ret |= lp5521_write(client, LP5521_REG_ENABLE, enable_reg); + if (lp5521_write(client, LP5521_REG_ENABLE, reg)) + dev_dbg(&client->dev, "failed writing to register %02x\n", + LP5521_REG_ENABLE); /* set op-mode to run for active channels, disabled for others */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, exec_state); + if (lp5521_write(client, LP5521_REG_OP_MODE, exec_state)) + dev_dbg(&client->dev, "failed writing to register %02x\n", + LP5521_REG_OP_MODE); -fail: - return ret; + return 0; } /*--------------------------------------------------------------*/ @@ -188,8 +184,8 @@ fail: /*--------------------------------------------------------------*/ static ssize_t show_active_channels(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct lp5521_chip *chip = dev_get_drvdata(dev); char channels[4]; @@ -208,8 +204,8 @@ static ssize_t show_active_channels(struct device *dev, } static ssize_t store_active_channels(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct lp5521_chip *chip = dev_get_drvdata(dev); @@ -228,26 +224,25 @@ static ssize_t store_active_channels(struct device *dev, } static ssize_t show_color(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct i2c_client *client = to_i2c_client(dev); - int ret = 0; - u8 r, g, b; + int r, g, b; - ret |= lp5521_read(client, LP5521_REG_R_PWM, &r); - ret |= lp5521_read(client, LP5521_REG_G_PWM, &g); - ret |= lp5521_read(client, LP5521_REG_B_PWM, &b); + r = lp5521_read(client, LP5521_REG_R_PWM); + g = lp5521_read(client, LP5521_REG_G_PWM); + b = lp5521_read(client, LP5521_REG_B_PWM); - if (ret) - return ret; + if (r < 0 || g < 0 || b < 0) + return -EINVAL; return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b); } static ssize_t store_color(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct i2c_client *client = to_i2c_client(dev); struct lp5521_chip *chip = i2c_get_clientdata(client); @@ -271,8 +266,8 @@ static ssize_t store_color(struct device *dev, } static ssize_t store_load(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct lp5521_chip *chip = dev_get_drvdata(dev); int ret, nrchars, offset = 0, i = 0; @@ -314,8 +309,8 @@ fail: } static ssize_t show_mode(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct lp5521_chip *chip = dev_get_drvdata(dev); @@ -323,8 +318,8 @@ static ssize_t show_mode(struct device *dev, } static ssize_t store_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct lp5521_chip *chip = dev_get_drvdata(dev); @@ -343,33 +338,29 @@ static ssize_t store_mode(struct device *dev, } static ssize_t show_current(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct i2c_client *client = to_i2c_client(dev); - int ret = 0; - u8 r_curr, g_curr, b_curr; + int r, g, b; - ret |= lp5521_read(client, LP5521_REG_R_CNTRL, &r_curr); - ret |= lp5521_read(client, LP5521_REG_G_CNTRL, &g_curr); - ret |= lp5521_read(client, LP5521_REG_B_CNTRL, &b_curr); + r = lp5521_read(client, LP5521_REG_R_CNTRL); + g = lp5521_read(client, LP5521_REG_G_CNTRL); + b = lp5521_read(client, LP5521_REG_B_CNTRL); - if (ret) - return ret; + if (r < 0 || g < 0 || b < 0) + return -EINVAL; - r_curr = r_curr >> 4; - g_curr = g_curr >> 4; - b_curr = b_curr >> 4; + r >>= 4; + g >>= 4; + b >>= 4; - if (r_curr == g_curr && g_curr == b_curr) - return sprintf(buf, "%x\n", r_curr); - else - return sprintf(buf, "%x %x %x\n", r_curr, g_curr, b_curr); + return sprintf(buf, "%x %x %x\n", r, g, b); } static ssize_t store_current(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct lp5521_chip *chip = dev_get_drvdata(dev); struct i2c_client *client = chip->client; @@ -398,7 +389,7 @@ static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color); static DEVICE_ATTR(load, S_IWUGO, NULL, store_load); static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode); static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO, - show_active_channels, store_active_channels); + show_active_channels, store_active_channels); static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); static int lp5521_register_sysfs(struct i2c_client *client) @@ -421,6 +412,7 @@ static int lp5521_register_sysfs(struct i2c_client *client) ret = device_create_file(dev, &dev_attr_led_current); if (ret) goto fail5; + return 0; fail5: @@ -437,16 +429,13 @@ fail1: static void lp5521_unregister_sysfs(struct i2c_client *client) { - struct lp5521_chip *chip = i2c_get_clientdata(client); struct device *dev = &client->dev; device_remove_file(dev, &dev_attr_led_current); device_remove_file(dev, &dev_attr_mode); device_remove_file(dev, &dev_attr_active_channels); device_remove_file(dev, &dev_attr_color); - - if (!strcmp(chip->mode, LP5521_MODE_LOAD)) - device_remove_file(dev, &dev_attr_load); + device_remove_file(dev, &dev_attr_load); } /*--------------------------------------------------------------*/ @@ -479,9 +468,8 @@ static int lp5521_set_mode(struct lp5521_chip *chip, char *mode) /*--------------------------------------------------------------*/ /* Probe, Attach, Remove */ /*--------------------------------------------------------------*/ -static struct i2c_driver lp5521_driver; -static int lp5521_probe(struct i2c_client *client, +static int __init lp5521_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lp5521_chip *chip; @@ -491,7 +479,7 @@ static int lp5521_probe(struct i2c_client *client, if (!chip) return -ENOMEM; - chip->client = client; + chip->client = client; strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE); i2c_set_clientdata(client, chip); @@ -520,7 +508,7 @@ fail1: return ret; } -static int lp5521_remove(struct i2c_client *client) +static int __exit lp5521_remove(struct i2c_client *client) { struct lp5521_chip *chip = i2c_get_clientdata(client); @@ -537,11 +525,11 @@ static const struct i2c_device_id lp5521_id[] = { MODULE_DEVICE_TABLE(i2c, lp5521_id); static struct i2c_driver lp5521_driver = { - .driver = { + .driver = { .name = LP5521_DRIVER_NAME, }, .probe = lp5521_probe, - .remove = __devexit_p(lp5521_remove), + .remove = __exit_p(lp5521_remove), .id_table = lp5521_id, }; @@ -549,15 +537,14 @@ static int __init lp5521_init(void) { return i2c_add_driver(&lp5521_driver); } +module_init(lp5521_init); static void __exit lp5521_exit(void) { i2c_del_driver(&lp5521_driver); } +module_exit(lp5521_exit); MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>"); MODULE_DESCRIPTION("lp5521 LED driver"); MODULE_LICENSE("GPL"); - -module_init(lp5521_init); -module_exit(lp5521_exit); -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 3/8] i2c: lp5521: simplify mode setting 2009-02-10 12:15 ` [PATCH 2/8] i2c: lp5521: cosmetic fixes Felipe Balbi @ 2009-02-10 12:16 ` Felipe Balbi 2009-02-10 12:16 ` [PATCH 4/8] i2c: lp5521: move to LED framework Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:16 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi Avoid using string magic and use integer for comparisson Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/lp5521.c | 52 ++++++++++++++++++++++++++++++++----------- 1 files changed, 38 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index e040c4d..9e94ff8 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -46,10 +46,6 @@ #define LP5521_REG_G_PROG_MEM 0x30 #define LP5521_REG_B_PROG_MEM 0x50 -#define LP5521_MODE_LOAD "load" -#define LP5521_MODE_RUN "run" -#define LP5521_MODE_DIRECT_CONTROL "direct" - #define LP5521_CURRENT_1m5 0x0f #define LP5521_CURRENT_3m1 0x1f #define LP5521_CURRENT_4m7 0x2f @@ -69,17 +65,23 @@ #define LP5521_PROGRAM_LENGTH 32 /* in bytes */ +enum lp5521_mode { + LP5521_MODE_LOAD, + LP5521_MODE_RUN, + LP5521_MODE_DIRECT_CONTROL, +}; + struct lp5521_chip { /* device lock */ struct mutex lock; struct i2c_client *client; - char *mode; + enum lp5521_mode mode; int red; int green; int blue; }; -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode); +static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode); static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) { @@ -313,8 +315,25 @@ static ssize_t show_mode(struct device *dev, char *buf) { struct lp5521_chip *chip = dev_get_drvdata(dev); + char *mode; + + mutex_lock(&chip->lock); + switch (chip->mode) { + case LP5521_MODE_RUN: + mode = "run"; + break; + case LP5521_MODE_LOAD: + mode = "load"; + break; + case LP5521_MODE_DIRECT_CONTROL: + mode = "direct"; + break; + default: + mode = "undefined"; + } + mutex_unlock(&chip->lock); - return sprintf(buf, "%s\n", chip->mode); + return sprintf(buf, "%s\n", mode); } static ssize_t store_mode(struct device *dev, @@ -442,23 +461,28 @@ static void lp5521_unregister_sysfs(struct i2c_client *client) /* Set chip operating mode */ /*--------------------------------------------------------------*/ -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode) +static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode) { struct i2c_client *client = chip->client ; int ret = 0; /* if in that mode already do nothing, except for run */ - if (!strcmp(mode, chip->mode) && strcmp(mode, LP5521_MODE_RUN)) + if (chip->mode == mode && mode != LP5521_MODE_RUN) return 0; - if (!strcmp(mode, LP5521_MODE_RUN)) + switch (mode) { + case LP5521_MODE_RUN: ret = lp5521_run_program(chip); - - if (!strcmp(mode, LP5521_MODE_LOAD)) + break; + case LP5521_MODE_LOAD: ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); - - if (!strcmp(mode, LP5521_MODE_DIRECT_CONTROL)) + break; + case LP5521_MODE_DIRECT_CONTROL: ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); + break; + default: + dev_dbg(&client->dev, "unsupported mode %d\n", mode); + } chip->mode = mode; -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 4/8] i2c: lp5521: move to LED framework 2009-02-10 12:16 ` [PATCH 3/8] i2c: lp5521: simplify mode setting Felipe Balbi @ 2009-02-10 12:16 ` Felipe Balbi 2009-02-10 12:16 ` [PATCH 5/8] leds: lp5521: move to drivers/leds Felipe Balbi 2009-02-12 22:18 ` [PATCH 4/8] i2c: lp5521: move to LED framework David Brownell 0 siblings, 2 replies; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:16 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi Register three separate leds for lp5521 and allow them to be controlled separately while keeping backwards compatibility with userspace programs based on old implementation. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/lp5521.c | 146 +++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 144 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index 9e94ff8..a5c3425 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -4,6 +4,7 @@ * Copyright (C) 2007 Nokia Corporation * * Written by Mathias Nyman <mathias.nyman@nokia.com> + * Updated by Felipe Balbi <felipe.balbi@nokia.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +24,9 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/leds.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #define LP5521_DRIVER_NAME "lp5521" @@ -75,7 +78,17 @@ struct lp5521_chip { /* device lock */ struct mutex lock; struct i2c_client *client; + + struct work_struct red_work; + struct work_struct green_work; + struct work_struct blue_work; + + struct led_classdev ledr; + struct led_classdev ledg; + struct led_classdev ledb; + enum lp5521_mode mode; + int red; int green; int blue; @@ -489,6 +502,87 @@ static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode) return ret; } +static void lp5521_red_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, red_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_R_PWM, chip->red); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_red_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledr); + + chip->red = value; + schedule_work(&chip->red_work); +} + +static void lp5521_green_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, green_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_G_PWM, chip->green); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_green_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledg); + + chip->green = value; + schedule_work(&chip->green_work); +} + +static void lp5521_blue_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, blue_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_B_PWM, chip->blue); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_blue_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledb); + + chip->blue = value; + schedule_work(&chip->blue_work); +} + /*--------------------------------------------------------------*/ /* Probe, Attach, Remove */ /*--------------------------------------------------------------*/ @@ -509,6 +603,10 @@ static int __init lp5521_probe(struct i2c_client *client, mutex_init(&chip->lock); + INIT_WORK(&chip->red_work, lp5521_red_work); + INIT_WORK(&chip->green_work, lp5521_green_work); + INIT_WORK(&chip->blue_work, lp5521_blue_work); + ret = lp5521_configure(client); if (ret < 0) { dev_err(&client->dev, "lp5521 error configuring chip \n"); @@ -521,14 +619,52 @@ static int __init lp5521_probe(struct i2c_client *client, chip->green = 1; chip->blue = 1; + chip->ledr.brightness_set = lp5521_red_set; + chip->ledr.default_trigger = NULL; + chip->ledr.name = "lp5521:red"; + ret = led_classdev_register(&client->dev, &chip->ledr); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register red led, %d\n", ret); + goto fail1; + } + + chip->ledg.brightness_set = lp5521_green_set; + chip->ledg.default_trigger = NULL; + chip->ledg.name = "lp5521:green"; + ret = led_classdev_register(&client->dev, &chip->ledg); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register green led, %d\n", + ret); + goto fail2; + } + + chip->ledb.brightness_set = lp5521_blue_set; + chip->ledb.default_trigger = NULL; + chip->ledb.name = "lp5521:blue"; + ret = led_classdev_register(&client->dev, &chip->ledb); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register blue led, %d\n", ret); + goto fail3; + } + ret = lp5521_register_sysfs(client); - if (ret) + if (ret) { dev_err(&client->dev, "lp5521 registering sysfs failed \n"); + goto fail4; + } - return ret; + return 0; +fail4: + led_classdev_unregister(&chip->ledb); +fail3: + led_classdev_unregister(&chip->ledg); +fail2: + led_classdev_unregister(&chip->ledr); fail1: + i2c_set_clientdata(client, NULL); kfree(chip); + return ret; } @@ -537,6 +673,12 @@ static int __exit lp5521_remove(struct i2c_client *client) struct lp5521_chip *chip = i2c_get_clientdata(client); lp5521_unregister_sysfs(client); + i2c_set_clientdata(client, NULL); + + led_classdev_unregister(&chip->ledb); + led_classdev_unregister(&chip->ledg); + led_classdev_unregister(&chip->ledr); + kfree(chip); return 0; -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 5/8] leds: lp5521: move to drivers/leds 2009-02-10 12:16 ` [PATCH 4/8] i2c: lp5521: move to LED framework Felipe Balbi @ 2009-02-10 12:16 ` Felipe Balbi 2009-02-10 12:16 ` [PATCH 6/8] input: lm8323: get rid of global pdata pointer Felipe Balbi 2009-02-12 22:18 ` [PATCH 4/8] i2c: lp5521: move to LED framework David Brownell 1 sibling, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:16 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi This driver should be sitting together with the other led drivers. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/Kconfig | 7 ------- drivers/i2c/chips/Makefile | 1 - drivers/leds/Kconfig | 10 ++++++++++ drivers/leds/Makefile | 1 + drivers/{i2c/chips/lp5521.c => leds/leds-lp5521.c} | 0 5 files changed, 11 insertions(+), 8 deletions(-) rename drivers/{i2c/chips/lp5521.c => leds/leds-lp5521.c} (100%) diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index bb95b3e..e4831e1 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -141,13 +141,6 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. -config LP5521 - tristate "LP5521 LED driver chip" - depends on I2C - help - If you say yes here you get support for the National Semiconductor - LP5521 LED driver. - config MENELAUS bool "TWL92330/Menelaus PM chip" depends on I2C=y && ARCH_OMAP24XX diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 32a395f..1c94712 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o obj-$(CONFIG_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_RTC_X1205_I2C) += x1205.o -obj-$(CONFIG_LP5521) += lp5521.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 4d4ff64..8d0f37e 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -134,6 +134,16 @@ config LEDS_GPIO outputs. To be useful the particular board must have LEDs and they must be connected to the GPIO lines. +config LEDS_LP5521 + tristate "LED Support for the LP5521 LEDs" + depends on LEDS_CLASS && I2C + help + If you say 'Y' here you get support for the National Semiconductor + LP5521 LED driver used in n8x0 boards. + + This driver can be built as a module by choosing 'M'. The module + will be called leds-lp5521. + config LEDS_CLEVO_MAIL tristate "Mail LED on Clevo notebook (EXPERIMENTAL)" depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI && EXPERIMENTAL diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 7ac6ad3..4ab09e8 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o +obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o diff --git a/drivers/i2c/chips/lp5521.c b/drivers/leds/leds-lp5521.c similarity index 100% rename from drivers/i2c/chips/lp5521.c rename to drivers/leds/leds-lp5521.c -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 6/8] input: lm8323: get rid of global pdata pointer 2009-02-10 12:16 ` [PATCH 5/8] leds: lp5521: move to drivers/leds Felipe Balbi @ 2009-02-10 12:16 ` Felipe Balbi 2009-02-10 12:16 ` [PATCH 7/8] input: lm8323: get rid of useless debug macro Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:16 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi pdata is only used during probe to initialize a few fields from lm8323 device structure. Moving pdata pointer to probe won't harm anybody. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/input/keyboard/lm8323.c | 34 ++++++++++++++++------------------ 1 files changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 342ef6a..60abe61 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -186,9 +186,6 @@ static struct lm8323_chip *pwm_to_lm8323(struct lm8323_pwm *pwm) } } -static struct lm8323_platform_data *lm8323_pdata; - - #define LM8323_MAX_DATA 8 /* @@ -682,6 +679,7 @@ static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable); static int lm8323_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct lm8323_platform_data *pdata; struct input_dev *idev; struct lm8323_chip *lm; int i, err = 0; @@ -694,11 +692,11 @@ static int lm8323_probe(struct i2c_client *client, i2c_set_clientdata(client, lm); lm->client = client; - lm8323_pdata = client->dev.platform_data; - if (!lm8323_pdata) + pdata = client->dev.platform_data; + if (!pdata) return -EINVAL; /* ? */ - lm->size_x = lm8323_pdata->size_x; + lm->size_x = pdata->size_x; if (lm->size_x == 0) { lm->size_x = 8; } else if (lm->size_x > 8) { @@ -707,7 +705,7 @@ static int lm8323_probe(struct i2c_client *client, lm->size_x = 8; } - lm->size_y = lm8323_pdata->size_y; + lm->size_y = pdata->size_y; if (lm->size_y == 0) { lm->size_y = 12; } else if (lm->size_y > 12) { @@ -718,13 +716,13 @@ static int lm8323_probe(struct i2c_client *client, debug(&c->dev, "Keypad size: %d x %d\n", lm->size_x, lm->size_y); - lm->debounce_time = lm8323_pdata->debounce_time; + lm->debounce_time = pdata->debounce_time; if (lm->debounce_time == 0) /* Default. */ lm->debounce_time = 12; else if (lm->debounce_time == -1) /* Disable debounce. */ lm->debounce_time = 0; - lm->active_time = lm8323_pdata->active_time; + lm->active_time = pdata->active_time; if (lm->active_time == 0) /* Default. */ lm->active_time = 500; else if (lm->active_time == -1) /* Disable sleep. */ @@ -756,11 +754,11 @@ static int lm8323_probe(struct i2c_client *client, goto fail2; } - if (init_pwm(lm, 1, &client->dev, lm8323_pdata->pwm1_name) < 0) + if (init_pwm(lm, 1, &client->dev, pdata->pwm1_name) < 0) goto fail3; - if (init_pwm(lm, 2, &client->dev, lm8323_pdata->pwm2_name) < 0) + if (init_pwm(lm, 2, &client->dev, pdata->pwm2_name) < 0) goto fail4; - if (init_pwm(lm, 3, &client->dev, lm8323_pdata->pwm3_name) < 0) + if (init_pwm(lm, 3, &client->dev, pdata->pwm3_name) < 0) goto fail5; mutex_init(&lm->lock); @@ -787,8 +785,8 @@ static int lm8323_probe(struct i2c_client *client, goto fail8; } - if (lm8323_pdata->name) - idev->name = lm8323_pdata->name; + if (pdata->name) + idev->name = pdata->name; else idev->name = "LM8323 keypad"; snprintf(lm->phys, sizeof(lm->phys), "%s/input-kp", client->dev.bus_id); @@ -797,13 +795,13 @@ static int lm8323_probe(struct i2c_client *client, lm->keys_down = 0; idev->evbit[0] = BIT(EV_KEY); for (i = 0; i < LM8323_KEYMAP_SIZE; i++) { - if (lm8323_pdata->keymap[i] > 0) - set_bit(lm8323_pdata->keymap[i], idev->keybit); + if (pdata->keymap[i] > 0) + set_bit(pdata->keymap[i], idev->keybit); - lm->keymap[i] = lm8323_pdata->keymap[i]; + lm->keymap[i] = pdata->keymap[i]; } - if (lm8323_pdata->repeat) + if (pdata->repeat) set_bit(EV_REP, idev->evbit); lm->idev = idev; -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 7/8] input: lm8323: get rid of useless debug macro 2009-02-10 12:16 ` [PATCH 6/8] input: lm8323: get rid of global pdata pointer Felipe Balbi @ 2009-02-10 12:16 ` Felipe Balbi 2009-02-10 12:16 ` [PATCH 8/8] input: lm8323: general clean up Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:16 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi we can use dev_vdbg() which is only true when VERBOSE is enabled. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/input/keyboard/lm8323.c | 28 +++++++++++----------------- 1 files changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 60abe61..0812bef 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -33,12 +33,6 @@ #include <asm/mach-types.h> #include <asm/mach/irq.h> -#ifdef VERBOSE -#define debug dev_dbg -#else -#define debug(...) -#endif - /* Commands to send to the chip. */ #define LM8323_CMD_READ_ID 0x80 /* Read chip ID. */ #define LM8323_CMD_WRITE_CFG 0x81 /* Set configuration item. */ @@ -303,7 +297,7 @@ static void process_keys(struct lm8323_chip *lm) s16 keycode = lm->keymap[key]; if (likely(keycode > 0)) { - debug(&lm->client->dev, "key 0x%02x %s\n", key, + dev_vdbg(&lm->client->dev, "key 0x%02x %s\n", key, isdown ? "down" : "up"); if (likely(lm->kp_enabled)) { input_report_key(lm->idev, keycode, isdown); @@ -337,13 +331,13 @@ static void lm8323_process_error(struct lm8323_chip *lm) if (lm8323_read(lm, LM8323_CMD_READ_ERR, &error, 1) == 1) { if (error & ERR_FIFOOVER) - debug(&lm->client->dev, "fifo overflow!\n"); + dev_vdbg(&lm->client->dev, "fifo overflow!\n"); if (error & ERR_KEYOVR) - debug(&lm->client->dev, "more than two keys pressed\n"); + dev_vdbg(&lm->client->dev, "more than two keys pressed\n"); if (error & ERR_CMDUNK) - debug(&lm->client->dev, "unknown command submitted\n"); + dev_vdbg(&lm->client->dev, "unknown command submitted\n"); if (error & ERR_BADPAR) - debug(&lm->client->dev, "bad command parameter\n"); + dev_vdbg(&lm->client->dev, "bad command parameter\n"); } } @@ -408,10 +402,10 @@ static void lm8323_work(struct work_struct *work) process_keys(lm); if (ints & INT_ROTATOR) { /* We don't currently support the rotator. */ - debug(&lm->client->dev, "rotator fired\n"); + dev_vdbg(&lm->client->dev, "rotator fired\n"); } if (ints & INT_ERROR) { - debug(&lm->client->dev, "error!\n"); + dev_vdbg(&lm->client->dev, "error!\n"); lm8323_process_error(lm); } if (ints & INT_NOINIT) { @@ -420,15 +414,15 @@ static void lm8323_work(struct work_struct *work) lm8323_configure(lm); } if (ints & INT_PWM1) { - debug(&lm->client->dev, "pwm1 engine completed\n"); + dev_vdbg(&lm->client->dev, "pwm1 engine completed\n"); pwm_done(&lm->pwm1); } if (ints & INT_PWM2) { - debug(&lm->client->dev, "pwm2 engine completed\n"); + dev_vdbg(&lm->client->dev, "pwm2 engine completed\n"); pwm_done(&lm->pwm2); } if (ints & INT_PWM3) { - debug(&lm->client->dev, "pwm3 engine completed\n"); + dev_vdbg(&lm->client->dev, "pwm3 engine completed\n"); pwm_done(&lm->pwm3); } } @@ -714,7 +708,7 @@ static int lm8323_probe(struct i2c_client *client, lm->size_x = 12; } - debug(&c->dev, "Keypad size: %d x %d\n", lm->size_x, lm->size_y); + dev_vdbg(&client->dev, "Keypad size: %d x %d\n", lm->size_x, lm->size_y); lm->debounce_time = pdata->debounce_time; if (lm->debounce_time == 0) /* Default. */ -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 8/8] input: lm8323: general clean up 2009-02-10 12:16 ` [PATCH 7/8] input: lm8323: get rid of useless debug macro Felipe Balbi @ 2009-02-10 12:16 ` Felipe Balbi 0 siblings, 0 replies; 27+ messages in thread From: Felipe Balbi @ 2009-02-10 12:16 UTC (permalink / raw) To: linux-omap; +Cc: Felipe Balbi This patch cleans up lm8323 driver a little bit: - don't include <asm/mach-types.h> nor <asm/mach/irq.h> - remove #define DRIVER_NAME - don't try to fix pdata if it comes wrong, return -errno - add __devexit to remove() call - move module_init() and module_exit() closer to their arguments - add missing fields to n800's lm8323's pdata Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- arch/arm/mach-omap2/board-n800.c | 14 ++++++--- drivers/input/keyboard/lm8323.c | 51 ++++++++++++++----------------------- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-omap2/board-n800.c b/arch/arm/mach-omap2/board-n800.c index b38b295..fe6e5c9 100644 --- a/arch/arm/mach-omap2/board-n800.c +++ b/arch/arm/mach-omap2/board-n800.c @@ -111,12 +111,16 @@ static s16 rx44_keymap[LM8323_KEYMAP_SIZE] = { }; static struct lm8323_platform_data lm8323_pdata = { - .repeat = 0, /* Repeat is handled in userspace for now. */ - .keymap = rx44_keymap, - - .name = "Internal keyboard", - .pwm1_name = "keyboard", - .pwm2_name = "cover", + .repeat = 0, /* Repeat is handled in userspace for now. */ + .keymap = rx44_keymap, + .size_x = 8, + .size_y = 8, + .debounce_time = 12, + .active_time = 500, + + .name = "Internal keyboard", + .pwm1_name = "keyboard", + .pwm2_name = "cover", }; #endif diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 0812bef..4df16d9 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -30,9 +30,6 @@ #include <linux/leds.h> #include <linux/i2c/lm8323.h> -#include <asm/mach-types.h> -#include <asm/mach/irq.h> - /* Commands to send to the chip. */ #define LM8323_CMD_READ_ID 0x80 /* Read chip ID. */ #define LM8323_CMD_WRITE_CFG 0x81 /* Set configuration item. */ @@ -127,8 +124,6 @@ /* Send trigger. Argument is same as PWM_WAIT_TRIG. */ #define PWM_SEND_TRIG(chans) (0xe000 | ((chans) & 0x7)) -#define DRIVER_NAME "lm8323" - struct lm8323_pwm { int id; int enabled; @@ -671,7 +666,7 @@ static ssize_t lm8323_set_disable(struct device *dev, static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable); static int lm8323_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct lm8323_platform_data *pdata; struct input_dev *idev; @@ -687,40 +682,32 @@ static int lm8323_probe(struct i2c_client *client, i2c_set_clientdata(client, lm); lm->client = client; pdata = client->dev.platform_data; - if (!pdata) - return -EINVAL; /* ? */ + if (!pdata || !pdata->size_x || !pdata->size_y) { + dev_err(&client->dev, "missing platform_data\n"); + err = -EINVAL; + goto fail2; + } lm->size_x = pdata->size_x; - if (lm->size_x == 0) { - lm->size_x = 8; - } else if (lm->size_x > 8) { + if (lm->size_x > 8) { dev_err(&client->dev, "invalid x size %d specified\n", lm->size_x); - lm->size_x = 8; + err = -EINVAL; + goto fail2; } lm->size_y = pdata->size_y; - if (lm->size_y == 0) { - lm->size_y = 12; - } else if (lm->size_y > 12) { + if (lm->size_y > 12) { dev_err(&client->dev, "invalid y size %d specified\n", lm->size_y); - lm->size_x = 12; + err = -EINVAL; + goto fail2; } dev_vdbg(&client->dev, "Keypad size: %d x %d\n", lm->size_x, lm->size_y); lm->debounce_time = pdata->debounce_time; - if (lm->debounce_time == 0) /* Default. */ - lm->debounce_time = 12; - else if (lm->debounce_time == -1) /* Disable debounce. */ - lm->debounce_time = 0; - lm->active_time = pdata->active_time; - if (lm->active_time == 0) /* Default. */ - lm->active_time = 500; - else if (lm->active_time == -1) /* Disable sleep. */ - lm->active_time = 0; lm8323_reset(lm); @@ -760,7 +747,7 @@ static int lm8323_probe(struct i2c_client *client, err = request_irq(client->irq, lm8323_irq, IRQF_TRIGGER_FALLING | IRQF_DISABLED | - IRQF_SAMPLE_RANDOM, DRIVER_NAME, lm); + IRQF_SAMPLE_RANDOM, "lm8323", lm); if (err) { dev_err(&client->dev, "could not get IRQ %d\n", client->irq); goto fail6; @@ -774,7 +761,7 @@ static int lm8323_probe(struct i2c_client *client, goto fail7; idev = input_allocate_device(); - if (idev == NULL) { + if (!idev) { err = -ENOMEM; goto fail8; } @@ -826,7 +813,7 @@ fail2: return err; } -static int lm8323_remove(struct i2c_client *client) +static int __devexit lm8323_remove(struct i2c_client *client) { struct lm8323_chip *lm = i2c_get_clientdata(client); @@ -892,13 +879,13 @@ static int lm8323_resume(struct i2c_client *client) } static const struct i2c_device_id lm8323_id[] = { - { DRIVER_NAME, 0 }, + { "lm8323", 0 }, { } }; static struct i2c_driver lm8323_i2c_driver = { .driver = { - .name = DRIVER_NAME, + .name = "lm8323", }, .probe = lm8323_probe, .remove = __devexit_p(lm8323_remove), @@ -912,15 +899,15 @@ static int __init lm8323_init(void) { return i2c_add_driver(&lm8323_i2c_driver); } +module_init(lm8323_init); static void __exit lm8323_exit(void) { i2c_del_driver(&lm8323_i2c_driver); } +module_exit(lm8323_exit); MODULE_AUTHOR("Timo O. Karjalainen <timo.o.karjalainen@nokia.com>, Daniel Stone"); MODULE_DESCRIPTION("LM8323 keypad driver"); MODULE_LICENSE("GPL"); -module_init(lm8323_init); -module_exit(lm8323_exit); -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH 4/8] i2c: lp5521: move to LED framework 2009-02-10 12:16 ` [PATCH 4/8] i2c: lp5521: move to LED framework Felipe Balbi 2009-02-10 12:16 ` [PATCH 5/8] leds: lp5521: move to drivers/leds Felipe Balbi @ 2009-02-12 22:18 ` David Brownell 2009-02-13 0:00 ` Felipe Balbi 1 sibling, 1 reply; 27+ messages in thread From: David Brownell @ 2009-02-12 22:18 UTC (permalink / raw) To: Felipe Balbi; +Cc: linux-omap On Tuesday 10 February 2009, Felipe Balbi wrote: > + chip->ledr.name = "lp5521:red"; Rule of thumb: assume there can always be multiple instances of a device. In this case that's trivially possible Exception to that rule: rare, based on system-wide concerns. Like there being only one PMIC, one OTG port, and so on. In this case, not applicable. I'd suggest allocating some memory in the per-lp5521 struct to hold the strings, and catenating them with a label provided in the platform data. That way you won't be assuming there's only a single lp5521, and the names for the LEDs can be more relevant to the board ... "n810::red" and so forth. - Dave -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 4/8] i2c: lp5521: move to LED framework 2009-02-12 22:18 ` [PATCH 4/8] i2c: lp5521: move to LED framework David Brownell @ 2009-02-13 0:00 ` Felipe Balbi 2009-02-13 12:43 ` [RESEND] lp5521 patches Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 0:00 UTC (permalink / raw) To: David Brownell; +Cc: Felipe Balbi, linux-omap On Thu, 12 Feb 2009 14:18:17 -0800, David Brownell <david-b@pacbell.net> wrote: > On Tuesday 10 February 2009, Felipe Balbi wrote: >> + chip->ledr.name = "lp5521:red"; > > Rule of thumb: assume there can always be multiple instances > of a device. In this case that's trivially possible > > Exception to that rule: rare, based on system-wide concerns. > Like there being only one PMIC, one OTG port, and so on. In > this case, not applicable. > > > I'd suggest allocating some memory in the per-lp5521 struct > to hold the strings, and catenating them with a label provided > in the platform data. That way you won't be assuming there's > only a single lp5521, and the names for the LEDs can be more > relevant to the board ... "n810::red" and so forth. makes sense to me, I'll update this patch and resend :-) -- Best Regards, Felipe Balbi http://blog.felipebalbi.com me@felipebalbi.com -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 27+ messages in thread
* [RESEND] lp5521 patches 2009-02-13 0:00 ` Felipe Balbi @ 2009-02-13 12:43 ` Felipe Balbi 2009-02-13 12:43 ` [PATCH 1/6] i2c: lp5521: remove dead code Felipe Balbi 2009-02-17 21:38 ` [RESEND] lp5521 patches Otto Solares 0 siblings, 2 replies; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 12:43 UTC (permalink / raw) To: linux-omap; +Cc: David Brownell Hi Dave, all could you look at the updated lp5521 patches ? Basically patches from 1 to 3 are the same. Patch 4 has the fix you asked me to implement, getting a label from pdata (then I also moved mode and the presence of each individual led to pdata as well), patch 5 only moves the file to drivers/leds and patch 6 is a new patch adding pdata to board-n800.c After these, lp5521 should be ok for going upstream. Thanks for your time ;-) ^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 1/6] i2c: lp5521: remove dead code 2009-02-13 12:43 ` [RESEND] lp5521 patches Felipe Balbi @ 2009-02-13 12:43 ` Felipe Balbi 2009-02-13 12:43 ` [PATCH 2/6] i2c: lp5521: cosmetic fixes Felipe Balbi 2009-02-17 21:38 ` [RESEND] lp5521 patches Otto Solares 1 sibling, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 12:43 UTC (permalink / raw) To: linux-omap; +Cc: David Brownell, Felipe Balbi That LED_CONNECTED_WRONG was never defined so removing. If someone needs those hooks, add back via proper platform_data instead of nasty ifdefery. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/lp5521.c | 22 ---------------------- 1 files changed, 0 insertions(+), 22 deletions(-) diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index c0862d9..7fb8091 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -28,13 +28,8 @@ #define LP5521_DRIVER_NAME "lp5521" -#ifdef LED_CONNECTED_WRONG -#define LP5521_REG_R_PWM 0x04 -#define LP5521_REG_B_PWM 0x02 -#else #define LP5521_REG_R_PWM 0x02 #define LP5521_REG_B_PWM 0x04 -#endif #define LP5521_REG_ENABLE 0x00 #define LP5521_REG_OP_MODE 0x01 #define LP5521_REG_G_PWM 0x03 @@ -200,22 +195,12 @@ static ssize_t show_active_channels(struct device *dev, char channels[4]; int pos = 0; -#ifdef LED_CONNECTED_WRONG - if (chip->blue) - pos += sprintf(channels + pos, "r"); - if (chip->green) - pos += sprintf(channels + pos, "g"); - if (chip->red) - pos += sprintf(channels + pos, "b"); - -#else if (chip->red) pos += sprintf(channels + pos, "r"); if (chip->green) pos += sprintf(channels + pos, "g"); if (chip->blue) pos += sprintf(channels + pos, "b"); -#endif channels[pos] = '\0'; @@ -232,17 +217,10 @@ static ssize_t store_active_channels(struct device *dev, chip->green = 0; chip->blue = 0; -#ifdef LED_CONNECTED_WRONG - if (strchr(buf, 'r') != NULL) - chip->blue = 1; - if (strchr(buf, 'b') != NULL) - chip->red = 1; -#else if (strchr(buf, 'r') != NULL) chip->red = 1; if (strchr(buf, 'b') != NULL) chip->blue = 1; -#endif if (strchr(buf, 'g') != NULL) chip->green = 1; -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 2/6] i2c: lp5521: cosmetic fixes 2009-02-13 12:43 ` [PATCH 1/6] i2c: lp5521: remove dead code Felipe Balbi @ 2009-02-13 12:43 ` Felipe Balbi 2009-02-13 12:43 ` [PATCH 3/6] i2c: lp5521: simplify mode setting Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 12:43 UTC (permalink / raw) To: linux-omap; +Cc: David Brownell, Felipe Balbi General cleanup to the code. Preparing to send it to mainline. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/lp5521.c | 159 ++++++++++++++++++++------------------------ 1 files changed, 73 insertions(+), 86 deletions(-) diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index 7fb8091..e040c4d 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -1,5 +1,5 @@ /* - * drivers/i2c/chips/lp5521.c + * lp5521.c - LP5521 LED Driver * * Copyright (C) 2007 Nokia Corporation * @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/mutex.h> -#include <mach/gpio.h> #define LP5521_DRIVER_NAME "lp5521" @@ -71,6 +70,7 @@ #define LP5521_PROGRAM_LENGTH 32 /* in bytes */ struct lp5521_chip { + /* device lock */ struct mutex lock; struct i2c_client *client; char *mode; @@ -81,20 +81,14 @@ struct lp5521_chip { static int lp5521_set_mode(struct lp5521_chip *chip, char *mode); -static int lp5521_write(struct i2c_client *client, u8 reg, u8 value) +static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } -static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf) +static inline int lp5521_read(struct i2c_client *client, u8 reg) { - s32 ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) - return -EIO; - - *buf = ret; - return 0; + return i2c_smbus_read_byte_data(client, reg); } static int lp5521_configure(struct i2c_client *client) @@ -136,19 +130,19 @@ static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) if (chip->red) ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_R_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); + LP5521_REG_R_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); if (chip->green) ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_G_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); + LP5521_REG_G_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); if (chip->blue) ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_B_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); + LP5521_REG_B_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); return ret; } @@ -156,31 +150,33 @@ static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) static int lp5521_run_program(struct lp5521_chip *chip) { struct i2c_client *client = chip->client; - int ret; + int reg; u8 mask = 0xc0; u8 exec_state = 0; - u8 enable_reg; - ret = lp5521_read(client, LP5521_REG_ENABLE, &enable_reg); - if (ret) - goto fail; + reg = lp5521_read(client, LP5521_REG_ENABLE); + if (reg < 0) + return reg; - enable_reg &= mask; + reg &= mask; /* set all active channels exec state to countinous run*/ - exec_state |= (chip->red << 5); + exec_state |= (chip->red << 5); exec_state |= (chip->green << 3); - exec_state |= (chip->blue << 1); + exec_state |= (chip->blue << 1); - enable_reg |= exec_state; + reg |= exec_state; - ret |= lp5521_write(client, LP5521_REG_ENABLE, enable_reg); + if (lp5521_write(client, LP5521_REG_ENABLE, reg)) + dev_dbg(&client->dev, "failed writing to register %02x\n", + LP5521_REG_ENABLE); /* set op-mode to run for active channels, disabled for others */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, exec_state); + if (lp5521_write(client, LP5521_REG_OP_MODE, exec_state)) + dev_dbg(&client->dev, "failed writing to register %02x\n", + LP5521_REG_OP_MODE); -fail: - return ret; + return 0; } /*--------------------------------------------------------------*/ @@ -188,8 +184,8 @@ fail: /*--------------------------------------------------------------*/ static ssize_t show_active_channels(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct lp5521_chip *chip = dev_get_drvdata(dev); char channels[4]; @@ -208,8 +204,8 @@ static ssize_t show_active_channels(struct device *dev, } static ssize_t store_active_channels(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct lp5521_chip *chip = dev_get_drvdata(dev); @@ -228,26 +224,25 @@ static ssize_t store_active_channels(struct device *dev, } static ssize_t show_color(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct i2c_client *client = to_i2c_client(dev); - int ret = 0; - u8 r, g, b; + int r, g, b; - ret |= lp5521_read(client, LP5521_REG_R_PWM, &r); - ret |= lp5521_read(client, LP5521_REG_G_PWM, &g); - ret |= lp5521_read(client, LP5521_REG_B_PWM, &b); + r = lp5521_read(client, LP5521_REG_R_PWM); + g = lp5521_read(client, LP5521_REG_G_PWM); + b = lp5521_read(client, LP5521_REG_B_PWM); - if (ret) - return ret; + if (r < 0 || g < 0 || b < 0) + return -EINVAL; return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b); } static ssize_t store_color(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct i2c_client *client = to_i2c_client(dev); struct lp5521_chip *chip = i2c_get_clientdata(client); @@ -271,8 +266,8 @@ static ssize_t store_color(struct device *dev, } static ssize_t store_load(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct lp5521_chip *chip = dev_get_drvdata(dev); int ret, nrchars, offset = 0, i = 0; @@ -314,8 +309,8 @@ fail: } static ssize_t show_mode(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct lp5521_chip *chip = dev_get_drvdata(dev); @@ -323,8 +318,8 @@ static ssize_t show_mode(struct device *dev, } static ssize_t store_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct lp5521_chip *chip = dev_get_drvdata(dev); @@ -343,33 +338,29 @@ static ssize_t store_mode(struct device *dev, } static ssize_t show_current(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct i2c_client *client = to_i2c_client(dev); - int ret = 0; - u8 r_curr, g_curr, b_curr; + int r, g, b; - ret |= lp5521_read(client, LP5521_REG_R_CNTRL, &r_curr); - ret |= lp5521_read(client, LP5521_REG_G_CNTRL, &g_curr); - ret |= lp5521_read(client, LP5521_REG_B_CNTRL, &b_curr); + r = lp5521_read(client, LP5521_REG_R_CNTRL); + g = lp5521_read(client, LP5521_REG_G_CNTRL); + b = lp5521_read(client, LP5521_REG_B_CNTRL); - if (ret) - return ret; + if (r < 0 || g < 0 || b < 0) + return -EINVAL; - r_curr = r_curr >> 4; - g_curr = g_curr >> 4; - b_curr = b_curr >> 4; + r >>= 4; + g >>= 4; + b >>= 4; - if (r_curr == g_curr && g_curr == b_curr) - return sprintf(buf, "%x\n", r_curr); - else - return sprintf(buf, "%x %x %x\n", r_curr, g_curr, b_curr); + return sprintf(buf, "%x %x %x\n", r, g, b); } static ssize_t store_current(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct lp5521_chip *chip = dev_get_drvdata(dev); struct i2c_client *client = chip->client; @@ -398,7 +389,7 @@ static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color); static DEVICE_ATTR(load, S_IWUGO, NULL, store_load); static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode); static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO, - show_active_channels, store_active_channels); + show_active_channels, store_active_channels); static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); static int lp5521_register_sysfs(struct i2c_client *client) @@ -421,6 +412,7 @@ static int lp5521_register_sysfs(struct i2c_client *client) ret = device_create_file(dev, &dev_attr_led_current); if (ret) goto fail5; + return 0; fail5: @@ -437,16 +429,13 @@ fail1: static void lp5521_unregister_sysfs(struct i2c_client *client) { - struct lp5521_chip *chip = i2c_get_clientdata(client); struct device *dev = &client->dev; device_remove_file(dev, &dev_attr_led_current); device_remove_file(dev, &dev_attr_mode); device_remove_file(dev, &dev_attr_active_channels); device_remove_file(dev, &dev_attr_color); - - if (!strcmp(chip->mode, LP5521_MODE_LOAD)) - device_remove_file(dev, &dev_attr_load); + device_remove_file(dev, &dev_attr_load); } /*--------------------------------------------------------------*/ @@ -479,9 +468,8 @@ static int lp5521_set_mode(struct lp5521_chip *chip, char *mode) /*--------------------------------------------------------------*/ /* Probe, Attach, Remove */ /*--------------------------------------------------------------*/ -static struct i2c_driver lp5521_driver; -static int lp5521_probe(struct i2c_client *client, +static int __init lp5521_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lp5521_chip *chip; @@ -491,7 +479,7 @@ static int lp5521_probe(struct i2c_client *client, if (!chip) return -ENOMEM; - chip->client = client; + chip->client = client; strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE); i2c_set_clientdata(client, chip); @@ -520,7 +508,7 @@ fail1: return ret; } -static int lp5521_remove(struct i2c_client *client) +static int __exit lp5521_remove(struct i2c_client *client) { struct lp5521_chip *chip = i2c_get_clientdata(client); @@ -537,11 +525,11 @@ static const struct i2c_device_id lp5521_id[] = { MODULE_DEVICE_TABLE(i2c, lp5521_id); static struct i2c_driver lp5521_driver = { - .driver = { + .driver = { .name = LP5521_DRIVER_NAME, }, .probe = lp5521_probe, - .remove = __devexit_p(lp5521_remove), + .remove = __exit_p(lp5521_remove), .id_table = lp5521_id, }; @@ -549,15 +537,14 @@ static int __init lp5521_init(void) { return i2c_add_driver(&lp5521_driver); } +module_init(lp5521_init); static void __exit lp5521_exit(void) { i2c_del_driver(&lp5521_driver); } +module_exit(lp5521_exit); MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>"); MODULE_DESCRIPTION("lp5521 LED driver"); MODULE_LICENSE("GPL"); - -module_init(lp5521_init); -module_exit(lp5521_exit); -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 3/6] i2c: lp5521: simplify mode setting 2009-02-13 12:43 ` [PATCH 2/6] i2c: lp5521: cosmetic fixes Felipe Balbi @ 2009-02-13 12:43 ` Felipe Balbi 2009-02-13 12:43 ` [PATCH 4/6] i2c: lp5521: move to LED framework Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 12:43 UTC (permalink / raw) To: linux-omap; +Cc: David Brownell, Felipe Balbi Avoid using string magic and use integer for comparisson Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/lp5521.c | 52 ++++++++++++++++++++++++++++++++----------- 1 files changed, 38 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index e040c4d..9e94ff8 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -46,10 +46,6 @@ #define LP5521_REG_G_PROG_MEM 0x30 #define LP5521_REG_B_PROG_MEM 0x50 -#define LP5521_MODE_LOAD "load" -#define LP5521_MODE_RUN "run" -#define LP5521_MODE_DIRECT_CONTROL "direct" - #define LP5521_CURRENT_1m5 0x0f #define LP5521_CURRENT_3m1 0x1f #define LP5521_CURRENT_4m7 0x2f @@ -69,17 +65,23 @@ #define LP5521_PROGRAM_LENGTH 32 /* in bytes */ +enum lp5521_mode { + LP5521_MODE_LOAD, + LP5521_MODE_RUN, + LP5521_MODE_DIRECT_CONTROL, +}; + struct lp5521_chip { /* device lock */ struct mutex lock; struct i2c_client *client; - char *mode; + enum lp5521_mode mode; int red; int green; int blue; }; -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode); +static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode); static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) { @@ -313,8 +315,25 @@ static ssize_t show_mode(struct device *dev, char *buf) { struct lp5521_chip *chip = dev_get_drvdata(dev); + char *mode; + + mutex_lock(&chip->lock); + switch (chip->mode) { + case LP5521_MODE_RUN: + mode = "run"; + break; + case LP5521_MODE_LOAD: + mode = "load"; + break; + case LP5521_MODE_DIRECT_CONTROL: + mode = "direct"; + break; + default: + mode = "undefined"; + } + mutex_unlock(&chip->lock); - return sprintf(buf, "%s\n", chip->mode); + return sprintf(buf, "%s\n", mode); } static ssize_t store_mode(struct device *dev, @@ -442,23 +461,28 @@ static void lp5521_unregister_sysfs(struct i2c_client *client) /* Set chip operating mode */ /*--------------------------------------------------------------*/ -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode) +static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode) { struct i2c_client *client = chip->client ; int ret = 0; /* if in that mode already do nothing, except for run */ - if (!strcmp(mode, chip->mode) && strcmp(mode, LP5521_MODE_RUN)) + if (chip->mode == mode && mode != LP5521_MODE_RUN) return 0; - if (!strcmp(mode, LP5521_MODE_RUN)) + switch (mode) { + case LP5521_MODE_RUN: ret = lp5521_run_program(chip); - - if (!strcmp(mode, LP5521_MODE_LOAD)) + break; + case LP5521_MODE_LOAD: ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); - - if (!strcmp(mode, LP5521_MODE_DIRECT_CONTROL)) + break; + case LP5521_MODE_DIRECT_CONTROL: ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); + break; + default: + dev_dbg(&client->dev, "unsupported mode %d\n", mode); + } chip->mode = mode; -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 4/6] i2c: lp5521: move to LED framework 2009-02-13 12:43 ` [PATCH 3/6] i2c: lp5521: simplify mode setting Felipe Balbi @ 2009-02-13 12:43 ` Felipe Balbi 2009-02-13 12:43 ` [PATCH 5/6] leds: lp5521: move to drivers/leds Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 12:43 UTC (permalink / raw) To: linux-omap; +Cc: David Brownell, Felipe Balbi Register three separate leds for lp5521 and allow them to be controlled separately while keeping backwards compatibility with userspace programs based on old implementation. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/lp5521.c | 172 ++++++++++++++++++++++++++++++++++++++++--- include/linux/i2c/lp5521.h | 43 +++++++++++ 2 files changed, 203 insertions(+), 12 deletions(-) create mode 100644 include/linux/i2c/lp5521.h diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index 9e94ff8..b3ba52a 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -4,6 +4,7 @@ * Copyright (C) 2007 Nokia Corporation * * Written by Mathias Nyman <mathias.nyman@nokia.com> + * Updated by Felipe Balbi <felipe.balbi@nokia.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +24,10 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/leds.h> #include <linux/mutex.h> +#include <linux/workqueue.h> +#include <linux/i2c/lp5521.h> #define LP5521_DRIVER_NAME "lp5521" @@ -65,17 +69,21 @@ #define LP5521_PROGRAM_LENGTH 32 /* in bytes */ -enum lp5521_mode { - LP5521_MODE_LOAD, - LP5521_MODE_RUN, - LP5521_MODE_DIRECT_CONTROL, -}; - struct lp5521_chip { /* device lock */ struct mutex lock; struct i2c_client *client; + + struct work_struct red_work; + struct work_struct green_work; + struct work_struct blue_work; + + struct led_classdev ledr; + struct led_classdev ledg; + struct led_classdev ledb; + enum lp5521_mode mode; + int red; int green; int blue; @@ -489,6 +497,87 @@ static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode) return ret; } +static void lp5521_red_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, red_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_R_PWM, chip->red); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_red_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledr); + + chip->red = value; + schedule_work(&chip->red_work); +} + +static void lp5521_green_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, green_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_G_PWM, chip->green); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_green_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledg); + + chip->green = value; + schedule_work(&chip->green_work); +} + +static void lp5521_blue_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, blue_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_B_PWM, chip->blue); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_blue_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledb); + + chip->blue = value; + schedule_work(&chip->blue_work); +} + /*--------------------------------------------------------------*/ /* Probe, Attach, Remove */ /*--------------------------------------------------------------*/ @@ -496,9 +585,16 @@ static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode) static int __init lp5521_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct lp5521_platform_data *pdata = client->dev.platform_data; struct lp5521_chip *chip; + char name[16]; int ret = 0; + if (!pdata) { + dev_err(&client->dev, "platform_data is missing\n"); + return -EINVAL; + } + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -509,6 +605,10 @@ static int __init lp5521_probe(struct i2c_client *client, mutex_init(&chip->lock); + INIT_WORK(&chip->red_work, lp5521_red_work); + INIT_WORK(&chip->green_work, lp5521_green_work); + INIT_WORK(&chip->blue_work, lp5521_blue_work); + ret = lp5521_configure(client); if (ret < 0) { dev_err(&client->dev, "lp5521 error configuring chip \n"); @@ -516,19 +616,61 @@ static int __init lp5521_probe(struct i2c_client *client, } /* Set default values */ - chip->mode = LP5521_MODE_DIRECT_CONTROL; - chip->red = 1; - chip->green = 1; - chip->blue = 1; + chip->mode = pdata->mode; + chip->red = pdata->red_present; + chip->green = pdata->green_present; + chip->blue = pdata->blue_present; + + chip->ledr.brightness_set = lp5521_red_set; + chip->ledr.default_trigger = NULL; + snprintf(name, sizeof(name), "%s::red", pdata->label); + chip->ledr.name = name; + ret = led_classdev_register(&client->dev, &chip->ledr); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register led %s, %d\n", + chip->ledb.name, ret); + goto fail1; + } + + chip->ledg.brightness_set = lp5521_green_set; + chip->ledg.default_trigger = NULL; + snprintf(name, sizeof(name), "%s::green", pdata->label); + chip->ledg.name = name; + ret = led_classdev_register(&client->dev, &chip->ledg); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register led %s, %d\n", + chip->ledb.name, ret); + goto fail2; + } + + chip->ledb.brightness_set = lp5521_blue_set; + chip->ledb.default_trigger = NULL; + snprintf(name, sizeof(name), "%s::blue", pdata->label); + chip->ledb.name = name; + ret = led_classdev_register(&client->dev, &chip->ledb); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register led %s, %d\n", chip->ledb.name, ret); + goto fail3; + } ret = lp5521_register_sysfs(client); - if (ret) + if (ret) { dev_err(&client->dev, "lp5521 registering sysfs failed \n"); + goto fail4; + } - return ret; + return 0; +fail4: + led_classdev_unregister(&chip->ledb); +fail3: + led_classdev_unregister(&chip->ledg); +fail2: + led_classdev_unregister(&chip->ledr); fail1: + i2c_set_clientdata(client, NULL); kfree(chip); + return ret; } @@ -537,6 +679,12 @@ static int __exit lp5521_remove(struct i2c_client *client) struct lp5521_chip *chip = i2c_get_clientdata(client); lp5521_unregister_sysfs(client); + i2c_set_clientdata(client, NULL); + + led_classdev_unregister(&chip->ledb); + led_classdev_unregister(&chip->ledg); + led_classdev_unregister(&chip->ledr); + kfree(chip); return 0; diff --git a/include/linux/i2c/lp5521.h b/include/linux/i2c/lp5521.h new file mode 100644 index 0000000..070e8be --- /dev/null +++ b/include/linux/i2c/lp5521.h @@ -0,0 +1,43 @@ +/* + * lp5521.h - header for LP5521 LED driver + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Felipe Balbi <felipe.balbi@nokia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __LP5521_H_ +#define __LP5521_H_ + +enum lp5521_mode { + LP5521_MODE_LOAD, + LP5521_MODE_RUN, + LP5521_MODE_DIRECT_CONTROL, +}; + +struct lp5521_platform_data { + enum lp5521_mode mode; + + unsigned red_present:1; + unsigned green_present:1; + unsigned blue_present:1; + + const char *label; +}; + +#endif /* End of __LP5521_H */ -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 5/6] leds: lp5521: move to drivers/leds 2009-02-13 12:43 ` [PATCH 4/6] i2c: lp5521: move to LED framework Felipe Balbi @ 2009-02-13 12:43 ` Felipe Balbi 2009-02-13 12:43 ` [PATCH 6/6] arm: omap: n810: add lp5521 platform_data Felipe Balbi 2009-02-13 20:49 ` [PATCH 5/6] leds: lp5521: move to drivers/leds David Brownell 0 siblings, 2 replies; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 12:43 UTC (permalink / raw) To: linux-omap; +Cc: David Brownell, Felipe Balbi This driver should be sitting together with the other led drivers. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/i2c/chips/Kconfig | 7 - drivers/i2c/chips/Makefile | 1 - drivers/i2c/chips/lp5521.c | 722 -------------------------------------------- drivers/leds/Kconfig | 10 + drivers/leds/Makefile | 1 + drivers/leds/leds-lp5521.c | 722 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 733 insertions(+), 730 deletions(-) delete mode 100644 drivers/i2c/chips/lp5521.c create mode 100644 drivers/leds/leds-lp5521.c diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index bb95b3e..e4831e1 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -141,13 +141,6 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. -config LP5521 - tristate "LP5521 LED driver chip" - depends on I2C - help - If you say yes here you get support for the National Semiconductor - LP5521 LED driver. - config MENELAUS bool "TWL92330/Menelaus PM chip" depends on I2C=y && ARCH_OMAP24XX diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 32a395f..1c94712 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o obj-$(CONFIG_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_RTC_X1205_I2C) += x1205.o -obj-$(CONFIG_LP5521) += lp5521.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c deleted file mode 100644 index b3ba52a..0000000 --- a/drivers/i2c/chips/lp5521.c +++ /dev/null @@ -1,722 +0,0 @@ -/* - * lp5521.c - LP5521 LED Driver - * - * Copyright (C) 2007 Nokia Corporation - * - * Written by Mathias Nyman <mathias.nyman@nokia.com> - * Updated by Felipe Balbi <felipe.balbi@nokia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/i2c.h> -#include <linux/leds.h> -#include <linux/mutex.h> -#include <linux/workqueue.h> -#include <linux/i2c/lp5521.h> - -#define LP5521_DRIVER_NAME "lp5521" - -#define LP5521_REG_R_PWM 0x02 -#define LP5521_REG_B_PWM 0x04 -#define LP5521_REG_ENABLE 0x00 -#define LP5521_REG_OP_MODE 0x01 -#define LP5521_REG_G_PWM 0x03 -#define LP5521_REG_R_CNTRL 0x05 -#define LP5521_REG_G_CNTRL 0x06 -#define LP5521_REG_B_CNTRL 0x07 -#define LP5521_REG_MISC 0x08 -#define LP5521_REG_R_CHANNEL_PC 0x09 -#define LP5521_REG_G_CHANNEL_PC 0x0a -#define LP5521_REG_B_CHANNEL_PC 0x0b -#define LP5521_REG_STATUS 0x0c -#define LP5521_REG_RESET 0x0d -#define LP5521_REG_GPO 0x0e -#define LP5521_REG_R_PROG_MEM 0x10 -#define LP5521_REG_G_PROG_MEM 0x30 -#define LP5521_REG_B_PROG_MEM 0x50 - -#define LP5521_CURRENT_1m5 0x0f -#define LP5521_CURRENT_3m1 0x1f -#define LP5521_CURRENT_4m7 0x2f -#define LP5521_CURRENT_6m3 0x3f -#define LP5521_CURRENT_7m9 0x4f -#define LP5521_CURRENT_9m5 0x5f -#define LP5521_CURRENT_11m1 0x6f -#define LP5521_CURRENT_12m7 0x7f -#define LP5521_CURRENT_14m3 0x8f -#define LP5521_CURRENT_15m9 0x9f -#define LP5521_CURRENT_17m5 0xaf -#define LP5521_CURRENT_19m1 0xbf -#define LP5521_CURRENT_20m7 0xcf -#define LP5521_CURRENT_22m3 0xdf -#define LP5521_CURRENT_23m9 0xef -#define LP5521_CURRENT_25m5 0xff - -#define LP5521_PROGRAM_LENGTH 32 /* in bytes */ - -struct lp5521_chip { - /* device lock */ - struct mutex lock; - struct i2c_client *client; - - struct work_struct red_work; - struct work_struct green_work; - struct work_struct blue_work; - - struct led_classdev ledr; - struct led_classdev ledg; - struct led_classdev ledb; - - enum lp5521_mode mode; - - int red; - int green; - int blue; -}; - -static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode); - -static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static inline int lp5521_read(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int lp5521_configure(struct i2c_client *client) -{ - int ret = 0; - - /* Enable chip and set light to logarithmic mode*/ - ret |= lp5521_write(client, LP5521_REG_ENABLE, 0xc0); - - /* setting all color pwms to direct control mode */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3f); - - /* setting current to 4.7 mA for all channels */ - ret |= lp5521_write(client, LP5521_REG_R_CNTRL, LP5521_CURRENT_4m7); - ret |= lp5521_write(client, LP5521_REG_G_CNTRL, LP5521_CURRENT_4m7); - ret |= lp5521_write(client, LP5521_REG_B_CNTRL, LP5521_CURRENT_4m7); - - /* Enable auto-powersave, set charge pump to auto, red to battery */ - ret |= lp5521_write(client, LP5521_REG_MISC, 0x3c); - - /* initialize all channels pwm to zero */ - ret |= lp5521_write(client, LP5521_REG_R_PWM, 0); - ret |= lp5521_write(client, LP5521_REG_G_PWM, 0); - ret |= lp5521_write(client, LP5521_REG_B_PWM, 0); - - /* Not much can be done about errors at this point */ - return ret; -} - -static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) -{ - struct i2c_client *client = chip->client; - int ret = 0; - - /* Enter load program mode for all led channels */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); /* 0001 0101 */ - if (ret) - return ret; - - if (chip->red) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_R_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - if (chip->green) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_G_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - if (chip->blue) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_B_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - - return ret; -} - -static int lp5521_run_program(struct lp5521_chip *chip) -{ - struct i2c_client *client = chip->client; - int reg; - u8 mask = 0xc0; - u8 exec_state = 0; - - reg = lp5521_read(client, LP5521_REG_ENABLE); - if (reg < 0) - return reg; - - reg &= mask; - - /* set all active channels exec state to countinous run*/ - exec_state |= (chip->red << 5); - exec_state |= (chip->green << 3); - exec_state |= (chip->blue << 1); - - reg |= exec_state; - - if (lp5521_write(client, LP5521_REG_ENABLE, reg)) - dev_dbg(&client->dev, "failed writing to register %02x\n", - LP5521_REG_ENABLE); - - /* set op-mode to run for active channels, disabled for others */ - if (lp5521_write(client, LP5521_REG_OP_MODE, exec_state)) - dev_dbg(&client->dev, "failed writing to register %02x\n", - LP5521_REG_OP_MODE); - - return 0; -} - -/*--------------------------------------------------------------*/ -/* Sysfs interface */ -/*--------------------------------------------------------------*/ - -static ssize_t show_active_channels(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - char channels[4]; - int pos = 0; - - if (chip->red) - pos += sprintf(channels + pos, "r"); - if (chip->green) - pos += sprintf(channels + pos, "g"); - if (chip->blue) - pos += sprintf(channels + pos, "b"); - - channels[pos] = '\0'; - - return sprintf(buf, "%s\n", channels); -} - -static ssize_t store_active_channels(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - - chip->red = 0; - chip->green = 0; - chip->blue = 0; - - if (strchr(buf, 'r') != NULL) - chip->red = 1; - if (strchr(buf, 'b') != NULL) - chip->blue = 1; - if (strchr(buf, 'g') != NULL) - chip->green = 1; - - return len; -} - -static ssize_t show_color(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - int r, g, b; - - r = lp5521_read(client, LP5521_REG_R_PWM); - g = lp5521_read(client, LP5521_REG_G_PWM); - b = lp5521_read(client, LP5521_REG_B_PWM); - - if (r < 0 || g < 0 || b < 0) - return -EINVAL; - - return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b); -} - -static ssize_t store_color(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5521_chip *chip = i2c_get_clientdata(client); - int ret; - unsigned r, g, b; - - - ret = sscanf(buf, "%2x:%2x:%2x", &r, &g, &b); - if (ret != 3) - return -EINVAL; - - mutex_lock(&chip->lock); - - ret = lp5521_write(client, LP5521_REG_R_PWM, (u8)r); - ret = lp5521_write(client, LP5521_REG_G_PWM, (u8)g); - ret = lp5521_write(client, LP5521_REG_B_PWM, (u8)b); - - mutex_unlock(&chip->lock); - - return len; -} - -static ssize_t store_load(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - int ret, nrchars, offset = 0, i = 0; - char c[3]; - unsigned cmd; - u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; - - while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { - - /* separate sscanfs because length is working only for %s */ - ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); - ret = sscanf(c, "%2x", &cmd); - if (ret != 1) - goto fail; - pattern[i] = (u8)cmd; - - offset += nrchars; - i++; - } - - /* pattern commands are always two bytes long */ - if (i % 2) - goto fail; - - mutex_lock(&chip->lock); - - ret = lp5521_load_program(chip, pattern); - mutex_unlock(&chip->lock); - - if (ret) { - dev_err(dev, "lp5521 failed loading pattern\n"); - return ret; - } - - return len; -fail: - dev_err(dev, "lp5521 wrong pattern format\n"); - return -EINVAL; -} - -static ssize_t show_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - char *mode; - - mutex_lock(&chip->lock); - switch (chip->mode) { - case LP5521_MODE_RUN: - mode = "run"; - break; - case LP5521_MODE_LOAD: - mode = "load"; - break; - case LP5521_MODE_DIRECT_CONTROL: - mode = "direct"; - break; - default: - mode = "undefined"; - } - mutex_unlock(&chip->lock); - - return sprintf(buf, "%s\n", mode); -} - -static ssize_t store_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - - mutex_lock(&chip->lock); - - if (!strncmp(buf, "run", 3)) - lp5521_set_mode(chip, LP5521_MODE_RUN); - else if (!strncmp(buf, "load", 4)) - lp5521_set_mode(chip, LP5521_MODE_LOAD); - else if (!strncmp(buf, "direct", 6)) - lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); - - mutex_unlock(&chip->lock); - - return len; -} - -static ssize_t show_current(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - int r, g, b; - - r = lp5521_read(client, LP5521_REG_R_CNTRL); - g = lp5521_read(client, LP5521_REG_G_CNTRL); - b = lp5521_read(client, LP5521_REG_B_CNTRL); - - if (r < 0 || g < 0 || b < 0) - return -EINVAL; - - r >>= 4; - g >>= 4; - b >>= 4; - - return sprintf(buf, "%x %x %x\n", r, g, b); -} - -static ssize_t store_current(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - struct i2c_client *client = chip->client; - int ret; - unsigned curr; - - ret = sscanf(buf, "%1x", &curr); - if (ret != 1) - return -EINVAL; - - /* current level is determined by the 4 upper bits, rest is ones */ - curr = (curr << 4) | 0x0f; - - mutex_lock(&chip->lock); - - ret |= lp5521_write(client, LP5521_REG_R_CNTRL, (u8)curr); - ret |= lp5521_write(client, LP5521_REG_G_CNTRL, (u8)curr); - ret |= lp5521_write(client, LP5521_REG_B_CNTRL, (u8)curr); - - mutex_unlock(&chip->lock); - - return len; -} - -static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color); -static DEVICE_ATTR(load, S_IWUGO, NULL, store_load); -static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode); -static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO, - show_active_channels, store_active_channels); -static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); - -static int lp5521_register_sysfs(struct i2c_client *client) -{ - struct device *dev = &client->dev; - int ret; - - ret = device_create_file(dev, &dev_attr_color); - if (ret) - goto fail1; - ret = device_create_file(dev, &dev_attr_load); - if (ret) - goto fail2; - ret = device_create_file(dev, &dev_attr_active_channels); - if (ret) - goto fail3; - ret = device_create_file(dev, &dev_attr_mode); - if (ret) - goto fail4; - ret = device_create_file(dev, &dev_attr_led_current); - if (ret) - goto fail5; - - return 0; - -fail5: - device_remove_file(dev, &dev_attr_mode); -fail4: - device_remove_file(dev, &dev_attr_active_channels); -fail3: - device_remove_file(dev, &dev_attr_load); -fail2: - device_remove_file(dev, &dev_attr_color); -fail1: - return ret; -} - -static void lp5521_unregister_sysfs(struct i2c_client *client) -{ - struct device *dev = &client->dev; - - device_remove_file(dev, &dev_attr_led_current); - device_remove_file(dev, &dev_attr_mode); - device_remove_file(dev, &dev_attr_active_channels); - device_remove_file(dev, &dev_attr_color); - device_remove_file(dev, &dev_attr_load); -} - -/*--------------------------------------------------------------*/ -/* Set chip operating mode */ -/*--------------------------------------------------------------*/ - -static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode) -{ - struct i2c_client *client = chip->client ; - int ret = 0; - - /* if in that mode already do nothing, except for run */ - if (chip->mode == mode && mode != LP5521_MODE_RUN) - return 0; - - switch (mode) { - case LP5521_MODE_RUN: - ret = lp5521_run_program(chip); - break; - case LP5521_MODE_LOAD: - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); - break; - case LP5521_MODE_DIRECT_CONTROL: - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); - break; - default: - dev_dbg(&client->dev, "unsupported mode %d\n", mode); - } - - chip->mode = mode; - - return ret; -} - -static void lp5521_red_work(struct work_struct *work) -{ - struct lp5521_chip *chip = container_of(work, struct lp5521_chip, red_work); - int ret; - - ret = lp5521_configure(chip->client); - if (ret) { - dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", - ret); - return; - } - - ret = lp5521_write(chip->client, LP5521_REG_R_PWM, chip->red); - if (ret) - dev_dbg(&chip->client->dev, "could not set brightness, %d\n", - ret); -} - -static void lp5521_red_set(struct led_classdev *led, - enum led_brightness value) -{ - struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledr); - - chip->red = value; - schedule_work(&chip->red_work); -} - -static void lp5521_green_work(struct work_struct *work) -{ - struct lp5521_chip *chip = container_of(work, struct lp5521_chip, green_work); - int ret; - - ret = lp5521_configure(chip->client); - if (ret) { - dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", - ret); - return; - } - - ret = lp5521_write(chip->client, LP5521_REG_G_PWM, chip->green); - if (ret) - dev_dbg(&chip->client->dev, "could not set brightness, %d\n", - ret); -} - -static void lp5521_green_set(struct led_classdev *led, - enum led_brightness value) -{ - struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledg); - - chip->green = value; - schedule_work(&chip->green_work); -} - -static void lp5521_blue_work(struct work_struct *work) -{ - struct lp5521_chip *chip = container_of(work, struct lp5521_chip, blue_work); - int ret; - - ret = lp5521_configure(chip->client); - if (ret) { - dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", - ret); - return; - } - - ret = lp5521_write(chip->client, LP5521_REG_B_PWM, chip->blue); - if (ret) - dev_dbg(&chip->client->dev, "could not set brightness, %d\n", - ret); -} - -static void lp5521_blue_set(struct led_classdev *led, - enum led_brightness value) -{ - struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledb); - - chip->blue = value; - schedule_work(&chip->blue_work); -} - -/*--------------------------------------------------------------*/ -/* Probe, Attach, Remove */ -/*--------------------------------------------------------------*/ - -static int __init lp5521_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct lp5521_platform_data *pdata = client->dev.platform_data; - struct lp5521_chip *chip; - char name[16]; - int ret = 0; - - if (!pdata) { - dev_err(&client->dev, "platform_data is missing\n"); - return -EINVAL; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->client = client; - strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE); - i2c_set_clientdata(client, chip); - - mutex_init(&chip->lock); - - INIT_WORK(&chip->red_work, lp5521_red_work); - INIT_WORK(&chip->green_work, lp5521_green_work); - INIT_WORK(&chip->blue_work, lp5521_blue_work); - - ret = lp5521_configure(client); - if (ret < 0) { - dev_err(&client->dev, "lp5521 error configuring chip \n"); - goto fail1; - } - - /* Set default values */ - chip->mode = pdata->mode; - chip->red = pdata->red_present; - chip->green = pdata->green_present; - chip->blue = pdata->blue_present; - - chip->ledr.brightness_set = lp5521_red_set; - chip->ledr.default_trigger = NULL; - snprintf(name, sizeof(name), "%s::red", pdata->label); - chip->ledr.name = name; - ret = led_classdev_register(&client->dev, &chip->ledr); - if (ret < 0) { - dev_dbg(&client->dev, "failed to register led %s, %d\n", - chip->ledb.name, ret); - goto fail1; - } - - chip->ledg.brightness_set = lp5521_green_set; - chip->ledg.default_trigger = NULL; - snprintf(name, sizeof(name), "%s::green", pdata->label); - chip->ledg.name = name; - ret = led_classdev_register(&client->dev, &chip->ledg); - if (ret < 0) { - dev_dbg(&client->dev, "failed to register led %s, %d\n", - chip->ledb.name, ret); - goto fail2; - } - - chip->ledb.brightness_set = lp5521_blue_set; - chip->ledb.default_trigger = NULL; - snprintf(name, sizeof(name), "%s::blue", pdata->label); - chip->ledb.name = name; - ret = led_classdev_register(&client->dev, &chip->ledb); - if (ret < 0) { - dev_dbg(&client->dev, "failed to register led %s, %d\n", chip->ledb.name, ret); - goto fail3; - } - - ret = lp5521_register_sysfs(client); - if (ret) { - dev_err(&client->dev, "lp5521 registering sysfs failed \n"); - goto fail4; - } - - return 0; - -fail4: - led_classdev_unregister(&chip->ledb); -fail3: - led_classdev_unregister(&chip->ledg); -fail2: - led_classdev_unregister(&chip->ledr); -fail1: - i2c_set_clientdata(client, NULL); - kfree(chip); - - return ret; -} - -static int __exit lp5521_remove(struct i2c_client *client) -{ - struct lp5521_chip *chip = i2c_get_clientdata(client); - - lp5521_unregister_sysfs(client); - i2c_set_clientdata(client, NULL); - - led_classdev_unregister(&chip->ledb); - led_classdev_unregister(&chip->ledg); - led_classdev_unregister(&chip->ledr); - - kfree(chip); - - return 0; -} - -static const struct i2c_device_id lp5521_id[] = { - { LP5521_DRIVER_NAME, 0}, - { }, -}; -MODULE_DEVICE_TABLE(i2c, lp5521_id); - -static struct i2c_driver lp5521_driver = { - .driver = { - .name = LP5521_DRIVER_NAME, - }, - .probe = lp5521_probe, - .remove = __exit_p(lp5521_remove), - .id_table = lp5521_id, -}; - -static int __init lp5521_init(void) -{ - return i2c_add_driver(&lp5521_driver); -} -module_init(lp5521_init); - -static void __exit lp5521_exit(void) -{ - i2c_del_driver(&lp5521_driver); -} -module_exit(lp5521_exit); - -MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>"); -MODULE_DESCRIPTION("lp5521 LED driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 4d4ff64..8d0f37e 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -134,6 +134,16 @@ config LEDS_GPIO outputs. To be useful the particular board must have LEDs and they must be connected to the GPIO lines. +config LEDS_LP5521 + tristate "LED Support for the LP5521 LEDs" + depends on LEDS_CLASS && I2C + help + If you say 'Y' here you get support for the National Semiconductor + LP5521 LED driver used in n8x0 boards. + + This driver can be built as a module by choosing 'M'. The module + will be called leds-lp5521. + config LEDS_CLEVO_MAIL tristate "Mail LED on Clevo notebook (EXPERIMENTAL)" depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI && EXPERIMENTAL diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 7ac6ad3..4ab09e8 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o +obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c new file mode 100644 index 0000000..b3ba52a --- /dev/null +++ b/drivers/leds/leds-lp5521.c @@ -0,0 +1,722 @@ +/* + * lp5521.c - LP5521 LED Driver + * + * Copyright (C) 2007 Nokia Corporation + * + * Written by Mathias Nyman <mathias.nyman@nokia.com> + * Updated by Felipe Balbi <felipe.balbi@nokia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/mutex.h> +#include <linux/workqueue.h> +#include <linux/i2c/lp5521.h> + +#define LP5521_DRIVER_NAME "lp5521" + +#define LP5521_REG_R_PWM 0x02 +#define LP5521_REG_B_PWM 0x04 +#define LP5521_REG_ENABLE 0x00 +#define LP5521_REG_OP_MODE 0x01 +#define LP5521_REG_G_PWM 0x03 +#define LP5521_REG_R_CNTRL 0x05 +#define LP5521_REG_G_CNTRL 0x06 +#define LP5521_REG_B_CNTRL 0x07 +#define LP5521_REG_MISC 0x08 +#define LP5521_REG_R_CHANNEL_PC 0x09 +#define LP5521_REG_G_CHANNEL_PC 0x0a +#define LP5521_REG_B_CHANNEL_PC 0x0b +#define LP5521_REG_STATUS 0x0c +#define LP5521_REG_RESET 0x0d +#define LP5521_REG_GPO 0x0e +#define LP5521_REG_R_PROG_MEM 0x10 +#define LP5521_REG_G_PROG_MEM 0x30 +#define LP5521_REG_B_PROG_MEM 0x50 + +#define LP5521_CURRENT_1m5 0x0f +#define LP5521_CURRENT_3m1 0x1f +#define LP5521_CURRENT_4m7 0x2f +#define LP5521_CURRENT_6m3 0x3f +#define LP5521_CURRENT_7m9 0x4f +#define LP5521_CURRENT_9m5 0x5f +#define LP5521_CURRENT_11m1 0x6f +#define LP5521_CURRENT_12m7 0x7f +#define LP5521_CURRENT_14m3 0x8f +#define LP5521_CURRENT_15m9 0x9f +#define LP5521_CURRENT_17m5 0xaf +#define LP5521_CURRENT_19m1 0xbf +#define LP5521_CURRENT_20m7 0xcf +#define LP5521_CURRENT_22m3 0xdf +#define LP5521_CURRENT_23m9 0xef +#define LP5521_CURRENT_25m5 0xff + +#define LP5521_PROGRAM_LENGTH 32 /* in bytes */ + +struct lp5521_chip { + /* device lock */ + struct mutex lock; + struct i2c_client *client; + + struct work_struct red_work; + struct work_struct green_work; + struct work_struct blue_work; + + struct led_classdev ledr; + struct led_classdev ledg; + struct led_classdev ledb; + + enum lp5521_mode mode; + + int red; + int green; + int blue; +}; + +static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode); + +static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int lp5521_read(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int lp5521_configure(struct i2c_client *client) +{ + int ret = 0; + + /* Enable chip and set light to logarithmic mode*/ + ret |= lp5521_write(client, LP5521_REG_ENABLE, 0xc0); + + /* setting all color pwms to direct control mode */ + ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3f); + + /* setting current to 4.7 mA for all channels */ + ret |= lp5521_write(client, LP5521_REG_R_CNTRL, LP5521_CURRENT_4m7); + ret |= lp5521_write(client, LP5521_REG_G_CNTRL, LP5521_CURRENT_4m7); + ret |= lp5521_write(client, LP5521_REG_B_CNTRL, LP5521_CURRENT_4m7); + + /* Enable auto-powersave, set charge pump to auto, red to battery */ + ret |= lp5521_write(client, LP5521_REG_MISC, 0x3c); + + /* initialize all channels pwm to zero */ + ret |= lp5521_write(client, LP5521_REG_R_PWM, 0); + ret |= lp5521_write(client, LP5521_REG_G_PWM, 0); + ret |= lp5521_write(client, LP5521_REG_B_PWM, 0); + + /* Not much can be done about errors at this point */ + return ret; +} + +static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + /* Enter load program mode for all led channels */ + ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); /* 0001 0101 */ + if (ret) + return ret; + + if (chip->red) + ret |= i2c_smbus_write_i2c_block_data(client, + LP5521_REG_R_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); + if (chip->green) + ret |= i2c_smbus_write_i2c_block_data(client, + LP5521_REG_G_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); + if (chip->blue) + ret |= i2c_smbus_write_i2c_block_data(client, + LP5521_REG_B_PROG_MEM, + LP5521_PROGRAM_LENGTH, + pattern); + + return ret; +} + +static int lp5521_run_program(struct lp5521_chip *chip) +{ + struct i2c_client *client = chip->client; + int reg; + u8 mask = 0xc0; + u8 exec_state = 0; + + reg = lp5521_read(client, LP5521_REG_ENABLE); + if (reg < 0) + return reg; + + reg &= mask; + + /* set all active channels exec state to countinous run*/ + exec_state |= (chip->red << 5); + exec_state |= (chip->green << 3); + exec_state |= (chip->blue << 1); + + reg |= exec_state; + + if (lp5521_write(client, LP5521_REG_ENABLE, reg)) + dev_dbg(&client->dev, "failed writing to register %02x\n", + LP5521_REG_ENABLE); + + /* set op-mode to run for active channels, disabled for others */ + if (lp5521_write(client, LP5521_REG_OP_MODE, exec_state)) + dev_dbg(&client->dev, "failed writing to register %02x\n", + LP5521_REG_OP_MODE); + + return 0; +} + +/*--------------------------------------------------------------*/ +/* Sysfs interface */ +/*--------------------------------------------------------------*/ + +static ssize_t show_active_channels(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct lp5521_chip *chip = dev_get_drvdata(dev); + char channels[4]; + int pos = 0; + + if (chip->red) + pos += sprintf(channels + pos, "r"); + if (chip->green) + pos += sprintf(channels + pos, "g"); + if (chip->blue) + pos += sprintf(channels + pos, "b"); + + channels[pos] = '\0'; + + return sprintf(buf, "%s\n", channels); +} + +static ssize_t store_active_channels(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct lp5521_chip *chip = dev_get_drvdata(dev); + + chip->red = 0; + chip->green = 0; + chip->blue = 0; + + if (strchr(buf, 'r') != NULL) + chip->red = 1; + if (strchr(buf, 'b') != NULL) + chip->blue = 1; + if (strchr(buf, 'g') != NULL) + chip->green = 1; + + return len; +} + +static ssize_t show_color(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int r, g, b; + + r = lp5521_read(client, LP5521_REG_R_PWM); + g = lp5521_read(client, LP5521_REG_G_PWM); + b = lp5521_read(client, LP5521_REG_B_PWM); + + if (r < 0 || g < 0 || b < 0) + return -EINVAL; + + return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b); +} + +static ssize_t store_color(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lp5521_chip *chip = i2c_get_clientdata(client); + int ret; + unsigned r, g, b; + + + ret = sscanf(buf, "%2x:%2x:%2x", &r, &g, &b); + if (ret != 3) + return -EINVAL; + + mutex_lock(&chip->lock); + + ret = lp5521_write(client, LP5521_REG_R_PWM, (u8)r); + ret = lp5521_write(client, LP5521_REG_G_PWM, (u8)g); + ret = lp5521_write(client, LP5521_REG_B_PWM, (u8)b); + + mutex_unlock(&chip->lock); + + return len; +} + +static ssize_t store_load(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct lp5521_chip *chip = dev_get_drvdata(dev); + int ret, nrchars, offset = 0, i = 0; + char c[3]; + unsigned cmd; + u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; + + while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { + + /* separate sscanfs because length is working only for %s */ + ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); + ret = sscanf(c, "%2x", &cmd); + if (ret != 1) + goto fail; + pattern[i] = (u8)cmd; + + offset += nrchars; + i++; + } + + /* pattern commands are always two bytes long */ + if (i % 2) + goto fail; + + mutex_lock(&chip->lock); + + ret = lp5521_load_program(chip, pattern); + mutex_unlock(&chip->lock); + + if (ret) { + dev_err(dev, "lp5521 failed loading pattern\n"); + return ret; + } + + return len; +fail: + dev_err(dev, "lp5521 wrong pattern format\n"); + return -EINVAL; +} + +static ssize_t show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct lp5521_chip *chip = dev_get_drvdata(dev); + char *mode; + + mutex_lock(&chip->lock); + switch (chip->mode) { + case LP5521_MODE_RUN: + mode = "run"; + break; + case LP5521_MODE_LOAD: + mode = "load"; + break; + case LP5521_MODE_DIRECT_CONTROL: + mode = "direct"; + break; + default: + mode = "undefined"; + } + mutex_unlock(&chip->lock); + + return sprintf(buf, "%s\n", mode); +} + +static ssize_t store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct lp5521_chip *chip = dev_get_drvdata(dev); + + mutex_lock(&chip->lock); + + if (!strncmp(buf, "run", 3)) + lp5521_set_mode(chip, LP5521_MODE_RUN); + else if (!strncmp(buf, "load", 4)) + lp5521_set_mode(chip, LP5521_MODE_LOAD); + else if (!strncmp(buf, "direct", 6)) + lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); + + mutex_unlock(&chip->lock); + + return len; +} + +static ssize_t show_current(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int r, g, b; + + r = lp5521_read(client, LP5521_REG_R_CNTRL); + g = lp5521_read(client, LP5521_REG_G_CNTRL); + b = lp5521_read(client, LP5521_REG_B_CNTRL); + + if (r < 0 || g < 0 || b < 0) + return -EINVAL; + + r >>= 4; + g >>= 4; + b >>= 4; + + return sprintf(buf, "%x %x %x\n", r, g, b); +} + +static ssize_t store_current(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct lp5521_chip *chip = dev_get_drvdata(dev); + struct i2c_client *client = chip->client; + int ret; + unsigned curr; + + ret = sscanf(buf, "%1x", &curr); + if (ret != 1) + return -EINVAL; + + /* current level is determined by the 4 upper bits, rest is ones */ + curr = (curr << 4) | 0x0f; + + mutex_lock(&chip->lock); + + ret |= lp5521_write(client, LP5521_REG_R_CNTRL, (u8)curr); + ret |= lp5521_write(client, LP5521_REG_G_CNTRL, (u8)curr); + ret |= lp5521_write(client, LP5521_REG_B_CNTRL, (u8)curr); + + mutex_unlock(&chip->lock); + + return len; +} + +static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color); +static DEVICE_ATTR(load, S_IWUGO, NULL, store_load); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode); +static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO, + show_active_channels, store_active_channels); +static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); + +static int lp5521_register_sysfs(struct i2c_client *client) +{ + struct device *dev = &client->dev; + int ret; + + ret = device_create_file(dev, &dev_attr_color); + if (ret) + goto fail1; + ret = device_create_file(dev, &dev_attr_load); + if (ret) + goto fail2; + ret = device_create_file(dev, &dev_attr_active_channels); + if (ret) + goto fail3; + ret = device_create_file(dev, &dev_attr_mode); + if (ret) + goto fail4; + ret = device_create_file(dev, &dev_attr_led_current); + if (ret) + goto fail5; + + return 0; + +fail5: + device_remove_file(dev, &dev_attr_mode); +fail4: + device_remove_file(dev, &dev_attr_active_channels); +fail3: + device_remove_file(dev, &dev_attr_load); +fail2: + device_remove_file(dev, &dev_attr_color); +fail1: + return ret; +} + +static void lp5521_unregister_sysfs(struct i2c_client *client) +{ + struct device *dev = &client->dev; + + device_remove_file(dev, &dev_attr_led_current); + device_remove_file(dev, &dev_attr_mode); + device_remove_file(dev, &dev_attr_active_channels); + device_remove_file(dev, &dev_attr_color); + device_remove_file(dev, &dev_attr_load); +} + +/*--------------------------------------------------------------*/ +/* Set chip operating mode */ +/*--------------------------------------------------------------*/ + +static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode) +{ + struct i2c_client *client = chip->client ; + int ret = 0; + + /* if in that mode already do nothing, except for run */ + if (chip->mode == mode && mode != LP5521_MODE_RUN) + return 0; + + switch (mode) { + case LP5521_MODE_RUN: + ret = lp5521_run_program(chip); + break; + case LP5521_MODE_LOAD: + ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); + break; + case LP5521_MODE_DIRECT_CONTROL: + ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); + break; + default: + dev_dbg(&client->dev, "unsupported mode %d\n", mode); + } + + chip->mode = mode; + + return ret; +} + +static void lp5521_red_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, red_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_R_PWM, chip->red); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_red_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledr); + + chip->red = value; + schedule_work(&chip->red_work); +} + +static void lp5521_green_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, green_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_G_PWM, chip->green); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_green_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledg); + + chip->green = value; + schedule_work(&chip->green_work); +} + +static void lp5521_blue_work(struct work_struct *work) +{ + struct lp5521_chip *chip = container_of(work, struct lp5521_chip, blue_work); + int ret; + + ret = lp5521_configure(chip->client); + if (ret) { + dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n", + ret); + return; + } + + ret = lp5521_write(chip->client, LP5521_REG_B_PWM, chip->blue); + if (ret) + dev_dbg(&chip->client->dev, "could not set brightness, %d\n", + ret); +} + +static void lp5521_blue_set(struct led_classdev *led, + enum led_brightness value) +{ + struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledb); + + chip->blue = value; + schedule_work(&chip->blue_work); +} + +/*--------------------------------------------------------------*/ +/* Probe, Attach, Remove */ +/*--------------------------------------------------------------*/ + +static int __init lp5521_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lp5521_platform_data *pdata = client->dev.platform_data; + struct lp5521_chip *chip; + char name[16]; + int ret = 0; + + if (!pdata) { + dev_err(&client->dev, "platform_data is missing\n"); + return -EINVAL; + } + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->client = client; + strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE); + i2c_set_clientdata(client, chip); + + mutex_init(&chip->lock); + + INIT_WORK(&chip->red_work, lp5521_red_work); + INIT_WORK(&chip->green_work, lp5521_green_work); + INIT_WORK(&chip->blue_work, lp5521_blue_work); + + ret = lp5521_configure(client); + if (ret < 0) { + dev_err(&client->dev, "lp5521 error configuring chip \n"); + goto fail1; + } + + /* Set default values */ + chip->mode = pdata->mode; + chip->red = pdata->red_present; + chip->green = pdata->green_present; + chip->blue = pdata->blue_present; + + chip->ledr.brightness_set = lp5521_red_set; + chip->ledr.default_trigger = NULL; + snprintf(name, sizeof(name), "%s::red", pdata->label); + chip->ledr.name = name; + ret = led_classdev_register(&client->dev, &chip->ledr); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register led %s, %d\n", + chip->ledb.name, ret); + goto fail1; + } + + chip->ledg.brightness_set = lp5521_green_set; + chip->ledg.default_trigger = NULL; + snprintf(name, sizeof(name), "%s::green", pdata->label); + chip->ledg.name = name; + ret = led_classdev_register(&client->dev, &chip->ledg); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register led %s, %d\n", + chip->ledb.name, ret); + goto fail2; + } + + chip->ledb.brightness_set = lp5521_blue_set; + chip->ledb.default_trigger = NULL; + snprintf(name, sizeof(name), "%s::blue", pdata->label); + chip->ledb.name = name; + ret = led_classdev_register(&client->dev, &chip->ledb); + if (ret < 0) { + dev_dbg(&client->dev, "failed to register led %s, %d\n", chip->ledb.name, ret); + goto fail3; + } + + ret = lp5521_register_sysfs(client); + if (ret) { + dev_err(&client->dev, "lp5521 registering sysfs failed \n"); + goto fail4; + } + + return 0; + +fail4: + led_classdev_unregister(&chip->ledb); +fail3: + led_classdev_unregister(&chip->ledg); +fail2: + led_classdev_unregister(&chip->ledr); +fail1: + i2c_set_clientdata(client, NULL); + kfree(chip); + + return ret; +} + +static int __exit lp5521_remove(struct i2c_client *client) +{ + struct lp5521_chip *chip = i2c_get_clientdata(client); + + lp5521_unregister_sysfs(client); + i2c_set_clientdata(client, NULL); + + led_classdev_unregister(&chip->ledb); + led_classdev_unregister(&chip->ledg); + led_classdev_unregister(&chip->ledr); + + kfree(chip); + + return 0; +} + +static const struct i2c_device_id lp5521_id[] = { + { LP5521_DRIVER_NAME, 0}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, lp5521_id); + +static struct i2c_driver lp5521_driver = { + .driver = { + .name = LP5521_DRIVER_NAME, + }, + .probe = lp5521_probe, + .remove = __exit_p(lp5521_remove), + .id_table = lp5521_id, +}; + +static int __init lp5521_init(void) +{ + return i2c_add_driver(&lp5521_driver); +} +module_init(lp5521_init); + +static void __exit lp5521_exit(void) +{ + i2c_del_driver(&lp5521_driver); +} +module_exit(lp5521_exit); + +MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>"); +MODULE_DESCRIPTION("lp5521 LED driver"); +MODULE_LICENSE("GPL"); -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 6/6] arm: omap: n810: add lp5521 platform_data 2009-02-13 12:43 ` [PATCH 5/6] leds: lp5521: move to drivers/leds Felipe Balbi @ 2009-02-13 12:43 ` Felipe Balbi 2009-02-13 20:49 ` [PATCH 5/6] leds: lp5521: move to drivers/leds David Brownell 1 sibling, 0 replies; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 12:43 UTC (permalink / raw) To: linux-omap; +Cc: David Brownell, Felipe Balbi Without it, driver won't probe. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- arch/arm/mach-omap2/board-n800.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-n800.c b/arch/arm/mach-omap2/board-n800.c index b38b295..18a0fe7 100644 --- a/arch/arm/mach-omap2/board-n800.c +++ b/arch/arm/mach-omap2/board-n800.c @@ -26,6 +26,7 @@ #include <linux/i2c.h> #include <linux/i2c/lm8323.h> #include <linux/i2c/menelaus.h> +#include <linux/i2c/lp5521.h> #include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -628,6 +629,14 @@ static struct i2c_board_info __initdata n800_i2c_board_info_1[] = { }, }; +static struct lp5521_platform_data n810_lp5521_platform_data = { + .mode = LP5521_MODE_DIRECT_CONTROL, + .label = "n810", + .red_present = true, + .green_present = true, + .blue_present = true, +}; + extern struct tcm825x_platform_data n800_tcm825x_platform_data; static struct i2c_board_info __initdata_or_module n8x0_i2c_board_info_2[] = { @@ -657,6 +666,7 @@ static struct i2c_board_info __initdata_or_module n810_i2c_board_info_2[] = { }, { I2C_BOARD_INFO("lp5521", 0x32), + .platform_data = &n810_lp5521_platform_data, }, }; -- 1.6.1.265.g9a013 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH 5/6] leds: lp5521: move to drivers/leds 2009-02-13 12:43 ` [PATCH 5/6] leds: lp5521: move to drivers/leds Felipe Balbi 2009-02-13 12:43 ` [PATCH 6/6] arm: omap: n810: add lp5521 platform_data Felipe Balbi @ 2009-02-13 20:49 ` David Brownell 2009-02-13 22:36 ` Felipe Balbi 1 sibling, 1 reply; 27+ messages in thread From: David Brownell @ 2009-02-13 20:49 UTC (permalink / raw) To: Felipe Balbi; +Cc: linux-omap On Friday 13 February 2009, Felipe Balbi wrote: > + if (!strncmp(buf, "run", 3)) > + lp5521_set_mode(chip, LP5521_MODE_RUN); > + else if (!strncmp(buf, "load", 4)) > + lp5521_set_mode(chip, LP5521_MODE_LOAD); > + else if (!strncmp(buf, "direct", 6)) > + lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); Minor nit, which could be addressed by a followon patch: This is an ideal use-case for using sysfs_streq(). And there's no terminal "else len = -EINVAL" to handle the case of illegal modes... - Dave -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 5/6] leds: lp5521: move to drivers/leds 2009-02-13 20:49 ` [PATCH 5/6] leds: lp5521: move to drivers/leds David Brownell @ 2009-02-13 22:36 ` Felipe Balbi 2009-02-13 23:54 ` David Brownell 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-13 22:36 UTC (permalink / raw) To: David Brownell; +Cc: Felipe Balbi, linux-omap On Fri, Feb 13, 2009 at 12:49:00PM -0800, David Brownell wrote: > On Friday 13 February 2009, Felipe Balbi wrote: > > + if (!strncmp(buf, "run", 3)) > > + lp5521_set_mode(chip, LP5521_MODE_RUN); > > + else if (!strncmp(buf, "load", 4)) > > + lp5521_set_mode(chip, LP5521_MODE_LOAD); > > + else if (!strncmp(buf, "direct", 6)) > > + lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); > > Minor nit, which could be addressed by a followon patch: > This is an ideal use-case for using sysfs_streq(). > > And there's no terminal "else len = -EINVAL" to handle the > case of illegal modes... Ok, here's an *untested* patch solving issues. ========== cut here ========== From 0872878daaa4a1768a3f56995ec416941758be6b Mon Sep 17 00:00:00 2001 From: Felipe Balbi <felipe.balbi@nokia.com> Date: Sat, 14 Feb 2009 00:34:56 +0200 Subject: [PATCH] leds: lp5521: use sysfs_streq() instead of using strcmp() for comparing strings, use sysfs_streq(). Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- drivers/leds/leds-lp5521.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index b3ba52a..3e1ca31 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -352,12 +352,14 @@ static ssize_t store_mode(struct device *dev, mutex_lock(&chip->lock); - if (!strncmp(buf, "run", 3)) + if (sysfs_streq(buf, "run")) lp5521_set_mode(chip, LP5521_MODE_RUN); - else if (!strncmp(buf, "load", 4)) + else if (sysfs_streq(buf, "load")) lp5521_set_mode(chip, LP5521_MODE_LOAD); - else if (!strncmp(buf, "direct", 6)) + else if (sysfs_streq(buf, "direct")) lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); + else + len = -EINVAL; mutex_unlock(&chip->lock); -- 1.6.2.rc0.61.g5cd12 -- balbi -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH 5/6] leds: lp5521: move to drivers/leds 2009-02-13 22:36 ` Felipe Balbi @ 2009-02-13 23:54 ` David Brownell 2009-02-14 0:07 ` Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: David Brownell @ 2009-02-13 23:54 UTC (permalink / raw) To: me; +Cc: Felipe Balbi, linux-omap On Friday 13 February 2009, Felipe Balbi wrote: > From: Felipe Balbi <felipe.balbi@nokia.com> > Date: Sat, 14 Feb 2009 00:34:56 +0200 > Subject: [PATCH] leds: lp5521: use sysfs_streq() > > instead of using strcmp() for comparing strings, > use sysfs_streq(). > > Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> Yes, just like that. > --- > drivers/leds/leds-lp5521.c | 8 +++++--- > 1 files changed, 5 insertions(+), 3 deletions(-) > > diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c > index b3ba52a..3e1ca31 100644 > --- a/drivers/leds/leds-lp5521.c > +++ b/drivers/leds/leds-lp5521.c > @@ -352,12 +352,14 @@ static ssize_t store_mode(struct device *dev, > > mutex_lock(&chip->lock); > > - if (!strncmp(buf, "run", 3)) > + if (sysfs_streq(buf, "run")) > lp5521_set_mode(chip, LP5521_MODE_RUN); > - else if (!strncmp(buf, "load", 4)) > + else if (sysfs_streq(buf, "load")) > lp5521_set_mode(chip, LP5521_MODE_LOAD); > - else if (!strncmp(buf, "direct", 6)) > + else if (sysfs_streq(buf, "direct")) > lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); > + else > + len = -EINVAL; > > mutex_unlock(&chip->lock); > > -- -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 5/6] leds: lp5521: move to drivers/leds 2009-02-13 23:54 ` David Brownell @ 2009-02-14 0:07 ` Felipe Balbi 0 siblings, 0 replies; 27+ messages in thread From: Felipe Balbi @ 2009-02-14 0:07 UTC (permalink / raw) To: David Brownell; +Cc: Felipe Balbi, linux-omap On Fri, 13 Feb 2009 15:54:20 -0800, David Brownell <david-b@pacbell.net> wrote: > On Friday 13 February 2009, Felipe Balbi wrote: >> From: Felipe Balbi <felipe.balbi@nokia.com> >> Date: Sat, 14 Feb 2009 00:34:56 +0200 >> Subject: [PATCH] leds: lp5521: use sysfs_streq() >> >> instead of using strcmp() for comparing strings, >> use sysfs_streq(). >> >> Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> > > Yes, just like that. Good, so we can apply these to l-o and I'll send the driver upstream after these patches are applied. Same for lm8323 > > >> --- >> drivers/leds/leds-lp5521.c | 8 +++++--- >> 1 files changed, 5 insertions(+), 3 deletions(-) >> >> diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c >> index b3ba52a..3e1ca31 100644 >> --- a/drivers/leds/leds-lp5521.c >> +++ b/drivers/leds/leds-lp5521.c >> @@ -352,12 +352,14 @@ static ssize_t store_mode(struct device *dev, >> >> mutex_lock(&chip->lock); >> >> - if (!strncmp(buf, "run", 3)) >> + if (sysfs_streq(buf, "run")) >> lp5521_set_mode(chip, LP5521_MODE_RUN); >> - else if (!strncmp(buf, "load", 4)) >> + else if (sysfs_streq(buf, "load")) >> lp5521_set_mode(chip, LP5521_MODE_LOAD); >> - else if (!strncmp(buf, "direct", 6)) >> + else if (sysfs_streq(buf, "direct")) >> lp5521_set_mode(chip, > LP5521_MODE_DIRECT_CONTROL); >> + else >> + len = -EINVAL; >> >> mutex_unlock(&chip->lock); >> >> -- -- Best Regards, Felipe Balbi http://blog.felipebalbi.com me@felipebalbi.com -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [RESEND] lp5521 patches 2009-02-13 12:43 ` [RESEND] lp5521 patches Felipe Balbi 2009-02-13 12:43 ` [PATCH 1/6] i2c: lp5521: remove dead code Felipe Balbi @ 2009-02-17 21:38 ` Otto Solares 2009-02-17 23:07 ` Felipe Balbi 1 sibling, 1 reply; 27+ messages in thread From: Otto Solares @ 2009-02-17 21:38 UTC (permalink / raw) To: Felipe Balbi; +Cc: linux-omap, David Brownell On Fri, Feb 13, 2009 at 02:43:46PM +0200, Felipe Balbi wrote: > Hi Dave, all > > could you look at the updated lp5521 patches ? > > Basically patches from 1 to 3 are the same. > Patch 4 has the fix you asked me to implement, getting > a label from pdata (then I also moved mode and the presence > of each individual led to pdata as well), patch 5 only moves > the file to drivers/leds and patch 6 is a new patch adding > pdata to board-n800.c > > After these, lp5521 should be ok for going upstream. > > Thanks for your time ;-) Hi Felipe, I don't see this patches on the l-o tree or am I missing something? -otto ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [RESEND] lp5521 patches 2009-02-17 21:38 ` [RESEND] lp5521 patches Otto Solares @ 2009-02-17 23:07 ` Felipe Balbi 2009-02-17 23:29 ` Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-17 23:07 UTC (permalink / raw) To: ext Otto Solares Cc: Balbi Felipe (Nokia-D/Helsinki), linux-omap, David Brownell [-- Attachment #1: Type: text/plain, Size: 888 bytes --] On Tue, Feb 17, 2009 at 10:38:19PM +0100, ext Otto Solares wrote: > On Fri, Feb 13, 2009 at 02:43:46PM +0200, Felipe Balbi wrote: > > Hi Dave, all > > > > could you look at the updated lp5521 patches ? > > > > Basically patches from 1 to 3 are the same. > > Patch 4 has the fix you asked me to implement, getting > > a label from pdata (then I also moved mode and the presence > > of each individual led to pdata as well), patch 5 only moves > > the file to drivers/leds and patch 6 is a new patch adding > > pdata to board-n800.c > > > > After these, lp5521 should be ok for going upstream. > > > > Thanks for your time ;-) > > Hi Felipe, > > I don't see this patches on the l-o tree or am I missing something? once again the didn't get applied. lp5521 is already in LED tree and we're gona have two forks of the same driver :-p Maybe, Tony, you could apply the attached. -- balbi [-- Attachment #2: 0001-i2c-chips-remove-lp5521-driver.patch --] [-- Type: text/x-diff, Size: 17040 bytes --] >From 66bf0442f949f4da02d5b4cae584cc7148f7b63c Mon Sep 17 00:00:00 2001 From: Felipe Balbi <me@felipebalbi.com> Date: Wed, 18 Feb 2009 01:17:28 +0200 Subject: [PATCH] i2c: chips: remove lp5521 driver It's now coming via LED tree so it should be safe to get rid of it here and wait till next mainline merge. Signed-off-by: Felipe Balbi <me@felipebalbi.com> --- drivers/i2c/chips/Kconfig | 7 - drivers/i2c/chips/Makefile | 1 - drivers/i2c/chips/lp5521.c | 585 -------------------------------------------- 3 files changed, 0 insertions(+), 593 deletions(-) delete mode 100644 drivers/i2c/chips/lp5521.c diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index bb95b3e..e4831e1 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -141,13 +141,6 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. -config LP5521 - tristate "LP5521 LED driver chip" - depends on I2C - help - If you say yes here you get support for the National Semiconductor - LP5521 LED driver. - config MENELAUS bool "TWL92330/Menelaus PM chip" depends on I2C=y && ARCH_OMAP24XX diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 32a395f..1c94712 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o obj-$(CONFIG_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_RTC_X1205_I2C) += x1205.o -obj-$(CONFIG_LP5521) += lp5521.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c deleted file mode 100644 index c0862d9..0000000 --- a/drivers/i2c/chips/lp5521.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * drivers/i2c/chips/lp5521.c - * - * Copyright (C) 2007 Nokia Corporation - * - * Written by Mathias Nyman <mathias.nyman@nokia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/i2c.h> -#include <linux/mutex.h> -#include <mach/gpio.h> - -#define LP5521_DRIVER_NAME "lp5521" - -#ifdef LED_CONNECTED_WRONG -#define LP5521_REG_R_PWM 0x04 -#define LP5521_REG_B_PWM 0x02 -#else -#define LP5521_REG_R_PWM 0x02 -#define LP5521_REG_B_PWM 0x04 -#endif -#define LP5521_REG_ENABLE 0x00 -#define LP5521_REG_OP_MODE 0x01 -#define LP5521_REG_G_PWM 0x03 -#define LP5521_REG_R_CNTRL 0x05 -#define LP5521_REG_G_CNTRL 0x06 -#define LP5521_REG_B_CNTRL 0x07 -#define LP5521_REG_MISC 0x08 -#define LP5521_REG_R_CHANNEL_PC 0x09 -#define LP5521_REG_G_CHANNEL_PC 0x0a -#define LP5521_REG_B_CHANNEL_PC 0x0b -#define LP5521_REG_STATUS 0x0c -#define LP5521_REG_RESET 0x0d -#define LP5521_REG_GPO 0x0e -#define LP5521_REG_R_PROG_MEM 0x10 -#define LP5521_REG_G_PROG_MEM 0x30 -#define LP5521_REG_B_PROG_MEM 0x50 - -#define LP5521_MODE_LOAD "load" -#define LP5521_MODE_RUN "run" -#define LP5521_MODE_DIRECT_CONTROL "direct" - -#define LP5521_CURRENT_1m5 0x0f -#define LP5521_CURRENT_3m1 0x1f -#define LP5521_CURRENT_4m7 0x2f -#define LP5521_CURRENT_6m3 0x3f -#define LP5521_CURRENT_7m9 0x4f -#define LP5521_CURRENT_9m5 0x5f -#define LP5521_CURRENT_11m1 0x6f -#define LP5521_CURRENT_12m7 0x7f -#define LP5521_CURRENT_14m3 0x8f -#define LP5521_CURRENT_15m9 0x9f -#define LP5521_CURRENT_17m5 0xaf -#define LP5521_CURRENT_19m1 0xbf -#define LP5521_CURRENT_20m7 0xcf -#define LP5521_CURRENT_22m3 0xdf -#define LP5521_CURRENT_23m9 0xef -#define LP5521_CURRENT_25m5 0xff - -#define LP5521_PROGRAM_LENGTH 32 /* in bytes */ - -struct lp5521_chip { - struct mutex lock; - struct i2c_client *client; - char *mode; - int red; - int green; - int blue; -}; - -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode); - -static int lp5521_write(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf) -{ - s32 ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) - return -EIO; - - *buf = ret; - return 0; -} - -static int lp5521_configure(struct i2c_client *client) -{ - int ret = 0; - - /* Enable chip and set light to logarithmic mode*/ - ret |= lp5521_write(client, LP5521_REG_ENABLE, 0xc0); - - /* setting all color pwms to direct control mode */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3f); - - /* setting current to 4.7 mA for all channels */ - ret |= lp5521_write(client, LP5521_REG_R_CNTRL, LP5521_CURRENT_4m7); - ret |= lp5521_write(client, LP5521_REG_G_CNTRL, LP5521_CURRENT_4m7); - ret |= lp5521_write(client, LP5521_REG_B_CNTRL, LP5521_CURRENT_4m7); - - /* Enable auto-powersave, set charge pump to auto, red to battery */ - ret |= lp5521_write(client, LP5521_REG_MISC, 0x3c); - - /* initialize all channels pwm to zero */ - ret |= lp5521_write(client, LP5521_REG_R_PWM, 0); - ret |= lp5521_write(client, LP5521_REG_G_PWM, 0); - ret |= lp5521_write(client, LP5521_REG_B_PWM, 0); - - /* Not much can be done about errors at this point */ - return ret; -} - -static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) -{ - struct i2c_client *client = chip->client; - int ret = 0; - - /* Enter load program mode for all led channels */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); /* 0001 0101 */ - if (ret) - return ret; - - if (chip->red) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_R_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - if (chip->green) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_G_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - if (chip->blue) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_B_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - - return ret; -} - -static int lp5521_run_program(struct lp5521_chip *chip) -{ - struct i2c_client *client = chip->client; - int ret; - u8 mask = 0xc0; - u8 exec_state = 0; - u8 enable_reg; - - ret = lp5521_read(client, LP5521_REG_ENABLE, &enable_reg); - if (ret) - goto fail; - - enable_reg &= mask; - - /* set all active channels exec state to countinous run*/ - exec_state |= (chip->red << 5); - exec_state |= (chip->green << 3); - exec_state |= (chip->blue << 1); - - enable_reg |= exec_state; - - ret |= lp5521_write(client, LP5521_REG_ENABLE, enable_reg); - - /* set op-mode to run for active channels, disabled for others */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, exec_state); - -fail: - return ret; -} - -/*--------------------------------------------------------------*/ -/* Sysfs interface */ -/*--------------------------------------------------------------*/ - -static ssize_t show_active_channels(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - char channels[4]; - int pos = 0; - -#ifdef LED_CONNECTED_WRONG - if (chip->blue) - pos += sprintf(channels + pos, "r"); - if (chip->green) - pos += sprintf(channels + pos, "g"); - if (chip->red) - pos += sprintf(channels + pos, "b"); - -#else - if (chip->red) - pos += sprintf(channels + pos, "r"); - if (chip->green) - pos += sprintf(channels + pos, "g"); - if (chip->blue) - pos += sprintf(channels + pos, "b"); -#endif - - channels[pos] = '\0'; - - return sprintf(buf, "%s\n", channels); -} - -static ssize_t store_active_channels(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - - chip->red = 0; - chip->green = 0; - chip->blue = 0; - -#ifdef LED_CONNECTED_WRONG - if (strchr(buf, 'r') != NULL) - chip->blue = 1; - if (strchr(buf, 'b') != NULL) - chip->red = 1; -#else - if (strchr(buf, 'r') != NULL) - chip->red = 1; - if (strchr(buf, 'b') != NULL) - chip->blue = 1; -#endif - if (strchr(buf, 'g') != NULL) - chip->green = 1; - - return len; -} - -static ssize_t show_color(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - int ret = 0; - u8 r, g, b; - - ret |= lp5521_read(client, LP5521_REG_R_PWM, &r); - ret |= lp5521_read(client, LP5521_REG_G_PWM, &g); - ret |= lp5521_read(client, LP5521_REG_B_PWM, &b); - - if (ret) - return ret; - - return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b); -} - -static ssize_t store_color(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5521_chip *chip = i2c_get_clientdata(client); - int ret; - unsigned r, g, b; - - - ret = sscanf(buf, "%2x:%2x:%2x", &r, &g, &b); - if (ret != 3) - return -EINVAL; - - mutex_lock(&chip->lock); - - ret = lp5521_write(client, LP5521_REG_R_PWM, (u8)r); - ret = lp5521_write(client, LP5521_REG_G_PWM, (u8)g); - ret = lp5521_write(client, LP5521_REG_B_PWM, (u8)b); - - mutex_unlock(&chip->lock); - - return len; -} - -static ssize_t store_load(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - int ret, nrchars, offset = 0, i = 0; - char c[3]; - unsigned cmd; - u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; - - while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { - - /* separate sscanfs because length is working only for %s */ - ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); - ret = sscanf(c, "%2x", &cmd); - if (ret != 1) - goto fail; - pattern[i] = (u8)cmd; - - offset += nrchars; - i++; - } - - /* pattern commands are always two bytes long */ - if (i % 2) - goto fail; - - mutex_lock(&chip->lock); - - ret = lp5521_load_program(chip, pattern); - mutex_unlock(&chip->lock); - - if (ret) { - dev_err(dev, "lp5521 failed loading pattern\n"); - return ret; - } - - return len; -fail: - dev_err(dev, "lp5521 wrong pattern format\n"); - return -EINVAL; -} - -static ssize_t show_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", chip->mode); -} - -static ssize_t store_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - - mutex_lock(&chip->lock); - - if (!strncmp(buf, "run", 3)) - lp5521_set_mode(chip, LP5521_MODE_RUN); - else if (!strncmp(buf, "load", 4)) - lp5521_set_mode(chip, LP5521_MODE_LOAD); - else if (!strncmp(buf, "direct", 6)) - lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); - - mutex_unlock(&chip->lock); - - return len; -} - -static ssize_t show_current(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - int ret = 0; - u8 r_curr, g_curr, b_curr; - - ret |= lp5521_read(client, LP5521_REG_R_CNTRL, &r_curr); - ret |= lp5521_read(client, LP5521_REG_G_CNTRL, &g_curr); - ret |= lp5521_read(client, LP5521_REG_B_CNTRL, &b_curr); - - if (ret) - return ret; - - r_curr = r_curr >> 4; - g_curr = g_curr >> 4; - b_curr = b_curr >> 4; - - if (r_curr == g_curr && g_curr == b_curr) - return sprintf(buf, "%x\n", r_curr); - else - return sprintf(buf, "%x %x %x\n", r_curr, g_curr, b_curr); -} - -static ssize_t store_current(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - struct i2c_client *client = chip->client; - int ret; - unsigned curr; - - ret = sscanf(buf, "%1x", &curr); - if (ret != 1) - return -EINVAL; - - /* current level is determined by the 4 upper bits, rest is ones */ - curr = (curr << 4) | 0x0f; - - mutex_lock(&chip->lock); - - ret |= lp5521_write(client, LP5521_REG_R_CNTRL, (u8)curr); - ret |= lp5521_write(client, LP5521_REG_G_CNTRL, (u8)curr); - ret |= lp5521_write(client, LP5521_REG_B_CNTRL, (u8)curr); - - mutex_unlock(&chip->lock); - - return len; -} - -static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color); -static DEVICE_ATTR(load, S_IWUGO, NULL, store_load); -static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode); -static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO, - show_active_channels, store_active_channels); -static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); - -static int lp5521_register_sysfs(struct i2c_client *client) -{ - struct device *dev = &client->dev; - int ret; - - ret = device_create_file(dev, &dev_attr_color); - if (ret) - goto fail1; - ret = device_create_file(dev, &dev_attr_load); - if (ret) - goto fail2; - ret = device_create_file(dev, &dev_attr_active_channels); - if (ret) - goto fail3; - ret = device_create_file(dev, &dev_attr_mode); - if (ret) - goto fail4; - ret = device_create_file(dev, &dev_attr_led_current); - if (ret) - goto fail5; - return 0; - -fail5: - device_remove_file(dev, &dev_attr_mode); -fail4: - device_remove_file(dev, &dev_attr_active_channels); -fail3: - device_remove_file(dev, &dev_attr_load); -fail2: - device_remove_file(dev, &dev_attr_color); -fail1: - return ret; -} - -static void lp5521_unregister_sysfs(struct i2c_client *client) -{ - struct lp5521_chip *chip = i2c_get_clientdata(client); - struct device *dev = &client->dev; - - device_remove_file(dev, &dev_attr_led_current); - device_remove_file(dev, &dev_attr_mode); - device_remove_file(dev, &dev_attr_active_channels); - device_remove_file(dev, &dev_attr_color); - - if (!strcmp(chip->mode, LP5521_MODE_LOAD)) - device_remove_file(dev, &dev_attr_load); -} - -/*--------------------------------------------------------------*/ -/* Set chip operating mode */ -/*--------------------------------------------------------------*/ - -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode) -{ - struct i2c_client *client = chip->client ; - int ret = 0; - - /* if in that mode already do nothing, except for run */ - if (!strcmp(mode, chip->mode) && strcmp(mode, LP5521_MODE_RUN)) - return 0; - - if (!strcmp(mode, LP5521_MODE_RUN)) - ret = lp5521_run_program(chip); - - if (!strcmp(mode, LP5521_MODE_LOAD)) - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); - - if (!strcmp(mode, LP5521_MODE_DIRECT_CONTROL)) - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); - - chip->mode = mode; - - return ret; -} - -/*--------------------------------------------------------------*/ -/* Probe, Attach, Remove */ -/*--------------------------------------------------------------*/ -static struct i2c_driver lp5521_driver; - -static int lp5521_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct lp5521_chip *chip; - int ret = 0; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->client = client; - strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE); - i2c_set_clientdata(client, chip); - - mutex_init(&chip->lock); - - ret = lp5521_configure(client); - if (ret < 0) { - dev_err(&client->dev, "lp5521 error configuring chip \n"); - goto fail1; - } - - /* Set default values */ - chip->mode = LP5521_MODE_DIRECT_CONTROL; - chip->red = 1; - chip->green = 1; - chip->blue = 1; - - ret = lp5521_register_sysfs(client); - if (ret) - dev_err(&client->dev, "lp5521 registering sysfs failed \n"); - - return ret; - -fail1: - kfree(chip); - return ret; -} - -static int lp5521_remove(struct i2c_client *client) -{ - struct lp5521_chip *chip = i2c_get_clientdata(client); - - lp5521_unregister_sysfs(client); - kfree(chip); - - return 0; -} - -static const struct i2c_device_id lp5521_id[] = { - { LP5521_DRIVER_NAME, 0}, - { }, -}; -MODULE_DEVICE_TABLE(i2c, lp5521_id); - -static struct i2c_driver lp5521_driver = { - .driver = { - .name = LP5521_DRIVER_NAME, - }, - .probe = lp5521_probe, - .remove = __devexit_p(lp5521_remove), - .id_table = lp5521_id, -}; - -static int __init lp5521_init(void) -{ - return i2c_add_driver(&lp5521_driver); -} - -static void __exit lp5521_exit(void) -{ - i2c_del_driver(&lp5521_driver); -} - -MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>"); -MODULE_DESCRIPTION("lp5521 LED driver"); -MODULE_LICENSE("GPL"); - -module_init(lp5521_init); -module_exit(lp5521_exit); -- 1.6.1.3 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [RESEND] lp5521 patches 2009-02-17 23:07 ` Felipe Balbi @ 2009-02-17 23:29 ` Felipe Balbi 2009-02-17 23:44 ` Tony Lindgren 0 siblings, 1 reply; 27+ messages in thread From: Felipe Balbi @ 2009-02-17 23:29 UTC (permalink / raw) To: Felipe Balbi; +Cc: ext Otto Solares, linux-omap, David Brownell On Wed, Feb 18, 2009 at 01:07:15AM +0200, Felipe Balbi wrote: > On Tue, Feb 17, 2009 at 10:38:19PM +0100, ext Otto Solares wrote: > > On Fri, Feb 13, 2009 at 02:43:46PM +0200, Felipe Balbi wrote: > > > Hi Dave, all > > > > > > could you look at the updated lp5521 patches ? > > > > > > Basically patches from 1 to 3 are the same. > > > Patch 4 has the fix you asked me to implement, getting > > > a label from pdata (then I also moved mode and the presence > > > of each individual led to pdata as well), patch 5 only moves > > > the file to drivers/leds and patch 6 is a new patch adding > > > pdata to board-n800.c > > > > > > After these, lp5521 should be ok for going upstream. > > > > > > Thanks for your time ;-) > > > > Hi Felipe, > > > > I don't see this patches on the l-o tree or am I missing something? > > once again the didn't get applied. lp5521 is already in LED tree and > we're gona have two forks of the same driver :-p > > Maybe, Tony, you could apply the attached. damn this new Nokia server is converting my tabs into spaces :-( here's again: ==== cut here ==== >From 66bf0442f949f4da02d5b4cae584cc7148f7b63c Mon Sep 17 00:00:00 2001 From: Felipe Balbi <me@felipebalbi.com> Date: Wed, 18 Feb 2009 01:17:28 +0200 Subject: [PATCH] i2c: chips: remove lp5521 driver It's now coming via LED tree so it should be safe to get rid of it here and wait till next mainline merge. Signed-off-by: Felipe Balbi <me@felipebalbi.com> --- drivers/i2c/chips/Kconfig | 7 - drivers/i2c/chips/Makefile | 1 - drivers/i2c/chips/lp5521.c | 585 -------------------------------------------- 3 files changed, 0 insertions(+), 593 deletions(-) delete mode 100644 drivers/i2c/chips/lp5521.c diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index bb95b3e..e4831e1 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -141,13 +141,6 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. -config LP5521 - tristate "LP5521 LED driver chip" - depends on I2C - help - If you say yes here you get support for the National Semiconductor - LP5521 LED driver. - config MENELAUS bool "TWL92330/Menelaus PM chip" depends on I2C=y && ARCH_OMAP24XX diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 32a395f..1c94712 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o obj-$(CONFIG_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_RTC_X1205_I2C) += x1205.o -obj-$(CONFIG_LP5521) += lp5521.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c deleted file mode 100644 index c0862d9..0000000 --- a/drivers/i2c/chips/lp5521.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * drivers/i2c/chips/lp5521.c - * - * Copyright (C) 2007 Nokia Corporation - * - * Written by Mathias Nyman <mathias.nyman@nokia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/i2c.h> -#include <linux/mutex.h> -#include <mach/gpio.h> - -#define LP5521_DRIVER_NAME "lp5521" - -#ifdef LED_CONNECTED_WRONG -#define LP5521_REG_R_PWM 0x04 -#define LP5521_REG_B_PWM 0x02 -#else -#define LP5521_REG_R_PWM 0x02 -#define LP5521_REG_B_PWM 0x04 -#endif -#define LP5521_REG_ENABLE 0x00 -#define LP5521_REG_OP_MODE 0x01 -#define LP5521_REG_G_PWM 0x03 -#define LP5521_REG_R_CNTRL 0x05 -#define LP5521_REG_G_CNTRL 0x06 -#define LP5521_REG_B_CNTRL 0x07 -#define LP5521_REG_MISC 0x08 -#define LP5521_REG_R_CHANNEL_PC 0x09 -#define LP5521_REG_G_CHANNEL_PC 0x0a -#define LP5521_REG_B_CHANNEL_PC 0x0b -#define LP5521_REG_STATUS 0x0c -#define LP5521_REG_RESET 0x0d -#define LP5521_REG_GPO 0x0e -#define LP5521_REG_R_PROG_MEM 0x10 -#define LP5521_REG_G_PROG_MEM 0x30 -#define LP5521_REG_B_PROG_MEM 0x50 - -#define LP5521_MODE_LOAD "load" -#define LP5521_MODE_RUN "run" -#define LP5521_MODE_DIRECT_CONTROL "direct" - -#define LP5521_CURRENT_1m5 0x0f -#define LP5521_CURRENT_3m1 0x1f -#define LP5521_CURRENT_4m7 0x2f -#define LP5521_CURRENT_6m3 0x3f -#define LP5521_CURRENT_7m9 0x4f -#define LP5521_CURRENT_9m5 0x5f -#define LP5521_CURRENT_11m1 0x6f -#define LP5521_CURRENT_12m7 0x7f -#define LP5521_CURRENT_14m3 0x8f -#define LP5521_CURRENT_15m9 0x9f -#define LP5521_CURRENT_17m5 0xaf -#define LP5521_CURRENT_19m1 0xbf -#define LP5521_CURRENT_20m7 0xcf -#define LP5521_CURRENT_22m3 0xdf -#define LP5521_CURRENT_23m9 0xef -#define LP5521_CURRENT_25m5 0xff - -#define LP5521_PROGRAM_LENGTH 32 /* in bytes */ - -struct lp5521_chip { - struct mutex lock; - struct i2c_client *client; - char *mode; - int red; - int green; - int blue; -}; - -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode); - -static int lp5521_write(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf) -{ - s32 ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) - return -EIO; - - *buf = ret; - return 0; -} - -static int lp5521_configure(struct i2c_client *client) -{ - int ret = 0; - - /* Enable chip and set light to logarithmic mode*/ - ret |= lp5521_write(client, LP5521_REG_ENABLE, 0xc0); - - /* setting all color pwms to direct control mode */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3f); - - /* setting current to 4.7 mA for all channels */ - ret |= lp5521_write(client, LP5521_REG_R_CNTRL, LP5521_CURRENT_4m7); - ret |= lp5521_write(client, LP5521_REG_G_CNTRL, LP5521_CURRENT_4m7); - ret |= lp5521_write(client, LP5521_REG_B_CNTRL, LP5521_CURRENT_4m7); - - /* Enable auto-powersave, set charge pump to auto, red to battery */ - ret |= lp5521_write(client, LP5521_REG_MISC, 0x3c); - - /* initialize all channels pwm to zero */ - ret |= lp5521_write(client, LP5521_REG_R_PWM, 0); - ret |= lp5521_write(client, LP5521_REG_G_PWM, 0); - ret |= lp5521_write(client, LP5521_REG_B_PWM, 0); - - /* Not much can be done about errors at this point */ - return ret; -} - -static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) -{ - struct i2c_client *client = chip->client; - int ret = 0; - - /* Enter load program mode for all led channels */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); /* 0001 0101 */ - if (ret) - return ret; - - if (chip->red) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_R_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - if (chip->green) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_G_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - if (chip->blue) - ret |= i2c_smbus_write_i2c_block_data(client, - LP5521_REG_B_PROG_MEM, - LP5521_PROGRAM_LENGTH, - pattern); - - return ret; -} - -static int lp5521_run_program(struct lp5521_chip *chip) -{ - struct i2c_client *client = chip->client; - int ret; - u8 mask = 0xc0; - u8 exec_state = 0; - u8 enable_reg; - - ret = lp5521_read(client, LP5521_REG_ENABLE, &enable_reg); - if (ret) - goto fail; - - enable_reg &= mask; - - /* set all active channels exec state to countinous run*/ - exec_state |= (chip->red << 5); - exec_state |= (chip->green << 3); - exec_state |= (chip->blue << 1); - - enable_reg |= exec_state; - - ret |= lp5521_write(client, LP5521_REG_ENABLE, enable_reg); - - /* set op-mode to run for active channels, disabled for others */ - ret |= lp5521_write(client, LP5521_REG_OP_MODE, exec_state); - -fail: - return ret; -} - -/*--------------------------------------------------------------*/ -/* Sysfs interface */ -/*--------------------------------------------------------------*/ - -static ssize_t show_active_channels(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - char channels[4]; - int pos = 0; - -#ifdef LED_CONNECTED_WRONG - if (chip->blue) - pos += sprintf(channels + pos, "r"); - if (chip->green) - pos += sprintf(channels + pos, "g"); - if (chip->red) - pos += sprintf(channels + pos, "b"); - -#else - if (chip->red) - pos += sprintf(channels + pos, "r"); - if (chip->green) - pos += sprintf(channels + pos, "g"); - if (chip->blue) - pos += sprintf(channels + pos, "b"); -#endif - - channels[pos] = '\0'; - - return sprintf(buf, "%s\n", channels); -} - -static ssize_t store_active_channels(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - - chip->red = 0; - chip->green = 0; - chip->blue = 0; - -#ifdef LED_CONNECTED_WRONG - if (strchr(buf, 'r') != NULL) - chip->blue = 1; - if (strchr(buf, 'b') != NULL) - chip->red = 1; -#else - if (strchr(buf, 'r') != NULL) - chip->red = 1; - if (strchr(buf, 'b') != NULL) - chip->blue = 1; -#endif - if (strchr(buf, 'g') != NULL) - chip->green = 1; - - return len; -} - -static ssize_t show_color(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - int ret = 0; - u8 r, g, b; - - ret |= lp5521_read(client, LP5521_REG_R_PWM, &r); - ret |= lp5521_read(client, LP5521_REG_G_PWM, &g); - ret |= lp5521_read(client, LP5521_REG_B_PWM, &b); - - if (ret) - return ret; - - return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b); -} - -static ssize_t store_color(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5521_chip *chip = i2c_get_clientdata(client); - int ret; - unsigned r, g, b; - - - ret = sscanf(buf, "%2x:%2x:%2x", &r, &g, &b); - if (ret != 3) - return -EINVAL; - - mutex_lock(&chip->lock); - - ret = lp5521_write(client, LP5521_REG_R_PWM, (u8)r); - ret = lp5521_write(client, LP5521_REG_G_PWM, (u8)g); - ret = lp5521_write(client, LP5521_REG_B_PWM, (u8)b); - - mutex_unlock(&chip->lock); - - return len; -} - -static ssize_t store_load(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - int ret, nrchars, offset = 0, i = 0; - char c[3]; - unsigned cmd; - u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; - - while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { - - /* separate sscanfs because length is working only for %s */ - ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); - ret = sscanf(c, "%2x", &cmd); - if (ret != 1) - goto fail; - pattern[i] = (u8)cmd; - - offset += nrchars; - i++; - } - - /* pattern commands are always two bytes long */ - if (i % 2) - goto fail; - - mutex_lock(&chip->lock); - - ret = lp5521_load_program(chip, pattern); - mutex_unlock(&chip->lock); - - if (ret) { - dev_err(dev, "lp5521 failed loading pattern\n"); - return ret; - } - - return len; -fail: - dev_err(dev, "lp5521 wrong pattern format\n"); - return -EINVAL; -} - -static ssize_t show_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", chip->mode); -} - -static ssize_t store_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - - mutex_lock(&chip->lock); - - if (!strncmp(buf, "run", 3)) - lp5521_set_mode(chip, LP5521_MODE_RUN); - else if (!strncmp(buf, "load", 4)) - lp5521_set_mode(chip, LP5521_MODE_LOAD); - else if (!strncmp(buf, "direct", 6)) - lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); - - mutex_unlock(&chip->lock); - - return len; -} - -static ssize_t show_current(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - int ret = 0; - u8 r_curr, g_curr, b_curr; - - ret |= lp5521_read(client, LP5521_REG_R_CNTRL, &r_curr); - ret |= lp5521_read(client, LP5521_REG_G_CNTRL, &g_curr); - ret |= lp5521_read(client, LP5521_REG_B_CNTRL, &b_curr); - - if (ret) - return ret; - - r_curr = r_curr >> 4; - g_curr = g_curr >> 4; - b_curr = b_curr >> 4; - - if (r_curr == g_curr && g_curr == b_curr) - return sprintf(buf, "%x\n", r_curr); - else - return sprintf(buf, "%x %x %x\n", r_curr, g_curr, b_curr); -} - -static ssize_t store_current(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = dev_get_drvdata(dev); - struct i2c_client *client = chip->client; - int ret; - unsigned curr; - - ret = sscanf(buf, "%1x", &curr); - if (ret != 1) - return -EINVAL; - - /* current level is determined by the 4 upper bits, rest is ones */ - curr = (curr << 4) | 0x0f; - - mutex_lock(&chip->lock); - - ret |= lp5521_write(client, LP5521_REG_R_CNTRL, (u8)curr); - ret |= lp5521_write(client, LP5521_REG_G_CNTRL, (u8)curr); - ret |= lp5521_write(client, LP5521_REG_B_CNTRL, (u8)curr); - - mutex_unlock(&chip->lock); - - return len; -} - -static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color); -static DEVICE_ATTR(load, S_IWUGO, NULL, store_load); -static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode); -static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO, - show_active_channels, store_active_channels); -static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); - -static int lp5521_register_sysfs(struct i2c_client *client) -{ - struct device *dev = &client->dev; - int ret; - - ret = device_create_file(dev, &dev_attr_color); - if (ret) - goto fail1; - ret = device_create_file(dev, &dev_attr_load); - if (ret) - goto fail2; - ret = device_create_file(dev, &dev_attr_active_channels); - if (ret) - goto fail3; - ret = device_create_file(dev, &dev_attr_mode); - if (ret) - goto fail4; - ret = device_create_file(dev, &dev_attr_led_current); - if (ret) - goto fail5; - return 0; - -fail5: - device_remove_file(dev, &dev_attr_mode); -fail4: - device_remove_file(dev, &dev_attr_active_channels); -fail3: - device_remove_file(dev, &dev_attr_load); -fail2: - device_remove_file(dev, &dev_attr_color); -fail1: - return ret; -} - -static void lp5521_unregister_sysfs(struct i2c_client *client) -{ - struct lp5521_chip *chip = i2c_get_clientdata(client); - struct device *dev = &client->dev; - - device_remove_file(dev, &dev_attr_led_current); - device_remove_file(dev, &dev_attr_mode); - device_remove_file(dev, &dev_attr_active_channels); - device_remove_file(dev, &dev_attr_color); - - if (!strcmp(chip->mode, LP5521_MODE_LOAD)) - device_remove_file(dev, &dev_attr_load); -} - -/*--------------------------------------------------------------*/ -/* Set chip operating mode */ -/*--------------------------------------------------------------*/ - -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode) -{ - struct i2c_client *client = chip->client ; - int ret = 0; - - /* if in that mode already do nothing, except for run */ - if (!strcmp(mode, chip->mode) && strcmp(mode, LP5521_MODE_RUN)) - return 0; - - if (!strcmp(mode, LP5521_MODE_RUN)) - ret = lp5521_run_program(chip); - - if (!strcmp(mode, LP5521_MODE_LOAD)) - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); - - if (!strcmp(mode, LP5521_MODE_DIRECT_CONTROL)) - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); - - chip->mode = mode; - - return ret; -} - -/*--------------------------------------------------------------*/ -/* Probe, Attach, Remove */ -/*--------------------------------------------------------------*/ -static struct i2c_driver lp5521_driver; - -static int lp5521_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct lp5521_chip *chip; - int ret = 0; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->client = client; - strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE); - i2c_set_clientdata(client, chip); - - mutex_init(&chip->lock); - - ret = lp5521_configure(client); - if (ret < 0) { - dev_err(&client->dev, "lp5521 error configuring chip \n"); - goto fail1; - } - - /* Set default values */ - chip->mode = LP5521_MODE_DIRECT_CONTROL; - chip->red = 1; - chip->green = 1; - chip->blue = 1; - - ret = lp5521_register_sysfs(client); - if (ret) - dev_err(&client->dev, "lp5521 registering sysfs failed \n"); - - return ret; - -fail1: - kfree(chip); - return ret; -} - -static int lp5521_remove(struct i2c_client *client) -{ - struct lp5521_chip *chip = i2c_get_clientdata(client); - - lp5521_unregister_sysfs(client); - kfree(chip); - - return 0; -} - -static const struct i2c_device_id lp5521_id[] = { - { LP5521_DRIVER_NAME, 0}, - { }, -}; -MODULE_DEVICE_TABLE(i2c, lp5521_id); - -static struct i2c_driver lp5521_driver = { - .driver = { - .name = LP5521_DRIVER_NAME, - }, - .probe = lp5521_probe, - .remove = __devexit_p(lp5521_remove), - .id_table = lp5521_id, -}; - -static int __init lp5521_init(void) -{ - return i2c_add_driver(&lp5521_driver); -} - -static void __exit lp5521_exit(void) -{ - i2c_del_driver(&lp5521_driver); -} - -MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>"); -MODULE_DESCRIPTION("lp5521 LED driver"); -MODULE_LICENSE("GPL"); - -module_init(lp5521_init); -module_exit(lp5521_exit); -- 1.6.1.3 -- balbi ^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [RESEND] lp5521 patches 2009-02-17 23:29 ` Felipe Balbi @ 2009-02-17 23:44 ` Tony Lindgren 2009-02-17 23:50 ` Felipe Balbi 0 siblings, 1 reply; 27+ messages in thread From: Tony Lindgren @ 2009-02-17 23:44 UTC (permalink / raw) To: Felipe Balbi; +Cc: Felipe Balbi, ext Otto Solares, linux-omap, David Brownell * Felipe Balbi <me@felipebalbi.com> [090217 15:30]: > On Wed, Feb 18, 2009 at 01:07:15AM +0200, Felipe Balbi wrote: > > On Tue, Feb 17, 2009 at 10:38:19PM +0100, ext Otto Solares wrote: > > > On Fri, Feb 13, 2009 at 02:43:46PM +0200, Felipe Balbi wrote: > > > > Hi Dave, all > > > > > > > > could you look at the updated lp5521 patches ? > > > > > > > > Basically patches from 1 to 3 are the same. > > > > Patch 4 has the fix you asked me to implement, getting > > > > a label from pdata (then I also moved mode and the presence > > > > of each individual led to pdata as well), patch 5 only moves > > > > the file to drivers/leds and patch 6 is a new patch adding > > > > pdata to board-n800.c > > > > > > > > After these, lp5521 should be ok for going upstream. > > > > > > > > Thanks for your time ;-) > > > > > > Hi Felipe, > > > > > > I don't see this patches on the l-o tree or am I missing something? > > > > once again the didn't get applied. lp5521 is already in LED tree and > > we're gona have two forks of the same driver :-p Just pushed your earlier series.. > > Maybe, Tony, you could apply the attached. So I guess this is no longer needed. I'll reset drives/leds to mainline at some point soonish. > damn this new Nokia server is converting my tabs into spaces :-( Also seems to encode them quoted-printable too :( Regards, Tony > here's again: > > ==== cut here ==== > From 66bf0442f949f4da02d5b4cae584cc7148f7b63c Mon Sep 17 00:00:00 2001 > From: Felipe Balbi <me@felipebalbi.com> > Date: Wed, 18 Feb 2009 01:17:28 +0200 > Subject: [PATCH] i2c: chips: remove lp5521 driver > > It's now coming via LED tree so it should be > safe to get rid of it here and wait till next > mainline merge. > Signed-off-by: Felipe Balbi <me@felipebalbi.com> > --- > drivers/i2c/chips/Kconfig | 7 - > drivers/i2c/chips/Makefile | 1 - > drivers/i2c/chips/lp5521.c | 585 -------------------------------------------- > 3 files changed, 0 insertions(+), 593 deletions(-) > delete mode 100644 drivers/i2c/chips/lp5521.c > > diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig > index bb95b3e..e4831e1 100644 > --- a/drivers/i2c/chips/Kconfig > +++ b/drivers/i2c/chips/Kconfig > @@ -141,13 +141,6 @@ config SENSORS_TSL2563 > This driver can also be built as a module. If so, the module > will be called tsl2563. > > -config LP5521 > - tristate "LP5521 LED driver chip" > - depends on I2C > - help > - If you say yes here you get support for the National Semiconductor > - LP5521 LED driver. > - > config MENELAUS > bool "TWL92330/Menelaus PM chip" > depends on I2C=y && ARCH_OMAP24XX > diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile > index 32a395f..1c94712 100644 > --- a/drivers/i2c/chips/Makefile > +++ b/drivers/i2c/chips/Makefile > @@ -21,7 +21,6 @@ obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o > obj-$(CONFIG_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o > obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o > obj-$(CONFIG_RTC_X1205_I2C) += x1205.o > -obj-$(CONFIG_LP5521) += lp5521.o > > ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) > EXTRA_CFLAGS += -DDEBUG > diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c > deleted file mode 100644 > index c0862d9..0000000 > --- a/drivers/i2c/chips/lp5521.c > +++ /dev/null > @@ -1,585 +0,0 @@ > -/* > - * drivers/i2c/chips/lp5521.c > - * > - * Copyright (C) 2007 Nokia Corporation > - * > - * Written by Mathias Nyman <mathias.nyman@nokia.com> > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation; either version 2 of the License, or > - * (at your option) any later version. > - * > - * 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. > - * > - * You should have received a copy of the GNU General Public License > - * along with this program; if not, write to the Free Software > - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > - */ > - > -#include <linux/module.h> > -#include <linux/init.h> > -#include <linux/i2c.h> > -#include <linux/mutex.h> > -#include <mach/gpio.h> > - > -#define LP5521_DRIVER_NAME "lp5521" > - > -#ifdef LED_CONNECTED_WRONG > -#define LP5521_REG_R_PWM 0x04 > -#define LP5521_REG_B_PWM 0x02 > -#else > -#define LP5521_REG_R_PWM 0x02 > -#define LP5521_REG_B_PWM 0x04 > -#endif > -#define LP5521_REG_ENABLE 0x00 > -#define LP5521_REG_OP_MODE 0x01 > -#define LP5521_REG_G_PWM 0x03 > -#define LP5521_REG_R_CNTRL 0x05 > -#define LP5521_REG_G_CNTRL 0x06 > -#define LP5521_REG_B_CNTRL 0x07 > -#define LP5521_REG_MISC 0x08 > -#define LP5521_REG_R_CHANNEL_PC 0x09 > -#define LP5521_REG_G_CHANNEL_PC 0x0a > -#define LP5521_REG_B_CHANNEL_PC 0x0b > -#define LP5521_REG_STATUS 0x0c > -#define LP5521_REG_RESET 0x0d > -#define LP5521_REG_GPO 0x0e > -#define LP5521_REG_R_PROG_MEM 0x10 > -#define LP5521_REG_G_PROG_MEM 0x30 > -#define LP5521_REG_B_PROG_MEM 0x50 > - > -#define LP5521_MODE_LOAD "load" > -#define LP5521_MODE_RUN "run" > -#define LP5521_MODE_DIRECT_CONTROL "direct" > - > -#define LP5521_CURRENT_1m5 0x0f > -#define LP5521_CURRENT_3m1 0x1f > -#define LP5521_CURRENT_4m7 0x2f > -#define LP5521_CURRENT_6m3 0x3f > -#define LP5521_CURRENT_7m9 0x4f > -#define LP5521_CURRENT_9m5 0x5f > -#define LP5521_CURRENT_11m1 0x6f > -#define LP5521_CURRENT_12m7 0x7f > -#define LP5521_CURRENT_14m3 0x8f > -#define LP5521_CURRENT_15m9 0x9f > -#define LP5521_CURRENT_17m5 0xaf > -#define LP5521_CURRENT_19m1 0xbf > -#define LP5521_CURRENT_20m7 0xcf > -#define LP5521_CURRENT_22m3 0xdf > -#define LP5521_CURRENT_23m9 0xef > -#define LP5521_CURRENT_25m5 0xff > - > -#define LP5521_PROGRAM_LENGTH 32 /* in bytes */ > - > -struct lp5521_chip { > - struct mutex lock; > - struct i2c_client *client; > - char *mode; > - int red; > - int green; > - int blue; > -}; > - > -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode); > - > -static int lp5521_write(struct i2c_client *client, u8 reg, u8 value) > -{ > - return i2c_smbus_write_byte_data(client, reg, value); > -} > - > -static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf) > -{ > - s32 ret = i2c_smbus_read_byte_data(client, reg); > - > - if (ret < 0) > - return -EIO; > - > - *buf = ret; > - return 0; > -} > - > -static int lp5521_configure(struct i2c_client *client) > -{ > - int ret = 0; > - > - /* Enable chip and set light to logarithmic mode*/ > - ret |= lp5521_write(client, LP5521_REG_ENABLE, 0xc0); > - > - /* setting all color pwms to direct control mode */ > - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3f); > - > - /* setting current to 4.7 mA for all channels */ > - ret |= lp5521_write(client, LP5521_REG_R_CNTRL, LP5521_CURRENT_4m7); > - ret |= lp5521_write(client, LP5521_REG_G_CNTRL, LP5521_CURRENT_4m7); > - ret |= lp5521_write(client, LP5521_REG_B_CNTRL, LP5521_CURRENT_4m7); > - > - /* Enable auto-powersave, set charge pump to auto, red to battery */ > - ret |= lp5521_write(client, LP5521_REG_MISC, 0x3c); > - > - /* initialize all channels pwm to zero */ > - ret |= lp5521_write(client, LP5521_REG_R_PWM, 0); > - ret |= lp5521_write(client, LP5521_REG_G_PWM, 0); > - ret |= lp5521_write(client, LP5521_REG_B_PWM, 0); > - > - /* Not much can be done about errors at this point */ > - return ret; > -} > - > -static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern) > -{ > - struct i2c_client *client = chip->client; > - int ret = 0; > - > - /* Enter load program mode for all led channels */ > - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); /* 0001 0101 */ > - if (ret) > - return ret; > - > - if (chip->red) > - ret |= i2c_smbus_write_i2c_block_data(client, > - LP5521_REG_R_PROG_MEM, > - LP5521_PROGRAM_LENGTH, > - pattern); > - if (chip->green) > - ret |= i2c_smbus_write_i2c_block_data(client, > - LP5521_REG_G_PROG_MEM, > - LP5521_PROGRAM_LENGTH, > - pattern); > - if (chip->blue) > - ret |= i2c_smbus_write_i2c_block_data(client, > - LP5521_REG_B_PROG_MEM, > - LP5521_PROGRAM_LENGTH, > - pattern); > - > - return ret; > -} > - > -static int lp5521_run_program(struct lp5521_chip *chip) > -{ > - struct i2c_client *client = chip->client; > - int ret; > - u8 mask = 0xc0; > - u8 exec_state = 0; > - u8 enable_reg; > - > - ret = lp5521_read(client, LP5521_REG_ENABLE, &enable_reg); > - if (ret) > - goto fail; > - > - enable_reg &= mask; > - > - /* set all active channels exec state to countinous run*/ > - exec_state |= (chip->red << 5); > - exec_state |= (chip->green << 3); > - exec_state |= (chip->blue << 1); > - > - enable_reg |= exec_state; > - > - ret |= lp5521_write(client, LP5521_REG_ENABLE, enable_reg); > - > - /* set op-mode to run for active channels, disabled for others */ > - ret |= lp5521_write(client, LP5521_REG_OP_MODE, exec_state); > - > -fail: > - return ret; > -} > - > -/*--------------------------------------------------------------*/ > -/* Sysfs interface */ > -/*--------------------------------------------------------------*/ > - > -static ssize_t show_active_channels(struct device *dev, > - struct device_attribute *attr, > - char *buf) > -{ > - struct lp5521_chip *chip = dev_get_drvdata(dev); > - char channels[4]; > - int pos = 0; > - > -#ifdef LED_CONNECTED_WRONG > - if (chip->blue) > - pos += sprintf(channels + pos, "r"); > - if (chip->green) > - pos += sprintf(channels + pos, "g"); > - if (chip->red) > - pos += sprintf(channels + pos, "b"); > - > -#else > - if (chip->red) > - pos += sprintf(channels + pos, "r"); > - if (chip->green) > - pos += sprintf(channels + pos, "g"); > - if (chip->blue) > - pos += sprintf(channels + pos, "b"); > -#endif > - > - channels[pos] = '\0'; > - > - return sprintf(buf, "%s\n", channels); > -} > - > -static ssize_t store_active_channels(struct device *dev, > - struct device_attribute *attr, > - const char *buf, size_t len) > -{ > - struct lp5521_chip *chip = dev_get_drvdata(dev); > - > - chip->red = 0; > - chip->green = 0; > - chip->blue = 0; > - > -#ifdef LED_CONNECTED_WRONG > - if (strchr(buf, 'r') != NULL) > - chip->blue = 1; > - if (strchr(buf, 'b') != NULL) > - chip->red = 1; > -#else > - if (strchr(buf, 'r') != NULL) > - chip->red = 1; > - if (strchr(buf, 'b') != NULL) > - chip->blue = 1; > -#endif > - if (strchr(buf, 'g') != NULL) > - chip->green = 1; > - > - return len; > -} > - > -static ssize_t show_color(struct device *dev, > - struct device_attribute *attr, > - char *buf) > -{ > - struct i2c_client *client = to_i2c_client(dev); > - int ret = 0; > - u8 r, g, b; > - > - ret |= lp5521_read(client, LP5521_REG_R_PWM, &r); > - ret |= lp5521_read(client, LP5521_REG_G_PWM, &g); > - ret |= lp5521_read(client, LP5521_REG_B_PWM, &b); > - > - if (ret) > - return ret; > - > - return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b); > -} > - > -static ssize_t store_color(struct device *dev, > - struct device_attribute *attr, > - const char *buf, size_t len) > -{ > - struct i2c_client *client = to_i2c_client(dev); > - struct lp5521_chip *chip = i2c_get_clientdata(client); > - int ret; > - unsigned r, g, b; > - > - > - ret = sscanf(buf, "%2x:%2x:%2x", &r, &g, &b); > - if (ret != 3) > - return -EINVAL; > - > - mutex_lock(&chip->lock); > - > - ret = lp5521_write(client, LP5521_REG_R_PWM, (u8)r); > - ret = lp5521_write(client, LP5521_REG_G_PWM, (u8)g); > - ret = lp5521_write(client, LP5521_REG_B_PWM, (u8)b); > - > - mutex_unlock(&chip->lock); > - > - return len; > -} > - > -static ssize_t store_load(struct device *dev, > - struct device_attribute *attr, > - const char *buf, size_t len) > -{ > - struct lp5521_chip *chip = dev_get_drvdata(dev); > - int ret, nrchars, offset = 0, i = 0; > - char c[3]; > - unsigned cmd; > - u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; > - > - while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { > - > - /* separate sscanfs because length is working only for %s */ > - ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); > - ret = sscanf(c, "%2x", &cmd); > - if (ret != 1) > - goto fail; > - pattern[i] = (u8)cmd; > - > - offset += nrchars; > - i++; > - } > - > - /* pattern commands are always two bytes long */ > - if (i % 2) > - goto fail; > - > - mutex_lock(&chip->lock); > - > - ret = lp5521_load_program(chip, pattern); > - mutex_unlock(&chip->lock); > - > - if (ret) { > - dev_err(dev, "lp5521 failed loading pattern\n"); > - return ret; > - } > - > - return len; > -fail: > - dev_err(dev, "lp5521 wrong pattern format\n"); > - return -EINVAL; > -} > - > -static ssize_t show_mode(struct device *dev, > - struct device_attribute *attr, > - char *buf) > -{ > - struct lp5521_chip *chip = dev_get_drvdata(dev); > - > - return sprintf(buf, "%s\n", chip->mode); > -} > - > -static ssize_t store_mode(struct device *dev, > - struct device_attribute *attr, > - const char *buf, size_t len) > -{ > - struct lp5521_chip *chip = dev_get_drvdata(dev); > - > - mutex_lock(&chip->lock); > - > - if (!strncmp(buf, "run", 3)) > - lp5521_set_mode(chip, LP5521_MODE_RUN); > - else if (!strncmp(buf, "load", 4)) > - lp5521_set_mode(chip, LP5521_MODE_LOAD); > - else if (!strncmp(buf, "direct", 6)) > - lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL); > - > - mutex_unlock(&chip->lock); > - > - return len; > -} > - > -static ssize_t show_current(struct device *dev, > - struct device_attribute *attr, > - char *buf) > -{ > - struct i2c_client *client = to_i2c_client(dev); > - int ret = 0; > - u8 r_curr, g_curr, b_curr; > - > - ret |= lp5521_read(client, LP5521_REG_R_CNTRL, &r_curr); > - ret |= lp5521_read(client, LP5521_REG_G_CNTRL, &g_curr); > - ret |= lp5521_read(client, LP5521_REG_B_CNTRL, &b_curr); > - > - if (ret) > - return ret; > - > - r_curr = r_curr >> 4; > - g_curr = g_curr >> 4; > - b_curr = b_curr >> 4; > - > - if (r_curr == g_curr && g_curr == b_curr) > - return sprintf(buf, "%x\n", r_curr); > - else > - return sprintf(buf, "%x %x %x\n", r_curr, g_curr, b_curr); > -} > - > -static ssize_t store_current(struct device *dev, > - struct device_attribute *attr, > - const char *buf, size_t len) > -{ > - struct lp5521_chip *chip = dev_get_drvdata(dev); > - struct i2c_client *client = chip->client; > - int ret; > - unsigned curr; > - > - ret = sscanf(buf, "%1x", &curr); > - if (ret != 1) > - return -EINVAL; > - > - /* current level is determined by the 4 upper bits, rest is ones */ > - curr = (curr << 4) | 0x0f; > - > - mutex_lock(&chip->lock); > - > - ret |= lp5521_write(client, LP5521_REG_R_CNTRL, (u8)curr); > - ret |= lp5521_write(client, LP5521_REG_G_CNTRL, (u8)curr); > - ret |= lp5521_write(client, LP5521_REG_B_CNTRL, (u8)curr); > - > - mutex_unlock(&chip->lock); > - > - return len; > -} > - > -static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color); > -static DEVICE_ATTR(load, S_IWUGO, NULL, store_load); > -static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode); > -static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO, > - show_active_channels, store_active_channels); > -static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); > - > -static int lp5521_register_sysfs(struct i2c_client *client) > -{ > - struct device *dev = &client->dev; > - int ret; > - > - ret = device_create_file(dev, &dev_attr_color); > - if (ret) > - goto fail1; > - ret = device_create_file(dev, &dev_attr_load); > - if (ret) > - goto fail2; > - ret = device_create_file(dev, &dev_attr_active_channels); > - if (ret) > - goto fail3; > - ret = device_create_file(dev, &dev_attr_mode); > - if (ret) > - goto fail4; > - ret = device_create_file(dev, &dev_attr_led_current); > - if (ret) > - goto fail5; > - return 0; > - > -fail5: > - device_remove_file(dev, &dev_attr_mode); > -fail4: > - device_remove_file(dev, &dev_attr_active_channels); > -fail3: > - device_remove_file(dev, &dev_attr_load); > -fail2: > - device_remove_file(dev, &dev_attr_color); > -fail1: > - return ret; > -} > - > -static void lp5521_unregister_sysfs(struct i2c_client *client) > -{ > - struct lp5521_chip *chip = i2c_get_clientdata(client); > - struct device *dev = &client->dev; > - > - device_remove_file(dev, &dev_attr_led_current); > - device_remove_file(dev, &dev_attr_mode); > - device_remove_file(dev, &dev_attr_active_channels); > - device_remove_file(dev, &dev_attr_color); > - > - if (!strcmp(chip->mode, LP5521_MODE_LOAD)) > - device_remove_file(dev, &dev_attr_load); > -} > - > -/*--------------------------------------------------------------*/ > -/* Set chip operating mode */ > -/*--------------------------------------------------------------*/ > - > -static int lp5521_set_mode(struct lp5521_chip *chip, char *mode) > -{ > - struct i2c_client *client = chip->client ; > - int ret = 0; > - > - /* if in that mode already do nothing, except for run */ > - if (!strcmp(mode, chip->mode) && strcmp(mode, LP5521_MODE_RUN)) > - return 0; > - > - if (!strcmp(mode, LP5521_MODE_RUN)) > - ret = lp5521_run_program(chip); > - > - if (!strcmp(mode, LP5521_MODE_LOAD)) > - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); > - > - if (!strcmp(mode, LP5521_MODE_DIRECT_CONTROL)) > - ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); > - > - chip->mode = mode; > - > - return ret; > -} > - > -/*--------------------------------------------------------------*/ > -/* Probe, Attach, Remove */ > -/*--------------------------------------------------------------*/ > -static struct i2c_driver lp5521_driver; > - > -static int lp5521_probe(struct i2c_client *client, > - const struct i2c_device_id *id) > -{ > - struct lp5521_chip *chip; > - int ret = 0; > - > - chip = kzalloc(sizeof(*chip), GFP_KERNEL); > - if (!chip) > - return -ENOMEM; > - > - chip->client = client; > - strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE); > - i2c_set_clientdata(client, chip); > - > - mutex_init(&chip->lock); > - > - ret = lp5521_configure(client); > - if (ret < 0) { > - dev_err(&client->dev, "lp5521 error configuring chip \n"); > - goto fail1; > - } > - > - /* Set default values */ > - chip->mode = LP5521_MODE_DIRECT_CONTROL; > - chip->red = 1; > - chip->green = 1; > - chip->blue = 1; > - > - ret = lp5521_register_sysfs(client); > - if (ret) > - dev_err(&client->dev, "lp5521 registering sysfs failed \n"); > - > - return ret; > - > -fail1: > - kfree(chip); > - return ret; > -} > - > -static int lp5521_remove(struct i2c_client *client) > -{ > - struct lp5521_chip *chip = i2c_get_clientdata(client); > - > - lp5521_unregister_sysfs(client); > - kfree(chip); > - > - return 0; > -} > - > -static const struct i2c_device_id lp5521_id[] = { > - { LP5521_DRIVER_NAME, 0}, > - { }, > -}; > -MODULE_DEVICE_TABLE(i2c, lp5521_id); > - > -static struct i2c_driver lp5521_driver = { > - .driver = { > - .name = LP5521_DRIVER_NAME, > - }, > - .probe = lp5521_probe, > - .remove = __devexit_p(lp5521_remove), > - .id_table = lp5521_id, > -}; > - > -static int __init lp5521_init(void) > -{ > - return i2c_add_driver(&lp5521_driver); > -} > - > -static void __exit lp5521_exit(void) > -{ > - i2c_del_driver(&lp5521_driver); > -} > - > -MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>"); > -MODULE_DESCRIPTION("lp5521 LED driver"); > -MODULE_LICENSE("GPL"); > - > -module_init(lp5521_init); > -module_exit(lp5521_exit); > -- > 1.6.1.3 > > -- > balbi > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [RESEND] lp5521 patches 2009-02-17 23:44 ` Tony Lindgren @ 2009-02-17 23:50 ` Felipe Balbi 0 siblings, 0 replies; 27+ messages in thread From: Felipe Balbi @ 2009-02-17 23:50 UTC (permalink / raw) To: Tony Lindgren Cc: Felipe Balbi, Felipe Balbi, ext Otto Solares, linux-omap, David Brownell On Tue, Feb 17, 2009 at 03:44:38PM -0800, Tony Lindgren wrote: > > > once again the didn't get applied. lp5521 is already in LED tree and > > > we're gona have two forks of the same driver :-p > > Just pushed your earlier series.. hmmm... cool, tks :-) > > > Maybe, Tony, you could apply the attached. > > So I guess this is no longer needed. I'll reset drives/leds to > mainline at some point soonish. it shoud merge cleanly :-) > > damn this new Nokia server is converting my tabs into spaces :-( > > Also seems to encode them quoted-printable too :( yeah, it sucks a lot. they're using some M$ servers now. -- balbi ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2009-02-17 23:50 UTC | newest] Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-02-10 12:15 [PATCH 0/8] updates to two nokia drivers Felipe Balbi 2009-02-10 12:15 ` [PATCH 1/8] i2c: lp5521: remove dead code Felipe Balbi 2009-02-10 12:15 ` [PATCH 2/8] i2c: lp5521: cosmetic fixes Felipe Balbi 2009-02-10 12:16 ` [PATCH 3/8] i2c: lp5521: simplify mode setting Felipe Balbi 2009-02-10 12:16 ` [PATCH 4/8] i2c: lp5521: move to LED framework Felipe Balbi 2009-02-10 12:16 ` [PATCH 5/8] leds: lp5521: move to drivers/leds Felipe Balbi 2009-02-10 12:16 ` [PATCH 6/8] input: lm8323: get rid of global pdata pointer Felipe Balbi 2009-02-10 12:16 ` [PATCH 7/8] input: lm8323: get rid of useless debug macro Felipe Balbi 2009-02-10 12:16 ` [PATCH 8/8] input: lm8323: general clean up Felipe Balbi 2009-02-12 22:18 ` [PATCH 4/8] i2c: lp5521: move to LED framework David Brownell 2009-02-13 0:00 ` Felipe Balbi 2009-02-13 12:43 ` [RESEND] lp5521 patches Felipe Balbi 2009-02-13 12:43 ` [PATCH 1/6] i2c: lp5521: remove dead code Felipe Balbi 2009-02-13 12:43 ` [PATCH 2/6] i2c: lp5521: cosmetic fixes Felipe Balbi 2009-02-13 12:43 ` [PATCH 3/6] i2c: lp5521: simplify mode setting Felipe Balbi 2009-02-13 12:43 ` [PATCH 4/6] i2c: lp5521: move to LED framework Felipe Balbi 2009-02-13 12:43 ` [PATCH 5/6] leds: lp5521: move to drivers/leds Felipe Balbi 2009-02-13 12:43 ` [PATCH 6/6] arm: omap: n810: add lp5521 platform_data Felipe Balbi 2009-02-13 20:49 ` [PATCH 5/6] leds: lp5521: move to drivers/leds David Brownell 2009-02-13 22:36 ` Felipe Balbi 2009-02-13 23:54 ` David Brownell 2009-02-14 0:07 ` Felipe Balbi 2009-02-17 21:38 ` [RESEND] lp5521 patches Otto Solares 2009-02-17 23:07 ` Felipe Balbi 2009-02-17 23:29 ` Felipe Balbi 2009-02-17 23:44 ` Tony Lindgren 2009-02-17 23:50 ` Felipe Balbi
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.