linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/4] leds-lp5521: support led pattern data
@ 2012-01-21 18:09 ` Kim, Milo
  2012-01-27 14:07   ` Linus Walleij
  0 siblings, 1 reply; 4+ messages in thread
From: Kim, Milo @ 2012-01-21 18:09 UTC (permalink / raw)
  To: linux-kernel, rpurdie

The lp5521 has autonomous operation mode without external control.
Using lp5521_platform_data, various led patterns can be configurable.
For supporting this feature, new functions and device attribute are added.

Structure of lp5521_led_pattern: 3 channels are supported - red, green and blue.
Pattern(s) of each channel and numbers of pattern(s) are defined in the platform data.
Pattern data are hexa codes which include pattern commands such like
set pwm, wait, ramp up/down, branch and so on.

Pattern mode functions:
* lp5521_clear_program_memory
	Before running new led pattern, program memory should be cleared.
* lp5521_write_program_memory
	Pattern data updated in the program memory via the i2c.
* lp5521_get_pattern
	Get pattern from predefined in the platform data.
* lp5521_run_led_pattern
	Stop current pattern or run new pattern.
	Transition time is required between different operation mode.

Device attribute - 'led_pattern':
To load specific led pattern, new device attribute is added.

When the lp5521 driver is unloaded, stop current led pattern mode.

Documentation updated : description about how to define the led patterns and example.

Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com>
---
 Documentation/leds/leds-lp5521.txt |   38 ++++++++++++++
 drivers/leds/leds-lp5521.c         |  100 ++++++++++++++++++++++++++++++++++++
 include/linux/leds-lp5521.h        |   11 ++++
 3 files changed, 149 insertions(+), 0 deletions(-)

diff --git a/Documentation/leds/leds-lp5521.txt b/Documentation/leds/leds-lp5521.txt
index e3c66c6..0e542ab 100644
--- a/Documentation/leds/leds-lp5521.txt
+++ b/Documentation/leds/leds-lp5521.txt
@@ -111,3 +111,41 @@ static struct lp5521_platform_data lp5521_pdata = {
 	.clock_mode = LP5521_CLOCK_INT,
 	.update_config = LP5521_CONFIGS,
 };
+
+LED patterns : LP5521 has autonomous operation without external control.
+Pattern data can be defined in the platform data.
+
+example of led pattern data :
+
+/* RGB(50,5,0) 500ms on, 500ms off, infinite loop */
+static u8 pattern_red[] = {
+		0x40, 0x32, 0x60, 0x00,	0x40, 0x00, 0x60, 0x00,
+		};
+
+static u8 pattern_green[] = {
+		0x40, 0x05, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00,
+		};
+
+static struct lp5521_led_pattern board_led_patterns[] = {
+	{
+		.r = pattern_red,
+		.g = pattern_green,
+		.size_r = ARRAY_SIZE(pattern_red),
+		.size_g = ARRAY_SIZE(pattern_green),
+	},
+};
+
+static struct lp5521_platform_data lp5521_platform_data = {
+        .led_config     = lp5521_led_config,
+        .num_channels   = ARRAY_SIZE(lp5521_led_config),
+        .clock_mode     = LP5521_CLOCK_EXT,
+	.patterns = board_led_patterns,
+	.num_patterns = ARRAY_SIZE(board_led_patterns),
+};
+
+Then predefined led pattern(s) can be executed via the sysfs.
+To start the pattern #1,
+# echo 1 > /sys/bus/i2c/devices/xxxx/led_pattern
+(xxxx : i2c bus & slave address)
+To end the pattern,
+# echo 0 > /sys/bus/i2c/devices/xxxx/led_pattern
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index 4fa792d..471cef1 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -85,6 +85,9 @@
 /* Status */
 #define LP5521_EXT_CLK_USED		0x08
 
