All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Panasonic AN30259A support
@ 2018-03-07  0:47 Simon Shields
  2018-03-07  0:47 ` [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings Simon Shields
  2018-03-07  0:47 ` [PATCH v2 2/2] leds: add Panasonic AN30259A support Simon Shields
  0 siblings, 2 replies; 11+ messages in thread
From: Simon Shields @ 2018-03-07  0:47 UTC (permalink / raw)
  To: linux-leds
  Cc: Richard Purdie, Jacek Anaszewski, Pavel Machek, devicetree,
	Rob Herring, Simon Shields

Hi,

This patch series adds DT bindings (patch #1) and the corresponding driver
(patch #2) for the Panasonic AN30259A 3-channel LED driver. AN30259A
uses an internal clock for controlling brightness/on-off cycles, but also supports
using an external PWM/clock input. This patch series only implements
support for the former.

The AN30259A is connected using I2C, and the datasheet is freely
available[0].

Changes since v1:
* Documentation formatting/grammar fixes.
* Use reg property instead of led-sources for leds.
* Add default-state support.
* Fix auto-probing when built as a module.
* Simplified DT parsing code.
* Use devm version of led_class_register().
* Fix LED naming scheme.
* Fixed checkpatch --strict issues.

Cheers,
Simon

[0]: https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf

Simon Shields (2):
  dt-bindings: leds: document Panasonic AN30259A bindings
  leds: add Panasonic AN30259A support

 .../devicetree/bindings/leds/leds-an30259a.txt     |  43 +++
 drivers/leds/Kconfig                               |  11 +
 drivers/leds/Makefile                              |   1 +
 drivers/leds/leds-an30259a.c                       | 382 +++++++++++++++++++++
 4 files changed, 437 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-an30259a.txt
 create mode 100644 drivers/leds/leds-an30259a.c

-- 
2.16.2

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

* [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings
  2018-03-07  0:47 [PATCH v2 0/2] Panasonic AN30259A support Simon Shields
@ 2018-03-07  0:47 ` Simon Shields
  2018-03-07 21:58   ` Pavel Machek
                     ` (2 more replies)
  2018-03-07  0:47 ` [PATCH v2 2/2] leds: add Panasonic AN30259A support Simon Shields
  1 sibling, 3 replies; 11+ messages in thread
From: Simon Shields @ 2018-03-07  0:47 UTC (permalink / raw)
  To: linux-leds
  Cc: Richard Purdie, Jacek Anaszewski, Pavel Machek, devicetree,
	Rob Herring, Simon Shields

Signed-off-by: Simon Shields <simon@lineageos.org>
---
 .../devicetree/bindings/leds/leds-an30259a.txt     | 43 ++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-an30259a.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-an30259a.txt b/Documentation/devicetree/bindings/leds/leds-an30259a.txt
new file mode 100644
index 000000000000..34ad4b189853
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-an30259a.txt
@@ -0,0 +1,43 @@
+* Panasonic AN30259A 3-channel LED driver
+
+The AN30259A is a LED controller capable of driving three LEDs independently. It supports
+constant current output and sloping current output modes. The chip is connected over I2C.
+
+Required properties:
+	- compatible: Must be "panasonic,an30259a".
+	- reg: I2C slave address.
+	- #address-cells: Must be 1.
+	- #size-cells: Must be 0.
+
+Each LED is represented as a sub-node of the panasonic,an30259a node.
+
+Required sub-node properties:
+	- reg: Pin that the LED is connected to. Must be 1, 2, or 3.
+
+Optional sub-node properties:
+	- label: see Documentation/devicetree/bindings/leds/common.txt
+	- linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt
+
+Example:
+leds@30 {
+	compatible = "panasonic,an30259a";
+	reg = <0x30>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	led@1 {
+		reg = <1>;
+		linux,default-trigger = "heartbeat";
+		label = "an30259a:red:notification";
+	};
+
+	led@2 {
+		reg = <2>;
+		label = "an30259a:green:notification";
+	};
+
+	led@3 {
+		reg = <3>;
+		label = "an30259a:blue:notification";
+	};
+};
-- 
2.16.2

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

* [PATCH v2 2/2] leds: add Panasonic AN30259A support
  2018-03-07  0:47 [PATCH v2 0/2] Panasonic AN30259A support Simon Shields
  2018-03-07  0:47 ` [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings Simon Shields
@ 2018-03-07  0:47 ` Simon Shields
  2018-03-07 22:07   ` Pavel Machek
  2018-03-08 22:17   ` Jacek Anaszewski
  1 sibling, 2 replies; 11+ messages in thread
From: Simon Shields @ 2018-03-07  0:47 UTC (permalink / raw)
  To: linux-leds
  Cc: Richard Purdie, Jacek Anaszewski, Pavel Machek, devicetree,
	Rob Herring, Simon Shields

AN30259A is a 3-channel LED driver which uses I2C. It supports timed
operation via an internal PWM clock, and variable brightness. This
driver offers support for basic hardware-based blinking and brightness
control.

The datasheet is freely available:
https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf

Signed-off-by: Simon Shields <simon@lineageos.org>
---
 drivers/leds/Kconfig         |  11 ++
 drivers/leds/Makefile        |   1 +
 drivers/leds/leds-an30259a.c | 382 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 394 insertions(+)
 create mode 100644 drivers/leds/leds-an30259a.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 3e763d2a0cb3..369bfb1227f8 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -57,6 +57,17 @@ config LEDS_AAT1290
 	depends on PINCTRL
 	help
 	 This option enables support for the LEDs on the AAT1290.
+
+config LEDS_AN30259A
+	tristate "LED support for Panasonic AN30259A"
+	depends on LEDS_CLASS && I2C && OF
+	help
+	  This option enables support for the AN30259A 3-channel
+	  LED driver.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-an30259a.
+
 config LEDS_APU
 	tristate "Front panel LED support for PC Engines APU/APU2 boards"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 987884a5b9a5..44f9b42d1600 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_88PM860X)		+= leds-88pm860x.o
 obj-$(CONFIG_LEDS_AAT1290)		+= leds-aat1290.o
 obj-$(CONFIG_LEDS_APU)			+= leds-apu.o
 obj-$(CONFIG_LEDS_AS3645A)		+= leds-as3645a.o
+obj-$(CONFIG_LEDS_AN30259A)		+= leds-an30259a.o
 obj-$(CONFIG_LEDS_BCM6328)		+= leds-bcm6328.o
 obj-$(CONFIG_LEDS_BCM6358)		+= leds-bcm6358.o
 obj-$(CONFIG_LEDS_BD2802)		+= leds-bd2802.o
diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c
new file mode 100644
index 000000000000..6170aa2e3adb
--- /dev/null
+++ b/drivers/leds/leds-an30259a.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Panasonic AN30259A 3-channel LED driver
+ *
+ * Copyright (c) 2018 Simon Shields <simon@lineageos.org>
+ *
+ * Datasheet:
+ * https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf
+ */
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#define MAX_LEDS 3
+
+#define REG_SRESET 0x00
+#define LED_SRESET BIT(0)
+
+/* LED power registers */
+#define REG_LEDON 0x01
+#define LED_EN(x) BIT(x - 1)
+#define LED_SLOPE(x) BIT((x - 1) + 4)
+
+#define REG_LEDCC(x) (0x03 + (x - 1))
+
+/* slope control registers */
+#define REG_SLOPE(x) (0x06 + (x - 1))
+#define LED_SLOPETIME1(x) (x)
+#define LED_SLOPETIME2(x) ((x) << 4)
+
+#define REG_LEDCNT1(x) (0x09 + (4 * (x - 1)))
+#define LED_DUTYMAX(x) ((x) << 4)
+#define LED_DUTYMID(x) (x)
+
+#define REG_LEDCNT2(x) (0x0A + (4 * (x - 1)))
+#define LED_DELAY(x) ((x) << 4)
+#define LED_DUTYMIN(x) (x)
+
+/* detention time control (length of each slope step) */
+#define REG_LEDCNT3(x) (0x0B + (4 * (x - 1)))
+#define LED_DT1(x) (x)
+#define LED_DT2(x) ((x) << 4)
+
+#define REG_LEDCNT4(x) (0x0C + (4 * (x - 1)))
+#define LED_DT3(x) (x)
+#define LED_DT4(x) ((x) << 4)
+
+#define REG_MAX 0x14
+
+#define BLINK_MAX_TIME 7500 /* ms */
+#define SLOPE_RESOLUTION 500 /* ms */
+
+#define STATE_OFF 0
+#define STATE_KEEP 1
+#define STATE_ON 2
+
+struct an30259a;
+
+struct an30259a_led {
+	struct an30259a *chip;
+	struct led_classdev cdev;
+	u32 num;
+	u32 default_state;
+};
+
+struct an30259a {
+	struct mutex mutex; /* held when writing to registers */
+	struct i2c_client *client;
+	struct an30259a_led leds[MAX_LEDS];
+	struct regmap *regmap;
+	int num_leds;
+};
+
+static u8 an30259a_get_dutymax(u8 brightness)
+{
+	u8 duty_max, floor, ceil;
+
+	/* squash 8 bit number into 7-bit PWM range */
+	duty_max = brightness >> 1;
+
+	/* bottom 3 bits are always set for DUTYMAX
+	 * figure out the closest value
+	 */
+	ceil = duty_max | 0x7;
+	floor = ceil - 0x8;
+
+	if ((duty_max - floor) < (ceil - duty_max))
+		duty_max = floor >> 3;
+	else
+		duty_max = ceil >> 3;
+
+	return duty_max;
+}
+
+static int an30259a_brightness(struct an30259a_led *led,
+			       enum led_brightness brightness)
+{
+	int ret;
+	unsigned int ledon;
+	u8 dutymax;
+
+	ret = regmap_read(led->chip->regmap, REG_LEDON, &ledon);
+	if (ret)
+		return ret;
+
+	switch (brightness) {
+	case LED_OFF:
+		ledon &= ~LED_EN(led->num);
+		ledon &= ~LED_SLOPE(led->num);
+		break;
+	default:
+		ledon |= LED_EN(led->num);
+		dutymax = an30259a_get_dutymax(brightness & 0xff);
+		ret = regmap_write(led->chip->regmap, REG_LEDCNT1(led->num),
+				   LED_DUTYMAX(dutymax) | LED_DUTYMID(dutymax));
+		if (ret)
+			return ret;
+		break;
+	}
+	ret = regmap_write(led->chip->regmap, REG_LEDON, ledon);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(led->chip->regmap, REG_LEDCC(led->num),
+			   brightness & 0xff);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int an30259a_blink(struct an30259a_led *led,
+			  unsigned long *poff, unsigned long *pon)
+{
+	int ret, num = led->num;
+	unsigned int ledon;
+	unsigned long off = *poff, on = *pon;
+
+	/* slope time - multiples of 500ms only, floored */
+	off -= off % SLOPE_RESOLUTION;
+	/* don't floor off time to zero if a non-zero time was requested */
+	if (!off && *poff)
+		off += SLOPE_RESOLUTION;
+	else if (off > BLINK_MAX_TIME)
+		off = BLINK_MAX_TIME;
+	*poff = off;
+
+	on -= on % SLOPE_RESOLUTION;
+	/* don't floor on time to zero if a non-zero time was requested */
+	if (!on && *pon)
+		on += SLOPE_RESOLUTION;
+	else if (on > BLINK_MAX_TIME)
+		on = BLINK_MAX_TIME;
+	*pon = on;
+
+	/* convert into values the HW will understand */
+	off /= SLOPE_RESOLUTION;
+	on /= SLOPE_RESOLUTION;
+
+	/* duty min should be zero (=off), delay should be zero */
+	ret = regmap_write(led->chip->regmap, REG_LEDCNT2(num),
+			   LED_DELAY(0) | LED_DUTYMIN(0));
+	if (ret)
+		return ret;
+
+	/* reset detention time (no "breathing" effect) */
+	ret = regmap_write(led->chip->regmap, REG_LEDCNT3(num),
+			   LED_DT1(0) | LED_DT2(0));
+	if (ret)
+		return ret;
+	ret = regmap_write(led->chip->regmap, REG_LEDCNT4(num),
+			   LED_DT3(0) | LED_DT4(0));
+	if (ret)
+		return ret;
+
+	/* slope time controls on/off cycle length */
+	ret = regmap_write(led->chip->regmap, REG_SLOPE(num),
+			   LED_SLOPETIME1(off) | LED_SLOPETIME2(on));
+	if (ret)
+		return ret;
+
+	/* Finally, enable slope mode. */
+	ret = regmap_read(led->chip->regmap, REG_LEDON, &ledon);
+	if (ret)
+		return ret;
+
+	ledon |= LED_SLOPE(num);
+
+	return regmap_write(led->chip->regmap, REG_LEDON, ledon);
+}
+
+static int an30259a_led_set(struct led_classdev *cdev,
+			    enum led_brightness value)
+{
+	struct an30259a_led *led;
+	int ret;
+
+	led = container_of(cdev, struct an30259a_led, cdev);
+
+	mutex_lock(&led->chip->mutex);
+	ret = an30259a_brightness(led, value);
+	mutex_unlock(&led->chip->mutex);
+
+	return ret;
+}
+
+static int an30259a_blink_set(struct led_classdev *cdev,
+			      unsigned long *delay_off, unsigned long *delay_on)
+{
+	struct an30259a_led *led;
+	int ret;
+
+	led = container_of(cdev, struct an30259a_led, cdev);
+
+	mutex_lock(&led->chip->mutex);
+	ret = an30259a_blink(led, delay_off, delay_on);
+	mutex_unlock(&led->chip->mutex);
+
+	return ret;
+}
+
+static int an30259a_dt_init(struct i2c_client *client, struct an30259a *chip)
+{
+	struct device_node *np = client->dev.of_node, *child;
+	int count, ret;
+	int i = 0;
+	const char *str;
+
+	count = of_get_child_count(np);
+	if (!count || count > MAX_LEDS)
+		return -EINVAL;
+
+	for_each_child_of_node(np, child) {
+		u32 source;
+
+		ret = of_property_read_u32(child, "reg", &source);
+		if (ret != 0 || !source || source > MAX_LEDS) {
+			count--;
+			continue;
+		}
+
+		chip->leds[i].num = source;
+		chip->leds[i].chip = chip;
+
+		if (of_property_read_string(child, "label",
+					    &chip->leds[i].cdev.name))
+			chip->leds[i].cdev.name = "an30259a::";
+
+		if (!of_property_read_string(child, "default-state",
+					     &str)) {
+			if (!strcmp(str, "on"))
+				chip->leds[i].default_state = STATE_ON;
+			else if (!strcmp(str, "keep"))
+				chip->leds[i].default_state = STATE_KEEP;
+			else
+				chip->leds[i].default_state = STATE_OFF;
+		}
+
+		of_property_read_string(child, "linux,default-trigger",
+					&chip->leds[i].cdev.default_trigger);
+
+		i++;
+	}
+
+	if (!count)
+		return -EINVAL;
+
+	chip->num_leds = i;
+
+	return 0;
+}
+
+static const struct regmap_config an30259a_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = REG_MAX,
+};
+
+static void an30259a_init_default_state(struct an30259a_led *led)
+{
+	struct an30259a *chip = led->chip;
+	int ledon, err;
+
+	switch (led->default_state) {
+	case STATE_ON:
+		led->cdev.brightness = LED_FULL;
+		break;
+	case STATE_KEEP:
+		err = regmap_read(chip->regmap, REG_LEDON, &ledon);
+		if (err)
+			break;
+
+		if (!(ledon & LED_EN(led->num))) {
+			led->cdev.brightness = LED_OFF;
+			break;
+		}
+		regmap_read(chip->regmap, REG_LEDCC(led->num),
+			    &led->cdev.brightness);
+		break;
+	default:
+		led->cdev.brightness = LED_OFF;
+	}
+
+	an30259a_led_set(&led->cdev, led->cdev.brightness);
+}
+
+static int an30259a_probe(struct i2c_client *client)
+{
+	struct an30259a *chip;
+	int i, err;
+
+	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	err = an30259a_dt_init(client, chip);
+	if (err < 0)
+		return err;
+
+	mutex_init(&chip->mutex);
+	chip->client = client;
+	i2c_set_clientdata(client, chip);
+
+	chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);
+
+	for (i = 0; i < chip->num_leds; i++) {
+		an30259a_init_default_state(&chip->leds[i]);
+		chip->leds[i].cdev.brightness_set_blocking = an30259a_led_set;
+		chip->leds[i].cdev.blink_set = an30259a_blink_set;
+
+		err = devm_led_classdev_register(&client->dev,
+						 &chip->leds[i].cdev);
+		if (err < 0)
+			goto exit;
+	}
+	return 0;
+
+exit:
+	mutex_destroy(&chip->mutex);
+	return err;
+}
+
+static int an30259a_remove(struct i2c_client *client)
+{
+	struct an30259a *chip = i2c_get_clientdata(client);
+
+	mutex_destroy(&chip->mutex);
+
+	return 0;
+}
+
+static const struct of_device_id an30259a_match_table[] = {
+	{ .compatible = "panasonic,an30259a", },
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, an30259a_match_table);
+
+static const struct i2c_device_id an30259a_id[] = {
+	{ "an30259a", NULL },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(i2c, an30259a_id);
+
+static struct i2c_driver an30259a_driver = {
+	.driver = {
+		.name = "leds-an32059a",
+		.of_match_table = of_match_ptr(an30259a_match_table),
+	},
+	.probe_new = an30259a_probe,
+	.remove = an30259a_remove,
+	.id_table = an30259a_id,
+};
+
+module_i2c_driver(an30259a_driver);
+
+MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
+MODULE_DESCRIPTION("AN32059A LED driver");
+MODULE_LICENSE("GPL v2");
-- 
2.16.2

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

* Re: [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings
  2018-03-07  0:47 ` [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings Simon Shields
@ 2018-03-07 21:58   ` Pavel Machek
  2018-03-08  2:02   ` Rob Herring
  2018-03-08 22:17   ` Jacek Anaszewski
  2 siblings, 0 replies; 11+ messages in thread
From: Pavel Machek @ 2018-03-07 21:58 UTC (permalink / raw)
  To: Simon Shields
  Cc: linux-leds, Richard Purdie, Jacek Anaszewski, devicetree, Rob Herring

[-- Attachment #1: Type: text/plain, Size: 2095 bytes --]

On Wed 2018-03-07 11:47:21, Simon Shields wrote:
> Signed-off-by: Simon Shields <simon@lineageos.org>

Well, single line for a changelog would not hurt :-).

Acked-by: Pavel Machek <pavel@ucw.cz>


> ---
>  .../devicetree/bindings/leds/leds-an30259a.txt     | 43 ++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-an30259a.txt
> 
> diff --git a/Documentation/devicetree/bindings/leds/leds-an30259a.txt b/Documentation/devicetree/bindings/leds/leds-an30259a.txt
> new file mode 100644
> index 000000000000..34ad4b189853
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-an30259a.txt
> @@ -0,0 +1,43 @@
> +* Panasonic AN30259A 3-channel LED driver
> +
> +The AN30259A is a LED controller capable of driving three LEDs independently. It supports
> +constant current output and sloping current output modes. The chip is connected over I2C.
> +
> +Required properties:
> +	- compatible: Must be "panasonic,an30259a".
> +	- reg: I2C slave address.
> +	- #address-cells: Must be 1.
> +	- #size-cells: Must be 0.
> +
> +Each LED is represented as a sub-node of the panasonic,an30259a node.
> +
> +Required sub-node properties:
> +	- reg: Pin that the LED is connected to. Must be 1, 2, or 3.
> +
> +Optional sub-node properties:
> +	- label: see Documentation/devicetree/bindings/leds/common.txt
> +	- linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example:
> +leds@30 {
> +	compatible = "panasonic,an30259a";
> +	reg = <0x30>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	led@1 {
> +		reg = <1>;
> +		linux,default-trigger = "heartbeat";
> +		label = "an30259a:red:notification";
> +	};
> +
> +	led@2 {
> +		reg = <2>;
> +		label = "an30259a:green:notification";
> +	};
> +
> +	led@3 {
> +		reg = <3>;
> +		label = "an30259a:blue:notification";
> +	};
> +};

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

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

* Re: [PATCH v2 2/2] leds: add Panasonic AN30259A support
  2018-03-07  0:47 ` [PATCH v2 2/2] leds: add Panasonic AN30259A support Simon Shields
@ 2018-03-07 22:07   ` Pavel Machek
  2018-03-08  0:48     ` Simon Shields
  2018-03-08 22:17   ` Jacek Anaszewski
  1 sibling, 1 reply; 11+ messages in thread
From: Pavel Machek @ 2018-03-07 22:07 UTC (permalink / raw)
  To: Simon Shields
  Cc: linux-leds, Richard Purdie, Jacek Anaszewski, devicetree, Rob Herring

[-- Attachment #1: Type: text/plain, Size: 1658 bytes --]

Hi!

> The datasheet is freely available:
> https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf

> +	  To compile this driver as a module, choose M here: the module
> +	  will be called leds-an30259a.

leds-an30259a.ko?

> @@ -0,0 +1,382 @@
> +// SPDX-License-Identifier: GPL-2.0

I'd prefer 2.0+, but... your choice.

> +/*
> + * Driver for Panasonic AN30259A 3-channel LED driver
> + *
> + * Copyright (c) 2018 Simon Shields <simon@lineageos.org>
> + *
> + * Datasheet:
> + * https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf
> + */
> +#include <linux/i2c.h>
> +#include <linux/leds.h>

I'd do empty line after the comment.

> +static u8 an30259a_get_dutymax(u8 brightness)
> +{
> +	u8 duty_max, floor, ceil;
> +
> +	/* squash 8 bit number into 7-bit PWM range */
> +	duty_max = brightness >> 1;

We should really start using max_brightness, so that userspace knows
what 

> +	/* bottom 3 bits are always set for DUTYMAX
> +	 * figure out the closest value
> +	 */

/*
 * Multiline comments like this.
 */

> +	/* slope time controls on/off cycle length */
> +	ret = regmap_write(led->chip->regmap, REG_SLOPE(num),
> +			   LED_SLOPETIME1(off) | LED_SLOPETIME2(on));
> +	if (ret)
> +		return ret;
> +
> +	/* Finally, enable slope mode. */

And yes, having sentences in all the comments would be nice. Or maybe
nowhere. But consistent ;-).

Since all I'm commenting is whitespace...

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

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

* Re: [PATCH v2 2/2] leds: add Panasonic AN30259A support
  2018-03-07 22:07   ` Pavel Machek
@ 2018-03-08  0:48     ` Simon Shields
  0 siblings, 0 replies; 11+ messages in thread
From: Simon Shields @ 2018-03-08  0:48 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-leds, Richard Purdie, Jacek Anaszewski, devicetree, Rob Herring

Hi Pavel,

On Wed, Mar 07, 2018 at 11:07:25PM +0100, Pavel Machek wrote:
> Hi!
> 
> > The datasheet is freely available:
> > https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf
> 
> > +	  To compile this driver as a module, choose M here: the module
> > +	  will be called leds-an30259a.
> 
> leds-an30259a.ko?

The vast majority of Kconfig options omit the .ko - a treewide grep
shows only 40 including the .ko.

> 
> > @@ -0,0 +1,382 @@
> > +// SPDX-License-Identifier: GPL-2.0
> 
> I'd prefer 2.0+, but... your choice.

I really don't mind.

> 
> > +/*
> > + * Driver for Panasonic AN30259A 3-channel LED driver
> > + *
> > + * Copyright (c) 2018 Simon Shields <simon@lineageos.org>
> > + *
> > + * Datasheet:
> > + * https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf
> > + */
> > +#include <linux/i2c.h>
> > +#include <linux/leds.h>
> 
> I'd do empty line after the comment.
> 
> > +static u8 an30259a_get_dutymax(u8 brightness)
> > +{
> > +	u8 duty_max, floor, ceil;
> > +
> > +	/* squash 8 bit number into 7-bit PWM range */
> > +	duty_max = brightness >> 1;
> 
> We should really start using max_brightness, so that userspace knows
> what 

When outputting constant brightness, the IC supports 8-bit PWM.
For sloped output mode, it's limited to 7 bits, and the bottom 3 bits
are always set.

> 
> > +	/* bottom 3 bits are always set for DUTYMAX
> > +	 * figure out the closest value
> > +	 */
> 
> /*
>  * Multiline comments like this.
>  */
> 
Oops.
> > +	/* slope time controls on/off cycle length */
> > +	ret = regmap_write(led->chip->regmap, REG_SLOPE(num),
> > +			   LED_SLOPETIME1(off) | LED_SLOPETIME2(on));
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Finally, enable slope mode. */
> 
> And yes, having sentences in all the comments would be nice. Or maybe
> nowhere. But consistent ;-).
> 
> Since all I'm commenting is whitespace...
> 
> Acked-by: Pavel Machek <pavel@ucw.cz>
> 

Thanks for the review!

> -- 
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

Cheers,
Simon

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

* Re: [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings
  2018-03-07  0:47 ` [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings Simon Shields
  2018-03-07 21:58   ` Pavel Machek
@ 2018-03-08  2:02   ` Rob Herring
  2018-03-08 22:17   ` Jacek Anaszewski
  2 siblings, 0 replies; 11+ messages in thread
From: Rob Herring @ 2018-03-08  2:02 UTC (permalink / raw)
  To: Simon Shields
  Cc: linux-leds, Richard Purdie, Jacek Anaszewski, Pavel Machek, devicetree

On Wed, Mar 07, 2018 at 11:47:21AM +1100, Simon Shields wrote:
> Signed-off-by: Simon Shields <simon@lineageos.org>
> ---
>  .../devicetree/bindings/leds/leds-an30259a.txt     | 43 ++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-an30259a.txt

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings
  2018-03-07  0:47 ` [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings Simon Shields
  2018-03-07 21:58   ` Pavel Machek
  2018-03-08  2:02   ` Rob Herring
@ 2018-03-08 22:17   ` Jacek Anaszewski
  2018-03-08 22:54     ` Pavel Machek
  2 siblings, 1 reply; 11+ messages in thread
From: Jacek Anaszewski @ 2018-03-08 22:17 UTC (permalink / raw)
  To: Simon Shields, linux-leds
  Cc: Richard Purdie, Pavel Machek, devicetree, Rob Herring

Hi Simon,

On 03/07/2018 01:47 AM, Simon Shields wrote:
> Signed-off-by: Simon Shields <simon@lineageos.org>
> ---
>  .../devicetree/bindings/leds/leds-an30259a.txt     | 43 ++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-an30259a.txt
> 
> diff --git a/Documentation/devicetree/bindings/leds/leds-an30259a.txt b/Documentation/devicetree/bindings/leds/leds-an30259a.txt
> new file mode 100644
> index 000000000000..34ad4b189853
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-an30259a.txt
> @@ -0,0 +1,43 @@
> +* Panasonic AN30259A 3-channel LED driver
> +
> +The AN30259A is a LED controller capable of driving three LEDs independently. It supports
> +constant current output and sloping current output modes. The chip is connected over I2C.
> +
> +Required properties:
> +	- compatible: Must be "panasonic,an30259a".
> +	- reg: I2C slave address.
> +	- #address-cells: Must be 1.
> +	- #size-cells: Must be 0.
> +
> +Each LED is represented as a sub-node of the panasonic,an30259a node.
> +
> +Required sub-node properties:
> +	- reg: Pin that the LED is connected to. Must be 1, 2, or 3.
> +
> +Optional sub-node properties:
> +	- label: see Documentation/devicetree/bindings/leds/common.txt
> +	- linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example:
> +leds@30 {

Let's start to keep the uniform convention, i.e.
led-controller for the LED controller node:

s/leds@30/led-controller@30/

> +	compatible = "panasonic,an30259a";
> +	reg = <0x30>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	led@1 {
> +		reg = <1>;
> +		linux,default-trigger = "heartbeat";
> +		label = "an30259a:red:notification";

s/an30259a:red:notification/red:notification/

Let's drop devicename section from label, and make it a LED class
driver responsibility to prepend the label with devicename when
composing LED class device name.

> +	};
> +
> +	led@2 {
> +		reg = <2>;
> +		label = "an30259a:green:notification";
> +	};
> +
> +	led@3 {
> +		reg = <3>;
> +		label = "an30259a:blue:notification";
> +	};
> +};
> 

-- 
Best regards,
Jacek Anaszewski

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

* Re: [PATCH v2 2/2] leds: add Panasonic AN30259A support
  2018-03-07  0:47 ` [PATCH v2 2/2] leds: add Panasonic AN30259A support Simon Shields
  2018-03-07 22:07   ` Pavel Machek
@ 2018-03-08 22:17   ` Jacek Anaszewski
  1 sibling, 0 replies; 11+ messages in thread
From: Jacek Anaszewski @ 2018-03-08 22:17 UTC (permalink / raw)
  To: Simon Shields, linux-leds
  Cc: Richard Purdie, Pavel Machek, devicetree, Rob Herring

Hi Simon,

Thanks for the update.

On 03/07/2018 01:47 AM, Simon Shields wrote:
> AN30259A is a 3-channel LED driver which uses I2C. It supports timed
> operation via an internal PWM clock, and variable brightness. This
> driver offers support for basic hardware-based blinking and brightness
> control.
> 
> The datasheet is freely available:
> https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf
> 
> Signed-off-by: Simon Shields <simon@lineageos.org>
> ---
>  drivers/leds/Kconfig         |  11 ++
>  drivers/leds/Makefile        |   1 +
>  drivers/leds/leds-an30259a.c | 382 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 394 insertions(+)
>  create mode 100644 drivers/leds/leds-an30259a.c
> 
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 3e763d2a0cb3..369bfb1227f8 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -57,6 +57,17 @@ config LEDS_AAT1290
>  	depends on PINCTRL
>  	help
>  	 This option enables support for the LEDs on the AAT1290.
> +
> +config LEDS_AN30259A
> +	tristate "LED support for Panasonic AN30259A"
> +	depends on LEDS_CLASS && I2C && OF
> +	help
> +	  This option enables support for the AN30259A 3-channel
> +	  LED driver.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called leds-an30259a.
> +
>  config LEDS_APU
>  	tristate "Front panel LED support for PC Engines APU/APU2 boards"
>  	depends on LEDS_CLASS
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 987884a5b9a5..44f9b42d1600 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_88PM860X)		+= leds-88pm860x.o
>  obj-$(CONFIG_LEDS_AAT1290)		+= leds-aat1290.o
>  obj-$(CONFIG_LEDS_APU)			+= leds-apu.o
>  obj-$(CONFIG_LEDS_AS3645A)		+= leds-as3645a.o
> +obj-$(CONFIG_LEDS_AN30259A)		+= leds-an30259a.o
>  obj-$(CONFIG_LEDS_BCM6328)		+= leds-bcm6328.o
>  obj-$(CONFIG_LEDS_BCM6358)		+= leds-bcm6358.o
>  obj-$(CONFIG_LEDS_BD2802)		+= leds-bd2802.o
> diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c
> new file mode 100644
> index 000000000000..6170aa2e3adb
> --- /dev/null
> +++ b/drivers/leds/leds-an30259a.c
> @@ -0,0 +1,382 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for Panasonic AN30259A 3-channel LED driver
> + *
> + * Copyright (c) 2018 Simon Shields <simon@lineageos.org>
> + *
> + * Datasheet:
> + * https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf
> + */

I'd go for '//' comment marker for this entire block.
We're already changing it (e.g. [0][1]) according to Linus
preference [2].

> +#include <linux/i2c.h>
> +#include <linux/leds.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/regmap.h>
> +
> +#define MAX_LEDS 3
> +
> +#define REG_SRESET 0x00
> +#define LED_SRESET BIT(0)
> +
> +/* LED power registers */
> +#define REG_LEDON 0x01
> +#define LED_EN(x) BIT(x - 1)
> +#define LED_SLOPE(x) BIT((x - 1) + 4)
> +
> +#define REG_LEDCC(x) (0x03 + (x - 1))
> +
> +/* slope control registers */
> +#define REG_SLOPE(x) (0x06 + (x - 1))
> +#define LED_SLOPETIME1(x) (x)
> +#define LED_SLOPETIME2(x) ((x) << 4)
> +
> +#define REG_LEDCNT1(x) (0x09 + (4 * (x - 1)))
> +#define LED_DUTYMAX(x) ((x) << 4)
> +#define LED_DUTYMID(x) (x)
> +
> +#define REG_LEDCNT2(x) (0x0A + (4 * (x - 1)))
> +#define LED_DELAY(x) ((x) << 4)
> +#define LED_DUTYMIN(x) (x)
> +
> +/* detention time control (length of each slope step) */
> +#define REG_LEDCNT3(x) (0x0B + (4 * (x - 1)))
> +#define LED_DT1(x) (x)
> +#define LED_DT2(x) ((x) << 4)
> +
> +#define REG_LEDCNT4(x) (0x0C + (4 * (x - 1)))
> +#define LED_DT3(x) (x)
> +#define LED_DT4(x) ((x) << 4)
> +
> +#define REG_MAX 0x14
> +
> +#define BLINK_MAX_TIME 7500 /* ms */
> +#define SLOPE_RESOLUTION 500 /* ms */
> +
> +#define STATE_OFF 0
> +#define STATE_KEEP 1
> +#define STATE_ON 2
> +
> +struct an30259a;
> +
> +struct an30259a_led {
> +	struct an30259a *chip;
> +	struct led_classdev cdev;
> +	u32 num;
> +	u32 default_state;
> +};
> +
> +struct an30259a {
> +	struct mutex mutex; /* held when writing to registers */
> +	struct i2c_client *client;
> +	struct an30259a_led leds[MAX_LEDS];
> +	struct regmap *regmap;
> +	int num_leds;
> +};
> +
> +static u8 an30259a_get_dutymax(u8 brightness)
> +{
> +	u8 duty_max, floor, ceil;
> +
> +	/* squash 8 bit number into 7-bit PWM range */
> +	duty_max = brightness >> 1;
> +
> +	/* bottom 3 bits are always set for DUTYMAX
> +	 * figure out the closest value
> +	 */
> +	ceil = duty_max | 0x7;
> +	floor = ceil - 0x8;
> +
> +	if ((duty_max - floor) < (ceil - duty_max))
> +		duty_max = floor >> 3;
> +	else
> +		duty_max = ceil >> 3;
> +
> +	return duty_max;
> +}
> +
> +static int an30259a_brightness(struct an30259a_led *led,
> +			       enum led_brightness brightness)
> +{
> +	int ret;
> +	unsigned int ledon;

s/ledon/led_on/

> +	u8 dutymax;
> +
> +	ret = regmap_read(led->chip->regmap, REG_LEDON, &ledon);
> +	if (ret)
> +		return ret;
> +
> +	switch (brightness) {
> +	case LED_OFF:
> +		ledon &= ~LED_EN(led->num);
> +		ledon &= ~LED_SLOPE(led->num);
> +		break;
> +	default:
> +		ledon |= LED_EN(led->num);
> +		dutymax = an30259a_get_dutymax(brightness & 0xff);
> +		ret = regmap_write(led->chip->regmap, REG_LEDCNT1(led->num),
> +				   LED_DUTYMAX(dutymax) | LED_DUTYMID(dutymax));
> +		if (ret)
> +			return ret;
> +		break;
> +	}
> +	ret = regmap_write(led->chip->regmap, REG_LEDON, ledon);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_write(led->chip->regmap, REG_LEDCC(led->num),
> +			   brightness & 0xff);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +static int an30259a_blink(struct an30259a_led *led,
> +			  unsigned long *poff, unsigned long *pon)
> +{
> +	int ret, num = led->num;
> +	unsigned int ledon;
> +	unsigned long off = *poff, on = *pon;
> +
> +	/* slope time - multiples of 500ms only, floored */
> +	off -= off % SLOPE_RESOLUTION;
> +	/* don't floor off time to zero if a non-zero time was requested */
> +	if (!off && *poff)
> +		off += SLOPE_RESOLUTION;
> +	else if (off > BLINK_MAX_TIME)
> +		off = BLINK_MAX_TIME;
> +	*poff = off;
> +
> +	on -= on % SLOPE_RESOLUTION;
> +	/* don't floor on time to zero if a non-zero time was requested */
> +	if (!on && *pon)
> +		on += SLOPE_RESOLUTION;
> +	else if (on > BLINK_MAX_TIME)
> +		on = BLINK_MAX_TIME;
> +	*pon = on;
> +
> +	/* convert into values the HW will understand */
> +	off /= SLOPE_RESOLUTION;
> +	on /= SLOPE_RESOLUTION;
> +
> +	/* duty min should be zero (=off), delay should be zero */
> +	ret = regmap_write(led->chip->regmap, REG_LEDCNT2(num),
> +			   LED_DELAY(0) | LED_DUTYMIN(0));
> +	if (ret)
> +		return ret;
> +
> +	/* reset detention time (no "breathing" effect) */
> +	ret = regmap_write(led->chip->regmap, REG_LEDCNT3(num),
> +			   LED_DT1(0) | LED_DT2(0));
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(led->chip->regmap, REG_LEDCNT4(num),
> +			   LED_DT3(0) | LED_DT4(0));
> +	if (ret)
> +		return ret;
> +
> +	/* slope time controls on/off cycle length */
> +	ret = regmap_write(led->chip->regmap, REG_SLOPE(num),
> +			   LED_SLOPETIME1(off) | LED_SLOPETIME2(on));
> +	if (ret)
> +		return ret;
> +
> +	/* Finally, enable slope mode. */
> +	ret = regmap_read(led->chip->regmap, REG_LEDON, &ledon);
> +	if (ret)
> +		return ret;
> +
> +	ledon |= LED_SLOPE(num);
> +
> +	return regmap_write(led->chip->regmap, REG_LEDON, ledon);
> +}
> +
> +static int an30259a_led_set(struct led_classdev *cdev,
> +			    enum led_brightness value)
> +{
> +	struct an30259a_led *led;
> +	int ret;
> +
> +	led = container_of(cdev, struct an30259a_led, cdev);
> +
> +	mutex_lock(&led->chip->mutex);
> +	ret = an30259a_brightness(led, value);

There is no verb in this function name and the reader wouldn't
know what actually we're doing with brightness here on the first glance.

But instead of fixing the function name I propose to put whole its
content directly here, You're not using an30259a_brightness() anywhere
besides this place.

I'd also rename an30259a_led_set to an30259a_brightness_set.

> +	mutex_unlock(&led->chip->mutex);
> +
> +	return ret;
> +}
> +
> +static int an30259a_blink_set(struct led_classdev *cdev,
> +			      unsigned long *delay_off, unsigned long *delay_on)
> +{
> +	struct an30259a_led *led;
> +	int ret;
> +
> +	led = container_of(cdev, struct an30259a_led, cdev);
> +
> +	mutex_lock(&led->chip->mutex);
> +	ret = an30259a_blink(led, delay_off, delay_on);

Ditto.

> +	mutex_unlock(&led->chip->mutex);
> +
> +	return ret;
> +}
> +
> +static int an30259a_dt_init(struct i2c_client *client, struct an30259a *chip)
> +{
> +	struct device_node *np = client->dev.of_node, *child;
> +	int count, ret;
> +	int i = 0;
> +	const char *str;
> +
> +	count = of_get_child_count(np);
> +	if (!count || count > MAX_LEDS)
> +		return -EINVAL;
> +
> +	for_each_child_of_node(np, child) {
> +		u32 source;
> +
> +		ret = of_property_read_u32(child, "reg", &source);
> +		if (ret != 0 || !source || source > MAX_LEDS) {
> +			count--;

Printing some error message here could be useful.

> +			continue;
> +		}
> +
> +		chip->leds[i].num = source;
> +		chip->leds[i].chip = chip;
> +
> +		if (of_property_read_string(child, "label",
> +					    &chip->leds[i].cdev.name))
> +			chip->leds[i].cdev.name = "an30259a::";

Please follow drivers/leds/leds-lm3692x.c when it comes to LED class
device name construction.

> +
> +		if (!of_property_read_string(child, "default-state",
> +					     &str)) {
> +			if (!strcmp(str, "on"))
> +				chip->leds[i].default_state = STATE_ON;
> +			else if (!strcmp(str, "keep"))
> +				chip->leds[i].default_state = STATE_KEEP;
> +			else
> +				chip->leds[i].default_state = STATE_OFF;
> +		}
> +
> +		of_property_read_string(child, "linux,default-trigger",
> +					&chip->leds[i].cdev.default_trigger);
> +
> +		i++;
> +	}
> +
> +	if (!count)
> +		return -EINVAL;
> +
> +	chip->num_leds = i;
> +
> +	return 0;
> +}
> +
> +static const struct regmap_config an30259a_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.max_register = REG_MAX,
> +};
> +
> +static void an30259a_init_default_state(struct an30259a_led *led)
> +{
> +	struct an30259a *chip = led->chip;
> +	int ledon, err;
> +
> +	switch (led->default_state) {
> +	case STATE_ON:
> +		led->cdev.brightness = LED_FULL;
> +		break;
> +	case STATE_KEEP:
> +		err = regmap_read(chip->regmap, REG_LEDON, &ledon);
> +		if (err)
> +			break;
> +
> +		if (!(ledon & LED_EN(led->num))) {
> +			led->cdev.brightness = LED_OFF;
> +			break;
> +		}
> +		regmap_read(chip->regmap, REG_LEDCC(led->num),
> +			    &led->cdev.brightness);
> +		break;
> +	default:
> +		led->cdev.brightness = LED_OFF;
> +	}
> +
> +	an30259a_led_set(&led->cdev, led->cdev.brightness);
> +}
> +
> +static int an30259a_probe(struct i2c_client *client)
> +{
> +	struct an30259a *chip;
> +	int i, err;
> +
> +	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +	if (!chip)
> +		return -ENOMEM;
> +
> +	err = an30259a_dt_init(client, chip);
> +	if (err < 0)
> +		return err;
> +
> +	mutex_init(&chip->mutex);
> +	chip->client = client;
> +	i2c_set_clientdata(client, chip);
> +
> +	chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);
> +
> +	for (i = 0; i < chip->num_leds; i++) {
> +		an30259a_init_default_state(&chip->leds[i]);
> +		chip->leds[i].cdev.brightness_set_blocking = an30259a_led_set;
> +		chip->leds[i].cdev.blink_set = an30259a_blink_set;
> +
> +		err = devm_led_classdev_register(&client->dev,
> +						 &chip->leds[i].cdev);
> +		if (err < 0)
> +			goto exit;
> +	}
> +	return 0;
> +
> +exit:
> +	mutex_destroy(&chip->mutex);
> +	return err;
> +}
> +
> +static int an30259a_remove(struct i2c_client *client)
> +{
> +	struct an30259a *chip = i2c_get_clientdata(client);
> +
> +	mutex_destroy(&chip->mutex);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id an30259a_match_table[] = {
> +	{ .compatible = "panasonic,an30259a", },
> +	{ /* sentinel */ },
> +};
> +
> +MODULE_DEVICE_TABLE(of, an30259a_match_table);
> +
> +static const struct i2c_device_id an30259a_id[] = {
> +	{ "an30259a", NULL },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(i2c, an30259a_id);
> +
> +static struct i2c_driver an30259a_driver = {
> +	.driver = {
> +		.name = "leds-an32059a",
> +		.of_match_table = of_match_ptr(an30259a_match_table),
> +	},
> +	.probe_new = an30259a_probe,
> +	.remove = an30259a_remove,
> +	.id_table = an30259a_id,
> +};
> +
> +module_i2c_driver(an30259a_driver);
> +
> +MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
> +MODULE_DESCRIPTION("AN32059A LED driver");
> +MODULE_LICENSE("GPL v2");
> 

[0] https://www.mail-archive.com/netdev@vger.kernel.org/msg204598.html
[1] https://lkml.org/lkml/2018/1/10/1110
[2] https://lkml.org/lkml/2017/11/2/715

-- 
Best regards,
Jacek Anaszewski

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

* Re: [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings
  2018-03-08 22:17   ` Jacek Anaszewski
@ 2018-03-08 22:54     ` Pavel Machek
  2018-03-09 22:33       ` Jacek Anaszewski
  0 siblings, 1 reply; 11+ messages in thread
From: Pavel Machek @ 2018-03-08 22:54 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Simon Shields, linux-leds, Richard Purdie, devicetree, Rob Herring

[-- Attachment #1: Type: text/plain, Size: 970 bytes --]

Hi!

> > +	led@1 {
> > +		reg = <1>;
> > +		linux,default-trigger = "heartbeat";
> > +		label = "an30259a:red:notification";
> 
> s/an30259a:red:notification/red:notification/
> 
> Let's drop devicename section from label, and make it a LED class
> driver responsibility to prepend the label with devicename when
> composing LED class device name.

Is it good idea?

(Some existing bindings specify three-part label in the label, some do
not. Documentation/devicetree/bindings/leds/leds-netxbig.txt
vs. Documentation/devicetree/bindings/leds/leds-mt6323.txt :-( We
should really solve that somehow).

I'd really like to see input0:white:numlock in the name, so same
software has a chance to work on PC and ARM notebook. Prepending
an30259a in the driver will break that...

Best regards,

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

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

* Re: [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings
  2018-03-08 22:54     ` Pavel Machek
@ 2018-03-09 22:33       ` Jacek Anaszewski
  0 siblings, 0 replies; 11+ messages in thread
From: Jacek Anaszewski @ 2018-03-09 22:33 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Simon Shields, linux-leds, Richard Purdie, devicetree, Rob Herring

On 03/08/2018 11:54 PM, Pavel Machek wrote:
> Hi!
> 
>>> +	led@1 {
>>> +		reg = <1>;
>>> +		linux,default-trigger = "heartbeat";
>>> +		label = "an30259a:red:notification";
>>
>> s/an30259a:red:notification/red:notification/
>>
>> Let's drop devicename section from label, and make it a LED class
>> driver responsibility to prepend the label with devicename when
>> composing LED class device name.
> 
> Is it good idea?
> 
> (Some existing bindings specify three-part label in the label, some do
> not. Documentation/devicetree/bindings/leds/leds-netxbig.txt
> vs. Documentation/devicetree/bindings/leds/leds-mt6323.txt :-( We
> should really solve that somehow).

It looks that we didn't pay enough attention to the label DT property
format, as long as the resulting LED class device name conformed
to the three-part LED naming scheme.

We certainly need to fix that, by defining the label format explicitly
in the common LED bindings. However we have two related issues, that
have been raised several times throughout last months:

1. label format

Rob's statement from [0]:

"I really dislike how this naming convention is used for label. label is
 supposed to be the physically identifiable name. Having the devicename
defeats that. We'd be better off with a color property.
It seems we're overloading the naming with too many things. Now we're
adding device association"

2. LED class device naming

Rob's statement from [0]:

"I do want to see standard names though. On 96boards for example, there
are defined LEDs and locations. The function on some are defined (e.g.
WiFi/BT) and somewhat undefined on others (user{1-4}). I'd like to see
the same label across all boards."


Now, we have to decide if label should map directly to LED class device.
I requested removing devicename from label to satisfy 1., provided
that there was no conclusion from the thread [0]. Also some LED class
drivers already follow this scheme.

Of course I meant it to be only a temporary solution until we unify
the LED class device naming across all drivers and bindings.

Driving LED controller name can be looked up in sysfs so it doesn't
need to be a part of the LED class device name.

> I'd really like to see input0:white:numlock in the name, so same
> software has a chance to work on PC and ARM notebook. Prepending
> an30259a in the driver will break that...

You have input0 in your example. It does not say too much
about the device the LED is associated with. I assume that this
is not a device node name, since in Device Tree you don't know the
associations between DT nodes and device node numbers.

[0] https://patchwork.kernel.org/patch/9956315/

-- 
Best regards,
Jacek Anaszewski

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

end of thread, other threads:[~2018-03-09 22:33 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-07  0:47 [PATCH v2 0/2] Panasonic AN30259A support Simon Shields
2018-03-07  0:47 ` [PATCH v2 1/2] dt-bindings: leds: document Panasonic AN30259A bindings Simon Shields
2018-03-07 21:58   ` Pavel Machek
2018-03-08  2:02   ` Rob Herring
2018-03-08 22:17   ` Jacek Anaszewski
2018-03-08 22:54     ` Pavel Machek
2018-03-09 22:33       ` Jacek Anaszewski
2018-03-07  0:47 ` [PATCH v2 2/2] leds: add Panasonic AN30259A support Simon Shields
2018-03-07 22:07   ` Pavel Machek
2018-03-08  0:48     ` Simon Shields
2018-03-08 22:17   ` Jacek Anaszewski

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.