devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/2] dt-bindings: leds: Add binding for spi-byte LED.
@ 2019-05-05 12:52 oss
  2019-05-05 12:52 ` [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver oss
  0 siblings, 1 reply; 8+ messages in thread
From: oss @ 2019-05-05 12:52 UTC (permalink / raw)
  To: linux-leds, devicetree, Jacek Anaszewski, Pavel Machek
  Cc: Dan Murphy, Rob Herring, Mark Rutland, Christian Mauderer

From: Christian Mauderer <oss@c-mauderer.de>

This patch adds the binding documentation for a simple SPI based LED
controller which use only one byte for setting the brightness.

Signed-off-by: Christian Mauderer <oss@c-mauderer.de>
---

Changes compared to v1:
- rename ubnt-spi to leds-spi-byte
- rename "ubnt-spi,off_bright" and "ubnt-spi,max_bright" to
  "leds-spi-byte,off-value" and "leds-spi-byte,max-value" and mark them required
- rename led-controller node to "led-controller"
- extend description
- remove SPI controller
- use "white:status" for the example label


 .../bindings/leds/leds-spi-byte.txt           | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-spi-byte.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-spi-byte.txt b/Documentation/devicetree/bindings/leds/leds-spi-byte.txt
new file mode 100644
index 000000000000..1dd6ab03a56d
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-spi-byte.txt
@@ -0,0 +1,47 @@
+* Single Byte SPI LED Device Driver.
+
+The driver can be used for controllers with a very simple SPI protocol: Only one
+byte will be sent. The value of the byte can be any value between the off-value
+and max-value defined in the properties.
+
+One example where the driver can be used is the controller in Ubiquiti airCube
+ISP devices. That LED controller is based on a 8 bit microcontroller (SONiX
+8F26E611LA) that has been programmed to control the single LED of the device.
+The controller supports four modes depending on the highest two bits in a byte:
+One setting for brightness, the other three provide different blink patterns.
+With the leds-spi-byte driver a basic support for the brightness mode of that
+controller can be easily achieved by setting the minimum and maximum to the
+brightness modes minimum and maximum byte value.
+
+Required properties:
+- compatible:		Should be "leds-spi-byte".
+
+Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
+apply. In particular, "reg" and "spi-max-frequency" properties must be given.
+
+The driver currently only supports one LED. The properties of the LED are
+configured in a sub-node in the device node.
+
+LED sub-node properties:
+- label:
+	see Documentation/devicetree/bindings/leds/common.txt
+- leds-spi-byte,off-value:
+	The SPI byte value that should be sent to switch the LED off. Has to be
+	smaller than max-value. Range: 0 to 254.
+- leds-spi-byte,max-value:
+	The SPI byte value that should be sent to set the LED to the maximum
+	brightness. Has to be bigger than off-value. Range: 1 to 255.
+
+Example:
+
+led-controller@0 {
+	compatible = "leds-spi-byte";
+	reg = <0>;
+	spi-max-frequency = <100000>;
+
+	led {
+		label = "white:status";
+		leds-spi-byte,off-value = /bits/ 8 <0>;
+		leds-spi-byte,max-value = /bits/ 8 <63>;
+	};
+};
-- 
2.21.0

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

* [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver
  2019-05-05 12:52 [PATCH v2 1/2] dt-bindings: leds: Add binding for spi-byte LED oss
@ 2019-05-05 12:52 ` oss
  2019-05-05 14:48   ` Jacek Anaszewski
  0 siblings, 1 reply; 8+ messages in thread
From: oss @ 2019-05-05 12:52 UTC (permalink / raw)
  To: linux-leds, devicetree, Jacek Anaszewski, Pavel Machek
  Cc: Dan Murphy, Rob Herring, Mark Rutland, Christian Mauderer

From: Christian Mauderer <oss@c-mauderer.de>

This driver adds support for simple SPI based LED controller which use
only one byte for setting the brightness.

Signed-off-by: Christian Mauderer <oss@c-mauderer.de>
---

Changes compared to v1:
- rename ubnt-spi to leds-spi-byte
- rework probe to get all parameters before allocating anything -> error checks
  all collected together and initializing all fields of the device structure is
  more obvious
- fix some unsteady indentations during variable declaration
- rework comment with protocol explanation
- handle case of off_bright > max_bright
- fix spelling in commit message
- mutex_destroy in remove
- change label to use either use the given one without a prefix or a default one
  NOTE: Should the label be a mandatory parameter instead of the default label?


 drivers/leds/Kconfig         |  12 ++++
 drivers/leds/Makefile        |   1 +
 drivers/leds/leds-spi-byte.c | 133 +++++++++++++++++++++++++++++++++++
 3 files changed, 146 insertions(+)
 create mode 100644 drivers/leds/leds-spi-byte.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index a72f97fca57b..0866c55e8004 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -766,6 +766,18 @@ config LEDS_NIC78BX
 	  To compile this driver as a module, choose M here: the module
 	  will be called leds-nic78bx.
 
+config LEDS_SPI_BYTE
+	tristate "LED support for SPI LED controller with a single byte"
+	depends on LEDS_CLASS
+	depends on SPI
+	depends on OF
+	help
+	  This option enables support for LED controller which use a single byte
+	  for controlling the brightness. The minimum and maximum value of the
+	  byte can be configured via a device tree. The driver can be used for
+	  example for the microcontroller based LED controller in the Ubiquiti
+	  airCube ISP devices.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 4c1b0054f379..1786d7e2c236 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_LEDS_PM8058)		+= leds-pm8058.o
 obj-$(CONFIG_LEDS_MLXCPLD)		+= leds-mlxcpld.o
 obj-$(CONFIG_LEDS_MLXREG)		+= leds-mlxreg.o
 obj-$(CONFIG_LEDS_NIC78BX)		+= leds-nic78bx.o
+obj-$(CONFIG_LEDS_SPI_BYTE)		+= leds-spi-byte.o
 obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
 obj-$(CONFIG_LEDS_SC27XX_BLTC)		+= leds-sc27xx-bltc.o
diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c
new file mode 100644
index 000000000000..19a68bce1a7c
--- /dev/null
+++ b/drivers/leds/leds-spi-byte.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Christian Mauderer <oss@c-mauderer.de>
+
+/*
+ * The driver can be used for controllers with a very simple SPI protocol: Only
+ * one byte between an off and a max value (defined by devicetree) will be sent.
+ */
+
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mutex.h>
+#include <uapi/linux/uleds.h>
+
+struct spi_byte_led {
+	struct led_classdev	ldev;
+	struct spi_device	*spi;
+	char			name[LED_MAX_NAME_SIZE];
+	struct mutex		mutex;
+	u8			off_value;
+	u8			max_value;
+};
+
+static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
+					    enum led_brightness brightness)
+{
+	struct spi_byte_led *led = container_of(dev, struct spi_byte_led, ldev);
+	u8 value;
+	int ret;
+
+	value = (u8) brightness + led->off_value;
+
+	mutex_lock(&led->mutex);
+	ret = spi_write(led->spi, &value, sizeof(value));
+	mutex_unlock(&led->mutex);
+
+	return ret;
+}
+
+static int spi_byte_probe(struct spi_device *spi)
+{
+	struct device *dev = &spi->dev;
+	struct device_node *child;
+	struct spi_byte_led *led;
+	int ret;
+	const char *default_name = "leds-spi-byte::";
+	const char *name;
+	u8 off_value;
+	u8 max_value;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	if (of_get_child_count(dev->of_node) != 1) {
+		dev_err(dev, "Device must have exactly one LED sub-node.");
+		return -EINVAL;
+	}
+	child = of_get_next_child(dev->of_node, NULL);
+
+	ret = of_property_read_string(child, "label", &name);
+	if (ret != 0)
+		name = default_name;
+
+	ret = of_property_read_u8(child, "leds-spi-byte,off-value", &off_value);
+	if (ret != 0) {
+		dev_err(dev, "LED node needs a leds-spi-byte,off-value.");
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u8(child, "leds-spi-byte,max-value", &max_value);
+	if (ret != 0) {
+		dev_err(dev, "LED node needs a leds-spi-byte,max-value.");
+		return -EINVAL;
+	}
+
+	if (off_value >= max_value) {
+		dev_err(dev, "off-value has to be smaller than max-value.");
+		return -EINVAL;
+	}
+
+	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
+
+	led->spi = spi;
+	strlcpy(led->name, name, sizeof(led->name));
+	mutex_init(&led->mutex);
+	led->off_value = off_value;
+	led->max_value = max_value;
+	led->ldev.name = led->name;
+	led->ldev.brightness = LED_OFF;
+	led->ldev.max_brightness = led->max_value - led->off_value;
+	led->ldev.brightness_set_blocking = spi_byte_brightness_set_blocking;
+	ret = led_classdev_register(&spi->dev, &led->ldev);
+	if (ret >= 0)
+		spi_set_drvdata(spi, led);
+
+	return ret;
+}
+
+static int spi_byte_remove(struct spi_device *spi)
+{
+	struct spi_byte_led	*led = spi_get_drvdata(spi);
+
+	led_classdev_unregister(&led->ldev);
+	mutex_destroy(&led->mutex);
+
+	return 0;
+}
+
+static const struct of_device_id spi_byte_dt_ids[] = {
+	{ .compatible = "leds-spi-byte", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, spi_byte_dt_ids);
+
+static struct spi_driver spi_byte_driver = {
+	.probe		= spi_byte_probe,
+	.remove		= spi_byte_remove,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= spi_byte_dt_ids,
+	},
+};
+
+module_spi_driver(spi_byte_driver);
+
+MODULE_AUTHOR("Christian Mauderer <oss@c-mauderer.de>");
+MODULE_DESCRIPTION("single byte SPI LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:leds-spi-byte");
-- 
2.21.0

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

* Re: [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver
  2019-05-05 12:52 ` [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver oss
@ 2019-05-05 14:48   ` Jacek Anaszewski
  2019-05-05 14:55     ` Christian Mauderer
  2019-05-05 20:12     ` Pavel Machek
  0 siblings, 2 replies; 8+ messages in thread
From: Jacek Anaszewski @ 2019-05-05 14:48 UTC (permalink / raw)
  To: oss, linux-leds, devicetree, Pavel Machek
  Cc: Dan Murphy, Rob Herring, Mark Rutland

Hi Christian,

Thank you for the update. I have some trivial nits,
please refer below.

On 5/5/19 2:52 PM, oss@c-mauderer.de wrote:
> From: Christian Mauderer <oss@c-mauderer.de>
> 
> This driver adds support for simple SPI based LED controller which use
> only one byte for setting the brightness.
> 
> Signed-off-by: Christian Mauderer <oss@c-mauderer.de>
> ---
> 
> Changes compared to v1:
> - rename ubnt-spi to leds-spi-byte
> - rework probe to get all parameters before allocating anything -> error checks
>    all collected together and initializing all fields of the device structure is
>    more obvious
> - fix some unsteady indentations during variable declaration
> - rework comment with protocol explanation
> - handle case of off_bright > max_bright
> - fix spelling in commit message
> - mutex_destroy in remove
> - change label to use either use the given one without a prefix or a default one
>    NOTE: Should the label be a mandatory parameter instead of the default label?
> 
> 
>   drivers/leds/Kconfig         |  12 ++++
>   drivers/leds/Makefile        |   1 +
>   drivers/leds/leds-spi-byte.c | 133 +++++++++++++++++++++++++++++++++++
>   3 files changed, 146 insertions(+)
>   create mode 100644 drivers/leds/leds-spi-byte.c
> 
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index a72f97fca57b..0866c55e8004 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -766,6 +766,18 @@ config LEDS_NIC78BX
>   	  To compile this driver as a module, choose M here: the module
>   	  will be called leds-nic78bx.
>   
> +config LEDS_SPI_BYTE
> +	tristate "LED support for SPI LED controller with a single byte"
> +	depends on LEDS_CLASS
> +	depends on SPI
> +	depends on OF
> +	help
> +	  This option enables support for LED controller which use a single byte
> +	  for controlling the brightness. The minimum and maximum value of the
> +	  byte can be configured via a device tree. The driver can be used for
> +	  example for the microcontroller based LED controller in the Ubiquiti
> +	  airCube ISP devices.
> +
>   comment "LED Triggers"
>   source "drivers/leds/trigger/Kconfig"
>   
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 4c1b0054f379..1786d7e2c236 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -75,6 +75,7 @@ obj-$(CONFIG_LEDS_PM8058)		+= leds-pm8058.o
>   obj-$(CONFIG_LEDS_MLXCPLD)		+= leds-mlxcpld.o
>   obj-$(CONFIG_LEDS_MLXREG)		+= leds-mlxreg.o
>   obj-$(CONFIG_LEDS_NIC78BX)		+= leds-nic78bx.o
> +obj-$(CONFIG_LEDS_SPI_BYTE)		+= leds-spi-byte.o
>   obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
>   obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
>   obj-$(CONFIG_LEDS_SC27XX_BLTC)		+= leds-sc27xx-bltc.o
> diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c
> new file mode 100644
> index 000000000000..19a68bce1a7c
> --- /dev/null
> +++ b/drivers/leds/leds-spi-byte.c
> @@ -0,0 +1,133 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2019 Christian Mauderer <oss@c-mauderer.de>
> +
> +/*
> + * The driver can be used for controllers with a very simple SPI protocol: Only
> + * one byte between an off and a max value (defined by devicetree) will be sent.
> + */
> +
> +#include <linux/leds.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/spi/spi.h>
> +#include <linux/mutex.h>
> +#include <uapi/linux/uleds.h>
> +
> +struct spi_byte_led {
> +	struct led_classdev	ldev;
> +	struct spi_device	*spi;
> +	char			name[LED_MAX_NAME_SIZE];
> +	struct mutex		mutex;
> +	u8			off_value;
> +	u8			max_value;
> +};
> +
> +static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
> +					    enum led_brightness brightness)
> +{
> +	struct spi_byte_led *led = container_of(dev, struct spi_byte_led, ldev);
> +	u8 value;
> +	int ret;
> +
> +	value = (u8) brightness + led->off_value;
> +
> +	mutex_lock(&led->mutex);
> +	ret = spi_write(led->spi, &value, sizeof(value));
> +	mutex_unlock(&led->mutex);
> +
> +	return ret;
> +}
> +
> +static int spi_byte_probe(struct spi_device *spi)
> +{
> +	struct device *dev = &spi->dev;
> +	struct device_node *child;
> +	struct spi_byte_led *led;
> +	int ret;
> +	const char *default_name = "leds-spi-byte::";
> +	const char *name;
> +	u8 off_value;
> +	u8 max_value;
> +
> +	if (!dev->of_node)
> +		return -ENODEV;
> +
> +	if (of_get_child_count(dev->of_node) != 1) {
> +		dev_err(dev, "Device must have exactly one LED sub-node.");
> +		return -EINVAL;
> +	}
> +	child = of_get_next_child(dev->of_node, NULL);
> +
> +	ret = of_property_read_string(child, "label", &name);
> +	if (ret != 0)

It is more customary to have "if (ret)" in such cases.
Applies to all occurrences below.

> +		name = default_name;
> +
> +	ret = of_property_read_u8(child, "leds-spi-byte,off-value", &off_value);
> +	if (ret != 0) {
> +		dev_err(dev, "LED node needs a leds-spi-byte,off-value.");
> +		return -EINVAL;
> +	}
> +
> +	ret = of_property_read_u8(child, "leds-spi-byte,max-value", &max_value);
> +	if (ret != 0) {
> +		dev_err(dev, "LED node needs a leds-spi-byte,max-value.");
> +		return -EINVAL;
> +	}
> +
> +	if (off_value >= max_value) {
> +		dev_err(dev, "off-value has to be smaller than max-value.");
> +		return -EINVAL;
> +	}
> +
> +	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
> +	if (!led)
> +		return -ENOMEM;
> +
> +	led->spi = spi;
> +	strlcpy(led->name, name, sizeof(led->name));
> +	mutex_init(&led->mutex);
> +	led->off_value = off_value;
> +	led->max_value = max_value;
> +	led->ldev.name = led->name;
> +	led->ldev.brightness = LED_OFF;

This line is redundant - already zeroed by kzalloc.

> +	led->ldev.max_brightness = led->max_value - led->off_value;
> +	led->ldev.brightness_set_blocking = spi_byte_brightness_set_blocking;
> +	ret = led_classdev_register(&spi->dev, &led->ldev);

Please use devm_led_classdev_register().

> +	if (ret >= 0)
> +		spi_set_drvdata(spi, led);

This looks quite odd. Please shape it as below:

	if (ret)
		return ret

	spi_set_drvdata(spi, led);

> +
> +	return ret;

	s/ret/0/

> +}
> +
> +static int spi_byte_remove(struct spi_device *spi)
> +{
> +	struct spi_byte_led	*led = spi_get_drvdata(spi);
> +
> +	led_classdev_unregister(&led->ldev);
> +	mutex_destroy(&led->mutex);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id spi_byte_dt_ids[] = {
> +	{ .compatible = "leds-spi-byte", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, spi_byte_dt_ids);
> +
> +static struct spi_driver spi_byte_driver = {
> +	.probe		= spi_byte_probe,
> +	.remove		= spi_byte_remove,
> +	.driver = {
> +		.name		= KBUILD_MODNAME,
> +		.of_match_table	= spi_byte_dt_ids,
> +	},
> +};
> +
> +module_spi_driver(spi_byte_driver);
> +
> +MODULE_AUTHOR("Christian Mauderer <oss@c-mauderer.de>");
> +MODULE_DESCRIPTION("single byte SPI LED driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("spi:leds-spi-byte");
> 

-- 
Best regards,
Jacek Anaszewski

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

* Re: [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver
  2019-05-05 14:48   ` Jacek Anaszewski
@ 2019-05-05 14:55     ` Christian Mauderer
  2019-05-05 20:12     ` Pavel Machek
  1 sibling, 0 replies; 8+ messages in thread
From: Christian Mauderer @ 2019-05-05 14:55 UTC (permalink / raw)
  To: Jacek Anaszewski, linux-leds, devicetree, Pavel Machek
  Cc: Dan Murphy, Rob Herring, Mark Rutland

On 05/05/2019 16:48, Jacek Anaszewski wrote:
> Hi Christian,
> 
> Thank you for the update. I have some trivial nits,
> please refer below.

Hello Jacek,

thanks for having a look. I don't have problems with the changes and
will integrate them into a v3. Sorry for the style nitpicks for example
with the (ret != 0). It's different for each project and I haven't
written much code with Linux style yet.

I'll wait for another few hours in case someone else wants additional
changes before posting v3.

Best regards

Christian

> 
> On 5/5/19 2:52 PM, oss@c-mauderer.de wrote:
>> From: Christian Mauderer <oss@c-mauderer.de>
>>
>> This driver adds support for simple SPI based LED controller which use
>> only one byte for setting the brightness.
>>
>> Signed-off-by: Christian Mauderer <oss@c-mauderer.de>
>> ---
>>
>> Changes compared to v1:
>> - rename ubnt-spi to leds-spi-byte
>> - rework probe to get all parameters before allocating anything ->
>> error checks
>>    all collected together and initializing all fields of the device
>> structure is
>>    more obvious
>> - fix some unsteady indentations during variable declaration
>> - rework comment with protocol explanation
>> - handle case of off_bright > max_bright
>> - fix spelling in commit message
>> - mutex_destroy in remove
>> - change label to use either use the given one without a prefix or a
>> default one
>>    NOTE: Should the label be a mandatory parameter instead of the
>> default label?
>>
>>
>>   drivers/leds/Kconfig         |  12 ++++
>>   drivers/leds/Makefile        |   1 +
>>   drivers/leds/leds-spi-byte.c | 133 +++++++++++++++++++++++++++++++++++
>>   3 files changed, 146 insertions(+)
>>   create mode 100644 drivers/leds/leds-spi-byte.c
>>
>> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
>> index a72f97fca57b..0866c55e8004 100644
>> --- a/drivers/leds/Kconfig
>> +++ b/drivers/leds/Kconfig
>> @@ -766,6 +766,18 @@ config LEDS_NIC78BX
>>         To compile this driver as a module, choose M here: the module
>>         will be called leds-nic78bx.
>>   +config LEDS_SPI_BYTE
>> +    tristate "LED support for SPI LED controller with a single byte"
>> +    depends on LEDS_CLASS
>> +    depends on SPI
>> +    depends on OF
>> +    help
>> +      This option enables support for LED controller which use a
>> single byte
>> +      for controlling the brightness. The minimum and maximum value
>> of the
>> +      byte can be configured via a device tree. The driver can be
>> used for
>> +      example for the microcontroller based LED controller in the
>> Ubiquiti
>> +      airCube ISP devices.
>> +
>>   comment "LED Triggers"
>>   source "drivers/leds/trigger/Kconfig"
>>   diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
>> index 4c1b0054f379..1786d7e2c236 100644
>> --- a/drivers/leds/Makefile
>> +++ b/drivers/leds/Makefile
>> @@ -75,6 +75,7 @@ obj-$(CONFIG_LEDS_PM8058)        += leds-pm8058.o
>>   obj-$(CONFIG_LEDS_MLXCPLD)        += leds-mlxcpld.o
>>   obj-$(CONFIG_LEDS_MLXREG)        += leds-mlxreg.o
>>   obj-$(CONFIG_LEDS_NIC78BX)        += leds-nic78bx.o
>> +obj-$(CONFIG_LEDS_SPI_BYTE)        += leds-spi-byte.o
>>   obj-$(CONFIG_LEDS_MT6323)        += leds-mt6323.o
>>   obj-$(CONFIG_LEDS_LM3692X)        += leds-lm3692x.o
>>   obj-$(CONFIG_LEDS_SC27XX_BLTC)        += leds-sc27xx-bltc.o
>> diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c
>> new file mode 100644
>> index 000000000000..19a68bce1a7c
>> --- /dev/null
>> +++ b/drivers/leds/leds-spi-byte.c
>> @@ -0,0 +1,133 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (c) 2019 Christian Mauderer <oss@c-mauderer.de>
>> +
>> +/*
>> + * The driver can be used for controllers with a very simple SPI
>> protocol: Only
>> + * one byte between an off and a max value (defined by devicetree)
>> will be sent.
>> + */
>> +
>> +#include <linux/leds.h>
>> +#include <linux/module.h>
>> +#include <linux/of_device.h>
>> +#include <linux/spi/spi.h>
>> +#include <linux/mutex.h>
>> +#include <uapi/linux/uleds.h>
>> +
>> +struct spi_byte_led {
>> +    struct led_classdev    ldev;
>> +    struct spi_device    *spi;
>> +    char            name[LED_MAX_NAME_SIZE];
>> +    struct mutex        mutex;
>> +    u8            off_value;
>> +    u8            max_value;
>> +};
>> +
>> +static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
>> +                        enum led_brightness brightness)
>> +{
>> +    struct spi_byte_led *led = container_of(dev, struct spi_byte_led,
>> ldev);
>> +    u8 value;
>> +    int ret;
>> +
>> +    value = (u8) brightness + led->off_value;
>> +
>> +    mutex_lock(&led->mutex);
>> +    ret = spi_write(led->spi, &value, sizeof(value));
>> +    mutex_unlock(&led->mutex);
>> +
>> +    return ret;
>> +}
>> +
>> +static int spi_byte_probe(struct spi_device *spi)
>> +{
>> +    struct device *dev = &spi->dev;
>> +    struct device_node *child;
>> +    struct spi_byte_led *led;
>> +    int ret;
>> +    const char *default_name = "leds-spi-byte::";
>> +    const char *name;
>> +    u8 off_value;
>> +    u8 max_value;
>> +
>> +    if (!dev->of_node)
>> +        return -ENODEV;
>> +
>> +    if (of_get_child_count(dev->of_node) != 1) {
>> +        dev_err(dev, "Device must have exactly one LED sub-node.");
>> +        return -EINVAL;
>> +    }
>> +    child = of_get_next_child(dev->of_node, NULL);
>> +
>> +    ret = of_property_read_string(child, "label", &name);
>> +    if (ret != 0)
> 
> It is more customary to have "if (ret)" in such cases.
> Applies to all occurrences below.
> 
>> +        name = default_name;
>> +
>> +    ret = of_property_read_u8(child, "leds-spi-byte,off-value",
>> &off_value);
>> +    if (ret != 0) {
>> +        dev_err(dev, "LED node needs a leds-spi-byte,off-value.");
>> +        return -EINVAL;
>> +    }
>> +
>> +    ret = of_property_read_u8(child, "leds-spi-byte,max-value",
>> &max_value);
>> +    if (ret != 0) {
>> +        dev_err(dev, "LED node needs a leds-spi-byte,max-value.");
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (off_value >= max_value) {
>> +        dev_err(dev, "off-value has to be smaller than max-value.");
>> +        return -EINVAL;
>> +    }
>> +
>> +    led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
>> +    if (!led)
>> +        return -ENOMEM;
>> +
>> +    led->spi = spi;
>> +    strlcpy(led->name, name, sizeof(led->name));
>> +    mutex_init(&led->mutex);
>> +    led->off_value = off_value;
>> +    led->max_value = max_value;
>> +    led->ldev.name = led->name;
>> +    led->ldev.brightness = LED_OFF;
> 
> This line is redundant - already zeroed by kzalloc.
> 
>> +    led->ldev.max_brightness = led->max_value - led->off_value;
>> +    led->ldev.brightness_set_blocking =
>> spi_byte_brightness_set_blocking;
>> +    ret = led_classdev_register(&spi->dev, &led->ldev);
> 
> Please use devm_led_classdev_register().
> 
>> +    if (ret >= 0)
>> +        spi_set_drvdata(spi, led);
> 
> This looks quite odd. Please shape it as below:
> 
>     if (ret)
>         return ret
> 
>     spi_set_drvdata(spi, led);
> 
>> +
>> +    return ret;
> 
>     s/ret/0/
> 
>> +}
>> +
>> +static int spi_byte_remove(struct spi_device *spi)
>> +{
>> +    struct spi_byte_led    *led = spi_get_drvdata(spi);
>> +
>> +    led_classdev_unregister(&led->ldev);
>> +    mutex_destroy(&led->mutex);
>> +
>> +    return 0;
>> +}
>> +
>> +static const struct of_device_id spi_byte_dt_ids[] = {
>> +    { .compatible = "leds-spi-byte", },
>> +    {},
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, spi_byte_dt_ids);
>> +
>> +static struct spi_driver spi_byte_driver = {
>> +    .probe        = spi_byte_probe,
>> +    .remove        = spi_byte_remove,
>> +    .driver = {
>> +        .name        = KBUILD_MODNAME,
>> +        .of_match_table    = spi_byte_dt_ids,
>> +    },
>> +};
>> +
>> +module_spi_driver(spi_byte_driver);
>> +
>> +MODULE_AUTHOR("Christian Mauderer <oss@c-mauderer.de>");
>> +MODULE_DESCRIPTION("single byte SPI LED driver");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_ALIAS("spi:leds-spi-byte");
>>
> 

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

* Re: [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver
  2019-05-05 14:48   ` Jacek Anaszewski
  2019-05-05 14:55     ` Christian Mauderer
@ 2019-05-05 20:12     ` Pavel Machek
  2019-05-06  8:48       ` Christian Mauderer
  2019-05-06 18:19       ` Jacek Anaszewski
  1 sibling, 2 replies; 8+ messages in thread
From: Pavel Machek @ 2019-05-05 20:12 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: oss, linux-leds, devicetree, Dan Murphy, Rob Herring,
	Mark Rutland

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

Hi!

> >+	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
> >+	if (!led)
> >+		return -ENOMEM;
> >+
> >+	led->spi = spi;
> >+	strlcpy(led->name, name, sizeof(led->name));
> >+	mutex_init(&led->mutex);
> >+	led->off_value = off_value;
> >+	led->max_value = max_value;
> >+	led->ldev.name = led->name;
> >+	led->ldev.brightness = LED_OFF;
> 
> This line is redundant - already zeroed by kzalloc.

Actually I'd prefer to leave it in. Yes, LED_OFF == 0, and will
probably stay == 0 in future, but...
									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] 8+ messages in thread

* Re: [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver
  2019-05-05 20:12     ` Pavel Machek
@ 2019-05-06  8:48       ` Christian Mauderer
  2019-05-06 18:34         ` Jacek Anaszewski
  2019-05-06 18:19       ` Jacek Anaszewski
  1 sibling, 1 reply; 8+ messages in thread
From: Christian Mauderer @ 2019-05-06  8:48 UTC (permalink / raw)
  To: Pavel Machek, Jacek Anaszewski
  Cc: linux-leds, devicetree, Dan Murphy, Rob Herring, Mark Rutland

On 05/05/2019 22:12, Pavel Machek wrote:
> Hi!
> 
>>> +	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
>>> +	if (!led)
>>> +		return -ENOMEM;
>>> +
>>> +	led->spi = spi;
>>> +	strlcpy(led->name, name, sizeof(led->name));
>>> +	mutex_init(&led->mutex);
>>> +	led->off_value = off_value;
>>> +	led->max_value = max_value;
>>> +	led->ldev.name = led->name;
>>> +	led->ldev.brightness = LED_OFF;
>>
>> This line is redundant - already zeroed by kzalloc.
> 
> Actually I'd prefer to leave it in. Yes, LED_OFF == 0, and will
> probably stay == 0 in future, but...
> 									Pavel
> 

Before I send v4: Currently the initial value isn't written to the LED
anywhere. The state that is set by U-Boot is just kept till the first
write to the brightness file.

I didn't implement "default-state" because the OpenWRT user space sets
the LED anyway a few seconds later (which is still my use case for that
driver). But now I noted that there is a remark in the documentation of
the option "default-state" in devicetree/bindings/leds/common.txt: "The
default is off if this property is not present."

Should I send an initial value to the device during initialization or is
it OK to just keep the original state?

Best regards

Christian

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

* Re: [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver
  2019-05-05 20:12     ` Pavel Machek
  2019-05-06  8:48       ` Christian Mauderer
@ 2019-05-06 18:19       ` Jacek Anaszewski
  1 sibling, 0 replies; 8+ messages in thread
From: Jacek Anaszewski @ 2019-05-06 18:19 UTC (permalink / raw)
  To: Pavel Machek
  Cc: oss, linux-leds, devicetree, Dan Murphy, Rob Herring,
	Mark Rutland

On 5/5/19 10:12 PM, Pavel Machek wrote:
> Hi!
> 
>>> +	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
>>> +	if (!led)
>>> +		return -ENOMEM;
>>> +
>>> +	led->spi = spi;
>>> +	strlcpy(led->name, name, sizeof(led->name));
>>> +	mutex_init(&led->mutex);
>>> +	led->off_value = off_value;
>>> +	led->max_value = max_value;
>>> +	led->ldev.name = led->name;
>>> +	led->ldev.brightness = LED_OFF;
>>
>> This line is redundant - already zeroed by kzalloc.
> 
> Actually I'd prefer to leave it in. Yes, LED_OFF == 0, and will
> probably stay == 0 in future, but...

but what? I don't really see a sufficient justification for
leaving it. Just redundant line. In other place in my LED naming
patch set you wondered if it wouldn't have been better to initialize
a struct partly using initialization list, I suspect to save few
LOC. So here you seem to be inconsistent :-)

-- 
Best regards,
Jacek Anaszewski

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

* Re: [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver
  2019-05-06  8:48       ` Christian Mauderer
@ 2019-05-06 18:34         ` Jacek Anaszewski
  0 siblings, 0 replies; 8+ messages in thread
From: Jacek Anaszewski @ 2019-05-06 18:34 UTC (permalink / raw)
  To: Christian Mauderer, Pavel Machek
  Cc: linux-leds, devicetree, Dan Murphy, Rob Herring, Mark Rutland

Hi Christian,

On 5/6/19 10:48 AM, Christian Mauderer wrote:
> On 05/05/2019 22:12, Pavel Machek wrote:
>> Hi!
>>
>>>> +	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
>>>> +	if (!led)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	led->spi = spi;
>>>> +	strlcpy(led->name, name, sizeof(led->name));
>>>> +	mutex_init(&led->mutex);
>>>> +	led->off_value = off_value;
>>>> +	led->max_value = max_value;
>>>> +	led->ldev.name = led->name;
>>>> +	led->ldev.brightness = LED_OFF;
>>>
>>> This line is redundant - already zeroed by kzalloc.
>>
>> Actually I'd prefer to leave it in. Yes, LED_OFF == 0, and will
>> probably stay == 0 in future, but...
>> 									Pavel
>>
> 
> Before I send v4: Currently the initial value isn't written to the LED
> anywhere. The state that is set by U-Boot is just kept till the first
> write to the brightness file.
> 
> I didn't implement "default-state" because the OpenWRT user space sets
> the LED anyway a few seconds later (which is still my use case for that
> driver). But now I noted that there is a remark in the documentation of
> the option "default-state" in devicetree/bindings/leds/common.txt: "The
> default is off if this property is not present."
> 
> Should I send an initial value to the device during initialization or is
> it OK to just keep the original state?

Yes, I would make use of default-state in this case.

-- 
Best regards,
Jacek Anaszewski

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

end of thread, other threads:[~2019-05-06 18:34 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-05-05 12:52 [PATCH v2 1/2] dt-bindings: leds: Add binding for spi-byte LED oss
2019-05-05 12:52 ` [PATCH v2 2/2] leds: spi-byte: add single byte SPI LED driver oss
2019-05-05 14:48   ` Jacek Anaszewski
2019-05-05 14:55     ` Christian Mauderer
2019-05-05 20:12     ` Pavel Machek
2019-05-06  8:48       ` Christian Mauderer
2019-05-06 18:34         ` Jacek Anaszewski
2019-05-06 18:19       ` Jacek Anaszewski

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