+/* Pattern Mode */
+#define PATTERN_OFF	0
+
 struct lp5521_engine {
 	int		id;
 	u8		mode;
@@ -522,6 +525,100 @@ static ssize_t lp5521_selftest(struct device *dev,
 	return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
 }
 
+static void lp5521_clear_program_memory(struct i2c_client *cl)
+{
+	int i;
+	u8 rgb_mem[] = {
+		LP5521_REG_R_PROG_MEM,
+		LP5521_REG_G_PROG_MEM,
+		LP5521_REG_B_PROG_MEM,
+	};
+
+	for (i = 0; i < ARRAY_SIZE(rgb_mem); i++) {
+		lp5521_write(cl, rgb_mem[i], 0);
+		lp5521_write(cl, rgb_mem[i] + 1, 0);
+	}
+}
+
+static void lp5521_write_program_memory(struct i2c_client *cl,
+				u8 base, u8 *rgb, int size)
+{
+	int i;
+
+	if (!rgb || size <= 0)
+		return;
+
+	for (i = 0; i < size; i++)
+		lp5521_write(cl, base + i, *(rgb + i));
+
+	lp5521_write(cl, base + i, 0);
+	lp5521_write(cl, base + i + 1, 0);
+}
+
+static inline struct lp5521_led_pattern *lp5521_get_pattern
+					(struct lp5521_chip *chip, u8 offset)
+{
+	struct lp5521_led_pattern *ptn;
+	ptn = chip->pdata->patterns + (offset - 1);
+	return ptn;
+}
+
+static void lp5521_run_led_pattern(int mode, struct lp5521_chip *chip)
+{
+	struct lp5521_led_pattern *ptn;
+	struct i2c_client *cl = chip->client;
+	int num_patterns = chip->pdata->num_patterns;
+
+	if (mode > num_patterns || !(chip->pdata->patterns))
+		return;
+
+	if (mode == PATTERN_OFF) {
+		lp5521_write(cl, LP5521_REG_ENABLE,
+			LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
+		usleep_range(1000, 2000);
+		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
+	} else {
+		ptn = lp5521_get_pattern(chip, mode);
+		if (!ptn)
+			return;
+
+		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
+		usleep_range(1000, 2000);
+
+		lp5521_clear_program_memory(cl);
+
+		lp5521_write_program_memory(cl, LP5521_REG_R_PROG_MEM,
+					ptn->r, ptn->size_r);
+		lp5521_write_program_memory(cl, LP5521_REG_G_PROG_MEM,
+					ptn->g, ptn->size_g);
+		lp5521_write_program_memory(cl, LP5521_REG_B_PROG_MEM,
+					ptn->b, ptn->size_b);
+
+		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_RUN);
+		usleep_range(1000, 2000);
+		lp5521_write(cl, LP5521_REG_ENABLE,
+			LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
+			LP5521_EXEC_RUN);
+	}
+}
+
+static ssize_t store_led_pattern(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
+	unsigned long val;
+	int ret;
+
+	ret = strict_strtoul(buf, 16, &val);
+	if (ret)
+		return ret;
+
+	lp5521_run_led_pattern(val, chip);
+
+	return len;
+}
+
 /* led class device attributes */
 static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
 static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
@@ -547,6 +644,7 @@ static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load);
 static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
 static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
 static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
+static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, store_led_pattern);
 
 static struct attribute *lp5521_attributes[] = {
 	&dev_attr_engine1_mode.attr,
@@ -556,6 +654,7 @@ static struct attribute *lp5521_attributes[] = {
 	&dev_attr_engine1_load.attr,
 	&dev_attr_engine2_load.attr,
 	&dev_attr_engine3_load.attr,
+	&dev_attr_led_pattern.attr,
 	NULL
 };
 
@@ -743,6 +842,7 @@ static int lp5521_remove(struct i2c_client *client)
 	struct lp5521_chip *chip = i2c_get_clientdata(client);
 	int i;
 
+	lp5521_run_led_pattern(PATTERN_OFF, chip);
 	lp5521_unregister_sysfs(client);
 
 	for (i = 0; i < chip->num_leds; i++) {
diff --git a/include/linux/leds-lp5521.h b/include/linux/leds-lp5521.h
index e9ab583..3f071ec 100644
--- a/include/linux/leds-lp5521.h
+++ b/include/linux/leds-lp5521.h
@@ -32,6 +32,15 @@ struct lp5521_led_config {
 	u8		max_current;
 };
 
+struct lp5521_led_pattern {
+	u8 *r;
+	u8 *g;
+	u8 *b;
+	u8 size_r;
+	u8 size_g;
+	u8 size_b;
+};
+
 #define LP5521_CLOCK_AUTO	0
 #define LP5521_CLOCK_INT	1
 #define LP5521_CLOCK_EXT	2
@@ -57,6 +66,8 @@ struct lp5521_platform_data {
 	void	(*enable)(bool state);
 	const char *label;
 	u8	update_config;
+	struct lp5521_led_pattern *patterns;
+	int num_patterns;
 };
 
 #endif /* __LINUX_LP5521_H */
-- 
1.7.4.1


Best Regards,
Milo (Woogyom) Kim
Texas Instruments Incorporated



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 3/4] leds-lp5521: support led pattern data
  2012-01-21 18:09 ` [PATCH 3/4] leds-lp5521: support led pattern data Kim, Milo
@ 2012-01-27 14:07   ` Linus Walleij
  0 siblings, 0 replies; 4+ messages in thread
From: Linus Walleij @ 2012-01-27 14:07 UTC (permalink / raw)
  To: Kim, Milo; +Cc: linux-kernel, rpurdie

On Sat, Jan 21, 2012 at 7:09 PM, Kim, Milo <Milo.Kim@ti.com> wrote:

> The lp5521 has autonomous operation mode without external control.
> Using lp5521_platform_data, various led patterns can be configurable.
> For supporting this feature, new functions and device attribute are added.

Good looking patch and interesting feature!
Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 3/4] leds-lp5521: support led pattern data
  2012-01-27  2:22 Kim, Milo
