All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lee Jones <lee@kernel.org>
To: Steffen Trumtrar <s.trumtrar@pengutronix.de>
Cc: Pavel Machek <pavel@kernel.org>,
	linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org
Subject: Re: [PATCH RESEND] leds: lp5860: detect and report fault state
Date: Mon, 9 Mar 2026 18:17:02 +0000	[thread overview]
Message-ID: <20260309181702.GX183676@google.com> (raw)
In-Reply-To: <20260305-v6-19-topic-ti-lp5860-fault-v1-1-2219827f0524@pengutronix.de>

On Thu, 05 Mar 2026, Steffen Trumtrar wrote:

> The lp5860 can detect shorts and open circuits. If an open (LOD) or
> short (LSD) is detected, the global bit in LP5860_FAULT_STATE is set.
> The channel that caused this can be read from the corresponding Dot_lsdX
> and Dot_lodX register and bit offset.
> 
> The global bits can be cleared by writing 0xf to the LOD/LSD_clear
> register.
> 
> Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
> ---
>  Documentation/ABI/testing/sysfs-class-spi-lp5860 |  50 +++++++++
>  drivers/leds/rgb/leds-lp5860-core.c              | 135 +++++++++++++++++++++++
>  include/linux/platform_data/leds-lp5860.h        |  12 +-
>  3 files changed, 196 insertions(+), 1 deletion(-)

I don't have a general issue with this.

Couple of nits to fix.

Also give the LED community chance to take a better look.

> diff --git a/Documentation/ABI/testing/sysfs-class-spi-lp5860 b/Documentation/ABI/testing/sysfs-class-spi-lp5860
> index 80b22a9d66421..ded9eec855bd9 100644
> --- a/Documentation/ABI/testing/sysfs-class-spi-lp5860
> +++ b/Documentation/ABI/testing/sysfs-class-spi-lp5860
> @@ -21,3 +21,53 @@ Contact:        Steffen Trumtrar <kernel@pengutronix.de>
>  Description:
>  	Contains and sets the global brightness for the R color group.
>  	Can be adjusted in 128 steps from 0% to 100% of the maximum brightness.

What is this applied to?

> +
> +What:           /sys/class/spi_master/spi<bus>/spi<bus>.<dev>/fault_state
> +Date:           January 2026
> +KernelVersion:  6.19

Update.

> +Contact:        Steffen Trumtrar <kernel@pengutronix.de>
> +Description:
> +	Contains and sets the global fault state:
> +
> +	* 3: Open and short detected
> +	* 2: Open detected
> +	* 1: Short detected
> +
> +	Can be cleared by writing the corresponding value back to fault_state.
> +
> +	Example usage::
> +
> +		## Read
> +		# cat /sys/class/spi_master/spi<bus>/spi<bus>.<dev>/fault_state
> +		2
> +
> +		## Write
> +		# echo 2 > /sys/class/spi_master/spi<bus>/spi<bus>.<dev>/fault_state
> +
> +What:           /sys/class/spi_master/spi<bus>/spi<bus>.<dev>/fault_state_open
> +Date:           January 2026
> +KernelVersion:  6.19
> +Contact:        Steffen Trumtrar <kernel@pengutronix.de>
> +Description:
> +	Contains all LEDs and channels where an open condition was detected.
> +	The format is ledname:channel.
> +
> +	Example usage::
> +
> +		## Read
> +		# cat /sys/class/spi_master/spi<bus>/spi<bus>.<dev>/fault_state_open
> +		rgb1:0 rgb2:4
> +
> +What:           /sys/class/spi_master/spi<bus>/spi<bus>.<dev>/fault_state_short
> +Date:           May 2025
> +KernelVersion:  6.15
> +Contact:        Steffen Trumtrar <kernel@pengutronix.de>
> +Description:
> +	Contains all LEDs and channels where a short condition was detected.
> +	The format is ledname:channel.
> +
> +	Example usage::
> +
> +		## Read
> +		# cat /sys/class/spi_master/spi<bus>/spi<bus>.<dev>/fault_state_short
> +		rgb1:0 rgb2:4
> diff --git a/drivers/leds/rgb/leds-lp5860-core.c b/drivers/leds/rgb/leds-lp5860-core.c
> index 79a932edd1d24..ef00577a63a73 100644
> --- a/drivers/leds/rgb/leds-lp5860-core.c
> +++ b/drivers/leds/rgb/leds-lp5860-core.c
> @@ -19,6 +19,138 @@ static struct lp5860_led *mcled_cdev_to_led(struct led_classdev_mc *mc_cdev)
>  	return container_of(mc_cdev, struct lp5860_led, mc_cdev);
>  }
>  
> +static const char *lp5860_find_led(struct lp5860 *lp, unsigned int idx)

