devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] leds: add LED driver for CR0014114 board
       [not found] <026d9ec2-f2bd-18b9-d5fa-f593d40e2f57@kaa.org.ua>
@ 2018-03-12 15:33 ` Oleh Kravchenko
  2018-03-12 15:45   ` Peter Meerwald-Stadler
  2018-03-17  8:19   ` Jacek Anaszewski
  2018-03-12 15:58 ` [PATCH v2] " Oleh Kravchenko
  1 sibling, 2 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-12 15:33 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

This patch adds a LED class driver for the RGB LEDs found on
the Crane Merchandising System CR0014114 LEDs board.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 drivers/leds/Kconfig                               |  13 +
 drivers/leds/Makefile                              |   1 +
 drivers/leds/leds-cr0014114.c                      | 282 +++++++++++++++++++++
 5 files changed, 343 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
 create mode 100644 drivers/leds/leds-cr0014114.c

diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
new file mode 100644
index 000000000000..56721598ee81
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
@@ -0,0 +1,46 @@
+Crane Merchandising System - cr0014114 LED driver
+-------------------------------------------------
+
+This LED Board widely used in vending machines produced
+by Crane Merchandising Systems.
+
+Required properties:
+- compatible: "cms,cr0014114"
+- reg: chip select address for the device
+- spi-cpha: shifted clock phase mode is required
+
+LED sub-node properties:
+- label : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+
+Example
+-------
+
+cr0014114@0 {
+	compatible = "crane,cr0014114";
+	reg = <0>;
+	spi-max-frequency = <50000>;
+	spi-cpha;
+
+	led0 {
+		label = "cr0:red:";
+	};
+	led1 {
+		label = "cr0:green:";
+	};
+	led2 {
+		label = "cr0:blue:";
+	};
+	led3 {
+		label = "cr1:red:";
+	};
+	led4 {
+		label = "cr1:green:";
+	};
+	led5 {
+		label = "cr1:blue:";
+	};
+	...
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ae850d6c0ad3..f17949c365f5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
 compulab	CompuLab Ltd.
 cortina	Cortina Systems, Inc.
 cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
 creative	Creative Technology Ltd
 crystalfontz	Crystalfontz America, Inc.
 cubietech	Cubietech, Ltd.
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..bb6a70ac5004 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -104,6 +104,19 @@ config LEDS_CPCAP
 	  This option enables support for LEDs offered by Motorola's
 	  CPCAP PMIC.
 
+config LEDS_CR0014114
+	tristate "LED Support for Crane CR0014114"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for CR0014114 LED Board which
+	  widely used in vending machines produced by
+	  Crane Merchandising Systems.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-cr0014114.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..0176e7335994 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 
 # LED SPI Drivers
+obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Userspace Drivers
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
new file mode 100644
index 000000000000..e3aecdbea73c
--- /dev/null
+++ b/drivers/leds/leds-cr0014114.c
@@ -0,0 +1,282 @@
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+
+/* CR0014114 SPI commands */
+#define CR_SET_BRIGHTNESS	0x80
+#define CR_INIT_REENUMERATE	0x81
+#define CR_NEXT_REENUMERATE	0x82
+
+/* CR0014114 default settings */
+#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
+#define CR_FW_DELAY_MSEC	10
+#define CR_RECOUNT_DELAY	(HZ * 3600)
+
+struct cr0014114_led {
+	const char		*name;
+	struct cr0014114	*priv;
+	struct led_classdev	ldev;
+	u8			brightness;
+};
+
+struct cr0014114 {
+	bool			do_recount;
+	size_t			count;
+	struct device		*dev;
+	struct mutex		lock;
+	struct spi_device	*spi;
+	struct timer_list	timer;
+	struct work_struct	work;
+	unsigned long		delay;
+	struct cr0014114_led	leds[];
+};
+
+static void cr0014114_calc_crc(u8 *buf, const size_t len)
+{
+	size_t	i;
+	u8	crc;
+
+	for (i = 1, crc = 1; i < len - 1; i++)
+		crc += buf[i];
+	crc |= BIT(7);
+
+	/* special case when CRC matches to SPI commands */
+	if (crc == CR_SET_BRIGHTNESS ||
+	    crc == CR_INIT_REENUMERATE ||
+	    crc == CR_NEXT_REENUMERATE)
+		crc = 0xfe;
+
+	buf[len - 1] = crc;
+}
+
+static int cr0014114_recount(struct cr0014114 *priv)
+{
+	int	ret;
+	size_t	i;
+	u8	cmd;
+
+	dev_dbg(priv->dev, "recount of LEDs is started\n");
+
+	do {
+		cmd = CR_INIT_REENUMERATE;
+		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+		if (ret)
+			break;
+
+		cmd = CR_NEXT_REENUMERATE;
+		for (i = 0; i < priv->count; i++) {
+			msleep(CR_FW_DELAY_MSEC);
+
+			ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+			if (ret)
+				break;
+		}
+	} while (0);
+
+	dev_dbg(priv->dev, "recount of LEDs is complete, error: %d\n", ret);
+
+	return ret;
+}
+
+static int cr0014114_sync(struct cr0014114 *priv)
+{
+	int		ret;
+	size_t		i;
+	u8		data[priv->count + 2];
+	unsigned long	udelay, now = jiffies;
+
+	/* to avoid SPI mistiming with firmware we should wait some time */
+	if (time_after(priv->delay, now)) {
+		udelay = jiffies_to_usecs(priv->delay - now);
+		usleep_range(udelay, udelay + 1);
+	}
+
+	do {
+		if (unlikely(priv->do_recount)) {
+			ret = cr0014114_recount(priv);
+			if (ret)
+				break;
+
+			priv->do_recount = false;
+		}
+
+		data[0] = CR_SET_BRIGHTNESS;
+		for (i = 0; i < priv->count; i++)
+			data[i + 1] = priv->leds[i].brightness;
+		cr0014114_calc_crc(data, sizeof(data));
+
+		ret = spi_write(priv->spi, data, sizeof(data));
+		if (ret)
+			break;
+	} while (0);
+
+	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	return ret;
+}
+
+static void cr0014114_recount_work(struct work_struct *work)
+{
+	int			ret;
+	struct cr0014114	*priv = container_of(work, struct cr0014114,
+						     work);
+
+	mutex_lock(&priv->lock);
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		dev_warn(priv->dev, "recount LEDs failed %d\n", ret);
+}
+
+int cr0014114_set_sync(struct led_classdev *ldev,
+		       enum led_brightness brightness)
+{
+	int			ret;
+	struct cr0014114_led    *led = container_of(ldev,
+						    struct cr0014114_led,
+						    ldev);
+
+	mutex_lock(&led->priv->lock);
+	led->brightness = (u8)brightness;
+	ret = cr0014114_sync(led->priv);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+void cr0014114_recount_timer(struct timer_list *t)
+{
+	struct cr0014114 *priv = from_timer(priv, t, timer);
+
+	schedule_work(&priv->work);
+	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
+}
+
+static int cr0014114_probe_dt(struct cr0014114 *priv)
+{
+	size_t			i = 0;
+	struct cr0014114_led	*led;
+	struct fwnode_handle	*child;
+	struct device_node	*np;
+	int			ret;
+
+	device_for_each_child_node(priv->dev, child) {
+		np = to_of_node(child);
+		led = &priv->leds[i];
+
+		ret = fwnode_property_read_string(child, "label",
+						  &led->name);
+		if (ret && IS_ENABLED(CONFIG_OF) && np)
+			led->name = np->name;
+
+		if (!led->name) {
+			fwnode_handle_put(child);
+			return -EINVAL;
+		}
+
+		fwnode_property_read_string(child, "linux,default-trigger",
+					    &led->ldev.default_trigger);
+
+		led->priv			  = priv;
+		led->ldev.name			  = led->name;
+		led->ldev.brightness		  = LED_OFF;
+		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
+		led->ldev.brightness_set_blocking = cr0014114_set_sync;
+
+		ret = devm_of_led_classdev_register(priv->dev, np,
+						    &led->ldev);
+		if (ret) {
+			fwnode_handle_put(child);
+			return ret;
+		}
+
+		led->ldev.dev->of_node = np;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int cr0014114_probe(struct spi_device *spi)
+{
+	struct cr0014114	*priv;
+	size_t			count;
+	int			ret;
+
+	count = device_get_child_node_count(&spi->dev);
+	if (!count) {
+		dev_err(&spi->dev, "LEDs are not defined in device tree");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&spi->dev,
+			    sizeof(*priv) + sizeof(*priv->leds) * count,
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	INIT_WORK(&priv->work, cr0014114_recount_work);
+	priv->do_recount	= true;
+	priv->count		= count;
+	priv->dev		= &spi->dev;
+	priv->spi		= spi;
+
+	ret = cr0014114_probe_dt(priv);
+	if (ret)
+		return ret;
+
+	ret = cr0014114_sync(priv);
+	if (ret)
+		return ret;
+
+	/* setup recount timer to workaround buggy firmware */
+	timer_setup(&priv->timer, cr0014114_recount_timer, 0);
+	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
+
+	spi_set_drvdata(spi, priv);
+
+	return 0;
+}
+
+static int cr0014114_remove(struct spi_device *spi)
+{
+	struct cr0014114 *priv = spi_get_drvdata(spi);
+
+	cancel_work_sync(&priv->work);
+	del_timer_sync(&priv->timer);
+
+	return 0;
+}
+
+static const struct of_device_id cr0014114_dt_ids[] = {
+	{ .compatible = "crane,cr0014114", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
+
+static struct spi_driver cr0014114_driver = {
+	.probe		= cr0014114_probe,
+	.remove		= cr0014114_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= cr0014114_dt_ids,
+	},
+};
+
+module_spi_driver(cr0014114_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("cr0014114 LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:cr0014114");
-- 
2.13.6


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

* Re: [PATCH] leds: add LED driver for CR0014114 board
  2018-03-12 15:33 ` [PATCH] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-03-12 15:45   ` Peter Meerwald-Stadler
  2018-03-12 15:54     ` Oleh Kravchenko
  2018-03-17  8:19   ` Jacek Anaszewski
  1 sibling, 1 reply; 46+ messages in thread
From: Peter Meerwald-Stadler @ 2018-03-12 15:45 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, linux-leds


trivial comments below

> This patch adds a LED class driver for the RGB LEDs found on
> the Crane Merchandising System CR0014114 LEDs board.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>  drivers/leds/Kconfig                               |  13 +
>  drivers/leds/Makefile                              |   1 +
>  drivers/leds/leds-cr0014114.c                      | 282 +++++++++++++++++++++
>  5 files changed, 343 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>  create mode 100644 drivers/leds/leds-cr0014114.c
> 
> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> new file mode 100644
> index 000000000000..56721598ee81
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> @@ -0,0 +1,46 @@
> +Crane Merchandising System - cr0014114 LED driver
> +-------------------------------------------------
> +
> +This LED Board widely used in vending machines produced

_is_ widely used

> +by Crane Merchandising Systems.
> +
> +Required properties:
> +- compatible: "cms,cr0014114"
> +- reg: chip select address for the device
> +- spi-cpha: shifted clock phase mode is required
> +
> +LED sub-node properties:
> +- label : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +- linux,default-trigger : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example
> +-------
> +
> +cr0014114@0 {
> +	compatible = "crane,cr0014114";
> +	reg = <0>;
> +	spi-max-frequency = <50000>;
> +	spi-cpha;
> +
> +	led0 {
> +		label = "cr0:red:";
> +	};
> +	led1 {
> +		label = "cr0:green:";
> +	};
> +	led2 {
> +		label = "cr0:blue:";
> +	};
> +	led3 {
> +		label = "cr1:red:";
> +	};
> +	led4 {
> +		label = "cr1:green:";
> +	};
> +	led5 {
> +		label = "cr1:blue:";
> +	};
> +	...
> +};
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index ae850d6c0ad3..f17949c365f5 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>  compulab	CompuLab Ltd.
>  cortina	Cortina Systems, Inc.
>  cosmic	Cosmic Circuits
> +crane	Crane Connectivity Solutions
>  creative	Creative Technology Ltd
>  crystalfontz	Crystalfontz America, Inc.
>  cubietech	Cubietech, Ltd.
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 2c896c0e69e1..bb6a70ac5004 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -104,6 +104,19 @@ config LEDS_CPCAP
>  	  This option enables support for LEDs offered by Motorola's
>  	  CPCAP PMIC.
>  
> +config LEDS_CR0014114
> +	tristate "LED Support for Crane CR0014114"
> +	depends on LEDS_CLASS
> +	depends on SPI
> +	depends on OF
> +	help
> +	  This option enables support for CR0014114 LED Board which
> +	  widely used in vending machines produced by

is widely

> +	  Crane Merchandising Systems.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called leds-cr0014114.
> +
>  config LEDS_LM3530
>  	tristate "LCD Backlight driver for LM3530"
>  	depends on LEDS_CLASS
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 91eca81cae82..0176e7335994 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
>  obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
>  
>  # LED SPI Drivers
> +obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
>  obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
>  
>  # LED Userspace Drivers
> diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
> new file mode 100644
> index 000000000000..e3aecdbea73c
> --- /dev/null
> +++ b/drivers/leds/leds-cr0014114.c
> @@ -0,0 +1,282 @@
> +#include <linux/delay.h>
> +#include <linux/leds.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/property.h>
> +#include <linux/spi/spi.h>
> +#include <linux/spinlock.h>
> +#include <linux/timer.h>
> +#include <linux/workqueue.h>
> +
> +/* CR0014114 SPI commands */
> +#define CR_SET_BRIGHTNESS	0x80
> +#define CR_INIT_REENUMERATE	0x81
> +#define CR_NEXT_REENUMERATE	0x82
> +
> +/* CR0014114 default settings */
> +#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
> +#define CR_FW_DELAY_MSEC	10
> +#define CR_RECOUNT_DELAY	(HZ * 3600)
> +
> +struct cr0014114_led {
> +	const char		*name;
> +	struct cr0014114	*priv;
> +	struct led_classdev	ldev;
> +	u8			brightness;
> +};
> +
> +struct cr0014114 {
> +	bool			do_recount;
> +	size_t			count;
> +	struct device		*dev;
> +	struct mutex		lock;
> +	struct spi_device	*spi;
> +	struct timer_list	timer;
> +	struct work_struct	work;
> +	unsigned long		delay;
> +	struct cr0014114_led	leds[];
> +};
> +
> +static void cr0014114_calc_crc(u8 *buf, const size_t len)
> +{
> +	size_t	i;
> +	u8	crc;
> +
> +	for (i = 1, crc = 1; i < len - 1; i++)
> +		crc += buf[i];
> +	crc |= BIT(7);
> +
> +	/* special case when CRC matches to SPI commands */

matches the

> +	if (crc == CR_SET_BRIGHTNESS ||
> +	    crc == CR_INIT_REENUMERATE ||
> +	    crc == CR_NEXT_REENUMERATE)
> +		crc = 0xfe;
> +
> +	buf[len - 1] = crc;
> +}
> +
> +static int cr0014114_recount(struct cr0014114 *priv)
> +{
> +	int	ret;
> +	size_t	i;
> +	u8	cmd;
> +
> +	dev_dbg(priv->dev, "recount of LEDs is started\n");
> +
> +	do {
> +		cmd = CR_INIT_REENUMERATE;
> +		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
> +		if (ret)
> +			break;
> +
> +		cmd = CR_NEXT_REENUMERATE;
> +		for (i = 0; i < priv->count; i++) {
> +			msleep(CR_FW_DELAY_MSEC);
> +
> +			ret = spi_write(priv->spi, &cmd, sizeof(cmd));
> +			if (ret)
> +				break;
> +		}
> +	} while (0);
> +
> +	dev_dbg(priv->dev, "recount of LEDs is complete, error: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cr0014114_sync(struct cr0014114 *priv)
> +{
> +	int		ret;
> +	size_t		i;
> +	u8		data[priv->count + 2];
> +	unsigned long	udelay, now = jiffies;
> +
> +	/* to avoid SPI mistiming with firmware we should wait some time */
> +	if (time_after(priv->delay, now)) {
> +		udelay = jiffies_to_usecs(priv->delay - now);
> +		usleep_range(udelay, udelay + 1);
> +	}
> +
> +	do {
> +		if (unlikely(priv->do_recount)) {
> +			ret = cr0014114_recount(priv);
> +			if (ret)
> +				break;
> +
> +			priv->do_recount = false;
> +		}
> +
> +		data[0] = CR_SET_BRIGHTNESS;
> +		for (i = 0; i < priv->count; i++)
> +			data[i + 1] = priv->leds[i].brightness;
> +		cr0014114_calc_crc(data, sizeof(data));
> +
> +		ret = spi_write(priv->spi, data, sizeof(data));
> +		if (ret)
> +			break;
> +	} while (0);
> +
> +	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
> +
> +	return ret;
> +}
> +
> +static void cr0014114_recount_work(struct work_struct *work)
> +{
> +	int			ret;
> +	struct cr0014114	*priv = container_of(work, struct cr0014114,
> +						     work);
> +
> +	mutex_lock(&priv->lock);
> +	priv->do_recount = true;
> +	ret = cr0014114_sync(priv);
> +	mutex_unlock(&priv->lock);
> +
> +	if (ret)
> +		dev_warn(priv->dev, "recount LEDs failed %d\n", ret);
> +}
> +
> +int cr0014114_set_sync(struct led_classdev *ldev,

static?

> +		       enum led_brightness brightness)
> +{
> +	int			ret;
> +	struct cr0014114_led    *led = container_of(ldev,
> +						    struct cr0014114_led,
> +						    ldev);
> +
> +	mutex_lock(&led->priv->lock);
> +	led->brightness = (u8)brightness;
> +	ret = cr0014114_sync(led->priv);
> +	mutex_unlock(&led->priv->lock);
> +
> +	return ret;
> +}
> +
> +void cr0014114_recount_timer(struct timer_list *t)

static?

> +{
> +	struct cr0014114 *priv = from_timer(priv, t, timer);
> +
> +	schedule_work(&priv->work);
> +	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
> +}
> +
> +static int cr0014114_probe_dt(struct cr0014114 *priv)
> +{
> +	size_t			i = 0;
> +	struct cr0014114_led	*led;
> +	struct fwnode_handle	*child;
> +	struct device_node	*np;
> +	int			ret;
> +
> +	device_for_each_child_node(priv->dev, child) {
> +		np = to_of_node(child);
> +		led = &priv->leds[i];
> +
> +		ret = fwnode_property_read_string(child, "label",
> +						  &led->name);
> +		if (ret && IS_ENABLED(CONFIG_OF) && np)
> +			led->name = np->name;
> +
> +		if (!led->name) {
> +			fwnode_handle_put(child);
> +			return -EINVAL;
> +		}
> +
> +		fwnode_property_read_string(child, "linux,default-trigger",
> +					    &led->ldev.default_trigger);
> +
> +		led->priv			  = priv;
> +		led->ldev.name			  = led->name;
> +		led->ldev.brightness		  = LED_OFF;
> +		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
> +		led->ldev.brightness_set_blocking = cr0014114_set_sync;
> +
> +		ret = devm_of_led_classdev_register(priv->dev, np,
> +						    &led->ldev);
> +		if (ret) {
> +			fwnode_handle_put(child);
> +			return ret;
> +		}
> +
> +		led->ldev.dev->of_node = np;
> +
> +		i++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cr0014114_probe(struct spi_device *spi)
> +{
> +	struct cr0014114	*priv;
> +	size_t			count;
> +	int			ret;
> +
> +	count = device_get_child_node_count(&spi->dev);
> +	if (!count) {
> +		dev_err(&spi->dev, "LEDs are not defined in device tree");
> +		return -ENODEV;
> +	}
> +
> +	priv = devm_kzalloc(&spi->dev,
> +			    sizeof(*priv) + sizeof(*priv->leds) * count,
> +			    GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	mutex_init(&priv->lock);
> +	INIT_WORK(&priv->work, cr0014114_recount_work);
> +	priv->do_recount	= true;
> +	priv->count		= count;
> +	priv->dev		= &spi->dev;
> +	priv->spi		= spi;
> +
> +	ret = cr0014114_probe_dt(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = cr0014114_sync(priv);
> +	if (ret)
> +		return ret;
> +
> +	/* setup recount timer to workaround buggy firmware */
> +	timer_setup(&priv->timer, cr0014114_recount_timer, 0);
> +	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
> +
> +	spi_set_drvdata(spi, priv);
> +
> +	return 0;
> +}
> +
> +static int cr0014114_remove(struct spi_device *spi)
> +{
> +	struct cr0014114 *priv = spi_get_drvdata(spi);
> +
> +	cancel_work_sync(&priv->work);
> +	del_timer_sync(&priv->timer);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id cr0014114_dt_ids[] = {
> +	{ .compatible = "crane,cr0014114", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
> +
> +static struct spi_driver cr0014114_driver = {
> +	.probe		= cr0014114_probe,
> +	.remove		= cr0014114_remove,
> +	.driver = {
> +		.name		= KBUILD_MODNAME,
> +		.of_match_table	= cr0014114_dt_ids,
> +	},
> +};
> +
> +module_spi_driver(cr0014114_driver);
> +
> +MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
> +MODULE_DESCRIPTION("cr0014114 LED driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("spi:cr0014114");
> 

-- 

Peter Meerwald-Stadler
Mobile: +43 664 24 44 418

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

* Re: [PATCH] leds: add LED driver for CR0014114 board
  2018-03-12 15:45   ` Peter Meerwald-Stadler
@ 2018-03-12 15:54     ` Oleh Kravchenko
  0 siblings, 0 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-12 15:54 UTC (permalink / raw)
  To: Peter Meerwald-Stadler; +Cc: devicetree, linux-leds


[-- Attachment #1.1: Type: text/plain, Size: 11841 bytes --]

Thanks for comments.


On 12.03.18 17:45, Peter Meerwald-Stadler wrote:
> trivial comments below
>
>> This patch adds a LED class driver for the RGB LEDs found on
>> the Crane Merchandising System CR0014114 LEDs board.
>>
>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
>> ---
>>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>>  drivers/leds/Kconfig                               |  13 +
>>  drivers/leds/Makefile                              |   1 +
>>  drivers/leds/leds-cr0014114.c                      | 282 +++++++++++++++++++++
>>  5 files changed, 343 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>  create mode 100644 drivers/leds/leds-cr0014114.c
>>
>> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>> new file mode 100644
>> index 000000000000..56721598ee81
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>> @@ -0,0 +1,46 @@
>> +Crane Merchandising System - cr0014114 LED driver
>> +-------------------------------------------------
>> +
>> +This LED Board widely used in vending machines produced
> _is_ widely used
>
>> +by Crane Merchandising Systems.
>> +
>> +Required properties:
>> +- compatible: "cms,cr0014114"
>> +- reg: chip select address for the device
>> +- spi-cpha: shifted clock phase mode is required
>> +
>> +LED sub-node properties:
>> +- label : (optional)
>> +	see Documentation/devicetree/bindings/leds/common.txt
>> +- linux,default-trigger : (optional)
>> +	see Documentation/devicetree/bindings/leds/common.txt
>> +
>> +Example
>> +-------
>> +
>> +cr0014114@0 {
>> +	compatible = "crane,cr0014114";
>> +	reg = <0>;
>> +	spi-max-frequency = <50000>;
>> +	spi-cpha;
>> +
>> +	led0 {
>> +		label = "cr0:red:";
>> +	};
>> +	led1 {
>> +		label = "cr0:green:";
>> +	};
>> +	led2 {
>> +		label = "cr0:blue:";
>> +	};
>> +	led3 {
>> +		label = "cr1:red:";
>> +	};
>> +	led4 {
>> +		label = "cr1:green:";
>> +	};
>> +	led5 {
>> +		label = "cr1:blue:";
>> +	};
>> +	...
>> +};
>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> index ae850d6c0ad3..f17949c365f5 100644
>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>>  compulab	CompuLab Ltd.
>>  cortina	Cortina Systems, Inc.
>>  cosmic	Cosmic Circuits
>> +crane	Crane Connectivity Solutions
>>  creative	Creative Technology Ltd
>>  crystalfontz	Crystalfontz America, Inc.
>>  cubietech	Cubietech, Ltd.
>> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
>> index 2c896c0e69e1..bb6a70ac5004 100644
>> --- a/drivers/leds/Kconfig
>> +++ b/drivers/leds/Kconfig
>> @@ -104,6 +104,19 @@ config LEDS_CPCAP
>>  	  This option enables support for LEDs offered by Motorola's
>>  	  CPCAP PMIC.
>>  
>> +config LEDS_CR0014114
>> +	tristate "LED Support for Crane CR0014114"
>> +	depends on LEDS_CLASS
>> +	depends on SPI
>> +	depends on OF
>> +	help
>> +	  This option enables support for CR0014114 LED Board which
>> +	  widely used in vending machines produced by
> is widely
>
>> +	  Crane Merchandising Systems.
>> +
>> +	  To compile this driver as a module, choose M here: the module
>> +	  will be called leds-cr0014114.
>> +
>>  config LEDS_LM3530
>>  	tristate "LCD Backlight driver for LM3530"
>>  	depends on LEDS_CLASS
>> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
>> index 91eca81cae82..0176e7335994 100644
>> --- a/drivers/leds/Makefile
>> +++ b/drivers/leds/Makefile
>> @@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
>>  obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
>>  
>>  # LED SPI Drivers
>> +obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
>>  obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
>>  
>>  # LED Userspace Drivers
>> diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
>> new file mode 100644
>> index 000000000000..e3aecdbea73c
>> --- /dev/null
>> +++ b/drivers/leds/leds-cr0014114.c
>> @@ -0,0 +1,282 @@
>> +#include <linux/delay.h>
>> +#include <linux/leds.h>
>> +#include <linux/module.h>
>> +#include <linux/of_device.h>
>> +#include <linux/property.h>
>> +#include <linux/spi/spi.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/timer.h>
>> +#include <linux/workqueue.h>
>> +
>> +/* CR0014114 SPI commands */
>> +#define CR_SET_BRIGHTNESS	0x80
>> +#define CR_INIT_REENUMERATE	0x81
>> +#define CR_NEXT_REENUMERATE	0x82
>> +
>> +/* CR0014114 default settings */
>> +#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
>> +#define CR_FW_DELAY_MSEC	10
>> +#define CR_RECOUNT_DELAY	(HZ * 3600)
>> +
>> +struct cr0014114_led {
>> +	const char		*name;
>> +	struct cr0014114	*priv;
>> +	struct led_classdev	ldev;
>> +	u8			brightness;
>> +};
>> +
>> +struct cr0014114 {
>> +	bool			do_recount;
>> +	size_t			count;
>> +	struct device		*dev;
>> +	struct mutex		lock;
>> +	struct spi_device	*spi;
>> +	struct timer_list	timer;
>> +	struct work_struct	work;
>> +	unsigned long		delay;
>> +	struct cr0014114_led	leds[];
>> +};
>> +
>> +static void cr0014114_calc_crc(u8 *buf, const size_t len)
>> +{
>> +	size_t	i;
>> +	u8	crc;
>> +
>> +	for (i = 1, crc = 1; i < len - 1; i++)
>> +		crc += buf[i];
>> +	crc |= BIT(7);
>> +
>> +	/* special case when CRC matches to SPI commands */
> matches the
>
>> +	if (crc == CR_SET_BRIGHTNESS ||
>> +	    crc == CR_INIT_REENUMERATE ||
>> +	    crc == CR_NEXT_REENUMERATE)
>> +		crc = 0xfe;
>> +
>> +	buf[len - 1] = crc;
>> +}
>> +
>> +static int cr0014114_recount(struct cr0014114 *priv)
>> +{
>> +	int	ret;
>> +	size_t	i;
>> +	u8	cmd;
>> +
>> +	dev_dbg(priv->dev, "recount of LEDs is started\n");
>> +
>> +	do {
>> +		cmd = CR_INIT_REENUMERATE;
>> +		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
>> +		if (ret)
>> +			break;
>> +
>> +		cmd = CR_NEXT_REENUMERATE;
>> +		for (i = 0; i < priv->count; i++) {
>> +			msleep(CR_FW_DELAY_MSEC);
>> +
>> +			ret = spi_write(priv->spi, &cmd, sizeof(cmd));
>> +			if (ret)
>> +				break;
>> +		}
>> +	} while (0);
>> +
>> +	dev_dbg(priv->dev, "recount of LEDs is complete, error: %d\n", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static int cr0014114_sync(struct cr0014114 *priv)
>> +{
>> +	int		ret;
>> +	size_t		i;
>> +	u8		data[priv->count + 2];
>> +	unsigned long	udelay, now = jiffies;
>> +
>> +	/* to avoid SPI mistiming with firmware we should wait some time */
>> +	if (time_after(priv->delay, now)) {
>> +		udelay = jiffies_to_usecs(priv->delay - now);
>> +		usleep_range(udelay, udelay + 1);
>> +	}
>> +
>> +	do {
>> +		if (unlikely(priv->do_recount)) {
>> +			ret = cr0014114_recount(priv);
>> +			if (ret)
>> +				break;
>> +
>> +			priv->do_recount = false;
>> +		}
>> +
>> +		data[0] = CR_SET_BRIGHTNESS;
>> +		for (i = 0; i < priv->count; i++)
>> +			data[i + 1] = priv->leds[i].brightness;
>> +		cr0014114_calc_crc(data, sizeof(data));
>> +
>> +		ret = spi_write(priv->spi, data, sizeof(data));
>> +		if (ret)
>> +			break;
>> +	} while (0);
>> +
>> +	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
>> +
>> +	return ret;
>> +}
>> +
>> +static void cr0014114_recount_work(struct work_struct *work)
>> +{
>> +	int			ret;
>> +	struct cr0014114	*priv = container_of(work, struct cr0014114,
>> +						     work);
>> +
>> +	mutex_lock(&priv->lock);
>> +	priv->do_recount = true;
>> +	ret = cr0014114_sync(priv);
>> +	mutex_unlock(&priv->lock);
>> +
>> +	if (ret)
>> +		dev_warn(priv->dev, "recount LEDs failed %d\n", ret);
>> +}
>> +
>> +int cr0014114_set_sync(struct led_classdev *ldev,
> static?
>
>> +		       enum led_brightness brightness)
>> +{
>> +	int			ret;
>> +	struct cr0014114_led    *led = container_of(ldev,
>> +						    struct cr0014114_led,
>> +						    ldev);
>> +
>> +	mutex_lock(&led->priv->lock);
>> +	led->brightness = (u8)brightness;
>> +	ret = cr0014114_sync(led->priv);
>> +	mutex_unlock(&led->priv->lock);
>> +
>> +	return ret;
>> +}
>> +
>> +void cr0014114_recount_timer(struct timer_list *t)
> static?
>
>> +{
>> +	struct cr0014114 *priv = from_timer(priv, t, timer);
>> +
>> +	schedule_work(&priv->work);
>> +	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
>> +}
>> +
>> +static int cr0014114_probe_dt(struct cr0014114 *priv)
>> +{
>> +	size_t			i = 0;
>> +	struct cr0014114_led	*led;
>> +	struct fwnode_handle	*child;
>> +	struct device_node	*np;
>> +	int			ret;
>> +
>> +	device_for_each_child_node(priv->dev, child) {
>> +		np = to_of_node(child);
>> +		led = &priv->leds[i];
>> +
>> +		ret = fwnode_property_read_string(child, "label",
>> +						  &led->name);
>> +		if (ret && IS_ENABLED(CONFIG_OF) && np)
>> +			led->name = np->name;
>> +
>> +		if (!led->name) {
>> +			fwnode_handle_put(child);
>> +			return -EINVAL;
>> +		}
>> +
>> +		fwnode_property_read_string(child, "linux,default-trigger",
>> +					    &led->ldev.default_trigger);
>> +
>> +		led->priv			  = priv;
>> +		led->ldev.name			  = led->name;
>> +		led->ldev.brightness		  = LED_OFF;
>> +		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
>> +		led->ldev.brightness_set_blocking = cr0014114_set_sync;
>> +
>> +		ret = devm_of_led_classdev_register(priv->dev, np,
>> +						    &led->ldev);
>> +		if (ret) {
>> +			fwnode_handle_put(child);
>> +			return ret;
>> +		}
>> +
>> +		led->ldev.dev->of_node = np;
>> +
>> +		i++;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int cr0014114_probe(struct spi_device *spi)
>> +{
>> +	struct cr0014114	*priv;
>> +	size_t			count;
>> +	int			ret;
>> +
>> +	count = device_get_child_node_count(&spi->dev);
>> +	if (!count) {
>> +		dev_err(&spi->dev, "LEDs are not defined in device tree");
>> +		return -ENODEV;
>> +	}
>> +
>> +	priv = devm_kzalloc(&spi->dev,
>> +			    sizeof(*priv) + sizeof(*priv->leds) * count,
>> +			    GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	mutex_init(&priv->lock);
>> +	INIT_WORK(&priv->work, cr0014114_recount_work);
>> +	priv->do_recount	= true;
>> +	priv->count		= count;
>> +	priv->dev		= &spi->dev;
>> +	priv->spi		= spi;
>> +
>> +	ret = cr0014114_probe_dt(priv);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = cr0014114_sync(priv);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* setup recount timer to workaround buggy firmware */
>> +	timer_setup(&priv->timer, cr0014114_recount_timer, 0);
>> +	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
>> +
>> +	spi_set_drvdata(spi, priv);
>> +
>> +	return 0;
>> +}
>> +
>> +static int cr0014114_remove(struct spi_device *spi)
>> +{
>> +	struct cr0014114 *priv = spi_get_drvdata(spi);
>> +
>> +	cancel_work_sync(&priv->work);
>> +	del_timer_sync(&priv->timer);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id cr0014114_dt_ids[] = {
>> +	{ .compatible = "crane,cr0014114", },
>> +	{},
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
>> +
>> +static struct spi_driver cr0014114_driver = {
>> +	.probe		= cr0014114_probe,
>> +	.remove		= cr0014114_remove,
>> +	.driver = {
>> +		.name		= KBUILD_MODNAME,
>> +		.of_match_table	= cr0014114_dt_ids,
>> +	},
>> +};
>> +
>> +module_spi_driver(cr0014114_driver);
>> +
>> +MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
>> +MODULE_DESCRIPTION("cr0014114 LED driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("spi:cr0014114");
>>

-- 
Best regards,
Oleh Kravchenko



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 858 bytes --]

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

* [PATCH v2] leds: add LED driver for CR0014114 board
       [not found] <026d9ec2-f2bd-18b9-d5fa-f593d40e2f57@kaa.org.ua>
  2018-03-12 15:33 ` [PATCH] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-03-12 15:58 ` Oleh Kravchenko
  2018-03-13 12:45   ` [PATCH v3] " Oleh Kravchenko
  1 sibling, 1 reply; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-12 15:58 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

This patch adds a LED class driver for the RGB LEDs found on
the Crane Merchandising System CR0014114 LEDs board.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 drivers/leds/Kconfig                               |  13 +
 drivers/leds/Makefile                              |   1 +
 drivers/leds/leds-cr0014114.c                      | 282 +++++++++++++++++++++
 5 files changed, 343 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
 create mode 100644 drivers/leds/leds-cr0014114.c

diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
new file mode 100644
index 000000000000..977a9929b04f
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
@@ -0,0 +1,46 @@
+Crane Merchandising System - cr0014114 LED driver
+-------------------------------------------------
+
+This LED Board is widely used in vending machines produced
+by Crane Merchandising Systems.
+
+Required properties:
+- compatible: "cms,cr0014114"
+- reg: chip select address for the device
+- spi-cpha: shifted clock phase mode is required
+
+LED sub-node properties:
+- label : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+
+Example
+-------
+
+cr0014114@0 {
+	compatible = "crane,cr0014114";
+	reg = <0>;
+	spi-max-frequency = <50000>;
+	spi-cpha;
+
+	led0 {
+		label = "cr0:red:";
+	};
+	led1 {
+		label = "cr0:green:";
+	};
+	led2 {
+		label = "cr0:blue:";
+	};
+	led3 {
+		label = "cr1:red:";
+	};
+	led4 {
+		label = "cr1:green:";
+	};
+	led5 {
+		label = "cr1:blue:";
+	};
+	...
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ae850d6c0ad3..f17949c365f5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
 compulab	CompuLab Ltd.
 cortina	Cortina Systems, Inc.
 cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
 creative	Creative Technology Ltd
 crystalfontz	Crystalfontz America, Inc.
 cubietech	Cubietech, Ltd.
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..5831814d01d0 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -104,6 +104,19 @@ config LEDS_CPCAP
 	  This option enables support for LEDs offered by Motorola's
 	  CPCAP PMIC.
 
+config LEDS_CR0014114
+	tristate "LED Support for Crane CR0014114"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for CR0014114 LED Board which
+	  is widely used in vending machines produced by
+	  Crane Merchandising Systems.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-cr0014114.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..0176e7335994 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 
 # LED SPI Drivers
+obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Userspace Drivers
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
new file mode 100644
index 000000000000..1cbe8aef2f5f
--- /dev/null
+++ b/drivers/leds/leds-cr0014114.c
@@ -0,0 +1,282 @@
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+
+/* CR0014114 SPI commands */
+#define CR_SET_BRIGHTNESS	0x80
+#define CR_INIT_REENUMERATE	0x81
+#define CR_NEXT_REENUMERATE	0x82
+
+/* CR0014114 default settings */
+#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
+#define CR_FW_DELAY_MSEC	10
+#define CR_RECOUNT_DELAY	(HZ * 3600)
+
+struct cr0014114_led {
+	const char		*name;
+	struct cr0014114	*priv;
+	struct led_classdev	ldev;
+	u8			brightness;
+};
+
+struct cr0014114 {
+	bool			do_recount;
+	size_t			count;
+	struct device		*dev;
+	struct mutex		lock;
+	struct spi_device	*spi;
+	struct timer_list	timer;
+	struct work_struct	work;
+	unsigned long		delay;
+	struct cr0014114_led	leds[];
+};
+
+static void cr0014114_calc_crc(u8 *buf, const size_t len)
+{
+	size_t	i;
+	u8	crc;
+
+	for (i = 1, crc = 1; i < len - 1; i++)
+		crc += buf[i];
+	crc |= BIT(7);
+
+	/* special case when CRC matches the SPI commands */
+	if (crc == CR_SET_BRIGHTNESS ||
+	    crc == CR_INIT_REENUMERATE ||
+	    crc == CR_NEXT_REENUMERATE)
+		crc = 0xfe;
+
+	buf[len - 1] = crc;
+}
+
+static int cr0014114_recount(struct cr0014114 *priv)
+{
+	int	ret;
+	size_t	i;
+	u8	cmd;
+
+	dev_dbg(priv->dev, "recount of LEDs is started\n");
+
+	do {
+		cmd = CR_INIT_REENUMERATE;
+		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+		if (ret)
+			break;
+
+		cmd = CR_NEXT_REENUMERATE;
+		for (i = 0; i < priv->count; i++) {
+			msleep(CR_FW_DELAY_MSEC);
+
+			ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+			if (ret)
+				break;
+		}
+	} while (0);
+
+	dev_dbg(priv->dev, "recount of LEDs is complete, error: %d\n", ret);
+
+	return ret;
+}
+
+static int cr0014114_sync(struct cr0014114 *priv)
+{
+	int		ret;
+	size_t		i;
+	u8		data[priv->count + 2];
+	unsigned long	udelay, now = jiffies;
+
+	/* to avoid SPI mistiming with firmware we should wait some time */
+	if (time_after(priv->delay, now)) {
+		udelay = jiffies_to_usecs(priv->delay - now);
+		usleep_range(udelay, udelay + 1);
+	}
+
+	do {
+		if (unlikely(priv->do_recount)) {
+			ret = cr0014114_recount(priv);
+			if (ret)
+				break;
+
+			priv->do_recount = false;
+		}
+
+		data[0] = CR_SET_BRIGHTNESS;
+		for (i = 0; i < priv->count; i++)
+			data[i + 1] = priv->leds[i].brightness;
+		cr0014114_calc_crc(data, sizeof(data));
+
+		ret = spi_write(priv->spi, data, sizeof(data));
+		if (ret)
+			break;
+	} while (0);
+
+	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	return ret;
+}
+
+static void cr0014114_recount_work(struct work_struct *work)
+{
+	int			ret;
+	struct cr0014114	*priv = container_of(work, struct cr0014114,
+						     work);
+
+	mutex_lock(&priv->lock);
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		dev_warn(priv->dev, "recount LEDs failed %d\n", ret);
+}
+
+static int cr0014114_set_sync(struct led_classdev *ldev,
+			      enum led_brightness brightness)
+{
+	int			ret;
+	struct cr0014114_led    *led = container_of(ldev,
+						    struct cr0014114_led,
+						    ldev);
+
+	mutex_lock(&led->priv->lock);
+	led->brightness = (u8)brightness;
+	ret = cr0014114_sync(led->priv);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static void cr0014114_recount_timer(struct timer_list *t)
+{
+	struct cr0014114 *priv = from_timer(priv, t, timer);
+
+	schedule_work(&priv->work);
+	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
+}
+
+static int cr0014114_probe_dt(struct cr0014114 *priv)
+{
+	size_t			i = 0;
+	struct cr0014114_led	*led;
+	struct fwnode_handle	*child;
+	struct device_node	*np;
+	int			ret;
+
+	device_for_each_child_node(priv->dev, child) {
+		np = to_of_node(child);
+		led = &priv->leds[i];
+
+		ret = fwnode_property_read_string(child, "label",
+						  &led->name);
+		if (ret && IS_ENABLED(CONFIG_OF) && np)
+			led->name = np->name;
+
+		if (!led->name) {
+			fwnode_handle_put(child);
+			return -EINVAL;
+		}
+
+		fwnode_property_read_string(child, "linux,default-trigger",
+					    &led->ldev.default_trigger);
+
+		led->priv			  = priv;
+		led->ldev.name			  = led->name;
+		led->ldev.brightness		  = LED_OFF;
+		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
+		led->ldev.brightness_set_blocking = cr0014114_set_sync;
+
+		ret = devm_of_led_classdev_register(priv->dev, np,
+						    &led->ldev);
+		if (ret) {
+			fwnode_handle_put(child);
+			return ret;
+		}
+
+		led->ldev.dev->of_node = np;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int cr0014114_probe(struct spi_device *spi)
+{
+	struct cr0014114	*priv;
+	size_t			count;
+	int			ret;
+
+	count = device_get_child_node_count(&spi->dev);
+	if (!count) {
+		dev_err(&spi->dev, "LEDs are not defined in device tree");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&spi->dev,
+			    sizeof(*priv) + sizeof(*priv->leds) * count,
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	INIT_WORK(&priv->work, cr0014114_recount_work);
+	priv->do_recount	= true;
+	priv->count		= count;
+	priv->dev		= &spi->dev;
+	priv->spi		= spi;
+
+	ret = cr0014114_probe_dt(priv);
+	if (ret)
+		return ret;
+
+	ret = cr0014114_sync(priv);
+	if (ret)
+		return ret;
+
+	/* setup recount timer to workaround buggy firmware */
+	timer_setup(&priv->timer, cr0014114_recount_timer, 0);
+	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
+
+	spi_set_drvdata(spi, priv);
+
+	return 0;
+}
+
+static int cr0014114_remove(struct spi_device *spi)
+{
+	struct cr0014114 *priv = spi_get_drvdata(spi);
+
+	cancel_work_sync(&priv->work);
+	del_timer_sync(&priv->timer);
+
+	return 0;
+}
+
+static const struct of_device_id cr0014114_dt_ids[] = {
+	{ .compatible = "crane,cr0014114", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
+
+static struct spi_driver cr0014114_driver = {
+	.probe		= cr0014114_probe,
+	.remove		= cr0014114_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= cr0014114_dt_ids,
+	},
+};
+
+module_spi_driver(cr0014114_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("cr0014114 LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:cr0014114");
-- 
2.13.6


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

* [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-12 15:58 ` [PATCH v2] " Oleh Kravchenko
@ 2018-03-13 12:45   ` Oleh Kravchenko
  2018-03-16 21:14     ` Pavel Machek
  2018-03-18 12:49     ` [PATCH v3] leds: add LED driver for CR0014114 board Rob Herring
  0 siblings, 2 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-13 12:45 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

This patch adds a LED class driver for the RGB LEDs found on
the Crane Merchandising System CR0014114 LEDs board.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 drivers/leds/Kconfig                               |  13 +
 drivers/leds/Makefile                              |   1 +
 drivers/leds/leds-cr0014114.c                      | 292 +++++++++++++++++++++
 5 files changed, 353 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
 create mode 100644 drivers/leds/leds-cr0014114.c

diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
new file mode 100644
index 000000000000..977a9929b04f
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
@@ -0,0 +1,46 @@
+Crane Merchandising System - cr0014114 LED driver
+-------------------------------------------------
+
+This LED Board is widely used in vending machines produced
+by Crane Merchandising Systems.
+
+Required properties:
+- compatible: "cms,cr0014114"
+- reg: chip select address for the device
+- spi-cpha: shifted clock phase mode is required
+
+LED sub-node properties:
+- label : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+
+Example
+-------
+
+cr0014114@0 {
+	compatible = "crane,cr0014114";
+	reg = <0>;
+	spi-max-frequency = <50000>;
+	spi-cpha;
+
+	led0 {
+		label = "cr0:red:";
+	};
+	led1 {
+		label = "cr0:green:";
+	};
+	led2 {
+		label = "cr0:blue:";
+	};
+	led3 {
+		label = "cr1:red:";
+	};
+	led4 {
+		label = "cr1:green:";
+	};
+	led5 {
+		label = "cr1:blue:";
+	};
+	...
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ae850d6c0ad3..f17949c365f5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
 compulab	CompuLab Ltd.
 cortina	Cortina Systems, Inc.
 cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
 creative	Creative Technology Ltd
 crystalfontz	Crystalfontz America, Inc.
 cubietech	Cubietech, Ltd.
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..5831814d01d0 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -104,6 +104,19 @@ config LEDS_CPCAP
 	  This option enables support for LEDs offered by Motorola's
 	  CPCAP PMIC.
 
+config LEDS_CR0014114
+	tristate "LED Support for Crane CR0014114"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for CR0014114 LED Board which
+	  is widely used in vending machines produced by
+	  Crane Merchandising Systems.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-cr0014114.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..0176e7335994 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 
 # LED SPI Drivers
+obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Userspace Drivers
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
new file mode 100644
index 000000000000..ef536a67dceb
--- /dev/null
+++ b/drivers/leds/leds-cr0014114.c
@@ -0,0 +1,292 @@
+/*
+ * LEDs driver for Crane CR0014114
+ *
+ * Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+
+/* CR0014114 SPI commands */
+#define CR_SET_BRIGHTNESS	0x80
+#define CR_INIT_REENUMERATE	0x81
+#define CR_NEXT_REENUMERATE	0x82
+
+/* CR0014114 default settings */
+#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
+#define CR_FW_DELAY_MSEC	10
+#define CR_RECOUNT_DELAY	(HZ * 3600)
+
+struct cr0014114_led {
+	const char		*name;
+	struct cr0014114	*priv;
+	struct led_classdev	ldev;
+	u8			brightness;
+};
+
+struct cr0014114 {
+	bool			do_recount;
+	size_t			count;
+	struct device		*dev;
+	struct mutex		lock;
+	struct spi_device	*spi;
+	struct timer_list	timer;
+	struct work_struct	work;
+	unsigned long		delay;
+	struct cr0014114_led	leds[];
+};
+
+static void cr0014114_calc_crc(u8 *buf, const size_t len)
+{
+	size_t	i;
+	u8	crc;
+
+	for (i = 1, crc = 1; i < len - 1; i++)
+		crc += buf[i];
+	crc |= BIT(7);
+
+	/* special case when CRC matches the SPI commands */
+	if (crc == CR_SET_BRIGHTNESS ||
+	    crc == CR_INIT_REENUMERATE ||
+	    crc == CR_NEXT_REENUMERATE)
+		crc = 0xfe;
+
+	buf[len - 1] = crc;
+}
+
+static int cr0014114_recount(struct cr0014114 *priv)
+{
+	int	ret;
+	size_t	i;
+	u8	cmd;
+
+	dev_dbg(priv->dev, "recount of LEDs is started\n");
+
+	do {
+		cmd = CR_INIT_REENUMERATE;
+		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+		if (ret)
+			break;
+
+		cmd = CR_NEXT_REENUMERATE;
+		for (i = 0; i < priv->count; i++) {
+			msleep(CR_FW_DELAY_MSEC);
+
+			ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+			if (ret)
+				break;
+		}
+	} while (0);
+
+	dev_dbg(priv->dev, "recount of LEDs is complete, error: %d\n", ret);
+
+	return ret;
+}
+
+static int cr0014114_sync(struct cr0014114 *priv)
+{
+	int		ret;
+	size_t		i;
+	u8		data[priv->count + 2];
+	unsigned long	udelay, now = jiffies;
+
+	/* to avoid SPI mistiming with firmware we should wait some time */
+	if (time_after(priv->delay, now)) {
+		udelay = jiffies_to_usecs(priv->delay - now);
+		usleep_range(udelay, udelay + 1);
+	}
+
+	do {
+		if (unlikely(priv->do_recount)) {
+			ret = cr0014114_recount(priv);
+			if (ret)
+				break;
+
+			priv->do_recount = false;
+		}
+
+		data[0] = CR_SET_BRIGHTNESS;
+		for (i = 0; i < priv->count; i++)
+			data[i + 1] = priv->leds[i].brightness;
+		cr0014114_calc_crc(data, sizeof(data));
+
+		ret = spi_write(priv->spi, data, sizeof(data));
+		if (ret)
+			break;
+	} while (0);
+
+	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	return ret;
+}
+
+static void cr0014114_recount_work(struct work_struct *work)
+{
+	int			ret;
+	struct cr0014114	*priv = container_of(work, struct cr0014114,
+						     work);
+
+	mutex_lock(&priv->lock);
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		dev_warn(priv->dev, "recount LEDs failed %d\n", ret);
+}
+
+static int cr0014114_set_sync(struct led_classdev *ldev,
+			      enum led_brightness brightness)
+{
+	int			ret;
+	struct cr0014114_led    *led = container_of(ldev,
+						    struct cr0014114_led,
+						    ldev);
+
+	mutex_lock(&led->priv->lock);
+	led->brightness = (u8)brightness;
+	ret = cr0014114_sync(led->priv);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static void cr0014114_recount_timer(struct timer_list *t)
+{
+	struct cr0014114 *priv = from_timer(priv, t, timer);
+
+	schedule_work(&priv->work);
+	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
+}
+
+static int cr0014114_probe_dt(struct cr0014114 *priv)
+{
+	size_t			i = 0;
+	struct cr0014114_led	*led;
+	struct fwnode_handle	*child;
+	struct device_node	*np;
+	int			ret;
+
+	device_for_each_child_node(priv->dev, child) {
+		np = to_of_node(child);
+		led = &priv->leds[i];
+
+		ret = fwnode_property_read_string(child, "label",
+						  &led->name);
+		if (ret && IS_ENABLED(CONFIG_OF) && np)
+			led->name = np->name;
+
+		if (!led->name) {
+			fwnode_handle_put(child);
+			return -EINVAL;
+		}
+
+		fwnode_property_read_string(child, "linux,default-trigger",
+					    &led->ldev.default_trigger);
+
+		led->priv			  = priv;
+		led->ldev.name			  = led->name;
+		led->ldev.brightness		  = LED_OFF;
+		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
+		led->ldev.brightness_set_blocking = cr0014114_set_sync;
+
+		ret = devm_of_led_classdev_register(priv->dev, np,
+						    &led->ldev);
+		if (ret) {
+			fwnode_handle_put(child);
+			return ret;
+		}
+
+		led->ldev.dev->of_node = np;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int cr0014114_probe(struct spi_device *spi)
+{
+	struct cr0014114	*priv;
+	size_t			count;
+	int			ret;
+
+	count = device_get_child_node_count(&spi->dev);
+	if (!count) {
+		dev_err(&spi->dev, "LEDs are not defined in device tree");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&spi->dev,
+			    sizeof(*priv) + sizeof(*priv->leds) * count,
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	INIT_WORK(&priv->work, cr0014114_recount_work);
+	priv->do_recount	= true;
+	priv->count		= count;
+	priv->dev		= &spi->dev;
+	priv->spi		= spi;
+
+	ret = cr0014114_probe_dt(priv);
+	if (ret)
+		return ret;
+
+	ret = cr0014114_sync(priv);
+	if (ret)
+		return ret;
+
+	/* setup recount timer to workaround buggy firmware */
+	timer_setup(&priv->timer, cr0014114_recount_timer, 0);
+	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
+
+	spi_set_drvdata(spi, priv);
+
+	return 0;
+}
+
+static int cr0014114_remove(struct spi_device *spi)
+{
+	struct cr0014114 *priv = spi_get_drvdata(spi);
+
+	cancel_work_sync(&priv->work);
+	del_timer_sync(&priv->timer);
+
+	return 0;
+}
+
+static const struct of_device_id cr0014114_dt_ids[] = {
+	{ .compatible = "crane,cr0014114", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
+
+static struct spi_driver cr0014114_driver = {
+	.probe		= cr0014114_probe,
+	.remove		= cr0014114_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= cr0014114_dt_ids,
+	},
+};
+
+module_spi_driver(cr0014114_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("cr0014114 LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:cr0014114");
-- 
2.13.6


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

* Re: [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-13 12:45   ` [PATCH v3] " Oleh Kravchenko
@ 2018-03-16 21:14     ` Pavel Machek
  2018-03-16 21:29       ` Oleh Kravchenko
  2018-03-18 12:49     ` [PATCH v3] leds: add LED driver for CR0014114 board Rob Herring
  1 sibling, 1 reply; 46+ messages in thread
From: Pavel Machek @ 2018-03-16 21:14 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, linux-leds

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

On Tue 2018-03-13 14:45:48, Oleh Kravchenko wrote:
> This patch adds a LED class driver for the RGB LEDs found on
> the Crane Merchandising System CR0014114 LEDs board.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>

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

I just wonder if the recount stuff... could be somehow simplified.

									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] 46+ messages in thread

* Re: [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-16 21:14     ` Pavel Machek
@ 2018-03-16 21:29       ` Oleh Kravchenko
  2018-03-16 21:33         ` Pavel Machek
  0 siblings, 1 reply; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-16 21:29 UTC (permalink / raw)
  To: Pavel Machek; +Cc: devicetree, linux-leds


[-- Attachment #1.1: Type: text/plain, Size: 653 bytes --]

I can track state of recount stuff inside private struct,
it will allow to drop work and timer fields.

You will agree with it?

On 16.03.18 23:14, Pavel Machek wrote:
> On Tue 2018-03-13 14:45:48, Oleh Kravchenko wrote:
>> This patch adds a LED class driver for the RGB LEDs found on
>> the Crane Merchandising System CR0014114 LEDs board.
>>
>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> 
> Acked-by: Pavel Machek <pavel@ucw.cz>
> 
> I just wonder if the recount stuff... could be somehow simplified.
> 
> 									Pavel
> 

-- 
Best regards,
Oleh Kravchenko
Phone: +380972763224 | oleg@kaa.org.ua | Skype: oleg_krava


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-16 21:29       ` Oleh Kravchenko
@ 2018-03-16 21:33         ` Pavel Machek
  2018-03-16 21:40           ` Oleh Kravchenko
  0 siblings, 1 reply; 46+ messages in thread
From: Pavel Machek @ 2018-03-16 21:33 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, linux-leds

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

On Fri 2018-03-16 23:29:22, Oleh Kravchenko wrote:
> I can track state of recount stuff inside private struct,
> it will allow to drop work and timer fields.
> 
> You will agree with it?

That will not help much. Would it be possible to get away without the
timer, for example? Just schedule work for the future?

									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] 46+ messages in thread

* Re: [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-16 21:33         ` Pavel Machek
@ 2018-03-16 21:40           ` Oleh Kravchenko
  2018-03-16 22:10             ` Pavel Machek
  2018-03-26 12:15             ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  0 siblings, 2 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-16 21:40 UTC (permalink / raw)
  To: Pavel Machek; +Cc: devicetree, linux-leds


[-- Attachment #1.1: Type: text/plain, Size: 517 bytes --]

Did you mean to do "recount" every 1000 brightness changes?

On 16.03.18 23:33, Pavel Machek wrote:
> On Fri 2018-03-16 23:29:22, Oleh Kravchenko wrote:
>> I can track state of recount stuff inside private struct,
>> it will allow to drop work and timer fields.
>>
>> You will agree with it?
> 
> That will not help much. Would it be possible to get away without the
> timer, for example? Just schedule work for the future?
> 
> 									Pavel
> 									
> 

-- 
Best regards,
Oleh Kravchenko



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-16 21:40           ` Oleh Kravchenko
@ 2018-03-16 22:10             ` Pavel Machek
  2018-03-26 12:15             ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  1 sibling, 0 replies; 46+ messages in thread
From: Pavel Machek @ 2018-03-16 22:10 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, linux-leds

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

On Fri 2018-03-16 23:40:36, Oleh Kravchenko wrote:
> Did you mean to do "recount" every 1000 brightness changes?

If that works, yes.

My idea was... you are already using schedule_work, so why not
schedule_delayed_work() and get rid of timer?

https://static.lwn.net/images/pdf/LDD3/ch07.pdf

									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] 46+ messages in thread

* Re: [PATCH] leds: add LED driver for CR0014114 board
  2018-03-12 15:33 ` [PATCH] leds: add LED driver for CR0014114 board Oleh Kravchenko
  2018-03-12 15:45   ` Peter Meerwald-Stadler
@ 2018-03-17  8:19   ` Jacek Anaszewski
  1 sibling, 0 replies; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-17  8:19 UTC (permalink / raw)
  To: Oleh Kravchenko, devicetree, linux-leds

Hi Oleh,

Thank you for the patch. Please see my comments below.

On 03/12/2018 04:33 PM, Oleh Kravchenko wrote:
> This patch adds a LED class driver for the RGB LEDs found on
> the Crane Merchandising System CR0014114 LEDs board.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>  drivers/leds/Kconfig                               |  13 +
>  drivers/leds/Makefile                              |   1 +
>  drivers/leds/leds-cr0014114.c                      | 282 +++++++++++++++++++++
>  5 files changed, 343 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>  create mode 100644 drivers/leds/leds-cr0014114.c
> 
> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> new file mode 100644
> index 000000000000..56721598ee81
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt

Please split DT bindings related changes to the separate patch.

> @@ -0,0 +1,46 @@
> +Crane Merchandising System - cr0014114 LED driver
> +-------------------------------------------------
> +
> +This LED Board widely used in vending machines produced
> +by Crane Merchandising Systems.
> +
> +Required properties:
> +- compatible: "cms,cr0014114"

Why here cms and crane in the example below? Please make it
consistent. I assume that vendor prefix should be "crane",
so in this case this should look like below:

- compatible: Must be "crane,cr0014114".

> +- reg: chip select address for the device
> +- spi-cpha: shifted clock phase mode is required

You don't have to say that it is required - it is already
under "Required properties". Apart from that - you don't
parse this property in the driver, so it doesn't seem to
be needed.

> +
> +LED sub-node properties:
> +- label : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +- linux,default-trigger : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example
> +-------
> +
> +cr0014114@0 {

led-controller@9

> +	compatible = "crane,cr0014114";

You need also below properties to avoid dtc warnings.

#address-cells = <1>;
#size-cells = <0>;


> +	reg = <0>;
> +	spi-max-frequency = <50000>;
> +	spi-cpha;

Please consider if this is really required.

> +	led0 {
> +		label = "cr0:red:";

Please separate "led" from the address with "@" character,
e.g. here it should be led@0.

Also why "cr0" and not full device name "cr0014114"?
You could also think of some exemplary LED functions to not
leave that section empty.


> +	};
> +	led1 {
> +		label = "cr0:green:";
> +	};
> +	led2 {
> +		label = "cr0:blue:";
> +	};
> +	led3 {
> +		label = "cr1:red:";
> +	};
> +	led4 {
> +		label = "cr1:green:";
> +	};
> +	led5 {
> +		label = "cr1:blue:";
> +	};
> +	...
> +};
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index ae850d6c0ad3..f17949c365f5 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>  compulab	CompuLab Ltd.
>  cortina	Cortina Systems, Inc.
>  cosmic	Cosmic Circuits
> +crane	Crane Connectivity Solutions
>  creative	Creative Technology Ltd
>  crystalfontz	Crystalfontz America, Inc.
>  cubietech	Cubietech, Ltd.
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 2c896c0e69e1..bb6a70ac5004 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -104,6 +104,19 @@ config LEDS_CPCAP
>  	  This option enables support for LEDs offered by Motorola's
>  	  CPCAP PMIC.
>  
> +config LEDS_CR0014114
> +	tristate "LED Support for Crane CR0014114"
> +	depends on LEDS_CLASS
> +	depends on SPI
> +	depends on OF
> +	help
> +	  This option enables support for CR0014114 LED Board which
> +	  widely used in vending machines produced by
> +	  Crane Merchandising Systems.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called leds-cr0014114.
> +
>  config LEDS_LM3530
>  	tristate "LCD Backlight driver for LM3530"
>  	depends on LEDS_CLASS
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 91eca81cae82..0176e7335994 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
>  obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
>  
>  # LED SPI Drivers
> +obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
>  obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
>  
>  # LED Userspace Drivers
> diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
> new file mode 100644
> index 000000000000..e3aecdbea73c
> --- /dev/null
> +++ b/drivers/leds/leds-cr0014114.c
> @@ -0,0 +1,282 @@
> +#include <linux/delay.h>
> +#include <linux/leds.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/property.h>
> +#include <linux/spi/spi.h>
> +#include <linux/spinlock.h>
> +#include <linux/timer.h>
> +#include <linux/workqueue.h>
> +
> +/* CR0014114 SPI commands */
> +#define CR_SET_BRIGHTNESS	0x80
> +#define CR_INIT_REENUMERATE	0x81
> +#define CR_NEXT_REENUMERATE	0x82
> +
> +/* CR0014114 default settings */
> +#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
> +#define CR_FW_DELAY_MSEC	10
> +#define CR_RECOUNT_DELAY	(HZ * 3600)
> +
> +struct cr0014114_led {
> +	const char		*name;
> +	struct cr0014114	*priv;
> +	struct led_classdev	ldev;
> +	u8			brightness;
> +};
> +
> +struct cr0014114 {
> +	bool			do_recount;
> +	size_t			count;
> +	struct device		*dev;
> +	struct mutex		lock;
> +	struct spi_device	*spi;
> +	struct timer_list	timer;
> +	struct work_struct	work;
> +	unsigned long		delay;
> +	struct cr0014114_led	leds[];
> +};
> +
> +static void cr0014114_calc_crc(u8 *buf, const size_t len)
> +{
> +	size_t	i;
> +	u8	crc;
> +
> +	for (i = 1, crc = 1; i < len - 1; i++)
> +		crc += buf[i];
> +	crc |= BIT(7);
> +
> +	/* special case when CRC matches to SPI commands */
> +	if (crc == CR_SET_BRIGHTNESS ||
> +	    crc == CR_INIT_REENUMERATE ||
> +	    crc == CR_NEXT_REENUMERATE)
> +		crc = 0xfe;
> +
> +	buf[len - 1] = crc;
> +}
> +
> +static int cr0014114_recount(struct cr0014114 *priv)
> +{
> +	int	ret;
> +	size_t	i;
> +	u8	cmd;
> +
> +	dev_dbg(priv->dev, "recount of LEDs is started\n");
> +
> +	do {

This do..while(0) loop isn't really required. Let's do it otherwise.

> +		cmd = CR_INIT_REENUMERATE;
> +		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
> +		if (ret)
> +			break;

Please add a label out_reenum at the end of the function
and goto there from here in case of error.

> +
> +		cmd = CR_NEXT_REENUMERATE;
> +		for (i = 0; i < priv->count; i++) {
> +			msleep(CR_FW_DELAY_MSEC);
> +
> +			ret = spi_write(priv->spi, &cmd, sizeof(cmd));
> +			if (ret)
> +				break;

Similarly goto out_reenum here.

> +		}
> +	} while (0);
> +
> +	dev_dbg(priv->dev, "recount of LEDs is complete, error: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cr0014114_sync(struct cr0014114 *priv)
> +{
> +	int		ret;
> +	size_t		i;
> +	u8		data[priv->count + 2];

sparse is not happy about this and it causes two more problems below:

drivers/leds/leds-cr0014114.c:101:42: warning: Variable length array is
used.
drivers/leds/leds-cr0014114.c:122:42: error: cannot size expression
drivers/leds/leds-cr0014114.c:124:50: error: cannot size expression


> +	unsigned long	udelay, now = jiffies;
> +
> +	/* to avoid SPI mistiming with firmware we should wait some time */
> +	if (time_after(priv->delay, now)) {
> +		udelay = jiffies_to_usecs(priv->delay - now);
> +		usleep_range(udelay, udelay + 1);
> +	}
> +
> +	do {
> +		if (unlikely(priv->do_recount)) {
> +			ret = cr0014114_recount(priv);
> +			if (ret)
> +				break;
> +
> +			priv->do_recount = false;
> +		}
> +
> +		data[0] = CR_SET_BRIGHTNESS;
> +		for (i = 0; i < priv->count; i++)
> +			data[i + 1] = priv->leds[i].brightness;
> +		cr0014114_calc_crc(data, sizeof(data));
> +
> +		ret = spi_write(priv->spi, data, sizeof(data));
> +		if (ret)
> +			break;
> +	} while (0);
> +
> +	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
> +
> +	return ret;
> +}
> +
> +static void cr0014114_recount_work(struct work_struct *work)
> +{
> +	int			ret;
> +	struct cr0014114	*priv = container_of(work, struct cr0014114,
> +						     work);
> +
> +	mutex_lock(&priv->lock);
> +	priv->do_recount = true;
> +	ret = cr0014114_sync(priv);
> +	mutex_unlock(&priv->lock);
> +
> +	if (ret)
> +		dev_warn(priv->dev, "recount LEDs failed %d\n", ret);
> +}
> +
> +int cr0014114_set_sync(struct led_classdev *ldev,
> +		       enum led_brightness brightness)
> +{
> +	int			ret;
> +	struct cr0014114_led    *led = container_of(ldev,
> +						    struct cr0014114_led,
> +						    ldev);
> +
> +	mutex_lock(&led->priv->lock);
> +	led->brightness = (u8)brightness;
> +	ret = cr0014114_sync(led->priv);
> +	mutex_unlock(&led->priv->lock);
> +
> +	return ret;
> +}
> +
> +void cr0014114_recount_timer(struct timer_list *t)
> +{
> +	struct cr0014114 *priv = from_timer(priv, t, timer);
> +
> +	schedule_work(&priv->work);
> +	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
> +}
> +
> +static int cr0014114_probe_dt(struct cr0014114 *priv)
> +{
> +	size_t			i = 0;
> +	struct cr0014114_led	*led;
> +	struct fwnode_handle	*child;
> +	struct device_node	*np;
> +	int			ret;
> +
> +	device_for_each_child_node(priv->dev, child) {
> +		np = to_of_node(child);
> +		led = &priv->leds[i];
> +
> +		ret = fwnode_property_read_string(child, "label",
> +						  &led->name);
> +		if (ret && IS_ENABLED(CONFIG_OF) && np)

The driver already depends on OF, so IS_ENABLED is redundant here.

> +			led->name = np->name;
> +
> +		if (!led->name) {
> +			fwnode_handle_put(child);
> +			return -EINVAL;
> +		}
> +
> +		fwnode_property_read_string(child, "linux,default-trigger",
> +					    &led->ldev.default_trigger);
> +
> +		led->priv			  = priv;
> +		led->ldev.name			  = led->name;
> +		led->ldev.brightness		  = LED_OFF;

This is already secured by kzalloc.

> +		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
> +		led->ldev.brightness_set_blocking = cr0014114_set_sync;
> +
> +		ret = devm_of_led_classdev_register(priv->dev, np,
> +						    &led->ldev);
> +		if (ret) {
> +			fwnode_handle_put(child);
> +			return ret;
> +		}
> +
> +		led->ldev.dev->of_node = np;
> +
> +		i++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cr0014114_probe(struct spi_device *spi)
> +{
> +	struct cr0014114	*priv;
> +	size_t			count;
> +	int			ret;
> +
> +	count = device_get_child_node_count(&spi->dev);
> +	if (!count) {
> +		dev_err(&spi->dev, "LEDs are not defined in device tree");
> +		return -ENODEV;
> +	}
> +
> +	priv = devm_kzalloc(&spi->dev,
> +			    sizeof(*priv) + sizeof(*priv->leds) * count,
> +			    GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	mutex_init(&priv->lock);
> +	INIT_WORK(&priv->work, cr0014114_recount_work);
> +	priv->do_recount	= true;
> +	priv->count		= count;
> +	priv->dev		= &spi->dev;
> +	priv->spi		= spi;
> +
> +	ret = cr0014114_probe_dt(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = cr0014114_sync(priv);
> +	if (ret)
> +		return ret;
> +
> +	/* setup recount timer to workaround buggy firmware */
> +	timer_setup(&priv->timer, cr0014114_recount_timer, 0);
> +	mod_timer(&priv->timer, jiffies + CR_RECOUNT_DELAY);
> +
> +	spi_set_drvdata(spi, priv);
> +
> +	return 0;
> +}
> +
> +static int cr0014114_remove(struct spi_device *spi)
> +{
> +	struct cr0014114 *priv = spi_get_drvdata(spi);
> +
> +	cancel_work_sync(&priv->work);
> +	del_timer_sync(&priv->timer);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id cr0014114_dt_ids[] = {
> +	{ .compatible = "crane,cr0014114", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
> +
> +static struct spi_driver cr0014114_driver = {
> +	.probe		= cr0014114_probe,
> +	.remove		= cr0014114_remove,
> +	.driver = {
> +		.name		= KBUILD_MODNAME,
> +		.of_match_table	= cr0014114_dt_ids,
> +	},
> +};
> +
> +module_spi_driver(cr0014114_driver);
> +
> +MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
> +MODULE_DESCRIPTION("cr0014114 LED driver");
> +MODULE_LICENSE("GPL");

Please add SPDX license identifier at the top of the file:
Documentation/process/license-rules.rst

> +MODULE_ALIAS("spi:cr0014114");
> 

-- 
Best regards,
Jacek Anaszewski

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

* Re: [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-13 12:45   ` [PATCH v3] " Oleh Kravchenko
  2018-03-16 21:14     ` Pavel Machek
@ 2018-03-18 12:49     ` Rob Herring
  2018-03-18 20:03       ` Jacek Anaszewski
  1 sibling, 1 reply; 46+ messages in thread
From: Rob Herring @ 2018-03-18 12:49 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, linux-leds

On Tue, Mar 13, 2018 at 02:45:48PM +0200, Oleh Kravchenko wrote:
> This patch adds a LED class driver for the RGB LEDs found on
> the Crane Merchandising System CR0014114 LEDs board.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +

Please split to separate patch.

>  drivers/leds/Kconfig                               |  13 +
>  drivers/leds/Makefile                              |   1 +
>  drivers/leds/leds-cr0014114.c                      | 292 +++++++++++++++++++++
>  5 files changed, 353 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>  create mode 100644 drivers/leds/leds-cr0014114.c
> 
> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> new file mode 100644
> index 000000000000..977a9929b04f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> @@ -0,0 +1,46 @@
> +Crane Merchandising System - cr0014114 LED driver
> +-------------------------------------------------
> +
> +This LED Board is widely used in vending machines produced
> +by Crane Merchandising Systems.
> +
> +Required properties:
> +- compatible: "cms,cr0014114"
> +- reg: chip select address for the device
> +- spi-cpha: shifted clock phase mode is required
> +
> +LED sub-node properties:
> +- label : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +- linux,default-trigger : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example
> +-------
> +
> +cr0014114@0 {

leds@...

> +	compatible = "crane,cr0014114";
> +	reg = <0>;
> +	spi-max-frequency = <50000>;
> +	spi-cpha;
> +
> +	led0 {

Is '0' meaningful to the controller as an address/channel. If so, use 
reg.

> +		label = "cr0:red:";
> +	};
> +	led1 {
> +		label = "cr0:green:";
> +	};
> +	led2 {
> +		label = "cr0:blue:";
> +	};
> +	led3 {
> +		label = "cr1:red:";
> +	};
> +	led4 {
> +		label = "cr1:green:";
> +	};
> +	led5 {
> +		label = "cr1:blue:";
> +	};
> +	...
> +};
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index ae850d6c0ad3..f17949c365f5 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>  compulab	CompuLab Ltd.
>  cortina	Cortina Systems, Inc.
>  cosmic	Cosmic Circuits
> +crane	Crane Connectivity Solutions
>  creative	Creative Technology Ltd
>  crystalfontz	Crystalfontz America, Inc.
>  cubietech	Cubietech, Ltd.

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

* Re: [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-18 12:49     ` [PATCH v3] leds: add LED driver for CR0014114 board Rob Herring
@ 2018-03-18 20:03       ` Jacek Anaszewski
  2018-03-18 23:38         ` Rob Herring
  0 siblings, 1 reply; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-18 20:03 UTC (permalink / raw)
  To: Rob Herring, Oleh Kravchenko; +Cc: devicetree, linux-leds

On 03/18/2018 01:49 PM, Rob Herring wrote:
> On Tue, Mar 13, 2018 at 02:45:48PM +0200, Oleh Kravchenko wrote:
>> This patch adds a LED class driver for the RGB LEDs found on
>> the Crane Merchandising System CR0014114 LEDs board.
>>
>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
>> ---
>>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
> 
> Please split to separate patch.
> 
>>  drivers/leds/Kconfig                               |  13 +
>>  drivers/leds/Makefile                              |   1 +
>>  drivers/leds/leds-cr0014114.c                      | 292 +++++++++++++++++++++
>>  5 files changed, 353 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>  create mode 100644 drivers/leds/leds-cr0014114.c
>>
>> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>> new file mode 100644
>> index 000000000000..977a9929b04f
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>> @@ -0,0 +1,46 @@
>> +Crane Merchandising System - cr0014114 LED driver
>> +-------------------------------------------------
>> +
>> +This LED Board is widely used in vending machines produced
>> +by Crane Merchandising Systems.
>> +
>> +Required properties:
>> +- compatible: "cms,cr0014114"
>> +- reg: chip select address for the device
>> +- spi-cpha: shifted clock phase mode is required
>> +
>> +LED sub-node properties:
>> +- label : (optional)
>> +	see Documentation/devicetree/bindings/leds/common.txt
>> +- linux,default-trigger : (optional)
>> +	see Documentation/devicetree/bindings/leds/common.txt
>> +
>> +Example
>> +-------
>> +
>> +cr0014114@0 {
> 
> leds@...

In [0] you required it to be led-controller and the rest like below:


led-controller@12 {
  reg = <12>;

  led@0 {
    reg = <0>;
  };
  led@1 {
    reg = <1>;
  };
};


Since that time I started to require adhering to this naming pattern
for LED controller node and led@address for child nodes, where
applicable.

I plan on submitting a patch for common LED bindings, that will
switch device names to led-controller in DT examples.

With this scheme another problem arises, because now we have:

- label: The label for this LED. If omitted, the label is taken from
         the node name (excluding the unit address).

With that DT child node name is useless, because it is "led" for
each sub-led. Therefore I propose to make label property required,
and avoid using child DT node name as a fallback.

>> +	compatible = "crane,cr0014114";
>> +	reg = <0>;
>> +	spi-max-frequency = <50000>;
>> +	spi-cpha;
>> +
>> +	led0 {
> 
> Is '0' meaningful to the controller as an address/channel. If so, use 
> reg.
> 
>> +		label = "cr0:red:";
>> +	};
>> +	led1 {
>> +		label = "cr0:green:";
>> +	};
>> +	led2 {
>> +		label = "cr0:blue:";
>> +	};
>> +	led3 {
>> +		label = "cr1:red:";
>> +	};
>> +	led4 {
>> +		label = "cr1:green:";
>> +	};
>> +	led5 {
>> +		label = "cr1:blue:";
>> +	};
>> +	...
>> +};
>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> index ae850d6c0ad3..f17949c365f5 100644
>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>>  compulab	CompuLab Ltd.
>>  cortina	Cortina Systems, Inc.
>>  cosmic	Cosmic Circuits
>> +crane	Crane Connectivity Solutions
>>  creative	Creative Technology Ltd
>>  crystalfontz	Crystalfontz America, Inc.
>>  cubietech	Cubietech, Ltd.
> 

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

-- 
Best regards,
Jacek Anaszewski

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

* Re: [PATCH v3] leds: add LED driver for CR0014114 board
  2018-03-18 20:03       ` Jacek Anaszewski
@ 2018-03-18 23:38         ` Rob Herring
  2018-03-19 21:18           ` Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board] Jacek Anaszewski
  0 siblings, 1 reply; 46+ messages in thread
From: Rob Herring @ 2018-03-18 23:38 UTC (permalink / raw)
  To: Jacek Anaszewski; +Cc: Oleh Kravchenko, devicetree, Linux LED Subsystem

On Sun, Mar 18, 2018 at 3:03 PM, Jacek Anaszewski
<jacek.anaszewski@gmail.com> wrote:
> On 03/18/2018 01:49 PM, Rob Herring wrote:
>> On Tue, Mar 13, 2018 at 02:45:48PM +0200, Oleh Kravchenko wrote:
>>> This patch adds a LED class driver for the RGB LEDs found on
>>> the Crane Merchandising System CR0014114 LEDs board.
>>>
>>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
>>> ---
>>>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>>>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>>
>> Please split to separate patch.
>>
>>>  drivers/leds/Kconfig                               |  13 +
>>>  drivers/leds/Makefile                              |   1 +
>>>  drivers/leds/leds-cr0014114.c                      | 292 +++++++++++++++++++++
>>>  5 files changed, 353 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>  create mode 100644 drivers/leds/leds-cr0014114.c
>>>
>>> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>> new file mode 100644
>>> index 000000000000..977a9929b04f
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>> @@ -0,0 +1,46 @@
>>> +Crane Merchandising System - cr0014114 LED driver
>>> +-------------------------------------------------
>>> +
>>> +This LED Board is widely used in vending machines produced
>>> +by Crane Merchandising Systems.
>>> +
>>> +Required properties:
>>> +- compatible: "cms,cr0014114"
>>> +- reg: chip select address for the device
>>> +- spi-cpha: shifted clock phase mode is required
>>> +
>>> +LED sub-node properties:
>>> +- label : (optional)
>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>> +- linux,default-trigger : (optional)
>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>> +
>>> +Example
>>> +-------
>>> +
>>> +cr0014114@0 {
>>
>> leds@...
>
> In [0] you required it to be led-controller and the rest like below:

Ah yes, you're right. That's what I get for trying to go off my memory.

>
>
> led-controller@12 {
>   reg = <12>;
>
>   led@0 {
>     reg = <0>;
>   };
>   led@1 {
>     reg = <1>;
>   };
> };
>
>
> Since that time I started to require adhering to this naming pattern
> for LED controller node and led@address for child nodes, where
> applicable.
>
> I plan on submitting a patch for common LED bindings, that will
> switch device names to led-controller in DT examples.
>
> With this scheme another problem arises, because now we have:
>
> - label: The label for this LED. If omitted, the label is taken from
>          the node name (excluding the unit address).
>
> With that DT child node name is useless, because it is "led" for
> each sub-led. Therefore I propose to make label property required,
> and avoid using child DT node name as a fallback.

There was never any guarantee that the same child node name was not
used elsewhere.

I think the OS needs to be able to cope with no label or even that
label is not unique. Suppose you have an overlay for a addon board and
you can have multiple boards connected. They'd all have the same
label. So moving to label only reduces the problem. You could use the
reg property and/or compatible of the parent to construct the names.
Or just append an IDR value to the name like we do on platform
devices. If the user didn't specify a label, then they shouldn't
really care what the name is, so just use "led.X". Though likely folks
will care if the name changes on them.

Rob

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

* Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board]
  2018-03-18 23:38         ` Rob Herring
@ 2018-03-19 21:18           ` Jacek Anaszewski
  2018-03-27 15:31             ` Rob Herring
  2018-04-15 16:15             ` Pavel Machek
  0 siblings, 2 replies; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-19 21:18 UTC (permalink / raw)
  To: Rob Herring
  Cc: Oleh Kravchenko, devicetree, Linux LED Subsystem, Pavel Machek

On 03/19/2018 12:38 AM, Rob Herring wrote:
> On Sun, Mar 18, 2018 at 3:03 PM, Jacek Anaszewski
> <jacek.anaszewski@gmail.com> wrote:
>> On 03/18/2018 01:49 PM, Rob Herring wrote:
>>> On Tue, Mar 13, 2018 at 02:45:48PM +0200, Oleh Kravchenko wrote:
>>>> This patch adds a LED class driver for the RGB LEDs found on
>>>> the Crane Merchandising System CR0014114 LEDs board.
>>>>
>>>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
>>>> ---
>>>>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>>>>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>>>
>>> Please split to separate patch.
>>>
>>>>  drivers/leds/Kconfig                               |  13 +
>>>>  drivers/leds/Makefile                              |   1 +
>>>>  drivers/leds/leds-cr0014114.c                      | 292 +++++++++++++++++++++
>>>>  5 files changed, 353 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>  create mode 100644 drivers/leds/leds-cr0014114.c
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>> new file mode 100644
>>>> index 000000000000..977a9929b04f
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>> @@ -0,0 +1,46 @@
>>>> +Crane Merchandising System - cr0014114 LED driver
>>>> +-------------------------------------------------
>>>> +
>>>> +This LED Board is widely used in vending machines produced
>>>> +by Crane Merchandising Systems.
>>>> +
>>>> +Required properties:
>>>> +- compatible: "cms,cr0014114"
>>>> +- reg: chip select address for the device
>>>> +- spi-cpha: shifted clock phase mode is required
>>>> +
>>>> +LED sub-node properties:
>>>> +- label : (optional)
>>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>>> +- linux,default-trigger : (optional)
>>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>>> +
>>>> +Example
>>>> +-------
>>>> +
>>>> +cr0014114@0 {
>>>
>>> leds@...
>>
>> In [0] you required it to be led-controller and the rest like below:
> 
> Ah yes, you're right. That's what I get for trying to go off my memory.
> 
>>
>>
>> led-controller@12 {
>>   reg = <12>;
>>
>>   led@0 {
>>     reg = <0>;
>>   };
>>   led@1 {
>>     reg = <1>;
>>   };
>> };
>>
>>
>> Since that time I started to require adhering to this naming pattern
>> for LED controller node and led@address for child nodes, where
>> applicable.
>>
>> I plan on submitting a patch for common LED bindings, that will
>> switch device names to led-controller in DT examples.
>>
>> With this scheme another problem arises, because now we have:
>>
>> - label: The label for this LED. If omitted, the label is taken from
>>          the node name (excluding the unit address).
>>
>> With that DT child node name is useless, because it is "led" for
>> each sub-led. Therefore I propose to make label property required,
>> and avoid using child DT node name as a fallback.
> 
> There was never any guarantee that the same child node name was not
> used elsewhere.
> 
> I think the OS needs to be able to cope with no label or even that
> label is not unique. Suppose you have an overlay for a addon board and
> you can have multiple boards connected. They'd all have the same
> label.

LED subsystem is already protected against duplicated LED names:
a96aa64cb572 ("leds/led-class: Handle LEDs with the same name").

> So moving to label only reduces the problem. You could use the
> reg property and/or compatible of the parent to construct the names.
> Or just append an IDR value to the name like we do on platform
> devices. If the user didn't specify a label, then they shouldn't
> really care what the name is, so just use "led.X". Though likely folks
> will care if the name changes on them.

OK, so my main intention was to get rid of the part:

"If omitted, the label is taken from the node name (excluding
the unit address).",

because it won't make a sense after imposing an explicit requirement
on the child nodes to have only "led" in the main part of their names.

In effect, we need to change the fallback definition to make it sane.
You proposed reg property and/or compatible, but:

- reg property is not applicable in all cases (think of gpio LEDs).
- compatible on the other hand will have much in common with devicename,
  you once mentioned would be good to get rid of [0]:

"
A case I care about is I have a family of boards that all have a
common defined set of 4 LEDs. They could be driven by anything, but I
want the same interface presented to userspace across boards.
"

We also had a discussion about standardized LED function names, so I
retrieved all LED function names from dts files present in kernel,
and after unifying some similar occurrences I got something like
below. Perhaps it doesn't make a sense to add all of the below
definitions to the standard header, but some of them could certainly
find their place in e.g. include/dt-bindings/leds/led-functions.h.

Then we could have LED names in the form function:color, and below
defines could be used in dts files to avoid spawning similar LED names
describing the same function.

Of course in case of the names presented here with numerical suffixes
we could skip the suffix.


#define LED_FUNCTION_ACTIVITY "activity"
#define LED_FUNCTION_ADSL "adsl"
#define LED_FUNCTION_ALARM "alarm"
#define LED_FUNCTION_ALIVE "alive"
#define LED_FUNCTION_ALL "all"
#define LED_FUNCTION_APP "app"
#define LED_FUNCTION_AUX "aux"
#define LED_FUNCTION_BACKUP "backup"
#define LED_FUNCTION_BEEP "beep"
#define LED_FUNCTION_BLUETOOTH "bluetooth"
#define LED_FUNCTION_BOOT "boot"
#define LED_FUNCTION_BOTTOM "bottom"
#define LED_FUNCTION_BRICK-STATUS "brick-status"
#define LED_FUNCTION_BT "bt"
#define LED_FUNCTION_CEL "cel"
#define LED_FUNCTION_CEL-PWR "cel-pwr"
#define LED_FUNCTION_CEL-RESET "cel-reset"
#define LED_FUNCTION_CHRG "chrg"
#define LED_FUNCTION_COM "com"
#define LED_FUNCTION_COPY "copy"
#define LED_FUNCTION_CORE_MODULE "core_module"
#define LED_FUNCTION_CPU "cpu"
#define LED_FUNCTION_D "d"
#define LED_FUNCTION_DEBUG "debug"
#define LED_FUNCTION_DIA "dia"
#define LED_FUNCTION_DISK "disk"
#define LED_FUNCTION_DOWN "down"
#define LED_FUNCTION_DSL "dsl"
#define LED_FUNCTION_ENOCEAN "enocean"
#define LED_FUNCTION_ENTER "enter"
#define LED_FUNCTION_ERROR "error"
#define LED_FUNCTION_ESATA "esata"
#define LED_FUNCTION_ETHERNET-STATUS "ethernet-status"
#define LED_FUNCTION_FAIL "fail"
#define LED_FUNCTION_FAULT "fault"
#define LED_FUNCTION_FRONT "front"
#define LED_FUNCTION_FUNC "func"
#define LED_FUNCTION_G "g"
#define LED_FUNCTION_GHZ "ghz"
#define LED_FUNCTION_GHZ-1 "ghz-1"
#define LED_FUNCTION_GHZ-2 "ghz-2"
#define LED_FUNCTION_GPIO "gpio"
#define LED_FUNCTION_GSM "gsm"
#define LED_FUNCTION_HD "hd"
#define LED_FUNCTION_HDD "hdd"
#define LED_FUNCTION_HDDERR "hdderr"
#define LED_FUNCTION_HEALTH "health"
#define LED_FUNCTION_HEART "heart"
#define LED_FUNCTION_HEARTBEAT "heartbeat"
#define LED_FUNCTION_HOME "home"
#define LED_FUNCTION_INET "inet"
#define LED_FUNCTION_INFO "info"
#define LED_FUNCTION_INTERNET "internet"
#define LED_FUNCTION_KEYPAD "keypad"
#define LED_FUNCTION_L "l"
#define LED_FUNCTION_LAN "lan"
#define LED_FUNCTION_LEDB "ledb"
#define LED_FUNCTION_LEFT "left"
#define LED_FUNCTION_L_HDD "l_hdd"
#define LED_FUNCTION_LIVE "live"
#define LED_FUNCTION_LOGO "logo"
#define LED_FUNCTION_MICROSD "microsd"
#define LED_FUNCTION_MISC "misc"
#define LED_FUNCTION_MMC "mmc"
#define LED_FUNCTION_NAND "nand"
#define LED_FUNCTION_NETWORK "network"
#define LED_FUNCTION_ON "on"
#define LED_FUNCTION_ORANGE "orange"
#define LED_FUNCTION_OS "os"
#define LED_FUNCTION_PANEL "panel"
#define LED_FUNCTION_PMU_STAT "pmu_stat"
#define LED_FUNCTION_POWER "power"
#define LED_FUNCTION_PROG "prog"
#define LED_FUNCTION_PROGRAMMING "programming"
#define LED_FUNCTION_PROXIMITYSENSOR "proximitysensor"
#define LED_FUNCTION_PULSE "pulse"
#define LED_FUNCTION_PWR "pwr"
#define LED_FUNCTION_QSS "qss"
#define LED_FUNCTION_REBUILD "rebuild"
#define LED_FUNCTION_R_HDD "r_hdd"
#define LED_FUNCTION_RIGHT "right"
#define LED_FUNCTION_ROUTER "router"
#define LED_FUNCTION_RS "rs"
#define LED_FUNCTION_RX "rx"
#define LED_FUNCTION_SATA "sata"
#define LED_FUNCTION_SATA-L "sata-l"
#define LED_FUNCTION_SATA-R "sata-r"
#define LED_FUNCTION_SD "sd"
#define LED_FUNCTION_SLEEP "sleep"
#define LED_FUNCTION_STANDBY "standby"
#define LED_FUNCTION_STATE "state"
#define LED_FUNCTION_STATUS "status"
#define LED_FUNCTION_SW "sw"
#define LED_FUNCTION_SWRDY "swrdy"
#define LED_FUNCTION_SYS "sys"
#define LED_FUNCTION_SYSTEM "system"
#define LED_FUNCTION_SYSTEM-STATUS "system-status"
#define LED_FUNCTION_TEL "tel"
#define LED_FUNCTION_TOP "top"
#define LED_FUNCTION_TV "tv"
#define LED_FUNCTION_TX "tx"
#define LED_FUNCTION_UP "up"
#define LED_FUNCTION_USB "usb"
#define LED_FUNCTION_USB_1 "usb_1"
#define LED_FUNCTION_USB_2 "usb_2"
#define LED_FUNCTION_USB_COPY "usb_copy"
#define LED_FUNCTION_USB-PORT1 "usb-port1"
#define LED_FUNCTION_USB-PORT2 "usb-port2"
#define LED_FUNCTION_USER "user"
#define LED_FUNCTION_USR "usr"
#define LED_FUNCTION_WAN "wan"
#define LED_FUNCTION_WIFI "wifi"
#define LED_FUNCTION_WIFI_AP "wifi_ap"
#define LED_FUNCTION_WIFI-STATUS "wifi-status"
#define LED_FUNCTION_WIRELESS "wireless"
#define LED_FUNCTION_WLAN "wlan"
#define LED_FUNCTION_WLAN_G "wlan_g"
#define LED_FUNCTION_WMODE "wmode"
#define LED_FUNCTION_WPS "wps"


[0] https://patchwork.kernel.org/patch/10089047/
-- 
Best regards,
Jacek Anaszewski

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

* [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-16 21:40           ` Oleh Kravchenko
  2018-03-16 22:10             ` Pavel Machek
@ 2018-03-26 12:15             ` Oleh Kravchenko
  2018-03-26 12:15               ` [PATCH v4 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
                                 ` (2 more replies)
  1 sibling, 3 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-26 12:15 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 .../devicetree/bindings/leds/leds-cr0014114.txt    | 49 ++++++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 2 files changed, 50 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
new file mode 100644
index 000000000000..0818ac6c6ffa
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
@@ -0,0 +1,49 @@
+Crane Merchandising System - cr0014114 LED driver
+-------------------------------------------------
+
+This LED Board is widely used in vending machines produced
+by Crane Merchandising Systems.
+
+Required properties:
+- compatible: "crane,cr0014114"
+
+LED sub-node properties:
+- label :
+	see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+
+Example
+-------
+
+led-controller@0 {
+	compatible = "crane,cr0014114";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	led@0 {
+		reg = <0>;
+		label = "cr0:red:coin";
+	};
+	led@1 {
+		reg = <1>;
+		label = "cr0:green:coin";
+	};
+	led@2 {
+		reg = <2>;
+		label = "cr0:blue:coin";
+	};
+	led@3 {
+		reg = <3>;
+		label = "cr1:red:bill";
+	};
+	led@4 {
+		reg = <4>;
+		label = "cr1:green:bill";
+	};
+	led@5 {
+		reg = <5>;
+		label = "cr1:blue:bill";
+	};
+	...
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ae850d6c0ad3..f17949c365f5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
 compulab	CompuLab Ltd.
 cortina	Cortina Systems, Inc.
 cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
 creative	Creative Technology Ltd
 crystalfontz	Crystalfontz America, Inc.
 cubietech	Cubietech, Ltd.
-- 
2.16.1


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

* [PATCH v4 2/2] leds: add LED driver for CR0014114 board
  2018-03-26 12:15             ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
@ 2018-03-26 12:15               ` Oleh Kravchenko
  2018-03-27 16:14               ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Rob Herring
  2018-03-27 16:49               ` [PATCH " Oleh Kravchenko
  2 siblings, 0 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-26 12:15 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

This patch adds a LED class driver for the RGB LEDs found on
the Crane Merchandising System CR0014114 LEDs board.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 drivers/leds/Kconfig          |  13 ++
 drivers/leds/Makefile         |   1 +
 drivers/leds/leds-cr0014114.c | 304 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 318 insertions(+)
 create mode 100644 drivers/leds/leds-cr0014114.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..5831814d01d0 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -104,6 +104,19 @@ config LEDS_CPCAP
 	  This option enables support for LEDs offered by Motorola's
 	  CPCAP PMIC.
 
+config LEDS_CR0014114
+	tristate "LED Support for Crane CR0014114"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for CR0014114 LED Board which
+	  is widely used in vending machines produced by
+	  Crane Merchandising Systems.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-cr0014114.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..0176e7335994 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 
 # LED SPI Drivers
+obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Userspace Drivers
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
new file mode 100644
index 000000000000..6e35acae6cc9
--- /dev/null
+++ b/drivers/leds/leds-cr0014114.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * LEDs driver for Crane CR0014114
+ *
+ * Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * CR0014114 SPI protocol descrtiption:
+ * +----+-----------------------------------+----+
+ * | CMD|             BRIGHTNESS            |CRC |
+ * +----+-----------------------------------+----+
+ * |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
+ * |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ * |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
+ * | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
+ * |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
+ * |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ * |    |               18                  |    |
+ * +----+-----------------------------------+----+
+ * |                    20                       |
+ * +---------------------------------------------+
+ *
+ * PS: Boards can be connected to the chain:
+ *     SPI -> board0 -> board1 -> board2 ..
+ */
+
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+
+/* CR0014114 SPI commands */
+#define CR_SET_BRIGHTNESS	0x80
+#define CR_INIT_REENUMERATE	0x81
+#define CR_NEXT_REENUMERATE	0x82
+
+/* CR0014114 default settings */
+#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
+#define CR_FW_DELAY_MSEC	10
+#define CR_RECOUNT_DELAY	(HZ * 3600)
+
+struct cr0014114_led {
+	const char		*name;
+	struct cr0014114	*priv;
+	struct led_classdev	ldev;
+	u8			brightness;
+};
+
+struct cr0014114 {
+	bool			do_recount;
+	size_t			count;
+	struct delayed_work	work;
+	struct device		*dev;
+	struct mutex		lock;
+	struct spi_device	*spi;
+	u8			*buf;
+	unsigned long		delay;
+	struct cr0014114_led	leds[];
+};
+
+static void cr0014114_calc_crc(u8 *buf, const size_t len)
+{
+	size_t	i;
+	u8	crc;
+
+	for (i = 1, crc = 1; i < len - 1; i++)
+		crc += buf[i];
+	crc |= BIT(7);
+
+	/* special case when CRC matches the SPI commands */
+	if (crc == CR_SET_BRIGHTNESS ||
+	    crc == CR_INIT_REENUMERATE ||
+	    crc == CR_NEXT_REENUMERATE)
+		crc = 0xfe;
+
+	buf[len - 1] = crc;
+}
+
+static int cr0014114_recount(struct cr0014114 *priv)
+{
+	int	ret;
+	size_t	i;
+	u8	cmd;
+
+	cmd = CR_INIT_REENUMERATE;
+	ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+	if (ret)
+		goto err;
+
+	cmd = CR_NEXT_REENUMERATE;
+	for (i = 0; i < priv->count; i++) {
+		msleep(CR_FW_DELAY_MSEC);
+
+		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+		if (ret)
+			goto err;
+	}
+
+err:
+	if (ret)
+		dev_err(priv->dev, "recount is failed %d", ret);
+
+	return ret;
+}
+
+static int cr0014114_sync(struct cr0014114 *priv)
+{
+	int		ret;
+	size_t		i;
+	unsigned long	udelay, now = jiffies;
+
+	/* to avoid SPI mistiming with firmware we should wait some time */
+	if (time_after(priv->delay, now)) {
+		udelay = jiffies_to_usecs(priv->delay - now);
+		usleep_range(udelay, udelay + 1);
+	}
+
+	if (unlikely(priv->do_recount)) {
+		ret = cr0014114_recount(priv);
+		if (ret)
+			goto err;
+
+		priv->do_recount = false;
+		msleep(CR_FW_DELAY_MSEC);
+	}
+
+	priv->buf[0] = CR_SET_BRIGHTNESS;
+	for (i = 0; i < priv->count; i++)
+		priv->buf[i + 1] = priv->leds[i].brightness;
+	cr0014114_calc_crc(priv->buf, priv->count + 2);
+	ret = spi_write(priv->spi, priv->buf, priv->count + 2);
+
+err:
+	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	return ret;
+}
+
+static void cr0014114_recount_work(struct work_struct *work)
+{
+	int			ret;
+	struct cr0014114	*priv = container_of(work,
+						     struct cr0014114,
+						     work.work);
+
+	mutex_lock(&priv->lock);
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
+
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+}
+
+static int cr0014114_set_sync(struct led_classdev *ldev,
+			      enum led_brightness brightness)
+{
+	int			ret;
+	struct cr0014114_led    *led = container_of(ldev,
+						    struct cr0014114_led,
+						    ldev);
+
+	mutex_lock(&led->priv->lock);
+	led->brightness = (u8)brightness;
+	ret = cr0014114_sync(led->priv);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int cr0014114_probe_dt(struct cr0014114 *priv)
+{
+	size_t			i = 0;
+	struct cr0014114_led	*led;
+	struct fwnode_handle	*child;
+	struct device_node	*np;
+	int			ret;
+
+	device_for_each_child_node(priv->dev, child) {
+		np = to_of_node(child);
+		led = &priv->leds[i];
+
+		ret = fwnode_property_read_string(child, "label",
+						  &led->name);
+		if (ret) {
+			dev_err(priv->dev, "LED label is not defined!");
+			fwnode_handle_put(child);
+			return -EINVAL;
+		}
+
+		fwnode_property_read_string(child, "linux,default-trigger",
+					    &led->ldev.default_trigger);
+
+		led->priv			  = priv;
+		led->ldev.name			  = led->name;
+		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
+		led->ldev.brightness_set_blocking = cr0014114_set_sync;
+
+		ret = devm_of_led_classdev_register(priv->dev, np,
+						    &led->ldev);
+		if (ret) {
+			dev_err(priv->dev,
+				"failed to register LED device %s, err %d",
+				led->name, ret);
+			fwnode_handle_put(child);
+			return ret;
+		}
+
+		led->ldev.dev->of_node = np;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int cr0014114_probe(struct spi_device *spi)
+{
+	struct cr0014114	*priv;
+	size_t			count;
+	int			ret;
+
+	count = device_get_child_node_count(&spi->dev);
+	if (!count) {
+		dev_err(&spi->dev, "LEDs are not defined in device tree!");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&spi->dev,
+			    sizeof(*priv) + sizeof(*priv->leds) * count,
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
+	if (!priv->buf)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
+	priv->count		= count;
+	priv->dev		= &spi->dev;
+	priv->do_recount	= true;
+	priv->spi		= spi;
+	priv->delay		= jiffies -
+				  msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	ret = cr0014114_probe_dt(priv);
+	if (ret)
+		return ret;
+
+	ret = cr0014114_sync(priv);
+	if (ret) {
+		dev_err(priv->dev, "first sync of LEDs failed %d\n", ret);
+		return ret;
+	}
+
+	/* setup recount work to workaround buggy firmware */
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+
+	spi_set_drvdata(spi, priv);
+
+	return 0;
+}
+
+static int cr0014114_remove(struct spi_device *spi)
+{
+	struct cr0014114 *priv = spi_get_drvdata(spi);
+
+	cancel_delayed_work_sync(&priv->work);
+
+	return 0;
+}
+
+static const struct of_device_id cr0014114_dt_ids[] = {
+	{ .compatible = "crane,cr0014114", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
+
+static struct spi_driver cr0014114_driver = {
+	.probe		= cr0014114_probe,
+	.remove		= cr0014114_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= cr0014114_dt_ids,
+	},
+};
+
+module_spi_driver(cr0014114_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("cr0014114 LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:cr0014114");
-- 
2.16.1


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

* Re: Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board]
  2018-03-19 21:18           ` Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board] Jacek Anaszewski
@ 2018-03-27 15:31             ` Rob Herring
  2018-03-30 10:53               ` Jacek Anaszewski
  2018-04-15 16:15             ` Pavel Machek
  1 sibling, 1 reply; 46+ messages in thread
From: Rob Herring @ 2018-03-27 15:31 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Oleh Kravchenko, devicetree, Linux LED Subsystem, Pavel Machek

On Mon, Mar 19, 2018 at 4:18 PM, Jacek Anaszewski
<jacek.anaszewski@gmail.com> wrote:
> On 03/19/2018 12:38 AM, Rob Herring wrote:
>> On Sun, Mar 18, 2018 at 3:03 PM, Jacek Anaszewski
>> <jacek.anaszewski@gmail.com> wrote:
>>> On 03/18/2018 01:49 PM, Rob Herring wrote:
>>>> On Tue, Mar 13, 2018 at 02:45:48PM +0200, Oleh Kravchenko wrote:
>>>>> This patch adds a LED class driver for the RGB LEDs found on
>>>>> the Crane Merchandising System CR0014114 LEDs board.
>>>>>
>>>>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
>>>>> ---
>>>>>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>>>>>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>>>>
>>>> Please split to separate patch.
>>>>
>>>>>  drivers/leds/Kconfig                               |  13 +
>>>>>  drivers/leds/Makefile                              |   1 +
>>>>>  drivers/leds/leds-cr0014114.c                      | 292 +++++++++++++++++++++
>>>>>  5 files changed, 353 insertions(+)
>>>>>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>>  create mode 100644 drivers/leds/leds-cr0014114.c
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>> new file mode 100644
>>>>> index 000000000000..977a9929b04f
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>> @@ -0,0 +1,46 @@
>>>>> +Crane Merchandising System - cr0014114 LED driver
>>>>> +-------------------------------------------------
>>>>> +
>>>>> +This LED Board is widely used in vending machines produced
>>>>> +by Crane Merchandising Systems.
>>>>> +
>>>>> +Required properties:
>>>>> +- compatible: "cms,cr0014114"
>>>>> +- reg: chip select address for the device
>>>>> +- spi-cpha: shifted clock phase mode is required
>>>>> +
>>>>> +LED sub-node properties:
>>>>> +- label : (optional)
>>>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>>>> +- linux,default-trigger : (optional)
>>>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>>>> +
>>>>> +Example
>>>>> +-------
>>>>> +
>>>>> +cr0014114@0 {
>>>>
>>>> leds@...
>>>
>>> In [0] you required it to be led-controller and the rest like below:
>>
>> Ah yes, you're right. That's what I get for trying to go off my memory.
>>
>>>
>>>
>>> led-controller@12 {
>>>   reg = <12>;
>>>
>>>   led@0 {
>>>     reg = <0>;
>>>   };
>>>   led@1 {
>>>     reg = <1>;
>>>   };
>>> };
>>>
>>>
>>> Since that time I started to require adhering to this naming pattern
>>> for LED controller node and led@address for child nodes, where
>>> applicable.
>>>
>>> I plan on submitting a patch for common LED bindings, that will
>>> switch device names to led-controller in DT examples.
>>>
>>> With this scheme another problem arises, because now we have:
>>>
>>> - label: The label for this LED. If omitted, the label is taken from
>>>          the node name (excluding the unit address).
>>>
>>> With that DT child node name is useless, because it is "led" for
>>> each sub-led. Therefore I propose to make label property required,
>>> and avoid using child DT node name as a fallback.
>>
>> There was never any guarantee that the same child node name was not
>> used elsewhere.
>>
>> I think the OS needs to be able to cope with no label or even that
>> label is not unique. Suppose you have an overlay for a addon board and
>> you can have multiple boards connected. They'd all have the same
>> label.
>
> LED subsystem is already protected against duplicated LED names:
> a96aa64cb572 ("leds/led-class: Handle LEDs with the same name").
>
>> So moving to label only reduces the problem. You could use the
>> reg property and/or compatible of the parent to construct the names.
>> Or just append an IDR value to the name like we do on platform
>> devices. If the user didn't specify a label, then they shouldn't
>> really care what the name is, so just use "led.X". Though likely folks
>> will care if the name changes on them.
>
> OK, so my main intention was to get rid of the part:
>
> "If omitted, the label is taken from the node name (excluding
> the unit address).",
>
> because it won't make a sense after imposing an explicit requirement
> on the child nodes to have only "led" in the main part of their names.

Okay, agreed. That statement never really belonged because really the
OS is free to do whatever it wants.

> In effect, we need to change the fallback definition to make it sane.
> You proposed reg property and/or compatible, but:
>
> - reg property is not applicable in all cases (think of gpio LEDs).
> - compatible on the other hand will have much in common with devicename,
>   you once mentioned would be good to get rid of [0]:
>
> "
> A case I care about is I have a family of boards that all have a
> common defined set of 4 LEDs. They could be driven by anything, but I
> want the same interface presented to userspace across boards.
> "

Yes, and "label" should provide me with that ability as the context
was the practice of putting the controller name in the label.

> We also had a discussion about standardized LED function names, so I
> retrieved all LED function names from dts files present in kernel,
> and after unifying some similar occurrences I got something like
> below. Perhaps it doesn't make a sense to add all of the below
> definitions to the standard header, but some of them could certainly
> find their place in e.g. include/dt-bindings/leds/led-functions.h.

Looks like we could further unify things though I suppose just
changing dts files could break users. But at least we could document
which ones to use for new dts files. Then hopefully we don't have more
"bluetooth" vs. "bt".

Yes, I'd certainly limit the list to ones where we have multiple
similar names and leave out the oddballs.

> Then we could have LED names in the form function:color, and below
> defines could be used in dts files to avoid spawning similar LED names
> describing the same function.
>
> Of course in case of the names presented here with numerical suffixes
> we could skip the suffix.
>
>
> #define LED_FUNCTION_ACTIVITY "activity"
> #define LED_FUNCTION_ADSL "adsl"
> #define LED_FUNCTION_ALARM "alarm"
> #define LED_FUNCTION_ALIVE "alive"
> #define LED_FUNCTION_ALL "all"
> #define LED_FUNCTION_APP "app"
> #define LED_FUNCTION_AUX "aux"
> #define LED_FUNCTION_BACKUP "backup"
> #define LED_FUNCTION_BEEP "beep"
> #define LED_FUNCTION_BLUETOOTH "bluetooth"
> #define LED_FUNCTION_BOOT "boot"
> #define LED_FUNCTION_BOTTOM "bottom"
> #define LED_FUNCTION_BRICK-STATUS "brick-status"
> #define LED_FUNCTION_BT "bt"
> #define LED_FUNCTION_CEL "cel"
> #define LED_FUNCTION_CEL-PWR "cel-pwr"
> #define LED_FUNCTION_CEL-RESET "cel-reset"
> #define LED_FUNCTION_CHRG "chrg"
> #define LED_FUNCTION_COM "com"
> #define LED_FUNCTION_COPY "copy"
> #define LED_FUNCTION_CORE_MODULE "core_module"
> #define LED_FUNCTION_CPU "cpu"
> #define LED_FUNCTION_D "d"
> #define LED_FUNCTION_DEBUG "debug"
> #define LED_FUNCTION_DIA "dia"
> #define LED_FUNCTION_DISK "disk"
> #define LED_FUNCTION_DOWN "down"
> #define LED_FUNCTION_DSL "dsl"
> #define LED_FUNCTION_ENOCEAN "enocean"
> #define LED_FUNCTION_ENTER "enter"
> #define LED_FUNCTION_ERROR "error"
> #define LED_FUNCTION_ESATA "esata"
> #define LED_FUNCTION_ETHERNET-STATUS "ethernet-status"
> #define LED_FUNCTION_FAIL "fail"
> #define LED_FUNCTION_FAULT "fault"
> #define LED_FUNCTION_FRONT "front"
> #define LED_FUNCTION_FUNC "func"
> #define LED_FUNCTION_G "g"
> #define LED_FUNCTION_GHZ "ghz"
> #define LED_FUNCTION_GHZ-1 "ghz-1"
> #define LED_FUNCTION_GHZ-2 "ghz-2"
> #define LED_FUNCTION_GPIO "gpio"
> #define LED_FUNCTION_GSM "gsm"
> #define LED_FUNCTION_HD "hd"
> #define LED_FUNCTION_HDD "hdd"
> #define LED_FUNCTION_HDDERR "hdderr"
> #define LED_FUNCTION_HEALTH "health"
> #define LED_FUNCTION_HEART "heart"
> #define LED_FUNCTION_HEARTBEAT "heartbeat"
> #define LED_FUNCTION_HOME "home"
> #define LED_FUNCTION_INET "inet"
> #define LED_FUNCTION_INFO "info"
> #define LED_FUNCTION_INTERNET "internet"
> #define LED_FUNCTION_KEYPAD "keypad"
> #define LED_FUNCTION_L "l"
> #define LED_FUNCTION_LAN "lan"
> #define LED_FUNCTION_LEDB "ledb"
> #define LED_FUNCTION_LEFT "left"
> #define LED_FUNCTION_L_HDD "l_hdd"
> #define LED_FUNCTION_LIVE "live"
> #define LED_FUNCTION_LOGO "logo"
> #define LED_FUNCTION_MICROSD "microsd"
> #define LED_FUNCTION_MISC "misc"
> #define LED_FUNCTION_MMC "mmc"
> #define LED_FUNCTION_NAND "nand"
> #define LED_FUNCTION_NETWORK "network"
> #define LED_FUNCTION_ON "on"
> #define LED_FUNCTION_ORANGE "orange"
> #define LED_FUNCTION_OS "os"
> #define LED_FUNCTION_PANEL "panel"
> #define LED_FUNCTION_PMU_STAT "pmu_stat"
> #define LED_FUNCTION_POWER "power"
> #define LED_FUNCTION_PROG "prog"
> #define LED_FUNCTION_PROGRAMMING "programming"
> #define LED_FUNCTION_PROXIMITYSENSOR "proximitysensor"
> #define LED_FUNCTION_PULSE "pulse"
> #define LED_FUNCTION_PWR "pwr"
> #define LED_FUNCTION_QSS "qss"
> #define LED_FUNCTION_REBUILD "rebuild"
> #define LED_FUNCTION_R_HDD "r_hdd"
> #define LED_FUNCTION_RIGHT "right"
> #define LED_FUNCTION_ROUTER "router"
> #define LED_FUNCTION_RS "rs"
> #define LED_FUNCTION_RX "rx"
> #define LED_FUNCTION_SATA "sata"
> #define LED_FUNCTION_SATA-L "sata-l"
> #define LED_FUNCTION_SATA-R "sata-r"
> #define LED_FUNCTION_SD "sd"
> #define LED_FUNCTION_SLEEP "sleep"
> #define LED_FUNCTION_STANDBY "standby"
> #define LED_FUNCTION_STATE "state"
> #define LED_FUNCTION_STATUS "status"
> #define LED_FUNCTION_SW "sw"
> #define LED_FUNCTION_SWRDY "swrdy"
> #define LED_FUNCTION_SYS "sys"
> #define LED_FUNCTION_SYSTEM "system"
> #define LED_FUNCTION_SYSTEM-STATUS "system-status"
> #define LED_FUNCTION_TEL "tel"
> #define LED_FUNCTION_TOP "top"
> #define LED_FUNCTION_TV "tv"
> #define LED_FUNCTION_TX "tx"
> #define LED_FUNCTION_UP "up"
> #define LED_FUNCTION_USB "usb"
> #define LED_FUNCTION_USB_1 "usb_1"
> #define LED_FUNCTION_USB_2 "usb_2"
> #define LED_FUNCTION_USB_COPY "usb_copy"
> #define LED_FUNCTION_USB-PORT1 "usb-port1"
> #define LED_FUNCTION_USB-PORT2 "usb-port2"
> #define LED_FUNCTION_USER "user"
> #define LED_FUNCTION_USR "usr"
> #define LED_FUNCTION_WAN "wan"
> #define LED_FUNCTION_WIFI "wifi"
> #define LED_FUNCTION_WIFI_AP "wifi_ap"
> #define LED_FUNCTION_WIFI-STATUS "wifi-status"
> #define LED_FUNCTION_WIRELESS "wireless"
> #define LED_FUNCTION_WLAN "wlan"
> #define LED_FUNCTION_WLAN_G "wlan_g"
> #define LED_FUNCTION_WMODE "wmode"
> #define LED_FUNCTION_WPS "wps"
>
>
> [0] https://patchwork.kernel.org/patch/10089047/
> --
> Best regards,
> Jacek Anaszewski

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

* Re: [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-26 12:15             ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  2018-03-26 12:15               ` [PATCH v4 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-03-27 16:14               ` Rob Herring
  2018-03-27 16:49               ` [PATCH " Oleh Kravchenko
  2 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2018-03-27 16:14 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, linux-leds

On Mon, Mar 26, 2018 at 03:15:05PM +0300, Oleh Kravchenko wrote:
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>

Commit message?

> ---
>  .../devicetree/bindings/leds/leds-cr0014114.txt    | 49 ++++++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.txt        |  1 +
>  2 files changed, 50 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> 
> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> new file mode 100644
> index 000000000000..0818ac6c6ffa
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> @@ -0,0 +1,49 @@
> +Crane Merchandising System - cr0014114 LED driver
> +-------------------------------------------------
> +
> +This LED Board is widely used in vending machines produced
> +by Crane Merchandising Systems.
> +
> +Required properties:
> +- compatible: "crane,cr0014114"
> +
> +LED sub-node properties:
> +- label :
> +	see Documentation/devicetree/bindings/leds/common.txt
> +- linux,default-trigger : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example
> +-------
> +
> +led-controller@0 {

A unit-address needs a matching reg property. What happened to the SPI 
related properties? I think Jacek's comment was just about dropping 
spi-cpha.

> +	compatible = "crane,cr0014114";
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	led@0 {
> +		reg = <0>;
> +		label = "cr0:red:coin";
> +	};
> +	led@1 {
> +		reg = <1>;
> +		label = "cr0:green:coin";
> +	};
> +	led@2 {
> +		reg = <2>;
> +		label = "cr0:blue:coin";
> +	};
> +	led@3 {
> +		reg = <3>;
> +		label = "cr1:red:bill";
> +	};
> +	led@4 {
> +		reg = <4>;
> +		label = "cr1:green:bill";
> +	};
> +	led@5 {
> +		reg = <5>;
> +		label = "cr1:blue:bill";
> +	};
> +	...
> +};
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index ae850d6c0ad3..f17949c365f5 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>  compulab	CompuLab Ltd.
>  cortina	Cortina Systems, Inc.
>  cosmic	Cosmic Circuits
> +crane	Crane Connectivity Solutions
>  creative	Creative Technology Ltd
>  crystalfontz	Crystalfontz America, Inc.
>  cubietech	Cubietech, Ltd.
> -- 
> 2.16.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" 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] 46+ messages in thread

* [PATCH 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-26 12:15             ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  2018-03-26 12:15               ` [PATCH v4 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
  2018-03-27 16:14               ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Rob Herring
@ 2018-03-27 16:49               ` Oleh Kravchenko
  2018-03-27 16:49                 ` [PATCH 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
  2018-03-27 20:58                 ` [PATCH " Jacek Anaszewski
  2 siblings, 2 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-27 16:49 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

- add vendor prefix for Crane;
- add documentation and example for dt-bindings CR0014114.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 .../devicetree/bindings/leds/leds-cr0014114.txt    | 51 ++++++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 2 files changed, 52 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
new file mode 100644
index 000000000000..5f38f16aa08a
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
@@ -0,0 +1,51 @@
+Crane Merchandising System - cr0014114 LED driver
+-------------------------------------------------
+
+This LED Board is widely used in vending machines produced
+by Crane Merchandising Systems.
+
+Required properties:
+- compatible: "crane,cr0014114"
+
+LED sub-node properties:
+- label :
+	see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+
+Example
+-------
+
+led-controller@0 {
+	compatible = "crane,cr0014114";
+	reg = <0>;
+	spi-max-frequency = <50000>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	led@0 {
+		reg = <0>;
+		label = "cr0:red:coin";
+	};
+	led@1 {
+		reg = <1>;
+		label = "cr0:green:coin";
+	};
+	led@2 {
+		reg = <2>;
+		label = "cr0:blue:coin";
+	};
+	led@3 {
+		reg = <3>;
+		label = "cr1:red:bill";
+	};
+	led@4 {
+		reg = <4>;
+		label = "cr1:green:bill";
+	};
+	led@5 {
+		reg = <5>;
+		label = "cr1:blue:bill";
+	};
+	...
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ae850d6c0ad3..f17949c365f5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
 compulab	CompuLab Ltd.
 cortina	Cortina Systems, Inc.
 cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
 creative	Creative Technology Ltd
 crystalfontz	Crystalfontz America, Inc.
 cubietech	Cubietech, Ltd.
-- 
2.16.1


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

* [PATCH 2/2] leds: add LED driver for CR0014114 board
  2018-03-27 16:49               ` [PATCH " Oleh Kravchenko
@ 2018-03-27 16:49                 ` Oleh Kravchenko
  2018-03-27 20:58                   ` Jacek Anaszewski
  2018-03-28  6:53                   ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  2018-03-27 20:58                 ` [PATCH " Jacek Anaszewski
  1 sibling, 2 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-27 16:49 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

This patch adds a LED class driver for the RGB LEDs found on
the Crane Merchandising System CR0014114 LEDs board.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 drivers/leds/Kconfig          |  13 ++
 drivers/leds/Makefile         |   1 +
 drivers/leds/leds-cr0014114.c | 304 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 318 insertions(+)
 create mode 100644 drivers/leds/leds-cr0014114.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..5831814d01d0 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -104,6 +104,19 @@ config LEDS_CPCAP
 	  This option enables support for LEDs offered by Motorola's
 	  CPCAP PMIC.
 
+config LEDS_CR0014114
+	tristate "LED Support for Crane CR0014114"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for CR0014114 LED Board which
+	  is widely used in vending machines produced by
+	  Crane Merchandising Systems.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-cr0014114.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..0176e7335994 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 
 # LED SPI Drivers
+obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Userspace Drivers
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
new file mode 100644
index 000000000000..6e35acae6cc9
--- /dev/null
+++ b/drivers/leds/leds-cr0014114.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * LEDs driver for Crane CR0014114
+ *
+ * Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * CR0014114 SPI protocol descrtiption:
+ * +----+-----------------------------------+----+
+ * | CMD|             BRIGHTNESS            |CRC |
+ * +----+-----------------------------------+----+
+ * |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
+ * |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ * |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
+ * | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
+ * |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
+ * |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ * |    |               18                  |    |
+ * +----+-----------------------------------+----+
+ * |                    20                       |
+ * +---------------------------------------------+
+ *
+ * PS: Boards can be connected to the chain:
+ *     SPI -> board0 -> board1 -> board2 ..
+ */
+
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+
+/* CR0014114 SPI commands */
+#define CR_SET_BRIGHTNESS	0x80
+#define CR_INIT_REENUMERATE	0x81
+#define CR_NEXT_REENUMERATE	0x82
+
+/* CR0014114 default settings */
+#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
+#define CR_FW_DELAY_MSEC	10
+#define CR_RECOUNT_DELAY	(HZ * 3600)
+
+struct cr0014114_led {
+	const char		*name;
+	struct cr0014114	*priv;
+	struct led_classdev	ldev;
+	u8			brightness;
+};
+
+struct cr0014114 {
+	bool			do_recount;
+	size_t			count;
+	struct delayed_work	work;
+	struct device		*dev;
+	struct mutex		lock;
+	struct spi_device	*spi;
+	u8			*buf;
+	unsigned long		delay;
+	struct cr0014114_led	leds[];
+};
+
+static void cr0014114_calc_crc(u8 *buf, const size_t len)
+{
+	size_t	i;
+	u8	crc;
+
+	for (i = 1, crc = 1; i < len - 1; i++)
+		crc += buf[i];
+	crc |= BIT(7);
+
+	/* special case when CRC matches the SPI commands */
+	if (crc == CR_SET_BRIGHTNESS ||
+	    crc == CR_INIT_REENUMERATE ||
+	    crc == CR_NEXT_REENUMERATE)
+		crc = 0xfe;
+
+	buf[len - 1] = crc;
+}
+
+static int cr0014114_recount(struct cr0014114 *priv)
+{
+	int	ret;
+	size_t	i;
+	u8	cmd;
+
+	cmd = CR_INIT_REENUMERATE;
+	ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+	if (ret)
+		goto err;
+
+	cmd = CR_NEXT_REENUMERATE;
+	for (i = 0; i < priv->count; i++) {
+		msleep(CR_FW_DELAY_MSEC);
+
+		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+		if (ret)
+			goto err;
+	}
+
+err:
+	if (ret)
+		dev_err(priv->dev, "recount is failed %d", ret);
+
+	return ret;
+}
+
+static int cr0014114_sync(struct cr0014114 *priv)
+{
+	int		ret;
+	size_t		i;
+	unsigned long	udelay, now = jiffies;
+
+	/* to avoid SPI mistiming with firmware we should wait some time */
+	if (time_after(priv->delay, now)) {
+		udelay = jiffies_to_usecs(priv->delay - now);
+		usleep_range(udelay, udelay + 1);
+	}
+
+	if (unlikely(priv->do_recount)) {
+		ret = cr0014114_recount(priv);
+		if (ret)
+			goto err;
+
+		priv->do_recount = false;
+		msleep(CR_FW_DELAY_MSEC);
+	}
+
+	priv->buf[0] = CR_SET_BRIGHTNESS;
+	for (i = 0; i < priv->count; i++)
+		priv->buf[i + 1] = priv->leds[i].brightness;
+	cr0014114_calc_crc(priv->buf, priv->count + 2);
+	ret = spi_write(priv->spi, priv->buf, priv->count + 2);
+
+err:
+	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	return ret;
+}
+
+static void cr0014114_recount_work(struct work_struct *work)
+{
+	int			ret;
+	struct cr0014114	*priv = container_of(work,
+						     struct cr0014114,
+						     work.work);
+
+	mutex_lock(&priv->lock);
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
+
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+}
+
+static int cr0014114_set_sync(struct led_classdev *ldev,
+			      enum led_brightness brightness)
+{
+	int			ret;
+	struct cr0014114_led    *led = container_of(ldev,
+						    struct cr0014114_led,
+						    ldev);
+
+	mutex_lock(&led->priv->lock);
+	led->brightness = (u8)brightness;
+	ret = cr0014114_sync(led->priv);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int cr0014114_probe_dt(struct cr0014114 *priv)
+{
+	size_t			i = 0;
+	struct cr0014114_led	*led;
+	struct fwnode_handle	*child;
+	struct device_node	*np;
+	int			ret;
+
+	device_for_each_child_node(priv->dev, child) {
+		np = to_of_node(child);
+		led = &priv->leds[i];
+
+		ret = fwnode_property_read_string(child, "label",
+						  &led->name);
+		if (ret) {
+			dev_err(priv->dev, "LED label is not defined!");
+			fwnode_handle_put(child);
+			return -EINVAL;
+		}
+
+		fwnode_property_read_string(child, "linux,default-trigger",
+					    &led->ldev.default_trigger);
+
+		led->priv			  = priv;
+		led->ldev.name			  = led->name;
+		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
+		led->ldev.brightness_set_blocking = cr0014114_set_sync;
+
+		ret = devm_of_led_classdev_register(priv->dev, np,
+						    &led->ldev);
+		if (ret) {
+			dev_err(priv->dev,
+				"failed to register LED device %s, err %d",
+				led->name, ret);
+			fwnode_handle_put(child);
+			return ret;
+		}
+
+		led->ldev.dev->of_node = np;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int cr0014114_probe(struct spi_device *spi)
+{
+	struct cr0014114	*priv;
+	size_t			count;
+	int			ret;
+
+	count = device_get_child_node_count(&spi->dev);
+	if (!count) {
+		dev_err(&spi->dev, "LEDs are not defined in device tree!");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&spi->dev,
+			    sizeof(*priv) + sizeof(*priv->leds) * count,
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
+	if (!priv->buf)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
+	priv->count		= count;
+	priv->dev		= &spi->dev;
+	priv->do_recount	= true;
+	priv->spi		= spi;
+	priv->delay		= jiffies -
+				  msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	ret = cr0014114_probe_dt(priv);
+	if (ret)
+		return ret;
+
+	ret = cr0014114_sync(priv);
+	if (ret) {
+		dev_err(priv->dev, "first sync of LEDs failed %d\n", ret);
+		return ret;
+	}
+
+	/* setup recount work to workaround buggy firmware */
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+
+	spi_set_drvdata(spi, priv);
+
+	return 0;
+}
+
+static int cr0014114_remove(struct spi_device *spi)
+{
+	struct cr0014114 *priv = spi_get_drvdata(spi);
+
+	cancel_delayed_work_sync(&priv->work);
+
+	return 0;
+}
+
+static const struct of_device_id cr0014114_dt_ids[] = {
+	{ .compatible = "crane,cr0014114", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
+
+static struct spi_driver cr0014114_driver = {
+	.probe		= cr0014114_probe,
+	.remove		= cr0014114_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= cr0014114_dt_ids,
+	},
+};
+
+module_spi_driver(cr0014114_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("cr0014114 LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:cr0014114");
-- 
2.16.1


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

* Re: [PATCH 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-27 16:49               ` [PATCH " Oleh Kravchenko
  2018-03-27 16:49                 ` [PATCH 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-03-27 20:58                 ` Jacek Anaszewski
  2018-03-28  6:36                   ` Oleh Kravchenko
  1 sibling, 1 reply; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-27 20:58 UTC (permalink / raw)
  To: Oleh Kravchenko, devicetree, linux-leds

Hi Oleh,

Thanks for the update.

Patch version is missing in the subject e.g. [PATCH v5 1/2].

On 03/27/2018 06:49 PM, Oleh Kravchenko wrote:
> - add vendor prefix for Crane;
> - add documentation and example for dt-bindings CR0014114.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  .../devicetree/bindings/leds/leds-cr0014114.txt    | 51 ++++++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.txt        |  1 +
>  2 files changed, 52 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> 
> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> new file mode 100644
> index 000000000000..5f38f16aa08a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> @@ -0,0 +1,51 @@
> +Crane Merchandising System - cr0014114 LED driver
> +-------------------------------------------------
> +
> +This LED Board is widely used in vending machines produced
> +by Crane Merchandising Systems.
> +
> +Required properties:
> +- compatible: "crane,cr0014114"
> +
> +LED sub-node properties:
> +- label :
> +	see Documentation/devicetree/bindings/leds/common.txt
> +- linux,default-trigger : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example
> +-------
> +
> +led-controller@0 {
> +	compatible = "crane,cr0014114";
> +	reg = <0>;
> +	spi-max-frequency = <50000>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	led@0 {
> +		reg = <0>;
> +		label = "cr0:red:coin";
> +	};
> +	led@1 {
> +		reg = <1>;
> +		label = "cr0:green:coin";
> +	};
> +	led@2 {
> +		reg = <2>;
> +		label = "cr0:blue:coin";
> +	};
> +	led@3 {
> +		reg = <3>;
> +		label = "cr1:red:bill";
> +	};
> +	led@4 {
> +		reg = <4>;
> +		label = "cr1:green:bill";
> +	};
> +	led@5 {
> +		reg = <5>;
> +		label = "cr1:blue:bill";
> +	};

Why cr0 and cr1? It should be cr0014114 to stick to the
current LED naming pattern <devicename:colour:function>.

Nonetheless, we lately came to the conclusion that devicename
segment is redundant in LED class device name, so until we change
LED naming convention officially, let's remove devicename segment
at least from DT and prepend the label with "cr0014114" in the driver.

Please compare how it is approached in [0] (not merged yet).

> +};
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index ae850d6c0ad3..f17949c365f5 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>  compulab	CompuLab Ltd.
>  cortina	Cortina Systems, Inc.
>  cosmic	Cosmic Circuits
> +crane	Crane Connectivity Solutions
>  creative	Creative Technology Ltd
>  crystalfontz	Crystalfontz America, Inc.
>  cubietech	Cubietech, Ltd.
> 

[0] https://www.spinics.net/lists/devicetree/msg220561.html

-- 
Best regards,
Jacek Anaszewski



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

* Re: [PATCH 2/2] leds: add LED driver for CR0014114 board
  2018-03-27 16:49                 ` [PATCH 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-03-27 20:58                   ` Jacek Anaszewski
  2018-03-28  6:53                   ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  1 sibling, 0 replies; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-27 20:58 UTC (permalink / raw)
  To: Oleh Kravchenko, devicetree, linux-leds

Hi Oleh,

On 03/27/2018 06:49 PM, Oleh Kravchenko wrote:
> This patch adds a LED class driver for the RGB LEDs found on
> the Crane Merchandising System CR0014114 LEDs board.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  drivers/leds/Kconfig          |  13 ++
>  drivers/leds/Makefile         |   1 +
>  drivers/leds/leds-cr0014114.c | 304 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 318 insertions(+)
>  create mode 100644 drivers/leds/leds-cr0014114.c
> 
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 2c896c0e69e1..5831814d01d0 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -104,6 +104,19 @@ config LEDS_CPCAP
>  	  This option enables support for LEDs offered by Motorola's
>  	  CPCAP PMIC.
>  
> +config LEDS_CR0014114
> +	tristate "LED Support for Crane CR0014114"
> +	depends on LEDS_CLASS
> +	depends on SPI
> +	depends on OF
> +	help
> +	  This option enables support for CR0014114 LED Board which
> +	  is widely used in vending machines produced by
> +	  Crane Merchandising Systems.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called leds-cr0014114.
> +
>  config LEDS_LM3530
>  	tristate "LCD Backlight driver for LM3530"
>  	depends on LEDS_CLASS
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 91eca81cae82..0176e7335994 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
>  obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
>  
>  # LED SPI Drivers
> +obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
>  obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
>  
>  # LED Userspace Drivers
> diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
> new file mode 100644
> index 000000000000..6e35acae6cc9
> --- /dev/null
> +++ b/drivers/leds/leds-cr0014114.c
> @@ -0,0 +1,304 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * LEDs driver for Crane CR0014114
> + *
> + * Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.

SPDX is to avoid the need for this boilerplate, so please remove it.

Also, let's use uniform '//' style comment for the whole section.
Please compare e.g. drivers/leds/leds-mlxreg.c.

> + *
> + * CR0014114 SPI protocol descrtiption:
> + * +----+-----------------------------------+----+
> + * | CMD|             BRIGHTNESS            |CRC |
> + * +----+-----------------------------------+----+
> + * |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
> + * |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
> + * |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
> + * | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
> + * |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
> + * |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
> + * |    |               18                  |    |
> + * +----+-----------------------------------+----+
> + * |                    20                       |
> + * +---------------------------------------------+
> + *
> + * PS: Boards can be connected to the chain:
> + *     SPI -> board0 -> board1 -> board2 ..
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/leds.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/spi/spi.h>
> +#include <linux/workqueue.h>
> +
> +/* CR0014114 SPI commands */
> +#define CR_SET_BRIGHTNESS	0x80
> +#define CR_INIT_REENUMERATE	0x81
> +#define CR_NEXT_REENUMERATE	0x82
> +
> +/* CR0014114 default settings */
> +#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
> +#define CR_FW_DELAY_MSEC	10
> +#define CR_RECOUNT_DELAY	(HZ * 3600)
> +
> +struct cr0014114_led {
> +	const char		*name;
> +	struct cr0014114	*priv;
> +	struct led_classdev	ldev;
> +	u8			brightness;
> +};
> +
> +struct cr0014114 {
> +	bool			do_recount;
> +	size_t			count;
> +	struct delayed_work	work;
> +	struct device		*dev;
> +	struct mutex		lock;
> +	struct spi_device	*spi;
> +	u8			*buf;
> +	unsigned long		delay;
> +	struct cr0014114_led	leds[];
> +};
> +
> +static void cr0014114_calc_crc(u8 *buf, const size_t len)
> +{
> +	size_t	i;
> +	u8	crc;
> +
> +	for (i = 1, crc = 1; i < len - 1; i++)
> +		crc += buf[i];
> +	crc |= BIT(7);
> +
> +	/* special case when CRC matches the SPI commands */
> +	if (crc == CR_SET_BRIGHTNESS ||
> +	    crc == CR_INIT_REENUMERATE ||
> +	    crc == CR_NEXT_REENUMERATE)
> +		crc = 0xfe;
> +
> +	buf[len - 1] = crc;
> +}
> +
> +static int cr0014114_recount(struct cr0014114 *priv)
> +{
> +	int	ret;
> +	size_t	i;
> +	u8	cmd;
> +
> +	cmd = CR_INIT_REENUMERATE;
> +	ret = spi_write(priv->spi, &cmd, sizeof(cmd));
> +	if (ret)
> +		goto err;
> +
> +	cmd = CR_NEXT_REENUMERATE;
> +	for (i = 0; i < priv->count; i++) {
> +		msleep(CR_FW_DELAY_MSEC);
> +
> +		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
> +		if (ret)
> +			goto err;
> +	}
> +
> +err:
> +	if (ret)
> +		dev_err(priv->dev, "recount is failed %d", ret);
> +
> +	return ret;
> +}
> +
> +static int cr0014114_sync(struct cr0014114 *priv)
> +{
> +	int		ret;
> +	size_t		i;
> +	unsigned long	udelay, now = jiffies;
> +
> +	/* to avoid SPI mistiming with firmware we should wait some time */
> +	if (time_after(priv->delay, now)) {
> +		udelay = jiffies_to_usecs(priv->delay - now);
> +		usleep_range(udelay, udelay + 1);
> +	}
> +
> +	if (unlikely(priv->do_recount)) {
> +		ret = cr0014114_recount(priv);
> +		if (ret)
> +			goto err;
> +
> +		priv->do_recount = false;
> +		msleep(CR_FW_DELAY_MSEC);
> +	}
> +
> +	priv->buf[0] = CR_SET_BRIGHTNESS;
> +	for (i = 0; i < priv->count; i++)
> +		priv->buf[i + 1] = priv->leds[i].brightness;
> +	cr0014114_calc_crc(priv->buf, priv->count + 2);
> +	ret = spi_write(priv->spi, priv->buf, priv->count + 2);
> +
> +err:
> +	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
> +
> +	return ret;
> +}
> +
> +static void cr0014114_recount_work(struct work_struct *work)
> +{
> +	int			ret;
> +	struct cr0014114	*priv = container_of(work,
> +						     struct cr0014114,
> +						     work.work);
> +
> +	mutex_lock(&priv->lock);
> +	priv->do_recount = true;
> +	ret = cr0014114_sync(priv);
> +	mutex_unlock(&priv->lock);
> +
> +	if (ret)
> +		dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
> +
> +	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
> +}
> +
> +static int cr0014114_set_sync(struct led_classdev *ldev,
> +			      enum led_brightness brightness)
> +{
> +	int			ret;
> +	struct cr0014114_led    *led = container_of(ldev,
> +						    struct cr0014114_led,
> +						    ldev);
> +
> +	mutex_lock(&led->priv->lock);
> +	led->brightness = (u8)brightness;
> +	ret = cr0014114_sync(led->priv);
> +	mutex_unlock(&led->priv->lock);
> +
> +	return ret;
> +}
> +
> +static int cr0014114_probe_dt(struct cr0014114 *priv)
> +{
> +	size_t			i = 0;
> +	struct cr0014114_led	*led;
> +	struct fwnode_handle	*child;
> +	struct device_node	*np;
> +	int			ret;
> +
> +	device_for_each_child_node(priv->dev, child) {
> +		np = to_of_node(child);
> +		led = &priv->leds[i];
> +
> +		ret = fwnode_property_read_string(child, "label",
> +						  &led->name);
> +		if (ret) {
> +			dev_err(priv->dev, "LED label is not defined!");
> +			fwnode_handle_put(child);
> +			return -EINVAL;
> +		}
> +
> +		fwnode_property_read_string(child, "linux,default-trigger",
> +					    &led->ldev.default_trigger);
> +
> +		led->priv			  = priv;
> +		led->ldev.name			  = led->name;
> +		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
> +		led->ldev.brightness_set_blocking = cr0014114_set_sync;
> +
> +		ret = devm_of_led_classdev_register(priv->dev, np,
> +						    &led->ldev);
> +		if (ret) {
> +			dev_err(priv->dev,
> +				"failed to register LED device %s, err %d",
> +				led->name, ret);
> +			fwnode_handle_put(child);
> +			return ret;
> +		}
> +
> +		led->ldev.dev->of_node = np;
> +
> +		i++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cr0014114_probe(struct spi_device *spi)
> +{
> +	struct cr0014114	*priv;
> +	size_t			count;
> +	int			ret;
> +
> +	count = device_get_child_node_count(&spi->dev);
> +	if (!count) {
> +		dev_err(&spi->dev, "LEDs are not defined in device tree!");
> +		return -ENODEV;
> +	}
> +
> +	priv = devm_kzalloc(&spi->dev,
> +			    sizeof(*priv) + sizeof(*priv->leds) * count,
> +			    GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
> +	if (!priv->buf)
> +		return -ENOMEM;
> +
> +	mutex_init(&priv->lock);
> +	INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
> +	priv->count		= count;
> +	priv->dev		= &spi->dev;
> +	priv->do_recount	= true;
> +	priv->spi		= spi;
> +	priv->delay		= jiffies -
> +				  msecs_to_jiffies(CR_FW_DELAY_MSEC);
> +
> +	ret = cr0014114_probe_dt(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = cr0014114_sync(priv);
> +	if (ret) {
> +		dev_err(priv->dev, "first sync of LEDs failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* setup recount work to workaround buggy firmware */
> +	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
> +
> +	spi_set_drvdata(spi, priv);
> +
> +	return 0;
> +}
> +
> +static int cr0014114_remove(struct spi_device *spi)
> +{
> +	struct cr0014114 *priv = spi_get_drvdata(spi);
> +
> +	cancel_delayed_work_sync(&priv->work);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id cr0014114_dt_ids[] = {
> +	{ .compatible = "crane,cr0014114", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
> +
> +static struct spi_driver cr0014114_driver = {
> +	.probe		= cr0014114_probe,
> +	.remove		= cr0014114_remove,
> +	.driver = {
> +		.name		= KBUILD_MODNAME,
> +		.of_match_table	= cr0014114_dt_ids,
> +	},
> +};
> +
> +module_spi_driver(cr0014114_driver);
> +
> +MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
> +MODULE_DESCRIPTION("cr0014114 LED driver");
> +MODULE_LICENSE("GPL");

To match the SPDX license identifier it would have to be "GPL v2".

> +MODULE_ALIAS("spi:cr0014114");
> 

-- 
Best regards,
Jacek Anaszewski

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

* Re: [PATCH 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-27 20:58                 ` [PATCH " Jacek Anaszewski
@ 2018-03-28  6:36                   ` Oleh Kravchenko
  2018-03-28 19:21                     ` Jacek Anaszewski
  0 siblings, 1 reply; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-28  6:36 UTC (permalink / raw)
  To: Jacek Anaszewski, devicetree, linux-leds

Hello Jacek,

On 27.03.18 23:58, Jacek Anaszewski wrote:
>> +Example
>> +-------
>> +
>> +led-controller@0 {
>> +	compatible = "crane,cr0014114";
>> +	reg = <0>;
>> +	spi-max-frequency = <50000>;
>> +	#address-cells = <1>;
>> +	#size-cells = <0>;
>> +
>> +	led@0 {
>> +		reg = <0>;
>> +		label = "cr0:red:coin";
>> +	};
>> +	led@1 {
>> +		reg = <1>;
>> +		label = "cr0:green:coin";
>> +	};
>> +	led@2 {
>> +		reg = <2>;
>> +		label = "cr0:blue:coin";
>> +	};
>> +	led@3 {
>> +		reg = <3>;
>> +		label = "cr1:red:bill";
>> +	};
>> +	led@4 {
>> +		reg = <4>;
>> +		label = "cr1:green:bill";
>> +	};
>> +	led@5 {
>> +		reg = <5>;
>> +		label = "cr1:blue:bill";
>> +	};
> 
> Why cr0 and cr1? It should be cr0014114 to stick to the
> current LED naming pattern <devicename:colour:function>.
> 
> Nonetheless, we lately came to the conclusion that devicename
> segment is redundant in LED class device name, so until we change
> LED naming convention officially, let's remove devicename segment
> at least from DT and prepend the label with "cr0014114" in the driver.
> 
> Please compare how it is approached in [0] (not merged yet).
> 

It's just example.
But anyway our applications works with LEDs by numbers.

Using function names instead numbers will increase code complexity,
so we use numbers :)

>> +};
>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> index ae850d6c0ad3..f17949c365f5 100644
>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>>  compulab	CompuLab Ltd.
>>  cortina	Cortina Systems, Inc.
>>  cosmic	Cosmic Circuits
>> +crane	Crane Connectivity Solutions
>>  creative	Creative Technology Ltd
>>  crystalfontz	Crystalfontz America, Inc.
>>  cubietech	Cubietech, Ltd.
>>
> 
> [0] https://www.spinics.net/lists/devicetree/msg220561.html
> 

-- 
Best regards,
Oleh Kravchenko


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

* [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-27 16:49                 ` [PATCH 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
  2018-03-27 20:58                   ` Jacek Anaszewski
@ 2018-03-28  6:53                   ` Oleh Kravchenko
  2018-03-28  6:53                     ` [PATCH v6 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
                                       ` (2 more replies)
  1 sibling, 3 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-28  6:53 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

add vendor prefix for Crane;
add documentation and example for dt-bindings CR0014114.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 .../devicetree/bindings/leds/leds-cr0014114.txt    | 51 ++++++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 2 files changed, 52 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
new file mode 100644
index 000000000000..6e8b135bb59f
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
@@ -0,0 +1,51 @@
+Crane Merchandising System - cr0014114 LED driver
+-------------------------------------------------
+
+This LED Board is widely used in vending machines produced
+by Crane Merchandising Systems.
+
+Required properties:
+- compatible: "crane,cr0014114"
+
+LED sub-node properties:
+- label :
+	see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+
+Example
+-------
+
+led-controller@0 {
+	compatible = "crane,cr0014114";
+	reg = <0>;
+	spi-max-frequency = <50000>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	led@0 {
+		reg = <0>;
+		label = "cr0014114:red:coin";
+	};
+	led@1 {
+		reg = <1>;
+		label = "cr0014114:green:coin";
+	};
+	led@2 {
+		reg = <2>;
+		label = "cr0014114:blue:coin";
+	};
+	led@3 {
+		reg = <3>;
+		label = "cr0014114:red:bill";
+	};
+	led@4 {
+		reg = <4>;
+		label = "cr0014114:green:bill";
+	};
+	led@5 {
+		reg = <5>;
+		label = "cr0014114:blue:bill";
+	};
+	...
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ae850d6c0ad3..f17949c365f5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
 compulab	CompuLab Ltd.
 cortina	Cortina Systems, Inc.
 cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
 creative	Creative Technology Ltd
 crystalfontz	Crystalfontz America, Inc.
 cubietech	Cubietech, Ltd.
-- 
2.16.1


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

* [PATCH v6 2/2] leds: add LED driver for CR0014114 board
  2018-03-28  6:53                   ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
@ 2018-03-28  6:53                     ` Oleh Kravchenko
  2018-03-28 15:43                     ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Rob Herring
  2018-03-28 18:56                     ` [PATCH v7 " Oleh Kravchenko
  2 siblings, 0 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-28  6:53 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

This patch adds a LED class driver for the RGB LEDs found on
the Crane Merchandising System CR0014114 LEDs board.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 drivers/leds/Kconfig          |  13 ++
 drivers/leds/Makefile         |   1 +
 drivers/leds/leds-cr0014114.c | 298 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 312 insertions(+)
 create mode 100644 drivers/leds/leds-cr0014114.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..5831814d01d0 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -104,6 +104,19 @@ config LEDS_CPCAP
 	  This option enables support for LEDs offered by Motorola's
 	  CPCAP PMIC.
 
+config LEDS_CR0014114
+	tristate "LED Support for Crane CR0014114"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for CR0014114 LED Board which
+	  is widely used in vending machines produced by
+	  Crane Merchandising Systems.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-cr0014114.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..0176e7335994 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 
 # LED SPI Drivers
+obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Userspace Drivers
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
new file mode 100644
index 000000000000..701ab30e260c
--- /dev/null
+++ b/drivers/leds/leds-cr0014114.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Crane Merchandising Systems. All rights reserved.
+// Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
+
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+
+/*
+ *  CR0014114 SPI protocol descrtiption:
+ *  +----+-----------------------------------+----+
+ *  | CMD|             BRIGHTNESS            |CRC |
+ *  +----+-----------------------------------+----+
+ *  |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
+ *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ *  |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
+ *  | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
+ *  |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
+ *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ *  |    |               18                  |    |
+ *  +----+-----------------------------------+----+
+ *  |                    20                       |
+ *  +---------------------------------------------+
+ *
+ *  PS: Boards can be connected to the chain:
+ *      SPI -> board0 -> board1 -> board2 ..
+ */
+
+/* CR0014114 SPI commands */
+#define CR_SET_BRIGHTNESS	0x80
+#define CR_INIT_REENUMERATE	0x81
+#define CR_NEXT_REENUMERATE	0x82
+
+/* CR0014114 default settings */
+#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
+#define CR_FW_DELAY_MSEC	10
+#define CR_RECOUNT_DELAY	(HZ * 3600)
+
+struct cr0014114_led {
+	const char		*name;
+	struct cr0014114	*priv;
+	struct led_classdev	ldev;
+	u8			brightness;
+};
+
+struct cr0014114 {
+	bool			do_recount;
+	size_t			count;
+	struct delayed_work	work;
+	struct device		*dev;
+	struct mutex		lock;
+	struct spi_device	*spi;
+	u8			*buf;
+	unsigned long		delay;
+	struct cr0014114_led	leds[];
+};
+
+static void cr0014114_calc_crc(u8 *buf, const size_t len)
+{
+	size_t	i;
+	u8	crc;
+
+	for (i = 1, crc = 1; i < len - 1; i++)
+		crc += buf[i];
+	crc |= BIT(7);
+
+	/* special case when CRC matches the SPI commands */
+	if (crc == CR_SET_BRIGHTNESS ||
+	    crc == CR_INIT_REENUMERATE ||
+	    crc == CR_NEXT_REENUMERATE)
+		crc = 0xfe;
+
+	buf[len - 1] = crc;
+}
+
+static int cr0014114_recount(struct cr0014114 *priv)
+{
+	int	ret;
+	size_t	i;
+	u8	cmd;
+
+	cmd = CR_INIT_REENUMERATE;
+	ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+	if (ret)
+		goto err;
+
+	cmd = CR_NEXT_REENUMERATE;
+	for (i = 0; i < priv->count; i++) {
+		msleep(CR_FW_DELAY_MSEC);
+
+		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+		if (ret)
+			goto err;
+	}
+
+err:
+	if (ret)
+		dev_err(priv->dev, "recount is failed %d", ret);
+
+	return ret;
+}
+
+static int cr0014114_sync(struct cr0014114 *priv)
+{
+	int		ret;
+	size_t		i;
+	unsigned long	udelay, now = jiffies;
+
+	/* to avoid SPI mistiming with firmware we should wait some time */
+	if (time_after(priv->delay, now)) {
+		udelay = jiffies_to_usecs(priv->delay - now);
+		usleep_range(udelay, udelay + 1);
+	}
+
+	if (unlikely(priv->do_recount)) {
+		ret = cr0014114_recount(priv);
+		if (ret)
+			goto err;
+
+		priv->do_recount = false;
+		msleep(CR_FW_DELAY_MSEC);
+	}
+
+	priv->buf[0] = CR_SET_BRIGHTNESS;
+	for (i = 0; i < priv->count; i++)
+		priv->buf[i + 1] = priv->leds[i].brightness;
+	cr0014114_calc_crc(priv->buf, priv->count + 2);
+	ret = spi_write(priv->spi, priv->buf, priv->count + 2);
+
+err:
+	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	return ret;
+}
+
+static void cr0014114_recount_work(struct work_struct *work)
+{
+	int			ret;
+	struct cr0014114	*priv = container_of(work,
+						     struct cr0014114,
+						     work.work);
+
+	mutex_lock(&priv->lock);
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
+
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+}
+
+static int cr0014114_set_sync(struct led_classdev *ldev,
+			      enum led_brightness brightness)
+{
+	int			ret;
+	struct cr0014114_led    *led = container_of(ldev,
+						    struct cr0014114_led,
+						    ldev);
+
+	mutex_lock(&led->priv->lock);
+	led->brightness = (u8)brightness;
+	ret = cr0014114_sync(led->priv);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int cr0014114_probe_dt(struct cr0014114 *priv)
+{
+	size_t			i = 0;
+	struct cr0014114_led	*led;
+	struct fwnode_handle	*child;
+	struct device_node	*np;
+	int			ret;
+
+	device_for_each_child_node(priv->dev, child) {
+		np = to_of_node(child);
+		led = &priv->leds[i];
+
+		ret = fwnode_property_read_string(child, "label",
+						  &led->name);
+		if (ret) {
+			dev_err(priv->dev, "LED label is not defined!");
+			fwnode_handle_put(child);
+			return -EINVAL;
+		}
+
+		fwnode_property_read_string(child, "linux,default-trigger",
+					    &led->ldev.default_trigger);
+
+		led->priv			  = priv;
+		led->ldev.name			  = led->name;
+		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
+		led->ldev.brightness_set_blocking = cr0014114_set_sync;
+
+		ret = devm_of_led_classdev_register(priv->dev, np,
+						    &led->ldev);
+		if (ret) {
+			dev_err(priv->dev,
+				"failed to register LED device %s, err %d",
+				led->name, ret);
+			fwnode_handle_put(child);
+			return ret;
+		}
+
+		led->ldev.dev->of_node = np;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int cr0014114_probe(struct spi_device *spi)
+{
+	struct cr0014114	*priv;
+	size_t			count;
+	int			ret;
+
+	count = device_get_child_node_count(&spi->dev);
+	if (!count) {
+		dev_err(&spi->dev, "LEDs are not defined in device tree!");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&spi->dev,
+			    sizeof(*priv) + sizeof(*priv->leds) * count,
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
+	if (!priv->buf)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
+	priv->count		= count;
+	priv->dev		= &spi->dev;
+	priv->do_recount	= true;
+	priv->spi		= spi;
+	priv->delay		= jiffies -
+				  msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	ret = cr0014114_probe_dt(priv);
+	if (ret)
+		return ret;
+
+	ret = cr0014114_sync(priv);
+	if (ret) {
+		dev_err(priv->dev, "first sync of LEDs failed %d\n", ret);
+		return ret;
+	}
+
+	/* setup recount work to workaround buggy firmware */
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+
+	spi_set_drvdata(spi, priv);
+
+	return 0;
+}
+
+static int cr0014114_remove(struct spi_device *spi)
+{
+	struct cr0014114 *priv = spi_get_drvdata(spi);
+
+	cancel_delayed_work_sync(&priv->work);
+
+	return 0;
+}
+
+static const struct of_device_id cr0014114_dt_ids[] = {
+	{ .compatible = "crane,cr0014114", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
+
+static struct spi_driver cr0014114_driver = {
+	.probe		= cr0014114_probe,
+	.remove		= cr0014114_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= cr0014114_dt_ids,
+	},
+};
+
+module_spi_driver(cr0014114_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("cr0014114 LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:cr0014114");
-- 
2.16.1


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

* Re: [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-28  6:53                   ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  2018-03-28  6:53                     ` [PATCH v6 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-03-28 15:43                     ` Rob Herring
  2018-03-28 18:56                     ` [PATCH v7 " Oleh Kravchenko
  2 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2018-03-28 15:43 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, Linux LED Subsystem

On Wed, Mar 28, 2018 at 1:53 AM, Oleh Kravchenko <oleg@kaa.org.ua> wrote:
> add vendor prefix for Crane;
> add documentation and example for dt-bindings CR0014114.
>
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  .../devicetree/bindings/leds/leds-cr0014114.txt    | 51 ++++++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.txt        |  1 +
>  2 files changed, 52 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>
> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> new file mode 100644
> index 000000000000..6e8b135bb59f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> @@ -0,0 +1,51 @@
> +Crane Merchandising System - cr0014114 LED driver
> +-------------------------------------------------
> +
> +This LED Board is widely used in vending machines produced
> +by Crane Merchandising Systems.
> +
> +Required properties:
> +- compatible: "crane,cr0014114"
> +
> +LED sub-node properties:
> +- label :
> +       see Documentation/devicetree/bindings/leds/common.txt
> +- linux,default-trigger : (optional)
> +       see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example
> +-------
> +
> +led-controller@0 {
> +       compatible = "crane,cr0014114";
> +       reg = <0>;
> +       spi-max-frequency = <50000>;

And they have to be documented above...

> +       #address-cells = <1>;
> +       #size-cells = <0>;
> +
> +       led@0 {
> +               reg = <0>;
> +               label = "cr0014114:red:coin";
> +       };
> +       led@1 {
> +               reg = <1>;
> +               label = "cr0014114:green:coin";
> +       };
> +       led@2 {
> +               reg = <2>;
> +               label = "cr0014114:blue:coin";
> +       };
> +       led@3 {
> +               reg = <3>;
> +               label = "cr0014114:red:bill";
> +       };
> +       led@4 {
> +               reg = <4>;
> +               label = "cr0014114:green:bill";
> +       };
> +       led@5 {
> +               reg = <5>;
> +               label = "cr0014114:blue:bill";
> +       };
> +       ...
> +};
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index ae850d6c0ad3..f17949c365f5 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -75,6 +75,7 @@ cnxt  Conexant Systems, Inc.
>  compulab       CompuLab Ltd.
>  cortina        Cortina Systems, Inc.
>  cosmic Cosmic Circuits
> +crane  Crane Connectivity Solutions
>  creative       Creative Technology Ltd
>  crystalfontz   Crystalfontz America, Inc.
>  cubietech      Cubietech, Ltd.
> --
> 2.16.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" 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] 46+ messages in thread

* [PATCH v7 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-28  6:53                   ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  2018-03-28  6:53                     ` [PATCH v6 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
  2018-03-28 15:43                     ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Rob Herring
@ 2018-03-28 18:56                     ` Oleh Kravchenko
  2018-03-28 18:56                       ` [PATCH v7 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
  2 siblings, 1 reply; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-28 18:56 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

add vendor prefix for Crane;
add documentation and example for dt-bindings CR0014114.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 .../devicetree/bindings/leds/leds-cr0014114.txt    | 54 ++++++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 2 files changed, 55 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
new file mode 100644
index 000000000000..3d03681bb2d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
@@ -0,0 +1,54 @@
+Crane Merchandising System - cr0014114 LED driver
+-------------------------------------------------
+
+This LED Board is widely used in vending machines produced
+by Crane Merchandising Systems.
+
+Required properties:
+- compatible: "crane,cr0014114"
+
+Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
+apply. In particular, "reg" and "spi-max-frequency" properties must be given.
+
+LED sub-node properties:
+- label :
+	see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+
+Example
+-------
+
+led-controller@0 {
+	compatible = "crane,cr0014114";
+	reg = <0>;
+	spi-max-frequency = <50000>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	led@0 {
+		reg = <0>;
+		label = "cr0014114:red:coin";
+	};
+	led@1 {
+		reg = <1>;
+		label = "cr0014114:green:coin";
+	};
+	led@2 {
+		reg = <2>;
+		label = "cr0014114:blue:coin";
+	};
+	led@3 {
+		reg = <3>;
+		label = "cr0014114:red:bill";
+	};
+	led@4 {
+		reg = <4>;
+		label = "cr0014114:green:bill";
+	};
+	led@5 {
+		reg = <5>;
+		label = "cr0014114:blue:bill";
+	};
+	...
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ae850d6c0ad3..f17949c365f5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
 compulab	CompuLab Ltd.
 cortina	Cortina Systems, Inc.
 cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
 creative	Creative Technology Ltd
 crystalfontz	Crystalfontz America, Inc.
 cubietech	Cubietech, Ltd.
-- 
2.16.1


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

* [PATCH v7 2/2] leds: add LED driver for CR0014114 board
  2018-03-28 18:56                     ` [PATCH v7 " Oleh Kravchenko
@ 2018-03-28 18:56                       ` Oleh Kravchenko
  2018-04-02 12:53                         ` [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  0 siblings, 1 reply; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-28 18:56 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

This patch adds a LED class driver for the RGB LEDs found on
the Crane Merchandising System CR0014114 LEDs board.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 drivers/leds/Kconfig          |  13 ++
 drivers/leds/Makefile         |   1 +
 drivers/leds/leds-cr0014114.c | 298 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 312 insertions(+)
 create mode 100644 drivers/leds/leds-cr0014114.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..5831814d01d0 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -104,6 +104,19 @@ config LEDS_CPCAP
 	  This option enables support for LEDs offered by Motorola's
 	  CPCAP PMIC.
 
+config LEDS_CR0014114
+	tristate "LED Support for Crane CR0014114"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for CR0014114 LED Board which
+	  is widely used in vending machines produced by
+	  Crane Merchandising Systems.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-cr0014114.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..0176e7335994 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 
 # LED SPI Drivers
+obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Userspace Drivers
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
new file mode 100644
index 000000000000..701ab30e260c
--- /dev/null
+++ b/drivers/leds/leds-cr0014114.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Crane Merchandising Systems. All rights reserved.
+// Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
+
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+
+/*
+ *  CR0014114 SPI protocol descrtiption:
+ *  +----+-----------------------------------+----+
+ *  | CMD|             BRIGHTNESS            |CRC |
+ *  +----+-----------------------------------+----+
+ *  |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
+ *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ *  |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
+ *  | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
+ *  |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
+ *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ *  |    |               18                  |    |
+ *  +----+-----------------------------------+----+
+ *  |                    20                       |
+ *  +---------------------------------------------+
+ *
+ *  PS: Boards can be connected to the chain:
+ *      SPI -> board0 -> board1 -> board2 ..
+ */
+
+/* CR0014114 SPI commands */
+#define CR_SET_BRIGHTNESS	0x80
+#define CR_INIT_REENUMERATE	0x81
+#define CR_NEXT_REENUMERATE	0x82
+
+/* CR0014114 default settings */
+#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
+#define CR_FW_DELAY_MSEC	10
+#define CR_RECOUNT_DELAY	(HZ * 3600)
+
+struct cr0014114_led {
+	const char		*name;
+	struct cr0014114	*priv;
+	struct led_classdev	ldev;
+	u8			brightness;
+};
+
+struct cr0014114 {
+	bool			do_recount;
+	size_t			count;
+	struct delayed_work	work;
+	struct device		*dev;
+	struct mutex		lock;
+	struct spi_device	*spi;
+	u8			*buf;
+	unsigned long		delay;
+	struct cr0014114_led	leds[];
+};
+
+static void cr0014114_calc_crc(u8 *buf, const size_t len)
+{
+	size_t	i;
+	u8	crc;
+
+	for (i = 1, crc = 1; i < len - 1; i++)
+		crc += buf[i];
+	crc |= BIT(7);
+
+	/* special case when CRC matches the SPI commands */
+	if (crc == CR_SET_BRIGHTNESS ||
+	    crc == CR_INIT_REENUMERATE ||
+	    crc == CR_NEXT_REENUMERATE)
+		crc = 0xfe;
+
+	buf[len - 1] = crc;
+}
+
+static int cr0014114_recount(struct cr0014114 *priv)
+{
+	int	ret;
+	size_t	i;
+	u8	cmd;
+
+	cmd = CR_INIT_REENUMERATE;
+	ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+	if (ret)
+		goto err;
+
+	cmd = CR_NEXT_REENUMERATE;
+	for (i = 0; i < priv->count; i++) {
+		msleep(CR_FW_DELAY_MSEC);
+
+		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+		if (ret)
+			goto err;
+	}
+
+err:
+	if (ret)
+		dev_err(priv->dev, "recount is failed %d", ret);
+
+	return ret;
+}
+
+static int cr0014114_sync(struct cr0014114 *priv)
+{
+	int		ret;
+	size_t		i;
+	unsigned long	udelay, now = jiffies;
+
+	/* to avoid SPI mistiming with firmware we should wait some time */
+	if (time_after(priv->delay, now)) {
+		udelay = jiffies_to_usecs(priv->delay - now);
+		usleep_range(udelay, udelay + 1);
+	}
+
+	if (unlikely(priv->do_recount)) {
+		ret = cr0014114_recount(priv);
+		if (ret)
+			goto err;
+
+		priv->do_recount = false;
+		msleep(CR_FW_DELAY_MSEC);
+	}
+
+	priv->buf[0] = CR_SET_BRIGHTNESS;
+	for (i = 0; i < priv->count; i++)
+		priv->buf[i + 1] = priv->leds[i].brightness;
+	cr0014114_calc_crc(priv->buf, priv->count + 2);
+	ret = spi_write(priv->spi, priv->buf, priv->count + 2);
+
+err:
+	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	return ret;
+}
+
+static void cr0014114_recount_work(struct work_struct *work)
+{
+	int			ret;
+	struct cr0014114	*priv = container_of(work,
+						     struct cr0014114,
+						     work.work);
+
+	mutex_lock(&priv->lock);
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
+
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+}
+
+static int cr0014114_set_sync(struct led_classdev *ldev,
+			      enum led_brightness brightness)
+{
+	int			ret;
+	struct cr0014114_led    *led = container_of(ldev,
+						    struct cr0014114_led,
+						    ldev);
+
+	mutex_lock(&led->priv->lock);
+	led->brightness = (u8)brightness;
+	ret = cr0014114_sync(led->priv);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int cr0014114_probe_dt(struct cr0014114 *priv)
+{
+	size_t			i = 0;
+	struct cr0014114_led	*led;
+	struct fwnode_handle	*child;
+	struct device_node	*np;
+	int			ret;
+
+	device_for_each_child_node(priv->dev, child) {
+		np = to_of_node(child);
+		led = &priv->leds[i];
+
+		ret = fwnode_property_read_string(child, "label",
+						  &led->name);
+		if (ret) {
+			dev_err(priv->dev, "LED label is not defined!");
+			fwnode_handle_put(child);
+			return -EINVAL;
+		}
+
+		fwnode_property_read_string(child, "linux,default-trigger",
+					    &led->ldev.default_trigger);
+
+		led->priv			  = priv;
+		led->ldev.name			  = led->name;
+		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
+		led->ldev.brightness_set_blocking = cr0014114_set_sync;
+
+		ret = devm_of_led_classdev_register(priv->dev, np,
+						    &led->ldev);
+		if (ret) {
+			dev_err(priv->dev,
+				"failed to register LED device %s, err %d",
+				led->name, ret);
+			fwnode_handle_put(child);
+			return ret;
+		}
+
+		led->ldev.dev->of_node = np;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int cr0014114_probe(struct spi_device *spi)
+{
+	struct cr0014114	*priv;
+	size_t			count;
+	int			ret;
+
+	count = device_get_child_node_count(&spi->dev);
+	if (!count) {
+		dev_err(&spi->dev, "LEDs are not defined in device tree!");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&spi->dev,
+			    sizeof(*priv) + sizeof(*priv->leds) * count,
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
+	if (!priv->buf)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
+	priv->count		= count;
+	priv->dev		= &spi->dev;
+	priv->do_recount	= true;
+	priv->spi		= spi;
+	priv->delay		= jiffies -
+				  msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	ret = cr0014114_probe_dt(priv);
+	if (ret)
+		return ret;
+
+	ret = cr0014114_sync(priv);
+	if (ret) {
+		dev_err(priv->dev, "first sync of LEDs failed %d\n", ret);
+		return ret;
+	}
+
+	/* setup recount work to workaround buggy firmware */
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+
+	spi_set_drvdata(spi, priv);
+
+	return 0;
+}
+
+static int cr0014114_remove(struct spi_device *spi)
+{
+	struct cr0014114 *priv = spi_get_drvdata(spi);
+
+	cancel_delayed_work_sync(&priv->work);
+
+	return 0;
+}
+
+static const struct of_device_id cr0014114_dt_ids[] = {
+	{ .compatible = "crane,cr0014114", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
+
+static struct spi_driver cr0014114_driver = {
+	.probe		= cr0014114_probe,
+	.remove		= cr0014114_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= cr0014114_dt_ids,
+	},
+};
+
+module_spi_driver(cr0014114_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("cr0014114 LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:cr0014114");
-- 
2.16.1


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

* Re: [PATCH 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-28  6:36                   ` Oleh Kravchenko
@ 2018-03-28 19:21                     ` Jacek Anaszewski
  2018-03-28 19:48                       ` Oleh Kravchenko
  0 siblings, 1 reply; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-28 19:21 UTC (permalink / raw)
  To: Oleh Kravchenko, devicetree, linux-leds

On 03/28/2018 08:36 AM, Oleh Kravchenko wrote:
> Hello Jacek,
> 
> On 27.03.18 23:58, Jacek Anaszewski wrote:
>>> +Example
>>> +-------
>>> +
>>> +led-controller@0 {
>>> +	compatible = "crane,cr0014114";
>>> +	reg = <0>;
>>> +	spi-max-frequency = <50000>;
>>> +	#address-cells = <1>;
>>> +	#size-cells = <0>;
>>> +
>>> +	led@0 {
>>> +		reg = <0>;
>>> +		label = "cr0:red:coin";
>>> +	};
>>> +	led@1 {
>>> +		reg = <1>;
>>> +		label = "cr0:green:coin";
>>> +	};
>>> +	led@2 {
>>> +		reg = <2>;
>>> +		label = "cr0:blue:coin";
>>> +	};
>>> +	led@3 {
>>> +		reg = <3>;
>>> +		label = "cr1:red:bill";
>>> +	};
>>> +	led@4 {
>>> +		reg = <4>;
>>> +		label = "cr1:green:bill";
>>> +	};
>>> +	led@5 {
>>> +		reg = <5>;
>>> +		label = "cr1:blue:bill";
>>> +	};
>>
>> Why cr0 and cr1? It should be cr0014114 to stick to the
>> current LED naming pattern <devicename:colour:function>.
>>
>> Nonetheless, we lately came to the conclusion that devicename
>> segment is redundant in LED class device name, so until we change
>> LED naming convention officially, let's remove devicename segment
>> at least from DT and prepend the label with "cr0014114" in the driver.
>>
>> Please compare how it is approached in [0] (not merged yet).
>>
> 
> It's just example.
> But anyway our applications works with LEDs by numbers.
> 
> Using function names instead numbers will increase code complexity,
> so we use numbers :)

This is LED class device naming convention in mainline and examples
also must stick to it to keep the things consistent.

Please switch labels so that they matched the pattern

label = "color:function";

Regardless of how LEDs are named in your port of kernel,
they for sure have some functions for the vending machine
user. Just use those names in DT :-)

Best regards,
Jacek Anaszewski

>>> +};
>>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>>> index ae850d6c0ad3..f17949c365f5 100644
>>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>>> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>>>  compulab	CompuLab Ltd.
>>>  cortina	Cortina Systems, Inc.
>>>  cosmic	Cosmic Circuits
>>> +crane	Crane Connectivity Solutions
>>>  creative	Creative Technology Ltd
>>>  crystalfontz	Crystalfontz America, Inc.
>>>  cubietech	Cubietech, Ltd.
>>>
>>
>> [0] https://www.spinics.net/lists/devicetree/msg220561.html
>>
> 


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

* Re: [PATCH 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-28 19:21                     ` Jacek Anaszewski
@ 2018-03-28 19:48                       ` Oleh Kravchenko
  2018-03-28 20:23                         ` Jacek Anaszewski
  0 siblings, 1 reply; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-28 19:48 UTC (permalink / raw)
  To: Jacek Anaszewski, devicetree, linux-leds



On 28.03.18 22:21, Jacek Anaszewski wrote:
> On 03/28/2018 08:36 AM, Oleh Kravchenko wrote:
>> Hello Jacek,
>>
>> On 27.03.18 23:58, Jacek Anaszewski wrote:
>>>> +Example
>>>> +-------
>>>> +
>>>> +led-controller@0 {
>>>> +	compatible = "crane,cr0014114";
>>>> +	reg = <0>;
>>>> +	spi-max-frequency = <50000>;
>>>> +	#address-cells = <1>;
>>>> +	#size-cells = <0>;
>>>> +
>>>> +	led@0 {
>>>> +		reg = <0>;
>>>> +		label = "cr0:red:coin";
>>>> +	};
>>>> +	led@1 {
>>>> +		reg = <1>;
>>>> +		label = "cr0:green:coin";
>>>> +	};
>>>> +	led@2 {
>>>> +		reg = <2>;
>>>> +		label = "cr0:blue:coin";
>>>> +	};
>>>> +	led@3 {
>>>> +		reg = <3>;
>>>> +		label = "cr1:red:bill";
>>>> +	};
>>>> +	led@4 {
>>>> +		reg = <4>;
>>>> +		label = "cr1:green:bill";
>>>> +	};
>>>> +	led@5 {
>>>> +		reg = <5>;
>>>> +		label = "cr1:blue:bill";
>>>> +	};
>>>
>>> Why cr0 and cr1? It should be cr0014114 to stick to the
>>> current LED naming pattern <devicename:colour:function>.
>>>
>>> Nonetheless, we lately came to the conclusion that devicename
>>> segment is redundant in LED class device name, so until we change
>>> LED naming convention officially, let's remove devicename segment
>>> at least from DT and prepend the label with "cr0014114" in the driver.
>>>
>>> Please compare how it is approached in [0] (not merged yet).
>>>
>>
>> It's just example.
>> But anyway our applications works with LEDs by numbers.
>>
>> Using function names instead numbers will increase code complexity,
>> so we use numbers :)
> 
> This is LED class device naming convention in mainline and examples
> also must stick to it to keep the things consistent.
> 
> Please switch labels so that they matched the pattern
> 
> label = "color:function";

> Why cr0 and cr1? It should be cr0014114 to stick to the
> current LED naming pattern <devicename:colour:function>.

So how it should be? I'm confused :(


> 
> Regardless of how LEDs are named in your port of kernel,
> they for sure have some functions for the vending machine
> user. Just use those names in DT :-)
> 
> Best regards,
> Jacek Anaszewski
> 
>>>> +};
>>>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>>>> index ae850d6c0ad3..f17949c365f5 100644
>>>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>>>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>>>> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>>>>  compulab	CompuLab Ltd.
>>>>  cortina	Cortina Systems, Inc.
>>>>  cosmic	Cosmic Circuits
>>>> +crane	Crane Connectivity Solutions
>>>>  creative	Creative Technology Ltd
>>>>  crystalfontz	Crystalfontz America, Inc.
>>>>  cubietech	Cubietech, Ltd.
>>>>
>>>
>>> [0] https://www.spinics.net/lists/devicetree/msg220561.html
>>>
>>
> 

-- 
Best regards,
Oleh Kravchenko
Phone: +380972763224 | oleg@kaa.org.ua | Skype: oleg_krava

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

* Re: [PATCH 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-28 19:48                       ` Oleh Kravchenko
@ 2018-03-28 20:23                         ` Jacek Anaszewski
  2018-03-29 18:56                           ` Oleh Kravchenko
  0 siblings, 1 reply; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-28 20:23 UTC (permalink / raw)
  To: Oleh Kravchenko, devicetree, linux-leds

On 03/28/2018 09:48 PM, Oleh Kravchenko wrote:
> 
> 
> On 28.03.18 22:21, Jacek Anaszewski wrote:
>> On 03/28/2018 08:36 AM, Oleh Kravchenko wrote:
>>> Hello Jacek,
>>>
>>> On 27.03.18 23:58, Jacek Anaszewski wrote:
>>>>> +Example
>>>>> +-------
>>>>> +
>>>>> +led-controller@0 {
>>>>> +	compatible = "crane,cr0014114";
>>>>> +	reg = <0>;
>>>>> +	spi-max-frequency = <50000>;
>>>>> +	#address-cells = <1>;
>>>>> +	#size-cells = <0>;
>>>>> +
>>>>> +	led@0 {
>>>>> +		reg = <0>;
>>>>> +		label = "cr0:red:coin";
>>>>> +	};
>>>>> +	led@1 {
>>>>> +		reg = <1>;
>>>>> +		label = "cr0:green:coin";
>>>>> +	};
>>>>> +	led@2 {
>>>>> +		reg = <2>;
>>>>> +		label = "cr0:blue:coin";
>>>>> +	};
>>>>> +	led@3 {
>>>>> +		reg = <3>;
>>>>> +		label = "cr1:red:bill";
>>>>> +	};
>>>>> +	led@4 {
>>>>> +		reg = <4>;
>>>>> +		label = "cr1:green:bill";
>>>>> +	};
>>>>> +	led@5 {
>>>>> +		reg = <5>;
>>>>> +		label = "cr1:blue:bill";
>>>>> +	};
>>>>
>>>> Why cr0 and cr1? It should be cr0014114 to stick to the
>>>> current LED naming pattern <devicename:colour:function>.
>>>>
>>>> Nonetheless, we lately came to the conclusion that devicename
>>>> segment is redundant in LED class device name, so until we change
>>>> LED naming convention officially, let's remove devicename segment
>>>> at least from DT and prepend the label with "cr0014114" in the driver.
>>>>
>>>> Please compare how it is approached in [0] (not merged yet).
>>>>
>>>
>>> It's just example.
>>> But anyway our applications works with LEDs by numbers.
>>>
>>> Using function names instead numbers will increase code complexity,
>>> so we use numbers :)
>>
>> This is LED class device naming convention in mainline and examples
>> also must stick to it to keep the things consistent.
>>
>> Please switch labels so that they matched the pattern
>>
>> label = "color:function";
> 
>> Why cr0 and cr1? It should be cr0014114 to stick to the
>> current LED naming pattern <devicename:colour:function>.
> 
> So how it should be? I'm confused :(

You seem to have overlooked second part of my previous message:

"
Nonetheless, we lately came to the conclusion that devicename
segment is redundant in LED class device name, so until we change
LED naming convention officially, let's remove devicename segment
at least from DT and prepend the label with "cr0014114" in the driver.

Please compare how it is approached in [0] (not merged yet).
"

Please note that DT label is not intended to be used as-is
for LED class device name, but it's been frequently abused so.

Here is the example of how you could modify your code:

DT:

led@0 {
	reg = <0>;
	label = "red:coin";
};

LED class driver:

#include <uapi/linux/uleds.h>


struct cr0014114_led {
        char                    name[LED_MAX_NAME_SIZE];
        struct cr0014114        *priv;
        struct led_classdev     ldev;
        u8                      brightness;
};


static int cr0014114_probe_dt(struct cr0014114 *priv)
{
...
const char *str;
...
device_for_each_child_node(priv->dev, child)
{
...
if (fwnode_property_read_string(child, "label", &str))
	snprintf(led->name, sizeof(led->name), "cr0014114::"),
else
	snprintf(led->name, sizeof(led->name), "cr0014114:%s", str),


I hope it makes all clear now.

> 
>>
>> Regardless of how LEDs are named in your port of kernel,
>> they for sure have some functions for the vending machine
>> user. Just use those names in DT :-)
>>
>> Best regards,
>> Jacek Anaszewski
>>
>>>>> +};
>>>>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>>>>> index ae850d6c0ad3..f17949c365f5 100644
>>>>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>>>>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>>>>> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>>>>>  compulab	CompuLab Ltd.
>>>>>  cortina	Cortina Systems, Inc.
>>>>>  cosmic	Cosmic Circuits
>>>>> +crane	Crane Connectivity Solutions
>>>>>  creative	Creative Technology Ltd
>>>>>  crystalfontz	Crystalfontz America, Inc.
>>>>>  cubietech	Cubietech, Ltd.
>>>>>
>>>>
>>>> [0] https://www.spinics.net/lists/devicetree/msg220561.html
>>>>
>>>
>>
> 

-- 
Best regards,
Jacek Anaszewski

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

* Re: [PATCH 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-28 20:23                         ` Jacek Anaszewski
@ 2018-03-29 18:56                           ` Oleh Kravchenko
  2018-03-30 10:10                             ` Jacek Anaszewski
  0 siblings, 1 reply; 46+ messages in thread
From: Oleh Kravchenko @ 2018-03-29 18:56 UTC (permalink / raw)
  To: Jacek Anaszewski, devicetree, linux-leds



On 28.03.18 23:23, Jacek Anaszewski wrote:
> On 03/28/2018 09:48 PM, Oleh Kravchenko wrote:
>>
>>
>> On 28.03.18 22:21, Jacek Anaszewski wrote:
>>> On 03/28/2018 08:36 AM, Oleh Kravchenko wrote:
>>>> Hello Jacek,
>>>>
>>>> On 27.03.18 23:58, Jacek Anaszewski wrote:
>>>>>> +Example
>>>>>> +-------
>>>>>> +
>>>>>> +led-controller@0 {
>>>>>> +	compatible = "crane,cr0014114";
>>>>>> +	reg = <0>;
>>>>>> +	spi-max-frequency = <50000>;
>>>>>> +	#address-cells = <1>;
>>>>>> +	#size-cells = <0>;
>>>>>> +
>>>>>> +	led@0 {
>>>>>> +		reg = <0>;
>>>>>> +		label = "cr0:red:coin";
>>>>>> +	};
>>>>>> +	led@1 {
>>>>>> +		reg = <1>;
>>>>>> +		label = "cr0:green:coin";
>>>>>> +	};
>>>>>> +	led@2 {
>>>>>> +		reg = <2>;
>>>>>> +		label = "cr0:blue:coin";
>>>>>> +	};
>>>>>> +	led@3 {
>>>>>> +		reg = <3>;
>>>>>> +		label = "cr1:red:bill";
>>>>>> +	};
>>>>>> +	led@4 {
>>>>>> +		reg = <4>;
>>>>>> +		label = "cr1:green:bill";
>>>>>> +	};
>>>>>> +	led@5 {
>>>>>> +		reg = <5>;
>>>>>> +		label = "cr1:blue:bill";
>>>>>> +	};
>>>>>
>>>>> Why cr0 and cr1? It should be cr0014114 to stick to the
>>>>> current LED naming pattern <devicename:colour:function>.
>>>>>
>>>>> Nonetheless, we lately came to the conclusion that devicename
>>>>> segment is redundant in LED class device name, so until we change
>>>>> LED naming convention officially, let's remove devicename segment
>>>>> at least from DT and prepend the label with "cr0014114" in the driver.
>>>>>
>>>>> Please compare how it is approached in [0] (not merged yet).
>>>>>
>>>>
>>>> It's just example.
>>>> But anyway our applications works with LEDs by numbers.
>>>>
>>>> Using function names instead numbers will increase code complexity,
>>>> so we use numbers :)
>>>
>>> This is LED class device naming convention in mainline and examples
>>> also must stick to it to keep the things consistent.
>>>
>>> Please switch labels so that they matched the pattern
>>>
>>> label = "color:function";
>>
>>> Why cr0 and cr1? It should be cr0014114 to stick to the
>>> current LED naming pattern <devicename:colour:function>.
>>
>> So how it should be? I'm confused :(
> 
> You seem to have overlooked second part of my previous message:
> 
> "
> Nonetheless, we lately came to the conclusion that devicename
> segment is redundant in LED class device name, so until we change
> LED naming convention officially, let's remove devicename segment
> at least from DT and prepend the label with "cr0014114" in the driver.
> 
> Please compare how it is approached in [0] (not merged yet).
> "
> 
> Please note that DT label is not intended to be used as-is
> for LED class device name, but it's been frequently abused so.
> 
> Here is the example of how you could modify your code:
> 
> DT:
> 
> led@0 {
> 	reg = <0>;
> 	label = "red:coin";
> };
> 
> LED class driver:
> 
> #include <uapi/linux/uleds.h>
> 
> 
> struct cr0014114_led {
>         char                    name[LED_MAX_NAME_SIZE];
>         struct cr0014114        *priv;
>         struct led_classdev     ldev;
>         u8                      brightness;
> };
> 
> 
> static int cr0014114_probe_dt(struct cr0014114 *priv)
> {
> ...
> const char *str;
> ...
> device_for_each_child_node(priv->dev, child)
> {
> ...
> if (fwnode_property_read_string(child, "label", &str))
> 	snprintf(led->name, sizeof(led->name), "cr0014114::"),
> else
> 	snprintf(led->name, sizeof(led->name), "cr0014114:%s", str),
> 
> 
> I hope it makes all clear now.

I would like to keep current implementation.
This is acceptable?

-- 
Best regards,
Oleh Kravchenko


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

* Re: [PATCH 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-29 18:56                           ` Oleh Kravchenko
@ 2018-03-30 10:10                             ` Jacek Anaszewski
  0 siblings, 0 replies; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-30 10:10 UTC (permalink / raw)
  To: Oleh Kravchenko, devicetree, linux-leds

On 03/29/2018 08:56 PM, Oleh Kravchenko wrote:
> 
> 
> On 28.03.18 23:23, Jacek Anaszewski wrote:
>> On 03/28/2018 09:48 PM, Oleh Kravchenko wrote:
>>>
>>>
>>> On 28.03.18 22:21, Jacek Anaszewski wrote:
>>>> On 03/28/2018 08:36 AM, Oleh Kravchenko wrote:
>>>>> Hello Jacek,
>>>>>
>>>>> On 27.03.18 23:58, Jacek Anaszewski wrote:
>>>>>>> +Example
>>>>>>> +-------
>>>>>>> +
>>>>>>> +led-controller@0 {
>>>>>>> +	compatible = "crane,cr0014114";
>>>>>>> +	reg = <0>;
>>>>>>> +	spi-max-frequency = <50000>;
>>>>>>> +	#address-cells = <1>;
>>>>>>> +	#size-cells = <0>;
>>>>>>> +
>>>>>>> +	led@0 {
>>>>>>> +		reg = <0>;
>>>>>>> +		label = "cr0:red:coin";
>>>>>>> +	};
>>>>>>> +	led@1 {
>>>>>>> +		reg = <1>;
>>>>>>> +		label = "cr0:green:coin";
>>>>>>> +	};
>>>>>>> +	led@2 {
>>>>>>> +		reg = <2>;
>>>>>>> +		label = "cr0:blue:coin";
>>>>>>> +	};
>>>>>>> +	led@3 {
>>>>>>> +		reg = <3>;
>>>>>>> +		label = "cr1:red:bill";
>>>>>>> +	};
>>>>>>> +	led@4 {
>>>>>>> +		reg = <4>;
>>>>>>> +		label = "cr1:green:bill";
>>>>>>> +	};
>>>>>>> +	led@5 {
>>>>>>> +		reg = <5>;
>>>>>>> +		label = "cr1:blue:bill";
>>>>>>> +	};
>>>>>>
>>>>>> Why cr0 and cr1? It should be cr0014114 to stick to the
>>>>>> current LED naming pattern <devicename:colour:function>.
>>>>>>
>>>>>> Nonetheless, we lately came to the conclusion that devicename
>>>>>> segment is redundant in LED class device name, so until we change
>>>>>> LED naming convention officially, let's remove devicename segment
>>>>>> at least from DT and prepend the label with "cr0014114" in the driver.
>>>>>>
>>>>>> Please compare how it is approached in [0] (not merged yet).
>>>>>>
>>>>>
>>>>> It's just example.
>>>>> But anyway our applications works with LEDs by numbers.
>>>>>
>>>>> Using function names instead numbers will increase code complexity,
>>>>> so we use numbers :)
>>>>
>>>> This is LED class device naming convention in mainline and examples
>>>> also must stick to it to keep the things consistent.
>>>>
>>>> Please switch labels so that they matched the pattern
>>>>
>>>> label = "color:function";
>>>
>>>> Why cr0 and cr1? It should be cr0014114 to stick to the
>>>> current LED naming pattern <devicename:colour:function>.
>>>
>>> So how it should be? I'm confused :(
>>
>> You seem to have overlooked second part of my previous message:
>>
>> "
>> Nonetheless, we lately came to the conclusion that devicename
>> segment is redundant in LED class device name, so until we change
>> LED naming convention officially, let's remove devicename segment
>> at least from DT and prepend the label with "cr0014114" in the driver.
>>
>> Please compare how it is approached in [0] (not merged yet).
>> "
>>
>> Please note that DT label is not intended to be used as-is
>> for LED class device name, but it's been frequently abused so.
>>
>> Here is the example of how you could modify your code:
>>
>> DT:
>>
>> led@0 {
>> 	reg = <0>;
>> 	label = "red:coin";
>> };
>>
>> LED class driver:
>>
>> #include <uapi/linux/uleds.h>
>>
>>
>> struct cr0014114_led {
>>         char                    name[LED_MAX_NAME_SIZE];
>>         struct cr0014114        *priv;
>>         struct led_classdev     ldev;
>>         u8                      brightness;
>> };
>>
>>
>> static int cr0014114_probe_dt(struct cr0014114 *priv)
>> {
>> ...
>> const char *str;
>> ...
>> device_for_each_child_node(priv->dev, child)
>> {
>> ...
>> if (fwnode_property_read_string(child, "label", &str))
>> 	snprintf(led->name, sizeof(led->name), "cr0014114::"),
>> else
>> 	snprintf(led->name, sizeof(led->name), "cr0014114:%s", str),
>>
>>
>> I hope it makes all clear now.
> 
> I would like to keep current implementation.
> This is acceptable?

It heavily depends on DT label property value, since in your
current implementation you're adopting label as-is for the
LED class device name. I plan on removing devicename from all
LED labels in all existing dts files and modify drivers to add
devicename by themselves. Effectively the driver code will anyway
end up in this form. Let's do it right at once.

-- 
Best regards,
Jacek Anaszewski

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

* Re: Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board]
  2018-03-27 15:31             ` Rob Herring
@ 2018-03-30 10:53               ` Jacek Anaszewski
  2018-03-30 20:59                 ` Rob Herring
  2018-04-15 16:15                 ` Pavel Machek
  0 siblings, 2 replies; 46+ messages in thread
From: Jacek Anaszewski @ 2018-03-30 10:53 UTC (permalink / raw)
  To: Rob Herring
  Cc: Oleh Kravchenko, devicetree, Linux LED Subsystem, Pavel Machek

On 03/27/2018 05:31 PM, Rob Herring wrote:
> On Mon, Mar 19, 2018 at 4:18 PM, Jacek Anaszewski
> <jacek.anaszewski@gmail.com> wrote:
>> On 03/19/2018 12:38 AM, Rob Herring wrote:
>>> On Sun, Mar 18, 2018 at 3:03 PM, Jacek Anaszewski
>>> <jacek.anaszewski@gmail.com> wrote:
>>>> On 03/18/2018 01:49 PM, Rob Herring wrote:
>>>>> On Tue, Mar 13, 2018 at 02:45:48PM +0200, Oleh Kravchenko wrote:
>>>>>> This patch adds a LED class driver for the RGB LEDs found on
>>>>>> the Crane Merchandising System CR0014114 LEDs board.
>>>>>>
>>>>>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
>>>>>> ---
>>>>>>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>>>>>>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>>>>>
>>>>> Please split to separate patch.
>>>>>
>>>>>>  drivers/leds/Kconfig                               |  13 +
>>>>>>  drivers/leds/Makefile                              |   1 +
>>>>>>  drivers/leds/leds-cr0014114.c                      | 292 +++++++++++++++++++++
>>>>>>  5 files changed, 353 insertions(+)
>>>>>>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>>>  create mode 100644 drivers/leds/leds-cr0014114.c
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>>> new file mode 100644
>>>>>> index 000000000000..977a9929b04f
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>>> @@ -0,0 +1,46 @@
>>>>>> +Crane Merchandising System - cr0014114 LED driver
>>>>>> +-------------------------------------------------
>>>>>> +
>>>>>> +This LED Board is widely used in vending machines produced
>>>>>> +by Crane Merchandising Systems.
>>>>>> +
>>>>>> +Required properties:
>>>>>> +- compatible: "cms,cr0014114"
>>>>>> +- reg: chip select address for the device
>>>>>> +- spi-cpha: shifted clock phase mode is required
>>>>>> +
>>>>>> +LED sub-node properties:
>>>>>> +- label : (optional)
>>>>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>>>>> +- linux,default-trigger : (optional)
>>>>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>>>>> +
>>>>>> +Example
>>>>>> +-------
>>>>>> +
>>>>>> +cr0014114@0 {
>>>>>
>>>>> leds@...
>>>>
>>>> In [0] you required it to be led-controller and the rest like below:
>>>
>>> Ah yes, you're right. That's what I get for trying to go off my memory.
>>>
>>>>
>>>>
>>>> led-controller@12 {
>>>>   reg = <12>;
>>>>
>>>>   led@0 {
>>>>     reg = <0>;
>>>>   };
>>>>   led@1 {
>>>>     reg = <1>;
>>>>   };
>>>> };
>>>>
>>>>
>>>> Since that time I started to require adhering to this naming pattern
>>>> for LED controller node and led@address for child nodes, where
>>>> applicable.
>>>>
>>>> I plan on submitting a patch for common LED bindings, that will
>>>> switch device names to led-controller in DT examples.
>>>>
>>>> With this scheme another problem arises, because now we have:
>>>>
>>>> - label: The label for this LED. If omitted, the label is taken from
>>>>          the node name (excluding the unit address).
>>>>
>>>> With that DT child node name is useless, because it is "led" for
>>>> each sub-led. Therefore I propose to make label property required,
>>>> and avoid using child DT node name as a fallback.
>>>
>>> There was never any guarantee that the same child node name was not
>>> used elsewhere.
>>>
>>> I think the OS needs to be able to cope with no label or even that
>>> label is not unique. Suppose you have an overlay for a addon board and
>>> you can have multiple boards connected. They'd all have the same
>>> label.
>>
>> LED subsystem is already protected against duplicated LED names:
>> a96aa64cb572 ("leds/led-class: Handle LEDs with the same name").
>>
>>> So moving to label only reduces the problem. You could use the
>>> reg property and/or compatible of the parent to construct the names.
>>> Or just append an IDR value to the name like we do on platform
>>> devices. If the user didn't specify a label, then they shouldn't
>>> really care what the name is, so just use "led.X". Though likely folks
>>> will care if the name changes on them.
>>
>> OK, so my main intention was to get rid of the part:
>>
>> "If omitted, the label is taken from the node name (excluding
>> the unit address).",
>>
>> because it won't make a sense after imposing an explicit requirement
>> on the child nodes to have only "led" in the main part of their names.
> 
> Okay, agreed. That statement never really belonged because really the
> OS is free to do whatever it wants.

It implies that label property should be made required.

>> In effect, we need to change the fallback definition to make it sane.
>> You proposed reg property and/or compatible, but:
>>
>> - reg property is not applicable in all cases (think of gpio LEDs).
>> - compatible on the other hand will have much in common with devicename,
>>   you once mentioned would be good to get rid of [0]:
>>
>> "
>> A case I care about is I have a family of boards that all have a
>> common defined set of 4 LEDs. They could be driven by anything, but I
>> want the same interface presented to userspace across boards.
>> "
> 
> Yes, and "label" should provide me with that ability as the context
> was the practice of putting the controller name in the label.

Exactly. There are two options:

1.
- label format : "<color>:<function"
2.
- label format : "<function>"
- new "color" DT property

>> We also had a discussion about standardized LED function names, so I
>> retrieved all LED function names from dts files present in kernel,
>> and after unifying some similar occurrences I got something like
>> below. Perhaps it doesn't make a sense to add all of the below
>> definitions to the standard header, but some of them could certainly
>> find their place in e.g. include/dt-bindings/leds/led-functions.h.
> 
> Looks like we could further unify things though I suppose just
> changing dts files could break users.

The changes in dts files would have to be accompanied by changes in
DT parsing part of LED class drivers. Also, I wonder if it wouldn't
make sense to add config option to choose between old and new LED
naming convention to avoid userspace breakage.

It would allow to use dts files with old style labels with
newer kernels. The LED class device names would differ like below:

Old style name (current):
	/sys/class/leds/netxbig:red:power

New style name:
	/sys/class/leds/red:power (we could also think of dropping
                                   color from name and adding sysfs
                                   file for it)


> But at least we could document
> which ones to use for new dts files. Then hopefully we don't have more
> "bluetooth" vs. "bt".
> 
> Yes, I'd certainly limit the list to ones where we have multiple
> similar names and leave out the oddballs.
> 
>> Then we could have LED names in the form function:color, and below
>> defines could be used in dts files to avoid spawning similar LED names
>> describing the same function.
>>
>> Of course in case of the names presented here with numerical suffixes
>> we could skip the suffix.
>>
>>
>> #define LED_FUNCTION_ACTIVITY "activity"
>> #define LED_FUNCTION_ADSL "adsl"
>> #define LED_FUNCTION_ALARM "alarm"
>> #define LED_FUNCTION_ALIVE "alive"
>> #define LED_FUNCTION_ALL "all"
>> #define LED_FUNCTION_APP "app"
>> #define LED_FUNCTION_AUX "aux"
>> #define LED_FUNCTION_BACKUP "backup"
>> #define LED_FUNCTION_BEEP "beep"
>> #define LED_FUNCTION_BLUETOOTH "bluetooth"
>> #define LED_FUNCTION_BOOT "boot"
>> #define LED_FUNCTION_BOTTOM "bottom"
>> #define LED_FUNCTION_BRICK-STATUS "brick-status"
>> #define LED_FUNCTION_BT "bt"
>> #define LED_FUNCTION_CEL "cel"
>> #define LED_FUNCTION_CEL-PWR "cel-pwr"
>> #define LED_FUNCTION_CEL-RESET "cel-reset"
>> #define LED_FUNCTION_CHRG "chrg"
>> #define LED_FUNCTION_COM "com"
>> #define LED_FUNCTION_COPY "copy"
>> #define LED_FUNCTION_CORE_MODULE "core_module"
>> #define LED_FUNCTION_CPU "cpu"
>> #define LED_FUNCTION_D "d"
>> #define LED_FUNCTION_DEBUG "debug"
>> #define LED_FUNCTION_DIA "dia"
>> #define LED_FUNCTION_DISK "disk"
>> #define LED_FUNCTION_DOWN "down"
>> #define LED_FUNCTION_DSL "dsl"
>> #define LED_FUNCTION_ENOCEAN "enocean"
>> #define LED_FUNCTION_ENTER "enter"
>> #define LED_FUNCTION_ERROR "error"
>> #define LED_FUNCTION_ESATA "esata"
>> #define LED_FUNCTION_ETHERNET-STATUS "ethernet-status"
>> #define LED_FUNCTION_FAIL "fail"
>> #define LED_FUNCTION_FAULT "fault"
>> #define LED_FUNCTION_FRONT "front"
>> #define LED_FUNCTION_FUNC "func"
>> #define LED_FUNCTION_G "g"
>> #define LED_FUNCTION_GHZ "ghz"
>> #define LED_FUNCTION_GHZ-1 "ghz-1"
>> #define LED_FUNCTION_GHZ-2 "ghz-2"
>> #define LED_FUNCTION_GPIO "gpio"
>> #define LED_FUNCTION_GSM "gsm"
>> #define LED_FUNCTION_HD "hd"
>> #define LED_FUNCTION_HDD "hdd"
>> #define LED_FUNCTION_HDDERR "hdderr"
>> #define LED_FUNCTION_HEALTH "health"
>> #define LED_FUNCTION_HEART "heart"
>> #define LED_FUNCTION_HEARTBEAT "heartbeat"
>> #define LED_FUNCTION_HOME "home"
>> #define LED_FUNCTION_INET "inet"
>> #define LED_FUNCTION_INFO "info"
>> #define LED_FUNCTION_INTERNET "internet"
>> #define LED_FUNCTION_KEYPAD "keypad"
>> #define LED_FUNCTION_L "l"
>> #define LED_FUNCTION_LAN "lan"
>> #define LED_FUNCTION_LEDB "ledb"
>> #define LED_FUNCTION_LEFT "left"
>> #define LED_FUNCTION_L_HDD "l_hdd"
>> #define LED_FUNCTION_LIVE "live"
>> #define LED_FUNCTION_LOGO "logo"
>> #define LED_FUNCTION_MICROSD "microsd"
>> #define LED_FUNCTION_MISC "misc"
>> #define LED_FUNCTION_MMC "mmc"
>> #define LED_FUNCTION_NAND "nand"
>> #define LED_FUNCTION_NETWORK "network"
>> #define LED_FUNCTION_ON "on"
>> #define LED_FUNCTION_ORANGE "orange"
>> #define LED_FUNCTION_OS "os"
>> #define LED_FUNCTION_PANEL "panel"
>> #define LED_FUNCTION_PMU_STAT "pmu_stat"
>> #define LED_FUNCTION_POWER "power"
>> #define LED_FUNCTION_PROG "prog"
>> #define LED_FUNCTION_PROGRAMMING "programming"
>> #define LED_FUNCTION_PROXIMITYSENSOR "proximitysensor"
>> #define LED_FUNCTION_PULSE "pulse"
>> #define LED_FUNCTION_PWR "pwr"
>> #define LED_FUNCTION_QSS "qss"
>> #define LED_FUNCTION_REBUILD "rebuild"
>> #define LED_FUNCTION_R_HDD "r_hdd"
>> #define LED_FUNCTION_RIGHT "right"
>> #define LED_FUNCTION_ROUTER "router"
>> #define LED_FUNCTION_RS "rs"
>> #define LED_FUNCTION_RX "rx"
>> #define LED_FUNCTION_SATA "sata"
>> #define LED_FUNCTION_SATA-L "sata-l"
>> #define LED_FUNCTION_SATA-R "sata-r"
>> #define LED_FUNCTION_SD "sd"
>> #define LED_FUNCTION_SLEEP "sleep"
>> #define LED_FUNCTION_STANDBY "standby"
>> #define LED_FUNCTION_STATE "state"
>> #define LED_FUNCTION_STATUS "status"
>> #define LED_FUNCTION_SW "sw"
>> #define LED_FUNCTION_SWRDY "swrdy"
>> #define LED_FUNCTION_SYS "sys"
>> #define LED_FUNCTION_SYSTEM "system"
>> #define LED_FUNCTION_SYSTEM-STATUS "system-status"
>> #define LED_FUNCTION_TEL "tel"
>> #define LED_FUNCTION_TOP "top"
>> #define LED_FUNCTION_TV "tv"
>> #define LED_FUNCTION_TX "tx"
>> #define LED_FUNCTION_UP "up"
>> #define LED_FUNCTION_USB "usb"
>> #define LED_FUNCTION_USB_1 "usb_1"
>> #define LED_FUNCTION_USB_2 "usb_2"
>> #define LED_FUNCTION_USB_COPY "usb_copy"
>> #define LED_FUNCTION_USB-PORT1 "usb-port1"
>> #define LED_FUNCTION_USB-PORT2 "usb-port2"
>> #define LED_FUNCTION_USER "user"
>> #define LED_FUNCTION_USR "usr"
>> #define LED_FUNCTION_WAN "wan"
>> #define LED_FUNCTION_WIFI "wifi"
>> #define LED_FUNCTION_WIFI_AP "wifi_ap"
>> #define LED_FUNCTION_WIFI-STATUS "wifi-status"
>> #define LED_FUNCTION_WIRELESS "wireless"
>> #define LED_FUNCTION_WLAN "wlan"
>> #define LED_FUNCTION_WLAN_G "wlan_g"
>> #define LED_FUNCTION_WMODE "wmode"
>> #define LED_FUNCTION_WPS "wps"
>>
>>
>> [0] https://patchwork.kernel.org/patch/10089047/
>> --
>> Best regards,
>> Jacek Anaszewski
> 

-- 
Best regards,
Jacek Anaszewski

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

* Re: Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board]
  2018-03-30 10:53               ` Jacek Anaszewski
@ 2018-03-30 20:59                 ` Rob Herring
  2018-04-15 16:15                 ` Pavel Machek
  1 sibling, 0 replies; 46+ messages in thread
From: Rob Herring @ 2018-03-30 20:59 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Oleh Kravchenko, devicetree, Linux LED Subsystem, Pavel Machek

On Fri, Mar 30, 2018 at 5:53 AM, Jacek Anaszewski <jacek.anaszewski@gmail.com> wrote:
> On 03/27/2018 05:31 PM, Rob Herring wrote:
>> On Mon, Mar 19, 2018 at 4:18 PM, Jacek Anaszewski
>> <jacek.anaszewski@gmail.com> wrote:
>>> On 03/19/2018 12:38 AM, Rob Herring wrote:
>>>> On Sun, Mar 18, 2018 at 3:03 PM, Jacek Anaszewski
>>>> <jacek.anaszewski@gmail.com> wrote:
>>>>> On 03/18/2018 01:49 PM, Rob Herring wrote:
>>>>>> On Tue, Mar 13, 2018 at 02:45:48PM +0200, Oleh Kravchenko wrote:
>>>>>>> This patch adds a LED class driver for the RGB LEDs found on
>>>>>>> the Crane Merchandising System CR0014114 LEDs board.
>>>>>>>
>>>>>>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
>>>>>>> ---
>>>>>>>  .../devicetree/bindings/leds/leds-cr0014114.txt    |  46 ++++
>>>>>>>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>>>>>>
>>>>>> Please split to separate patch.
>>>>>>
>>>>>>>  drivers/leds/Kconfig                               |  13 +
>>>>>>>  drivers/leds/Makefile                              |   1 +
>>>>>>>  drivers/leds/leds-cr0014114.c                      | 292 +++++++++++++++++++++
>>>>>>>  5 files changed, 353 insertions(+)
>>>>>>>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>>>>  create mode 100644 drivers/leds/leds-cr0014114.c
>>>>>>>
>>>>>>> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..977a9929b04f
>>>>>>> --- /dev/null
>>>>>>> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
>>>>>>> @@ -0,0 +1,46 @@
>>>>>>> +Crane Merchandising System - cr0014114 LED driver
>>>>>>> +-------------------------------------------------
>>>>>>> +
>>>>>>> +This LED Board is widely used in vending machines produced
>>>>>>> +by Crane Merchandising Systems.
>>>>>>> +
>>>>>>> +Required properties:
>>>>>>> +- compatible: "cms,cr0014114"
>>>>>>> +- reg: chip select address for the device
>>>>>>> +- spi-cpha: shifted clock phase mode is required
>>>>>>> +
>>>>>>> +LED sub-node properties:
>>>>>>> +- label : (optional)
>>>>>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>>>>>> +- linux,default-trigger : (optional)
>>>>>>> +    see Documentation/devicetree/bindings/leds/common.txt
>>>>>>> +
>>>>>>> +Example
>>>>>>> +-------
>>>>>>> +
>>>>>>> +cr0014114@0 {
>>>>>>
>>>>>> leds@...
>>>>>
>>>>> In [0] you required it to be led-controller and the rest like below:
>>>>
>>>> Ah yes, you're right. That's what I get for trying to go off my memory.
>>>>
>>>>>
>>>>>
>>>>> led-controller@12 {
>>>>>   reg = <12>;
>>>>>
>>>>>   led@0 {
>>>>>     reg = <0>;
>>>>>   };
>>>>>   led@1 {
>>>>>     reg = <1>;
>>>>>   };
>>>>> };
>>>>>
>>>>>
>>>>> Since that time I started to require adhering to this naming pattern
>>>>> for LED controller node and led@address for child nodes, where
>>>>> applicable.
>>>>>
>>>>> I plan on submitting a patch for common LED bindings, that will
>>>>> switch device names to led-controller in DT examples.
>>>>>
>>>>> With this scheme another problem arises, because now we have:
>>>>>
>>>>> - label: The label for this LED. If omitted, the label is taken from
>>>>>          the node name (excluding the unit address).
>>>>>
>>>>> With that DT child node name is useless, because it is "led" for
>>>>> each sub-led. Therefore I propose to make label property required,
>>>>> and avoid using child DT node name as a fallback.
>>>>
>>>> There was never any guarantee that the same child node name was not
>>>> used elsewhere.
>>>>
>>>> I think the OS needs to be able to cope with no label or even that
>>>> label is not unique. Suppose you have an overlay for a addon board and
>>>> you can have multiple boards connected. They'd all have the same
>>>> label.
>>>
>>> LED subsystem is already protected against duplicated LED names:
>>> a96aa64cb572 ("leds/led-class: Handle LEDs with the same name").
>>>
>>>> So moving to label only reduces the problem. You could use the
>>>> reg property and/or compatible of the parent to construct the names.
>>>> Or just append an IDR value to the name like we do on platform
>>>> devices. If the user didn't specify a label, then they shouldn't
>>>> really care what the name is, so just use "led.X". Though likely folks
>>>> will care if the name changes on them.
>>>
>>> OK, so my main intention was to get rid of the part:
>>>
>>> "If omitted, the label is taken from the node name (excluding
>>> the unit address).",
>>>
>>> because it won't make a sense after imposing an explicit requirement
>>> on the child nodes to have only "led" in the main part of their names.
>>
>> Okay, agreed. That statement never really belonged because really the
>> OS is free to do whatever it wants.
>
> It implies that label property should be made required.
>
>>> In effect, we need to change the fallback definition to make it sane.
>>> You proposed reg property and/or compatible, but:
>>>
>>> - reg property is not applicable in all cases (think of gpio LEDs).
>>> - compatible on the other hand will have much in common with devicename,
>>>   you once mentioned would be good to get rid of [0]:
>>>
>>> "
>>> A case I care about is I have a family of boards that all have a
>>> common defined set of 4 LEDs. They could be driven by anything, but I
>>> want the same interface presented to userspace across boards.
>>> "
>>
>> Yes, and "label" should provide me with that ability as the context
>> was the practice of putting the controller name in the label.
>
> Exactly. There are two options:
>
> 1.
> - label format : "<color>:<function"
> 2.
> - label format : "<function>"
> - new "color" DT property

This would be my preference.

>>> We also had a discussion about standardized LED function names, so I
>>> retrieved all LED function names from dts files present in kernel,
>>> and after unifying some similar occurrences I got something like
>>> below. Perhaps it doesn't make a sense to add all of the below
>>> definitions to the standard header, but some of them could certainly
>>> find their place in e.g. include/dt-bindings/leds/led-functions.h.
>>
>> Looks like we could further unify things though I suppose just
>> changing dts files could break users.
>
> The changes in dts files would have to be accompanied by changes in
> DT parsing part of LED class drivers. Also, I wonder if it wouldn't
> make sense to add config option to choose between old and new LED
> naming convention to avoid userspace breakage.
>
> It would allow to use dts files with old style labels with
> newer kernels. The LED class device names would differ like below:
>
> Old style name (current):
>         /sys/class/leds/netxbig:red:power
>
> New style name:
>         /sys/class/leds/red:power (we could also think of dropping
>                                    color from name and adding sysfs
>                                    file for it)

Following the sysfs principle of 1
>
>
>> But at least we could document
>> which ones to use for new dts files. Then hopefully we don't have more
>> "bluetooth" vs. "bt".
>>
>> Yes, I'd certainly limit the list to ones where we have multiple
>> similar names and leave out the oddballs.
>>
>>> Then we could have LED names in the form function:color, and below
>>> defines could be used in dts files to avoid spawning similar LED names
>>> describing the same function.
>>>
>>> Of course in case of the names presented here with numerical suffixes
>>> we could skip the suffix.
>>>
>>>
>>> #define LED_FUNCTION_ACTIVITY "activity"
>>> #define LED_FUNCTION_ADSL "adsl"
>>> #define LED_FUNCTION_ALARM "alarm"
>>> #define LED_FUNCTION_ALIVE "alive"
>>> #define LED_FUNCTION_ALL "all"
>>> #define LED_FUNCTION_APP "app"
>>> #define LED_FUNCTION_AUX "aux"
>>> #define LED_FUNCTION_BACKUP "backup"
>>> #define LED_FUNCTION_BEEP "beep"
>>> #define LED_FUNCTION_BLUETOOTH "bluetooth"
>>> #define LED_FUNCTION_BOOT "boot"
>>> #define LED_FUNCTION_BOTTOM "bottom"
>>> #define LED_FUNCTION_BRICK-STATUS "brick-status"
>>> #define LED_FUNCTION_BT "bt"
>>> #define LED_FUNCTION_CEL "cel"
>>> #define LED_FUNCTION_CEL-PWR "cel-pwr"
>>> #define LED_FUNCTION_CEL-RESET "cel-reset"
>>> #define LED_FUNCTION_CHRG "chrg"
>>> #define LED_FUNCTION_COM "com"
>>> #define LED_FUNCTION_COPY "copy"
>>> #define LED_FUNCTION_CORE_MODULE "core_module"
>>> #define LED_FUNCTION_CPU "cpu"
>>> #define LED_FUNCTION_D "d"
>>> #define LED_FUNCTION_DEBUG "debug"
>>> #define LED_FUNCTION_DIA "dia"
>>> #define LED_FUNCTION_DISK "disk"
>>> #define LED_FUNCTION_DOWN "down"
>>> #define LED_FUNCTION_DSL "dsl"
>>> #define LED_FUNCTION_ENOCEAN "enocean"
>>> #define LED_FUNCTION_ENTER "enter"
>>> #define LED_FUNCTION_ERROR "error"
>>> #define LED_FUNCTION_ESATA "esata"
>>> #define LED_FUNCTION_ETHERNET-STATUS "ethernet-status"
>>> #define LED_FUNCTION_FAIL "fail"
>>> #define LED_FUNCTION_FAULT "fault"
>>> #define LED_FUNCTION_FRONT "front"
>>> #define LED_FUNCTION_FUNC "func"
>>> #define LED_FUNCTION_G "g"
>>> #define LED_FUNCTION_GHZ "ghz"
>>> #define LED_FUNCTION_GHZ-1 "ghz-1"
>>> #define LED_FUNCTION_GHZ-2 "ghz-2"
>>> #define LED_FUNCTION_GPIO "gpio"
>>> #define LED_FUNCTION_GSM "gsm"
>>> #define LED_FUNCTION_HD "hd"
>>> #define LED_FUNCTION_HDD "hdd"
>>> #define LED_FUNCTION_HDDERR "hdderr"
>>> #define LED_FUNCTION_HEALTH "health"
>>> #define LED_FUNCTION_HEART "heart"
>>> #define LED_FUNCTION_HEARTBEAT "heartbeat"
>>> #define LED_FUNCTION_HOME "home"
>>> #define LED_FUNCTION_INET "inet"
>>> #define LED_FUNCTION_INFO "info"
>>> #define LED_FUNCTION_INTERNET "internet"
>>> #define LED_FUNCTION_KEYPAD "keypad"
>>> #define LED_FUNCTION_L "l"
>>> #define LED_FUNCTION_LAN "lan"
>>> #define LED_FUNCTION_LEDB "ledb"
>>> #define LED_FUNCTION_LEFT "left"
>>> #define LED_FUNCTION_L_HDD "l_hdd"
>>> #define LED_FUNCTION_LIVE "live"
>>> #define LED_FUNCTION_LOGO "logo"
>>> #define LED_FUNCTION_MICROSD "microsd"
>>> #define LED_FUNCTION_MISC "misc"
>>> #define LED_FUNCTION_MMC "mmc"
>>> #define LED_FUNCTION_NAND "nand"
>>> #define LED_FUNCTION_NETWORK "network"
>>> #define LED_FUNCTION_ON "on"
>>> #define LED_FUNCTION_ORANGE "orange"
>>> #define LED_FUNCTION_OS "os"
>>> #define LED_FUNCTION_PANEL "panel"
>>> #define LED_FUNCTION_PMU_STAT "pmu_stat"
>>> #define LED_FUNCTION_POWER "power"
>>> #define LED_FUNCTION_PROG "prog"
>>> #define LED_FUNCTION_PROGRAMMING "programming"
>>> #define LED_FUNCTION_PROXIMITYSENSOR "proximitysensor"
>>> #define LED_FUNCTION_PULSE "pulse"
>>> #define LED_FUNCTION_PWR "pwr"
>>> #define LED_FUNCTION_QSS "qss"
>>> #define LED_FUNCTION_REBUILD "rebuild"
>>> #define LED_FUNCTION_R_HDD "r_hdd"
>>> #define LED_FUNCTION_RIGHT "right"
>>> #define LED_FUNCTION_ROUTER "router"
>>> #define LED_FUNCTION_RS "rs"
>>> #define LED_FUNCTION_RX "rx"
>>> #define LED_FUNCTION_SATA "sata"
>>> #define LED_FUNCTION_SATA-L "sata-l"
>>> #define LED_FUNCTION_SATA-R "sata-r"
>>> #define LED_FUNCTION_SD "sd"
>>> #define LED_FUNCTION_SLEEP "sleep"
>>> #define LED_FUNCTION_STANDBY "standby"
>>> #define LED_FUNCTION_STATE "state"
>>> #define LED_FUNCTION_STATUS "status"
>>> #define LED_FUNCTION_SW "sw"
>>> #define LED_FUNCTION_SWRDY "swrdy"
>>> #define LED_FUNCTION_SYS "sys"
>>> #define LED_FUNCTION_SYSTEM "system"
>>> #define LED_FUNCTION_SYSTEM-STATUS "system-status"
>>> #define LED_FUNCTION_TEL "tel"
>>> #define LED_FUNCTION_TOP "top"
>>> #define LED_FUNCTION_TV "tv"
>>> #define LED_FUNCTION_TX "tx"
>>> #define LED_FUNCTION_UP "up"
>>> #define LED_FUNCTION_USB "usb"
>>> #define LED_FUNCTION_USB_1 "usb_1"
>>> #define LED_FUNCTION_USB_2 "usb_2"
>>> #define LED_FUNCTION_USB_COPY "usb_copy"
>>> #define LED_FUNCTION_USB-PORT1 "usb-port1"
>>> #define LED_FUNCTION_USB-PORT2 "usb-port2"
>>> #define LED_FUNCTION_USER "user"
>>> #define LED_FUNCTION_USR "usr"
>>> #define LED_FUNCTION_WAN "wan"
>>> #define LED_FUNCTION_WIFI "wifi"
>>> #define LED_FUNCTION_WIFI_AP "wifi_ap"
>>> #define LED_FUNCTION_WIFI-STATUS "wifi-status"
>>> #define LED_FUNCTION_WIRELESS "wireless"
>>> #define LED_FUNCTION_WLAN "wlan"
>>> #define LED_FUNCTION_WLAN_G "wlan_g"
>>> #define LED_FUNCTION_WMODE "wmode"
>>> #define LED_FUNCTION_WPS "wps"
>>>
>>>
>>> [0] https://patchwork.kernel.org/patch/10089047/
>>> --
>>> Best regards,
>>> Jacek Anaszewski
>>
>
> --
> Best regards,
> Jacek Anaszewski

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

* [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-03-28 18:56                       ` [PATCH v7 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-04-02 12:53                         ` Oleh Kravchenko
  2018-04-02 12:53                           ` [PATCH v8 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
                                             ` (2 more replies)
  0 siblings, 3 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-04-02 12:53 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

add vendor prefix for Crane;
add documentation and example for dt-bindings CR0014114.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 .../devicetree/bindings/leds/leds-cr0014114.txt    | 54 ++++++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 2 files changed, 55 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
new file mode 100644
index 000000000000..4255b19ad25c
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
@@ -0,0 +1,54 @@
+Crane Merchandising System - cr0014114 LED driver
+-------------------------------------------------
+
+This LED Board is widely used in vending machines produced
+by Crane Merchandising Systems.
+
+Required properties:
+- compatible: "crane,cr0014114"
+
+Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
+apply. In particular, "reg" and "spi-max-frequency" properties must be given.
+
+LED sub-node properties:
+- label :
+	see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+	see Documentation/devicetree/bindings/leds/common.txt
+
+Example
+-------
+
+led-controller@0 {
+	compatible = "crane,cr0014114";
+	reg = <0>;
+	spi-max-frequency = <50000>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	led@0 {
+		reg = <0>;
+		label = "red:coin";
+	};
+	led@1 {
+		reg = <1>;
+		label = "green:coin";
+	};
+	led@2 {
+		reg = <2>;
+		label = "blue:coin";
+	};
+	led@3 {
+		reg = <3>;
+		label = "red:bill";
+	};
+	led@4 {
+		reg = <4>;
+		label = "green:bill";
+	};
+	led@5 {
+		reg = <5>;
+		label = "blue:bill";
+	};
+	...
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index b5f978a4cac6..8e1f0af48aed 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
 compulab	CompuLab Ltd.
 cortina	Cortina Systems, Inc.
 cosmic	Cosmic Circuits
+crane	Crane Connectivity Solutions
 creative	Creative Technology Ltd
 crystalfontz	Crystalfontz America, Inc.
 cubietech	Cubietech, Ltd.
-- 
2.16.1


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

* [PATCH v8 2/2] leds: add LED driver for CR0014114 board
  2018-04-02 12:53                         ` [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
@ 2018-04-02 12:53                           ` Oleh Kravchenko
  2018-04-03 10:48                             ` Pavel Machek
  2018-04-10 18:59                             ` Jacek Anaszewski
  2018-04-09 19:18                           ` [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Jacek Anaszewski
  2018-04-09 21:10                           ` Rob Herring
  2 siblings, 2 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-04-02 12:53 UTC (permalink / raw)
  To: devicetree, linux-leds; +Cc: Oleh Kravchenko

This patch adds a LED class driver for the RGB LEDs found on
the Crane Merchandising System CR0014114 LEDs board.

Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
---
 drivers/leds/Kconfig          |  13 ++
 drivers/leds/Makefile         |   1 +
 drivers/leds/leds-cr0014114.c | 314 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 328 insertions(+)
 create mode 100644 drivers/leds/leds-cr0014114.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c896c0e69e1..5831814d01d0 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -104,6 +104,19 @@ config LEDS_CPCAP
 	  This option enables support for LEDs offered by Motorola's
 	  CPCAP PMIC.
 
+config LEDS_CR0014114
+	tristate "LED Support for Crane CR0014114"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for CR0014114 LED Board which
+	  is widely used in vending machines produced by
+	  Crane Merchandising Systems.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-cr0014114.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 91eca81cae82..0176e7335994 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 
 # LED SPI Drivers
+obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
 # LED Userspace Drivers
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
new file mode 100644
index 000000000000..9d0417207827
--- /dev/null
+++ b/drivers/leds/leds-cr0014114.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Crane Merchandising Systems. All rights reserved.
+// Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
+
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <uapi/linux/uleds.h>
+
+/*
+ *  CR0014114 SPI protocol descrtiption:
+ *  +----+-----------------------------------+----+
+ *  | CMD|             BRIGHTNESS            |CRC |
+ *  +----+-----------------------------------+----+
+ *  |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
+ *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ *  |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
+ *  | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
+ *  |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
+ *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
+ *  |    |               18                  |    |
+ *  +----+-----------------------------------+----+
+ *  |                    20                       |
+ *  +---------------------------------------------+
+ *
+ *  PS: Boards can be connected to the chain:
+ *      SPI -> board0 -> board1 -> board2 ..
+ */
+
+/* CR0014114 SPI commands */
+#define CR_SET_BRIGHTNESS	0x80
+#define CR_INIT_REENUMERATE	0x81
+#define CR_NEXT_REENUMERATE	0x82
+
+/* CR0014114 default settings */
+#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
+#define CR_FW_DELAY_MSEC	10
+#define CR_RECOUNT_DELAY	(HZ * 3600)
+
+struct cr0014114_led {
+	char			name[LED_MAX_NAME_SIZE];
+	struct cr0014114	*priv;
+	struct led_classdev	ldev;
+	u8			brightness;
+};
+
+struct cr0014114 {
+	bool			do_recount;
+	size_t			count;
+	struct delayed_work	work;
+	struct device		*dev;
+	struct mutex		lock;
+	struct spi_device	*spi;
+	u8			*buf;
+	unsigned long		delay;
+	struct cr0014114_led	leds[];
+};
+
+static void cr0014114_calc_crc(u8 *buf, const size_t len)
+{
+	size_t	i;
+	u8	crc;
+
+	for (i = 1, crc = 1; i < len - 1; i++)
+		crc += buf[i];
+	crc |= BIT(7);
+
+	/* special case when CRC matches the SPI commands */
+	if (crc == CR_SET_BRIGHTNESS ||
+	    crc == CR_INIT_REENUMERATE ||
+	    crc == CR_NEXT_REENUMERATE)
+		crc = 0xfe;
+
+	buf[len - 1] = crc;
+}
+
+static int cr0014114_recount(struct cr0014114 *priv)
+{
+	int	ret;
+	size_t	i;
+	u8	cmd;
+
+	dev_dbg(priv->dev, "LEDs recount is started\n");
+
+	cmd = CR_INIT_REENUMERATE;
+	ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+	if (ret)
+		goto err;
+
+	cmd = CR_NEXT_REENUMERATE;
+	for (i = 0; i < priv->count; i++) {
+		msleep(CR_FW_DELAY_MSEC);
+
+		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
+		if (ret)
+			goto err;
+	}
+
+err:
+	dev_dbg(priv->dev, "LEDs recount is finished\n");
+
+	if (ret)
+		dev_err(priv->dev, "with error %d", ret);
+
+	return ret;
+}
+
+static int cr0014114_sync(struct cr0014114 *priv)
+{
+	int		ret;
+	size_t		i;
+	unsigned long	udelay, now = jiffies;
+
+	/* to avoid SPI mistiming with firmware we should wait some time */
+	if (time_after(priv->delay, now)) {
+		udelay = jiffies_to_usecs(priv->delay - now);
+		usleep_range(udelay, udelay + 1);
+	}
+
+	if (unlikely(priv->do_recount)) {
+		ret = cr0014114_recount(priv);
+		if (ret)
+			goto err;
+
+		priv->do_recount = false;
+		msleep(CR_FW_DELAY_MSEC);
+	}
+
+	priv->buf[0] = CR_SET_BRIGHTNESS;
+	for (i = 0; i < priv->count; i++)
+		priv->buf[i + 1] = priv->leds[i].brightness;
+	cr0014114_calc_crc(priv->buf, priv->count + 2);
+	ret = spi_write(priv->spi, priv->buf, priv->count + 2);
+
+err:
+	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	return ret;
+}
+
+static void cr0014114_recount_work(struct work_struct *work)
+{
+	int			ret;
+	struct cr0014114	*priv = container_of(work,
+						     struct cr0014114,
+						     work.work);
+
+	mutex_lock(&priv->lock);
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
+
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+}
+
+static int cr0014114_set_sync(struct led_classdev *ldev,
+			      enum led_brightness brightness)
+{
+	int			ret;
+	struct cr0014114_led    *led = container_of(ldev,
+						    struct cr0014114_led,
+						    ldev);
+
+	dev_dbg(led->priv->dev, "Set brightness of %s to %d\n",
+		led->name, brightness);
+
+	mutex_lock(&led->priv->lock);
+	led->brightness = (u8)brightness;
+	ret = cr0014114_sync(led->priv);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int cr0014114_probe_dt(struct cr0014114 *priv)
+{
+	size_t			i = 0;
+	struct cr0014114_led	*led;
+	struct fwnode_handle	*child;
+	struct device_node	*np;
+	int			ret;
+	const char		*str;
+
+	device_for_each_child_node(priv->dev, child) {
+		np = to_of_node(child);
+		led = &priv->leds[i];
+
+		ret = fwnode_property_read_string(child, "label", &str);
+		if (ret)
+			snprintf(led->name, sizeof(led->name),
+				 "cr0014114::");
+		else
+			snprintf(led->name, sizeof(led->name),
+				 "cr0014114:%s", str);
+
+		fwnode_property_read_string(child, "linux,default-trigger",
+					    &led->ldev.default_trigger);
+
+		led->priv			  = priv;
+		led->ldev.name			  = led->name;
+		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
+		led->ldev.brightness_set_blocking = cr0014114_set_sync;
+
+		ret = devm_of_led_classdev_register(priv->dev, np,
+						    &led->ldev);
+		if (ret) {
+			dev_err(priv->dev,
+				"failed to register LED device %s, err %d",
+				led->name, ret);
+			fwnode_handle_put(child);
+			return ret;
+		}
+
+		led->ldev.dev->of_node = np;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int cr0014114_probe(struct spi_device *spi)
+{
+	struct cr0014114	*priv;
+	size_t			count;
+	int			ret;
+
+	count = device_get_child_node_count(&spi->dev);
+	if (!count) {
+		dev_err(&spi->dev, "LEDs are not defined in device tree!");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&spi->dev,
+			    sizeof(*priv) + sizeof(*priv->leds) * count,
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
+	if (!priv->buf)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
+	priv->count	= count;
+	priv->dev	= &spi->dev;
+	priv->spi	= spi;
+	priv->delay	= jiffies -
+			  msecs_to_jiffies(CR_FW_DELAY_MSEC);
+
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	if (ret) {
+		dev_err(priv->dev, "first recount failed %d\n", ret);
+		return ret;
+	}
+
+	priv->do_recount = true;
+	ret = cr0014114_sync(priv);
+	if (ret) {
+		dev_err(priv->dev, "second recount failed %d\n", ret);
+		return ret;
+	}
+
+	ret = cr0014114_probe_dt(priv);
+	if (ret)
+		return ret;
+
+	/* setup recount work to workaround buggy firmware */
+	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
+
+	spi_set_drvdata(spi, priv);
+
+	return 0;
+}
+
+static int cr0014114_remove(struct spi_device *spi)
+{
+	struct cr0014114 *priv = spi_get_drvdata(spi);
+
+	cancel_delayed_work_sync(&priv->work);
+
+	return 0;
+}
+
+static const struct of_device_id cr0014114_dt_ids[] = {
+	{ .compatible = "crane,cr0014114", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
+
+static struct spi_driver cr0014114_driver = {
+	.probe		= cr0014114_probe,
+	.remove		= cr0014114_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= cr0014114_dt_ids,
+	},
+};
+
+module_spi_driver(cr0014114_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("cr0014114 LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:cr0014114");
-- 
2.16.1


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

* Re: [PATCH v8 2/2] leds: add LED driver for CR0014114 board
  2018-04-02 12:53                           ` [PATCH v8 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-04-03 10:48                             ` Pavel Machek
  2018-04-10 18:59                             ` Jacek Anaszewski
  1 sibling, 0 replies; 46+ messages in thread
From: Pavel Machek @ 2018-04-03 10:48 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, linux-leds

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

On Mon 2018-04-02 15:53:50, Oleh Kravchenko wrote:
> This patch adds a LED class driver for the RGB LEDs found on
> the Crane Merchandising System CR0014114 LEDs board.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>

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] 46+ messages in thread

* Re: [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-04-02 12:53                         ` [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  2018-04-02 12:53                           ` [PATCH v8 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
@ 2018-04-09 19:18                           ` Jacek Anaszewski
  2018-04-09 21:10                           ` Rob Herring
  2 siblings, 0 replies; 46+ messages in thread
From: Jacek Anaszewski @ 2018-04-09 19:18 UTC (permalink / raw)
  To: Oleh Kravchenko, devicetree, linux-leds, Rob Herring

Hi Rob,

We're missing DT maintainer ack for this patch.
especially for the part adding a new vendor prefix.

Could we get one?

Best regards,
Jacek Anaszewski

On 04/02/2018 02:53 PM, Oleh Kravchenko wrote:
> add vendor prefix for Crane;
> add documentation and example for dt-bindings CR0014114.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  .../devicetree/bindings/leds/leds-cr0014114.txt    | 54 ++++++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.txt        |  1 +
>  2 files changed, 55 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> 
> diff --git a/Documentation/devicetree/bindings/leds/leds-cr0014114.txt b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> new file mode 100644
> index 000000000000..4255b19ad25c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/leds/leds-cr0014114.txt
> @@ -0,0 +1,54 @@
> +Crane Merchandising System - cr0014114 LED driver
> +-------------------------------------------------
> +
> +This LED Board is widely used in vending machines produced
> +by Crane Merchandising Systems.
> +
> +Required properties:
> +- compatible: "crane,cr0014114"
> +
> +Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
> +apply. In particular, "reg" and "spi-max-frequency" properties must be given.
> +
> +LED sub-node properties:
> +- label :
> +	see Documentation/devicetree/bindings/leds/common.txt
> +- linux,default-trigger : (optional)
> +	see Documentation/devicetree/bindings/leds/common.txt
> +
> +Example
> +-------
> +
> +led-controller@0 {
> +	compatible = "crane,cr0014114";
> +	reg = <0>;
> +	spi-max-frequency = <50000>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	led@0 {
> +		reg = <0>;
> +		label = "red:coin";
> +	};
> +	led@1 {
> +		reg = <1>;
> +		label = "green:coin";
> +	};
> +	led@2 {
> +		reg = <2>;
> +		label = "blue:coin";
> +	};
> +	led@3 {
> +		reg = <3>;
> +		label = "red:bill";
> +	};
> +	led@4 {
> +		reg = <4>;
> +		label = "green:bill";
> +	};
> +	led@5 {
> +		reg = <5>;
> +		label = "blue:bill";
> +	};
> +	...
> +};
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index b5f978a4cac6..8e1f0af48aed 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -75,6 +75,7 @@ cnxt	Conexant Systems, Inc.
>  compulab	CompuLab Ltd.
>  cortina	Cortina Systems, Inc.
>  cosmic	Cosmic Circuits
> +crane	Crane Connectivity Solutions
>  creative	Creative Technology Ltd
>  crystalfontz	Crystalfontz America, Inc.
>  cubietech	Cubietech, Ltd.
> 

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

* Re: [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114
  2018-04-02 12:53                         ` [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
  2018-04-02 12:53                           ` [PATCH v8 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
  2018-04-09 19:18                           ` [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Jacek Anaszewski
@ 2018-04-09 21:10                           ` Rob Herring
  2 siblings, 0 replies; 46+ messages in thread
From: Rob Herring @ 2018-04-09 21:10 UTC (permalink / raw)
  To: Oleh Kravchenko; +Cc: devicetree, linux-leds

On Mon, Apr 02, 2018 at 03:53:49PM +0300, Oleh Kravchenko wrote:
> add vendor prefix for Crane;
> add documentation and example for dt-bindings CR0014114.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  .../devicetree/bindings/leds/leds-cr0014114.txt    | 54 ++++++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.txt        |  1 +
>  2 files changed, 55 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/leds/leds-cr0014114.txt

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

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

* Re: [PATCH v8 2/2] leds: add LED driver for CR0014114 board
  2018-04-02 12:53                           ` [PATCH v8 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
  2018-04-03 10:48                             ` Pavel Machek
@ 2018-04-10 18:59                             ` Jacek Anaszewski
  2018-04-10 20:24                               ` Oleh Kravchenko
  1 sibling, 1 reply; 46+ messages in thread
From: Jacek Anaszewski @ 2018-04-10 18:59 UTC (permalink / raw)
  To: Oleh Kravchenko, devicetree, linux-leds

Hi Oleh,

Thanks for the updated set.

On 04/02/2018 02:53 PM, Oleh Kravchenko wrote:
> This patch adds a LED class driver for the RGB LEDs found on
> the Crane Merchandising System CR0014114 LEDs board.
> 
> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
> ---
>  drivers/leds/Kconfig          |  13 ++
>  drivers/leds/Makefile         |   1 +
>  drivers/leds/leds-cr0014114.c | 314 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 328 insertions(+)
>  create mode 100644 drivers/leds/leds-cr0014114.c
> 
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 2c896c0e69e1..5831814d01d0 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -104,6 +104,19 @@ config LEDS_CPCAP
>  	  This option enables support for LEDs offered by Motorola's
>  	  CPCAP PMIC.
>  
> +config LEDS_CR0014114
> +	tristate "LED Support for Crane CR0014114"
> +	depends on LEDS_CLASS
> +	depends on SPI
> +	depends on OF
> +	help
> +	  This option enables support for CR0014114 LED Board which
> +	  is widely used in vending machines produced by
> +	  Crane Merchandising Systems.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called leds-cr0014114.
> +
>  config LEDS_LM3530
>  	tristate "LCD Backlight driver for LM3530"
>  	depends on LEDS_CLASS
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 91eca81cae82..0176e7335994 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
>  obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
>  
>  # LED SPI Drivers
> +obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
>  obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
>  
>  # LED Userspace Drivers
> diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
> new file mode 100644
> index 000000000000..9d0417207827
> --- /dev/null
> +++ b/drivers/leds/leds-cr0014114.c
> @@ -0,0 +1,314 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2018 Crane Merchandising Systems. All rights reserved.
> +// Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
> +
> +#include <linux/delay.h>
> +#include <linux/leds.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/spi/spi.h>
> +#include <linux/workqueue.h>
> +#include <uapi/linux/uleds.h>
> +
> +/*
> + *  CR0014114 SPI protocol descrtiption:
> + *  +----+-----------------------------------+----+
> + *  | CMD|             BRIGHTNESS            |CRC |
> + *  +----+-----------------------------------+----+
> + *  |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
> + *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
> + *  |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
> + *  | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
> + *  |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
> + *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
> + *  |    |               18                  |    |
> + *  +----+-----------------------------------+----+
> + *  |                    20                       |
> + *  +---------------------------------------------+
> + *
> + *  PS: Boards can be connected to the chain:
> + *      SPI -> board0 -> board1 -> board2 ..
> + */
> +
> +/* CR0014114 SPI commands */
> +#define CR_SET_BRIGHTNESS	0x80
> +#define CR_INIT_REENUMERATE	0x81
> +#define CR_NEXT_REENUMERATE	0x82
> +
> +/* CR0014114 default settings */
> +#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
> +#define CR_FW_DELAY_MSEC	10
> +#define CR_RECOUNT_DELAY	(HZ * 3600)
> +
> +struct cr0014114_led {
> +	char			name[LED_MAX_NAME_SIZE];
> +	struct cr0014114	*priv;
> +	struct led_classdev	ldev;
> +	u8			brightness;
> +};
> +
> +struct cr0014114 {
> +	bool			do_recount;
> +	size_t			count;
> +	struct delayed_work	work;
> +	struct device		*dev;
> +	struct mutex		lock;
> +	struct spi_device	*spi;
> +	u8			*buf;
> +	unsigned long		delay;
> +	struct cr0014114_led	leds[];
> +};
> +
> +static void cr0014114_calc_crc(u8 *buf, const size_t len)
> +{
> +	size_t	i;
> +	u8	crc;
> +
> +	for (i = 1, crc = 1; i < len - 1; i++)
> +		crc += buf[i];
> +	crc |= BIT(7);
> +
> +	/* special case when CRC matches the SPI commands */
> +	if (crc == CR_SET_BRIGHTNESS ||
> +	    crc == CR_INIT_REENUMERATE ||
> +	    crc == CR_NEXT_REENUMERATE)
> +		crc = 0xfe;
> +
> +	buf[len - 1] = crc;
> +}
> +
> +static int cr0014114_recount(struct cr0014114 *priv)
> +{
> +	int	ret;
> +	size_t	i;
> +	u8	cmd;
> +
> +	dev_dbg(priv->dev, "LEDs recount is started\n");
> +
> +	cmd = CR_INIT_REENUMERATE;
> +	ret = spi_write(priv->spi, &cmd, sizeof(cmd));
> +	if (ret)
> +		goto err;
> +
> +	cmd = CR_NEXT_REENUMERATE;
> +	for (i = 0; i < priv->count; i++) {
> +		msleep(CR_FW_DELAY_MSEC);
> +
> +		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
> +		if (ret)
> +			goto err;
> +	}
> +
> +err:
> +	dev_dbg(priv->dev, "LEDs recount is finished\n");
> +
> +	if (ret)
> +		dev_err(priv->dev, "with error %d", ret);
> +
> +	return ret;
> +}
> +
> +static int cr0014114_sync(struct cr0014114 *priv)
> +{
> +	int		ret;
> +	size_t		i;
> +	unsigned long	udelay, now = jiffies;
> +
> +	/* to avoid SPI mistiming with firmware we should wait some time */
> +	if (time_after(priv->delay, now)) {
> +		udelay = jiffies_to_usecs(priv->delay - now);
> +		usleep_range(udelay, udelay + 1);
> +	}
> +
> +	if (unlikely(priv->do_recount)) {
> +		ret = cr0014114_recount(priv);
> +		if (ret)
> +			goto err;
> +
> +		priv->do_recount = false;
> +		msleep(CR_FW_DELAY_MSEC);
> +	}
> +
> +	priv->buf[0] = CR_SET_BRIGHTNESS;
> +	for (i = 0; i < priv->count; i++)
> +		priv->buf[i + 1] = priv->leds[i].brightness;
> +	cr0014114_calc_crc(priv->buf, priv->count + 2);
> +	ret = spi_write(priv->spi, priv->buf, priv->count + 2);
> +
> +err:
> +	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
> +
> +	return ret;
> +}
> +
> +static void cr0014114_recount_work(struct work_struct *work)
> +{
> +	int			ret;
> +	struct cr0014114	*priv = container_of(work,
> +						     struct cr0014114,
> +						     work.work);
> +
> +	mutex_lock(&priv->lock);
> +	priv->do_recount = true;
> +	ret = cr0014114_sync(priv);
> +	mutex_unlock(&priv->lock);
> +
> +	if (ret)
> +		dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
> +
> +	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
> +}
> +
> +static int cr0014114_set_sync(struct led_classdev *ldev,
> +			      enum led_brightness brightness)
> +{
> +	int			ret;
> +	struct cr0014114_led    *led = container_of(ldev,
> +						    struct cr0014114_led,
> +						    ldev);
> +
> +	dev_dbg(led->priv->dev, "Set brightness of %s to %d\n",
> +		led->name, brightness);
> +
> +	mutex_lock(&led->priv->lock);
> +	led->brightness = (u8)brightness;
> +	ret = cr0014114_sync(led->priv);
> +	mutex_unlock(&led->priv->lock);
> +
> +	return ret;
> +}
> +
> +static int cr0014114_probe_dt(struct cr0014114 *priv)
> +{
> +	size_t			i = 0;
> +	struct cr0014114_led	*led;
> +	struct fwnode_handle	*child;
> +	struct device_node	*np;
> +	int			ret;
> +	const char		*str;
> +
> +	device_for_each_child_node(priv->dev, child) {
> +		np = to_of_node(child);
> +		led = &priv->leds[i];
> +
> +		ret = fwnode_property_read_string(child, "label", &str);
> +		if (ret)
> +			snprintf(led->name, sizeof(led->name),
> +				 "cr0014114::");
> +		else
> +			snprintf(led->name, sizeof(led->name),
> +				 "cr0014114:%s", str);
> +
> +		fwnode_property_read_string(child, "linux,default-trigger",
> +					    &led->ldev.default_trigger);
> +
> +		led->priv			  = priv;
> +		led->ldev.name			  = led->name;
> +		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
> +		led->ldev.brightness_set_blocking = cr0014114_set_sync;
> +
> +		ret = devm_of_led_classdev_register(priv->dev, np,
> +						    &led->ldev);
> +		if (ret) {
> +			dev_err(priv->dev,
> +				"failed to register LED device %s, err %d",
> +				led->name, ret);
> +			fwnode_handle_put(child);
> +			return ret;
> +		}
> +
> +		led->ldev.dev->of_node = np;
> +
> +		i++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cr0014114_probe(struct spi_device *spi)
> +{
> +	struct cr0014114	*priv;
> +	size_t			count;
> +	int			ret;
> +
> +	count = device_get_child_node_count(&spi->dev);
> +	if (!count) {
> +		dev_err(&spi->dev, "LEDs are not defined in device tree!");
> +		return -ENODEV;
> +	}
> +
> +	priv = devm_kzalloc(&spi->dev,
> +			    sizeof(*priv) + sizeof(*priv->leds) * count,
> +			    GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
> +	if (!priv->buf)
> +		return -ENOMEM;
> +
> +	mutex_init(&priv->lock);
> +	INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
> +	priv->count	= count;
> +	priv->dev	= &spi->dev;
> +	priv->spi	= spi;
> +	priv->delay	= jiffies -
> +			  msecs_to_jiffies(CR_FW_DELAY_MSEC);
> +
> +	priv->do_recount = true;
> +	ret = cr0014114_sync(priv);
> +	if (ret) {
> +		dev_err(priv->dev, "first recount failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	priv->do_recount = true;
> +	ret = cr0014114_sync(priv);
> +	if (ret) {
> +		dev_err(priv->dev, "second recount failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = cr0014114_probe_dt(priv);
> +	if (ret)
> +		return ret;
> +
> +	/* setup recount work to workaround buggy firmware */
> +	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
> +
> +	spi_set_drvdata(spi, priv);
> +
> +	return 0;
> +}
> +
> +static int cr0014114_remove(struct spi_device *spi)
> +{
> +	struct cr0014114 *priv = spi_get_drvdata(spi);
> +
> +	cancel_delayed_work_sync(&priv->work);

Added mutex_destroy(&priv->lock) here and applied the set
to the for-4.18 branch of linux-leds.git.

Thanks for your work.

Best regards,
Jacek Anaszewski

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id cr0014114_dt_ids[] = {
> +	{ .compatible = "crane,cr0014114", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
> +
> +static struct spi_driver cr0014114_driver = {
> +	.probe		= cr0014114_probe,
> +	.remove		= cr0014114_remove,
> +	.driver = {
> +		.name		= KBUILD_MODNAME,
> +		.of_match_table	= cr0014114_dt_ids,
> +	},
> +};
> +
> +module_spi_driver(cr0014114_driver);
> +
> +MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
> +MODULE_DESCRIPTION("cr0014114 LED driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("spi:cr0014114");
> 


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

* Re: [PATCH v8 2/2] leds: add LED driver for CR0014114 board
  2018-04-10 18:59                             ` Jacek Anaszewski
@ 2018-04-10 20:24                               ` Oleh Kravchenko
  0 siblings, 0 replies; 46+ messages in thread
From: Oleh Kravchenko @ 2018-04-10 20:24 UTC (permalink / raw)
  To: Jacek Anaszewski, devicetree, linux-leds


[-- Attachment #1.1: Type: text/plain, Size: 11165 bytes --]

Thank you!

On 10.04.18 21:59, Jacek Anaszewski wrote:
> Hi Oleh,
>
> Thanks for the updated set.
>
> On 04/02/2018 02:53 PM, Oleh Kravchenko wrote:
>> This patch adds a LED class driver for the RGB LEDs found on
>> the Crane Merchandising System CR0014114 LEDs board.
>>
>> Signed-off-by: Oleh Kravchenko <oleg@kaa.org.ua>
>> ---
>>  drivers/leds/Kconfig          |  13 ++
>>  drivers/leds/Makefile         |   1 +
>>  drivers/leds/leds-cr0014114.c | 314 ++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 328 insertions(+)
>>  create mode 100644 drivers/leds/leds-cr0014114.c
>>
>> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
>> index 2c896c0e69e1..5831814d01d0 100644
>> --- a/drivers/leds/Kconfig
>> +++ b/drivers/leds/Kconfig
>> @@ -104,6 +104,19 @@ config LEDS_CPCAP
>>  	  This option enables support for LEDs offered by Motorola's
>>  	  CPCAP PMIC.
>>  
>> +config LEDS_CR0014114
>> +	tristate "LED Support for Crane CR0014114"
>> +	depends on LEDS_CLASS
>> +	depends on SPI
>> +	depends on OF
>> +	help
>> +	  This option enables support for CR0014114 LED Board which
>> +	  is widely used in vending machines produced by
>> +	  Crane Merchandising Systems.
>> +
>> +	  To compile this driver as a module, choose M here: the module
>> +	  will be called leds-cr0014114.
>> +
>>  config LEDS_LM3530
>>  	tristate "LCD Backlight driver for LM3530"
>>  	depends on LEDS_CLASS
>> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
>> index 91eca81cae82..0176e7335994 100644
>> --- a/drivers/leds/Makefile
>> +++ b/drivers/leds/Makefile
>> @@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
>>  obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
>>  
>>  # LED SPI Drivers
>> +obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
>>  obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
>>  
>>  # LED Userspace Drivers
>> diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
>> new file mode 100644
>> index 000000000000..9d0417207827
>> --- /dev/null
>> +++ b/drivers/leds/leds-cr0014114.c
>> @@ -0,0 +1,314 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (c) 2018 Crane Merchandising Systems. All rights reserved.
>> +// Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
>> +
>> +#include <linux/delay.h>
>> +#include <linux/leds.h>
>> +#include <linux/module.h>
>> +#include <linux/of_device.h>
>> +#include <linux/spi/spi.h>
>> +#include <linux/workqueue.h>
>> +#include <uapi/linux/uleds.h>
>> +
>> +/*
>> + *  CR0014114 SPI protocol descrtiption:
>> + *  +----+-----------------------------------+----+
>> + *  | CMD|             BRIGHTNESS            |CRC |
>> + *  +----+-----------------------------------+----+
>> + *  |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
>> + *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
>> + *  |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
>> + *  | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
>> + *  |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
>> + *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
>> + *  |    |               18                  |    |
>> + *  +----+-----------------------------------+----+
>> + *  |                    20                       |
>> + *  +---------------------------------------------+
>> + *
>> + *  PS: Boards can be connected to the chain:
>> + *      SPI -> board0 -> board1 -> board2 ..
>> + */
>> +
>> +/* CR0014114 SPI commands */
>> +#define CR_SET_BRIGHTNESS	0x80
>> +#define CR_INIT_REENUMERATE	0x81
>> +#define CR_NEXT_REENUMERATE	0x82
>> +
>> +/* CR0014114 default settings */
>> +#define CR_MAX_BRIGHTNESS	GENMASK(6, 0)
>> +#define CR_FW_DELAY_MSEC	10
>> +#define CR_RECOUNT_DELAY	(HZ * 3600)
>> +
>> +struct cr0014114_led {
>> +	char			name[LED_MAX_NAME_SIZE];
>> +	struct cr0014114	*priv;
>> +	struct led_classdev	ldev;
>> +	u8			brightness;
>> +};
>> +
>> +struct cr0014114 {
>> +	bool			do_recount;
>> +	size_t			count;
>> +	struct delayed_work	work;
>> +	struct device		*dev;
>> +	struct mutex		lock;
>> +	struct spi_device	*spi;
>> +	u8			*buf;
>> +	unsigned long		delay;
>> +	struct cr0014114_led	leds[];
>> +};
>> +
>> +static void cr0014114_calc_crc(u8 *buf, const size_t len)
>> +{
>> +	size_t	i;
>> +	u8	crc;
>> +
>> +	for (i = 1, crc = 1; i < len - 1; i++)
>> +		crc += buf[i];
>> +	crc |= BIT(7);
>> +
>> +	/* special case when CRC matches the SPI commands */
>> +	if (crc == CR_SET_BRIGHTNESS ||
>> +	    crc == CR_INIT_REENUMERATE ||
>> +	    crc == CR_NEXT_REENUMERATE)
>> +		crc = 0xfe;
>> +
>> +	buf[len - 1] = crc;
>> +}
>> +
>> +static int cr0014114_recount(struct cr0014114 *priv)
>> +{
>> +	int	ret;
>> +	size_t	i;
>> +	u8	cmd;
>> +
>> +	dev_dbg(priv->dev, "LEDs recount is started\n");
>> +
>> +	cmd = CR_INIT_REENUMERATE;
>> +	ret = spi_write(priv->spi, &cmd, sizeof(cmd));
>> +	if (ret)
>> +		goto err;
>> +
>> +	cmd = CR_NEXT_REENUMERATE;
>> +	for (i = 0; i < priv->count; i++) {
>> +		msleep(CR_FW_DELAY_MSEC);
>> +
>> +		ret = spi_write(priv->spi, &cmd, sizeof(cmd));
>> +		if (ret)
>> +			goto err;
>> +	}
>> +
>> +err:
>> +	dev_dbg(priv->dev, "LEDs recount is finished\n");
>> +
>> +	if (ret)
>> +		dev_err(priv->dev, "with error %d", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static int cr0014114_sync(struct cr0014114 *priv)
>> +{
>> +	int		ret;
>> +	size_t		i;
>> +	unsigned long	udelay, now = jiffies;
>> +
>> +	/* to avoid SPI mistiming with firmware we should wait some time */
>> +	if (time_after(priv->delay, now)) {
>> +		udelay = jiffies_to_usecs(priv->delay - now);
>> +		usleep_range(udelay, udelay + 1);
>> +	}
>> +
>> +	if (unlikely(priv->do_recount)) {
>> +		ret = cr0014114_recount(priv);
>> +		if (ret)
>> +			goto err;
>> +
>> +		priv->do_recount = false;
>> +		msleep(CR_FW_DELAY_MSEC);
>> +	}
>> +
>> +	priv->buf[0] = CR_SET_BRIGHTNESS;
>> +	for (i = 0; i < priv->count; i++)
>> +		priv->buf[i + 1] = priv->leds[i].brightness;
>> +	cr0014114_calc_crc(priv->buf, priv->count + 2);
>> +	ret = spi_write(priv->spi, priv->buf, priv->count + 2);
>> +
>> +err:
>> +	priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
>> +
>> +	return ret;
>> +}
>> +
>> +static void cr0014114_recount_work(struct work_struct *work)
>> +{
>> +	int			ret;
>> +	struct cr0014114	*priv = container_of(work,
>> +						     struct cr0014114,
>> +						     work.work);
>> +
>> +	mutex_lock(&priv->lock);
>> +	priv->do_recount = true;
>> +	ret = cr0014114_sync(priv);
>> +	mutex_unlock(&priv->lock);
>> +
>> +	if (ret)
>> +		dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
>> +
>> +	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
>> +}
>> +
>> +static int cr0014114_set_sync(struct led_classdev *ldev,
>> +			      enum led_brightness brightness)
>> +{
>> +	int			ret;
>> +	struct cr0014114_led    *led = container_of(ldev,
>> +						    struct cr0014114_led,
>> +						    ldev);
>> +
>> +	dev_dbg(led->priv->dev, "Set brightness of %s to %d\n",
>> +		led->name, brightness);
>> +
>> +	mutex_lock(&led->priv->lock);
>> +	led->brightness = (u8)brightness;
>> +	ret = cr0014114_sync(led->priv);
>> +	mutex_unlock(&led->priv->lock);
>> +
>> +	return ret;
>> +}
>> +
>> +static int cr0014114_probe_dt(struct cr0014114 *priv)
>> +{
>> +	size_t			i = 0;
>> +	struct cr0014114_led	*led;
>> +	struct fwnode_handle	*child;
>> +	struct device_node	*np;
>> +	int			ret;
>> +	const char		*str;
>> +
>> +	device_for_each_child_node(priv->dev, child) {
>> +		np = to_of_node(child);
>> +		led = &priv->leds[i];
>> +
>> +		ret = fwnode_property_read_string(child, "label", &str);
>> +		if (ret)
>> +			snprintf(led->name, sizeof(led->name),
>> +				 "cr0014114::");
>> +		else
>> +			snprintf(led->name, sizeof(led->name),
>> +				 "cr0014114:%s", str);
>> +
>> +		fwnode_property_read_string(child, "linux,default-trigger",
>> +					    &led->ldev.default_trigger);
>> +
>> +		led->priv			  = priv;
>> +		led->ldev.name			  = led->name;
>> +		led->ldev.max_brightness	  = CR_MAX_BRIGHTNESS;
>> +		led->ldev.brightness_set_blocking = cr0014114_set_sync;
>> +
>> +		ret = devm_of_led_classdev_register(priv->dev, np,
>> +						    &led->ldev);
>> +		if (ret) {
>> +			dev_err(priv->dev,
>> +				"failed to register LED device %s, err %d",
>> +				led->name, ret);
>> +			fwnode_handle_put(child);
>> +			return ret;
>> +		}
>> +
>> +		led->ldev.dev->of_node = np;
>> +
>> +		i++;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int cr0014114_probe(struct spi_device *spi)
>> +{
>> +	struct cr0014114	*priv;
>> +	size_t			count;
>> +	int			ret;
>> +
>> +	count = device_get_child_node_count(&spi->dev);
>> +	if (!count) {
>> +		dev_err(&spi->dev, "LEDs are not defined in device tree!");
>> +		return -ENODEV;
>> +	}
>> +
>> +	priv = devm_kzalloc(&spi->dev,
>> +			    sizeof(*priv) + sizeof(*priv->leds) * count,
>> +			    GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
>> +	if (!priv->buf)
>> +		return -ENOMEM;
>> +
>> +	mutex_init(&priv->lock);
>> +	INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
>> +	priv->count	= count;
>> +	priv->dev	= &spi->dev;
>> +	priv->spi	= spi;
>> +	priv->delay	= jiffies -
>> +			  msecs_to_jiffies(CR_FW_DELAY_MSEC);
>> +
>> +	priv->do_recount = true;
>> +	ret = cr0014114_sync(priv);
>> +	if (ret) {
>> +		dev_err(priv->dev, "first recount failed %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	priv->do_recount = true;
>> +	ret = cr0014114_sync(priv);
>> +	if (ret) {
>> +		dev_err(priv->dev, "second recount failed %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = cr0014114_probe_dt(priv);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* setup recount work to workaround buggy firmware */
>> +	schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
>> +
>> +	spi_set_drvdata(spi, priv);
>> +
>> +	return 0;
>> +}
>> +
>> +static int cr0014114_remove(struct spi_device *spi)
>> +{
>> +	struct cr0014114 *priv = spi_get_drvdata(spi);
>> +
>> +	cancel_delayed_work_sync(&priv->work);
> Added mutex_destroy(&priv->lock) here and applied the set
> to the for-4.18 branch of linux-leds.git.
>
> Thanks for your work.
>
> Best regards,
> Jacek Anaszewski
>
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id cr0014114_dt_ids[] = {
>> +	{ .compatible = "crane,cr0014114", },
>> +	{},
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
>> +
>> +static struct spi_driver cr0014114_driver = {
>> +	.probe		= cr0014114_probe,
>> +	.remove		= cr0014114_remove,
>> +	.driver = {
>> +		.name		= KBUILD_MODNAME,
>> +		.of_match_table	= cr0014114_dt_ids,
>> +	},
>> +};
>> +
>> +module_spi_driver(cr0014114_driver);
>> +
>> +MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
>> +MODULE_DESCRIPTION("cr0014114 LED driver");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_ALIAS("spi:cr0014114");
>>

-- 
Best regards,
Oleh Kravchenko



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board]
  2018-03-19 21:18           ` Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board] Jacek Anaszewski
  2018-03-27 15:31             ` Rob Herring
@ 2018-04-15 16:15             ` Pavel Machek
  1 sibling, 0 replies; 46+ messages in thread
From: Pavel Machek @ 2018-04-15 16:15 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Rob Herring, Oleh Kravchenko, devicetree, Linux LED Subsystem

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

Hi!

> We also had a discussion about standardized LED function names, so I
> retrieved all LED function names from dts files present in kernel,
> and after unifying some similar occurrences I got something like
> below. Perhaps it doesn't make a sense to add all of the below
> definitions to the standard header, but some of them could certainly
> find their place in e.g. include/dt-bindings/leds/led-functions.h.

Yes, we should try to make names standard.

> Then we could have LED names in the form function:color, and below
> defines could be used in dts files to avoid spawning similar LED names
> describing the same function.

> Of course in case of the names presented here with numerical suffixes
> we could skip the suffix.

So we should certainly remove some stuff for the list. For example we
do not want "d" function, and we want to choose either "bluetooth" or
"bt", but don't want to have both.

Also for example "activity" should be removed, we need to be more
specific there. I suspect "nand" means activity on the nand flash, for
example.

> #define LED_FUNCTION_ACTIVITY "activity"
> #define LED_FUNCTION_ADSL "adsl"
> #define LED_FUNCTION_ALARM "alarm"
> #define LED_FUNCTION_ALIVE "alive"
> #define LED_FUNCTION_ALL "all"
> #define LED_FUNCTION_APP "app"
> #define LED_FUNCTION_AUX "aux"
> #define LED_FUNCTION_BACKUP "backup"
> #define LED_FUNCTION_BEEP "beep"
> #define LED_FUNCTION_BLUETOOTH "bluetooth"
> #define LED_FUNCTION_BOOT "boot"
> #define LED_FUNCTION_BOTTOM "bottom"
> #define LED_FUNCTION_BRICK-STATUS "brick-status"
> #define LED_FUNCTION_BT "bt"
> #define LED_FUNCTION_CEL "cel"
> #define LED_FUNCTION_CEL-PWR "cel-pwr"

									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] 46+ messages in thread

* Re: Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board]
  2018-03-30 10:53               ` Jacek Anaszewski
  2018-03-30 20:59                 ` Rob Herring
@ 2018-04-15 16:15                 ` Pavel Machek
  2018-04-15 18:30                   ` Jacek Anaszewski
  1 sibling, 1 reply; 46+ messages in thread
From: Pavel Machek @ 2018-04-15 16:15 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Rob Herring, Oleh Kravchenko, devicetree, Linux LED Subsystem

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

Hi!

> >> A case I care about is I have a family of boards that all have a
> >> common defined set of 4 LEDs. They could be driven by anything, but I
> >> want the same interface presented to userspace across boards.
> >> "
> > 
> > Yes, and "label" should provide me with that ability as the context
> > was the practice of putting the controller name in the label.
> 
> Exactly. There are two options:
> 
> 1.
> - label format : "<color>:<function"
> 2.
> - label format : "<function>"
> - new "color" DT property

We should provide compatibility here.

So we should really have new "color" property, and probably new
"function" property, too.

> The changes in dts files would have to be accompanied by changes in
> DT parsing part of LED class drivers. Also, I wonder if it wouldn't
> make sense to add config option to choose between old and new LED
> naming convention to avoid userspace breakage.

Both old and new kernels are expected to be working with both old and
new dts...

And having config option choosing userland interfaces would not be nice.

> It would allow to use dts files with old style labels with
> newer kernels. The LED class device names would differ like below:
> 
> Old style name (current):
> 	/sys/class/leds/netxbig:red:power
> 
> New style name:
> 	/sys/class/leds/red:power (we could also think of dropping
>                                    color from name and adding sysfs
>                                    file for it)

I believe color needs to stay: it is common to have "green:battery"
for "battery ok" and "yellow:battery" for charging, for
example. Notification LED has three channels, "red", "green",
"blue"...

Thanks for looking into this,
									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] 46+ messages in thread

* Re: Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board]
  2018-04-15 16:15                 ` Pavel Machek
@ 2018-04-15 18:30                   ` Jacek Anaszewski
  0 siblings, 0 replies; 46+ messages in thread
From: Jacek Anaszewski @ 2018-04-15 18:30 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Rob Herring, Oleh Kravchenko, devicetree, Linux LED Subsystem

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

On 04/15/2018 06:15 PM, Pavel Machek wrote:
> Hi!
> 
>>>> A case I care about is I have a family of boards that all have a
>>>> common defined set of 4 LEDs. They could be driven by anything, but I
>>>> want the same interface presented to userspace across boards.
>>>> "
>>>
>>> Yes, and "label" should provide me with that ability as the context
>>> was the practice of putting the controller name in the label.
>>
>> Exactly. There are two options:
>>
>> 1.
>> - label format : "<color>:<function"
>> 2.
>> - label format : "<function>"
>> - new "color" DT property
> 
> We should provide compatibility here.
> 
> So we should really have new "color" property, and probably new
> "function" property, too.
> 
>> The changes in dts files would have to be accompanied by changes in
>> DT parsing part of LED class drivers. Also, I wonder if it wouldn't
>> make sense to add config option to choose between old and new LED
>> naming convention to avoid userspace breakage.
> 
> Both old and new kernels are expected to be working with both old and
> new dts...
> 
> And having config option choosing userland interfaces would not be nice.

Agreed. So the naming pattern will be chosen basing on whether
there is 'label' property available or the 'function' and 'color' ones.

>> It would allow to use dts files with old style labels with
>> newer kernels. The LED class device names would differ like below:
>>
>> Old style name (current):
>> 	/sys/class/leds/netxbig:red:power
>>
>> New style name:
>> 	/sys/class/leds/red:power (we could also think of dropping
>>                                    color from name and adding sysfs
>>                                    file for it)
> 
> I believe color needs to stay: it is common to have "green:battery"
> for "battery ok" and "yellow:battery" for charging, for
> example. Notification LED has three channels, "red", "green",
> "blue"...

I don't have a strong opinion on that, so ack.

> Thanks for looking into this,

Thanks for the feedback. I'll try to come up with an initial
patchset when I'll find a moment.

-- 
Best regards,
Jacek Anaszewski


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

end of thread, other threads:[~2018-04-15 18:30 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <026d9ec2-f2bd-18b9-d5fa-f593d40e2f57@kaa.org.ua>
2018-03-12 15:33 ` [PATCH] leds: add LED driver for CR0014114 board Oleh Kravchenko
2018-03-12 15:45   ` Peter Meerwald-Stadler
2018-03-12 15:54     ` Oleh Kravchenko
2018-03-17  8:19   ` Jacek Anaszewski
2018-03-12 15:58 ` [PATCH v2] " Oleh Kravchenko
2018-03-13 12:45   ` [PATCH v3] " Oleh Kravchenko
2018-03-16 21:14     ` Pavel Machek
2018-03-16 21:29       ` Oleh Kravchenko
2018-03-16 21:33         ` Pavel Machek
2018-03-16 21:40           ` Oleh Kravchenko
2018-03-16 22:10             ` Pavel Machek
2018-03-26 12:15             ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
2018-03-26 12:15               ` [PATCH v4 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
2018-03-27 16:14               ` [PATCH v4 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Rob Herring
2018-03-27 16:49               ` [PATCH " Oleh Kravchenko
2018-03-27 16:49                 ` [PATCH 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
2018-03-27 20:58                   ` Jacek Anaszewski
2018-03-28  6:53                   ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
2018-03-28  6:53                     ` [PATCH v6 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
2018-03-28 15:43                     ` [PATCH v6 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Rob Herring
2018-03-28 18:56                     ` [PATCH v7 " Oleh Kravchenko
2018-03-28 18:56                       ` [PATCH v7 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
2018-04-02 12:53                         ` [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Oleh Kravchenko
2018-04-02 12:53                           ` [PATCH v8 2/2] leds: add LED driver for CR0014114 board Oleh Kravchenko
2018-04-03 10:48                             ` Pavel Machek
2018-04-10 18:59                             ` Jacek Anaszewski
2018-04-10 20:24                               ` Oleh Kravchenko
2018-04-09 19:18                           ` [PATCH v8 1/2] dt-bindings: Add vendor prefix and docs for CR0014114 Jacek Anaszewski
2018-04-09 21:10                           ` Rob Herring
2018-03-27 20:58                 ` [PATCH " Jacek Anaszewski
2018-03-28  6:36                   ` Oleh Kravchenko
2018-03-28 19:21                     ` Jacek Anaszewski
2018-03-28 19:48                       ` Oleh Kravchenko
2018-03-28 20:23                         ` Jacek Anaszewski
2018-03-29 18:56                           ` Oleh Kravchenko
2018-03-30 10:10                             ` Jacek Anaszewski
2018-03-18 12:49     ` [PATCH v3] leds: add LED driver for CR0014114 board Rob Herring
2018-03-18 20:03       ` Jacek Anaszewski
2018-03-18 23:38         ` Rob Herring
2018-03-19 21:18           ` Standardized LED function names [was: Re: [PATCH v3] leds: add LED driver for CR0014114 board] Jacek Anaszewski
2018-03-27 15:31             ` Rob Herring
2018-03-30 10:53               ` Jacek Anaszewski
2018-03-30 20:59                 ` Rob Herring
2018-04-15 16:15                 ` Pavel Machek
2018-04-15 18:30                   ` Jacek Anaszewski
2018-04-15 16:15             ` Pavel Machek

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).