@ 2012-01-27 14:07 ` Linus Walleij
  0 siblings, 0 replies; 4+ messages in thread
From: Linus Walleij @ 2012-01-27 14:07 UTC (permalink / raw)
  To: Kim, Milo
  Cc: linux-kernel, Arun MURTHY, srinidhi kasagar, Andrew Morton, rpurdie

On Fri, Jan 27, 2012 at 3:22 AM, Kim, Milo <Milo.Kim@ti.com> wrote:

> Add Arun, Srinidhi, Linus and Andrew on CC

When you resend these patches with ACKs etc better send directly
to Andrew because he can't apply a quoted patch I guess...

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH 3/4] leds-lp5521: support led pattern data
@ 2012-01-27  2:22 Kim, Milo
  2012-01-27 14:07 ` Linus Walleij
  0 siblings, 1 reply; 4+ messages in thread
From: Kim, Milo @ 2012-01-27  2:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: Arun MURTHY, srinidhi kasagar, Linus Walleij, Andrew Morton, rpurdie

Add Arun, Srinidhi, Linus and Andrew on CC

> -----Original Message-----
> From: Kim, Milo
> Sent: Sunday, January 22, 2012 3:10 AM
> To: 'linux-kernel@vger.kernel.org'; 'rpurdie@rpsys.net'
> Subject: [PATCH 3/4] leds-lp5521: support led pattern data
> 
> The lp5521 has autonomous operation mode without external control.
> Using lp5521_platform_data, various led patterns can be configurable.
> For supporting this feature, new functions and device attribute are
> added.
> 
> Structure of lp5521_led_pattern: 3 channels are supported - red, green
> and blue.
> Pattern(s) of each channel and numbers of pattern(s) are defined in the
> platform data.
> Pattern data are hexa codes which include pattern commands such like
> set pwm, wait, ramp up/down, branch and so on.
> 
> Pattern mode functions:
> * lp5521_clear_program_memory
> 	Before running new led pattern, program memory should be cleared.
> * lp5521_write_program_memory
> 	Pattern data updated in the program memory via the i2c.
> * lp5521_get_pattern
> 	Get pattern from predefined in the platform data.
> * lp5521_run_led_pattern
> 	Stop current pattern or run new pattern.
> 	Transition time is required between different operation mode.
> 
> Device attribute - 'led_pattern':
> To load specific led pattern, new device attribute is added.
> 
> When the lp5521 driver is unloaded, stop current led pattern mode.
> 
> Documentation updated : description about how to define the led
> patterns and example.
> 
> Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com>
> ---
>  Documentation/leds/leds-lp5521.txt |   38 ++++++++++++++
>  drivers/leds/leds-lp5521.c         |  100
> ++++++++++++++++++++++++++++++++++++
>  include/linux/leds-lp5521.h        |   11 ++++
>  3 files changed, 149 insertions(+), 0 deletions(-)
> 
> diff --git a/Documentation/leds/leds-lp5521.txt
> b/Documentation/leds/leds-lp5521.txt
> index e3c66c6..0e542ab 100644
> --- a/Documentation/leds/leds-lp5521.txt
> +++ b/Documentation/leds/leds-lp5521.txt
> @@ -111,3 +111,41 @@ static struct lp5521_platform_data lp5521_pdata =
> {
>  	.clock_mode = LP5521_CLOCK_INT,
>  	.update_config = LP5521_CONFIGS,
>  };
> +
> +LED patterns : LP5521 has autonomous operation without external
> control.
> +Pattern data can be defined in the platform data.
> +
> +example of led pattern data :
> +
> +/* RGB(50,5,0) 500ms on, 500ms off, infinite loop */
> +static u8 pattern_red[] = {
> +		0x40, 0x32, 0x60, 0x00,	0x40, 0x00, 0x60, 0x00,
> +		};
> +
> +static u8 pattern_green[] = {
> +		0x40, 0x05, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00,
> +		};
> +
> +static struct lp5521_led_pattern board_led_patterns[] = {
> +	{
> +		.r = pattern_red,
> +		.g = pattern_green,
> +		.size_r = ARRAY_SIZE(pattern_red),
> +		.size_g = ARRAY_SIZE(pattern_green),
> +	},
> +};
> +
> +static struct lp5521_platform_data lp5521_platform_data = {
> +        .led_config     = lp5521_led_config,
> +        .num_channels   = ARRAY_SIZE(lp5521_led_config),
> +        .clock_mode     = LP5521_CLOCK_EXT,
> +	.patterns = board_led_patterns,
> +	.num_patterns = ARRAY_SIZE(board_led_patterns),
> +};
> +
> +Then predefined led pattern(s) can be executed via the sysfs.
> +To start the pattern #1,
> +# echo 1 > /sys/bus/i2c/devices/xxxx/led_pattern
> +(xxxx : i2c bus & slave address)
> +To end the pattern,
> +# echo 0 > /sys/bus/i2c/devices/xxxx/led_pattern
> diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
> index 4fa792d..471cef1 100644
> --- a/drivers/leds/leds-lp5521.c
> +++ b/drivers/leds/leds-lp5521.c
> @@ -85,6 +85,9 @@
>  /* Status */
>  #define LP5521_EXT_CLK_USED		0x08
> 
> +/* Pattern Mode */
> +#define PATTERN_OFF	0
> +
>  struct lp5521_engine {
>  	int		id;
>  	u8		mode;
> @@ -522,6 +525,100 @@ static ssize_t lp5521_selftest(struct device *dev,
>  	return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
>  }
> 
> +static void lp5521_clear_program_memory(struct i2c_client *cl)
> +{
> +	int i;
> +	u8 rgb_mem[] = {
> +		LP5521_REG_R_PROG_MEM,
> +		LP5521_REG_G_PROG_MEM,
> +		LP5521_REG_B_PROG_MEM,
> +	};
> +
> +	for (i = 0; i < ARRAY_SIZE(rgb_mem); i++) {
> +		lp5521_write(cl, rgb_mem[i], 0);
> +		lp5521_write(cl, rgb_mem[i] + 1, 0);
> +	}
> +}
> +
> +static void lp5521_write_program_memory(struct i2c_client *cl,
> +				u8 base, u8 *rgb, int size)
> +{
> +	int i;
> +
> +	if (!rgb || size <= 0)
> +		return;
> +
> +	for (i = 0; i < size; i++)
> +		lp5521_write(cl, base + i, *(rgb + i));
> +
> +	lp5521_write(cl, base + i, 0);
> +	lp5521_write(cl, base + i + 1, 0);
> +}
> +
> +static inline struct lp5521_led_pattern *lp5521_get_pattern
> +					(struct lp5521_chip *chip, u8 offset)
> +{
> +	struct lp5521_led_pattern *ptn;
> +	ptn = chip->pdata->patterns + (offset - 1);
> +	return ptn;
> +}
> +
> +static void lp5521_run_led_pattern(int mode, struct lp5521_chip *chip)
> +{
> +	struct lp5521_led_pattern *ptn;
> +	struct i2c_client *cl = chip->client;
> +	int num_patterns = chip->pdata->num_patterns;
> +
> +	if (mode > num_patterns || !(chip->pdata->patterns))
> +		return;
> +
> +	if (mode == PATTERN_OFF) {
> +		lp5521_write(cl, LP5521_REG_ENABLE,
> +			LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
> +		usleep_range(1000, 2000);
> +		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
> +	} else {
> +		ptn = lp5521_get_pattern(chip, mode);
> +		if (!ptn)
> +			return;
> +
> +		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
> +		usleep_range(1000, 2000);
> +
> +		lp5521_clear_program_memory(cl);
> +
> +		lp5521_write_program_memory(cl, LP5521_REG_R_PROG_MEM,
> +					ptn->r, ptn->size_r);
> +		lp5521_write_program_memory(cl, LP5521_REG_G_PROG_MEM,
> +					ptn->g, ptn->size_g);
> +		lp5521_write_program_memory(cl, LP5521_REG_B_PROG_MEM,
> +					ptn->b, ptn->size_b);
> +
> +		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_RUN);
> +		usleep_range(1000, 2000);
> +		lp5521_write(cl, LP5521_REG_ENABLE,
> +			LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
> +			LP5521_EXEC_RUN);
> +	}
> +}
> +
> +static ssize_t store_led_pattern(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf, size_t len)
> +{
> +	struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
> +	unsigned long val;
> +	int ret;
> +
> +	ret = strict_strtoul(buf, 16, &val);
> +	if (ret)
> +		return ret;
> +
> +	lp5521_run_led_pattern(val, chip);
> +
> +	return len;
> +}
> +
>  /* led class device attributes */
>  static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current,
> store_current);
>  static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
> @@ -547,6 +644,7 @@ static DEVICE_ATTR(engine1_load, S_IWUSR, NULL,
> store_engine1_load);
>  static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
>  static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
>  static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
> +static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, store_led_pattern);
> 
>  static struct attribute *lp5521_attributes[] = {
>  	&dev_attr_engine1_mode.attr,
> @@ -556,6 +654,7 @@ static struct attribute *lp5521_attributes[] = {
>  	&dev_attr_engine1_load.attr,
>  	&dev_attr_engine2_load.attr,
>  	&dev_attr_engine3_load.attr,
> +	&dev_attr_led_pattern.attr,
>  	NULL
>  };
> 
> @@ -743,6 +842,7 @@ static int lp5521_remove(struct i2c_client *client)
>  	struct lp5521_chip *chip = i2c_get_clientdata(client);
>  	int i;
> 
> +	lp5521_run_led_pattern(PATTERN_OFF, chip);
>  	lp5521_unregister_sysfs(client);
> 
>  	for (i = 0; i < chip->num_leds; i++) {
> diff --git a/include/linux/leds-lp5521.h b/include/linux/leds-lp5521.h
> index e9ab583..3f071ec 100644
> --- a/include/linux/leds-lp5521.h
> +++ b/include/linux/leds-lp5521.h
> @@ -32,6 +32,15 @@ struct lp5521_led_config {
>  	u8		max_current;
>  };
> 
> +struct lp5521_led_pattern {
> +	u8 *r;
> +	u8 *g;
> +	u8 *b;
> +	u8 size_r;
> +	u8 size_g;
> +	u8 size_b;
> +};
> +
>  #define LP5521_CLOCK_AUTO	0
>  #define LP5521_CLOCK_INT	1
>  #define LP5521_CLOCK_EXT	2
> @@ -57,6 +66,8 @@ struct lp5521_platform_data {
>  	void	(*enable)(bool state);
>  	const char *label;
>  	u8	update_config;
> +	struct lp5521_led_pattern *patterns;
> +	int num_patterns;
>  };
> 
>  #endif /* __LINUX_LP5521_H */
> --
> 1.7.4.1
> 
> 
> Best Regards,
> Milo (Woogyom) Kim
> Texas Instruments Incorporated



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-01-27 14:07 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <AczYZ9XQzl/GODbbQ8iok7bA14umkA==>
2012-01-21 18:09 ` [PATCH 3/4] leds-lp5521: support led pattern data Kim, Milo
2012-01-27 14:07   ` Linus Walleij
2012-01-27  2:22 Kim, Milo
2012-01-27 14:07 ` Linus Walleij

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).