lp5860_led_name()

> +{
> +	struct mc_subled *mc_led_info;
> +	struct lp5860_led *led;

You could define these inside the scope.

> +	int i, j;
> +
> +	for (i = lp->leds_count - 1; i >= 0; i--) {

What's the reason for counting downwards?

> +		led = &lp->leds[i];
> +
> +		mc_led_info = led->mc_cdev.subled_info;
> +
> +		for (j = 0; j < led->mc_cdev.num_colors; j++) {

for (int j ... ?

> +			if (mc_led_info[j].channel == idx)

Is there no guarantee that j == channel?

Are there gaps?

> +				return led->mc_cdev.led_cdev.dev->kobj.name;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static ssize_t lp5860_fault_state_lod_lsd(struct lp5860 *led, char *buf,

What does that name even mean?

Can it be improved?

> +					  unsigned int reg, unsigned int length)
> +{
> +	unsigned int value = 0;
> +	unsigned int dot, bit;
> +	unsigned int max_bits;
> +	unsigned int offset = 0;
> +	int len = 0;
> +	bool match = false;

This doesn't need to be initialised.

> +	int ret;
> +
> +	for (dot = 0; dot < length; dot++) {
> +		match = false;

-ENOSQUISH - add a '\n'

> +		ret = regmap_read(led->regmap, reg + dot, &value)
> +		if (ret)
> +			return ret;
> +
> +		max_bits = BITS_PER_BYTE;
> +		/* every 3rd Dot_x register only has 2 bits */

Sentences start with an uppercase char.

> +		if (dot % 3 == 2)
> +			max_bits = 2;
> +
> +		for (bit = 0; bit < max_bits; bit++) {
> +			offset++;

-ENOSQUISH - add a '\n'

> +			if (value & BIT(bit)) {
> +				len += sprintf(buf + len, "%s:%d", lp5860_find_led(led, offset),
> +					       offset - 1);
> +				match = true;
> +				len += sprintf(buf + len, " ");
> +			}
> +		}
> +	}
> +
> +	buf[len++] = '\n';
> +
> +	return len;
> +}
> +
> +static ssize_t lp5860_fault_state_open_show(struct device *dev,
> +					    struct device_attribute *attr,
> +					    char *buf)
> +{
> +	struct lp5860 *led = dev_get_drvdata(dev);
> +	unsigned int value = 0;
> +	int ret;
> +
> +	ret = regmap_read(led->regmap, LP5860_REG_FAULT_STATE, &value);
> +	if (ret)
> +		return ret;
> +
> +	if (!(value & LP5860_FAULT_STATE_LOD))
> +		return 0;
> +
> +	return lp5860_fault_state_lod_lsd(led, buf, LP5860_REG_DOT_LOD_START,
> +					  LP5860_DOT_LOD_LENGTH);
> +}
> +static LP5860_DEV_ATTR_R(fault_state_open);
> +
> +static ssize_t lp5860_fault_state_short_show(struct device *dev,
> +					     struct device_attribute *attr, char *buf)
> +{
> +	struct lp5860 *led = dev_get_drvdata(dev);
> +	unsigned int value = 0;

Can regmap_read() succeed and not initialise value?

> +	int ret;
> +
> +	ret = regmap_read(led->regmap, LP5860_REG_FAULT_STATE, &value);
> +	if (ret)
> +		return ret;
> +
> +	if (!(value & LP5860_FAULT_STATE_LSD))
> +		return 0;
> +
> +	return lp5860_fault_state_lod_lsd(led, buf, LP5860_REG_DOT_LSD_START,
> +					  LP5860_DOT_LSD_LENGTH);
> +}
> +static LP5860_DEV_ATTR_R(fault_state_short);
> +
> +static ssize_t lp5860_fault_state_show(struct device *dev,
> +				  struct device_attribute *attr, char *buf)
> +{
> +	struct lp5860 *led = dev_get_drvdata(dev);
> +	unsigned int value = 0;
> +	int ret;
> +
> +	ret = regmap_read(led->regmap, LP5860_REG_FAULT_STATE, &value);
> +	if (ret)
> +		return ret;

-ENOSQUISH - add a '\n'

> +	return sysfs_emit(buf, "%d\n", (value & 0x3));
> +}
> +
> +static ssize_t lp5860_fault_state_store(struct device *dev,
> +					struct device_attribute *attr,
> +					const char *buf, size_t len)
> +{
> +	struct lp5860 *led = dev_get_drvdata(dev);
> +	unsigned int value = 0;
> +	int ret;
> +
> +	if (kstrtoint(buf, 0, &value))
> +		return -EINVAL;
> +
> +	if (value & LP5860_FAULT_STATE_LOD)
> +		ret = regmap_write(led->regmap, LP5860_REG_LOD_CLEAR, 0xf);
> +	if (value & LP5860_FAULT_STATE_LSD)
> +		ret = regmap_write(led->regmap, LP5860_REG_LSD_CLEAR, 0xf);
> +
> +	if (ret < 0)
> +		return ret;

-ENOSQUISH - add a '\n'

> +	return len;
> +}
> +static LP5860_DEV_ATTR_RW(fault_state);
> +
>  LP5860_SHOW_MODE(r_global_brightness_set, LP5860_REG_R_CURRENT_SET, LP5860_CC_GROUP_MASK, 0)
>  LP5860_STORE_MODE(r_global_brightness_set, LP5860_REG_R_CURRENT_SET, LP5860_CC_GROUP_MASK, 0)
>  DEVICE_ATTR_RW(r_global_brightness_set);
> @@ -35,6 +167,9 @@ static struct attribute *lp5860_led_attrs[] = {
>  	&dev_attr_r_global_brightness_set.attr,
>  	&dev_attr_g_global_brightness_set.attr,
>  	&dev_attr_b_global_brightness_set.attr,
> +	&dev_attr_fault_state_open.attr,
> +	&dev_attr_fault_state_short.attr,
> +	&dev_attr_fault_state.attr,
>  	NULL,
>  };
>  
> diff --git a/include/linux/platform_data/leds-lp5860.h b/include/linux/platform_data/leds-lp5860.h
> index 94d184702b11a..d032a0e6d2617 100644
> --- a/include/linux/platform_data/leds-lp5860.h
> +++ b/include/linux/platform_data/leds-lp5860.h
> @@ -189,6 +189,9 @@
>  #define LP5860_DOT_CS_OFF		0x00
>  
>  /* Dot lod value */
> +#define LP5860_FAULT_STATE_LOD		BIT(1)
> +#define LP5860_FAULT_STATE_LSD		BIT(0)

I don't see the point of defines if the nomenclature isn't self explanatory.

>  #define LP5860_DOT_LOD0_OFFSET		0
>  #define LP5860_DOT_LOD1_OFFSET		1
>  #define LP5860_DOT_LOD2_OFFSET		2
> @@ -201,7 +204,9 @@
>  #define LP5860_DOT_LOD_ON		0x01
>  #define LP5860_DOT_LOD_OFF		0x00
>  
> -/* dot lsd value */
> +/* Dot lsd value */
> +#define LP5860_DOT_LOD_LENGTH		0x20
> +
>  #define LP5860_DOT_LSD0_OFFSET		0
>  #define LP5860_DOT_LSD1_OFFSET		1
>  #define LP5860_DOT_LSD2_OFFSET		2
> @@ -215,6 +220,8 @@
>  #define LP5860_DOT_LSD_OFF		0x00
>  
>  /* Register lod state */
> +#define LP5860_DOT_LSD_LENGTH		0x20
> +
>  #define LP5860_GLOBAL_LOD_OFFSET	1
>  #define LP5860_GLOBAL_LOD_STATE		BIT(1)
>  #define LP5860_GLOBAL_LSD_OFFSET	0
> @@ -248,6 +255,9 @@
>   */
>  #define LP5860_MAX_LED_CHANNELS		4
>  
> +#define LP5860_DEV_ATTR_R(name)	\
> +	DEVICE_ATTR(name, 0444, lp5860_##name##_show, NULL)
> +
>  #define LP5860_DEV_ATTR_RW(name)	\
>  	DEVICE_ATTR(name, 0644, lp5860_##name##_show, lp5860_##name##_store)
>  
> 
> ---
> base-commit: d60f615f21e161506b3ac9bee8add471f0e27a8c
> change-id: 20260129-v6-19-topic-ti-lp5860-fault-c8bd1f59fc3f
> 
> Best regards,
> -- 
> Steffen Trumtrar <s.trumtrar@pengutronix.de>
> 
> 

-- 
Lee Jones [李琼斯]

      reply	other threads:[~2026-03-09 18:17 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-05  8:49 [PATCH RESEND] leds: lp5860: detect and report fault state Steffen Trumtrar
2026-03-09 18:17 ` Lee Jones [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260309181702.GX183676@google.com \
    --to=lee@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=pavel@kernel.org \
    --cc=s.trumtrar@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.