All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.