All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lee Jones <lee@kernel.org>
To: Christian Marangi <ansuelsmth@gmail.com>
Cc: Pavel Machek <pavel@ucw.cz>, Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Jacek Anaszewski <jacek.anaszewski@gmail.com>,
	linux-leds@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v6 20/20] leds: leds-lp5569: Add support for Texas Instruments LP5569
Date: Thu, 20 Jun 2024 17:03:48 +0100	[thread overview]
Message-ID: <20240620160348.GO3029315@google.com> (raw)
In-Reply-To: <20240616215226.2112-21-ansuelsmth@gmail.com>

On Sun, 16 Jun 2024, Christian Marangi wrote:

> Add support for Texas Instruments LP5569 LED driver.
> 
> Texas Instruments LP5569 is 9 channels chip with programmable engines.
> 
> It almost a copy of LP5523 with fundamental changes to regs order and
> regs content.
> 
> Has difference in how the clock is handled and doesn't support detecting
> clock time automatically, different handling for selftest and different
> scheme for the status regs.
> 
> LED chip supports ENGINE and MUX to group LED and run precompiled code
> with magic values to run patterns. This is loaded via the sysfs entry
> and it's passed as a string of ASCII HEX char.
> 
> One some devices using this LED Controller (a NBG7815 Router) it was
> found loading big precompiled pattern with up to 96 bytes of code. To
> have support for this "extended" scenario, hardcode each engine to
> support 4 pages of precompiled pattern (128 bytes of code) and 1 page
> for each MUX. This gives plenty of space for any kind precompiled
> pattern keeping simple logic for page handling of each engine and mux.
> 
> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> ---
>  drivers/leds/Kconfig       |  16 +-
>  drivers/leds/Makefile      |   1 +
>  drivers/leds/leds-lp5569.c | 542 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 556 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/leds/leds-lp5569.c
Pretty good, just a couple of tiny nits.

[...]

> +static ssize_t lp5569_led_short_test(struct lp55xx_led *led, char *buf)
> +{
> +	struct lp55xx_chip *chip = led->chip;
> +	struct lp55xx_platform_data *pdata = chip->pdata;
> +	bool leds_fault[LP5569_MAX_LEDS];
> +	struct lp55xx_led *led_tmp = led;
> +	int i, ret, pos = 0;
> +	u8 status;
> +
> +	/* Set in STANDBY state */
> +	ret = lp55xx_write(chip, LP5569_REG_ENABLE, 0);
> +	if (ret)
> +		goto exit;
> +
> +	/* Wait 1ms for device to enter STANDBY state */
> +	usleep_range(1000, 2000);
> +
> +	/* Set Charge Pump to 1x */
> +	ret = lp55xx_update_bits(chip, LP5569_REG_MISC,
> +				 FIELD_PREP(LP5569_CP_MODE_MASK, LP55XX_CP_BYPASS),
> +				 LP5569_CP_MODE_MASK);
> +	if (ret)
> +		goto exit;
> +
> +	/* Enable LED and set to 100% brightness and current to 100% (25.5mA) */
> +	for (i = 0; i < pdata->num_channels; i++) {
> +		ret = lp55xx_write(chip, LP5569_REG_LED_PWM_BASE + led_tmp->chan_nr,
> +				   LED_FULL);
> +		if (ret)
> +			goto exit;
> +
> +		ret = lp55xx_write(chip, LP5569_REG_LED_CURRENT_BASE + led_tmp->chan_nr,
> +				   LED_FULL);
> +		if (ret)
> +			goto exit;
> +
> +		led_tmp++;
> +	}
> +
> +	/* Put Device in NORMAL state */
> +	ret = lp55xx_write(chip, LP5569_REG_ENABLE, LP5569_ENABLE);
> +	if (ret)
> +		goto exit;
> +
> +	/* Wait 500 us for device to enter NORMAL state */
> +	usleep_range(500, 750);
> +
> +	/* Enable LED Shorted Test */
> +	ret = lp55xx_update_bits(chip, LP5569_REG_MISC2, LP5569_LED_OPEN_TEST,
> +				 LP5569_LED_SHORT_TEST);
> +	if (ret)
> +		goto exit;
> +
> +	/* Wait 500 us for device to fill status regs */
> +	usleep_range(500, 750);
> +
> +	/* Parse status led fault 1 regs */
> +	ret = lp55xx_read(chip, LP5569_REG_LED_FAULT1, &status);
> +	if (ret < 0)
> +		goto exit;
> +
> +	for (i = 0; i < 8; i++)
> +		leds_fault[i] = !!LEDn_STATUS_FAULT(i, status);
> +
> +	/* Parse status led fault 2 regs */
> +	ret = lp55xx_read(chip, LP5569_REG_LED_FAULT2, &status);
> +	if (ret < 0)
> +		goto exit;
> +
> +	for (i = 0; i < 1; i++)
> +		leds_fault[i + 8] = !!LEDn_STATUS_FAULT(i, status);
> +
> +	/* Report LED fault */
> +	led_tmp = led;
> +	for (i = 0; i < pdata->num_channels; i++) {
> +		if (leds_fault[led_tmp->chan_nr])
> +			pos += sprintf(buf + pos, "LED %d SHORTED FAIL\n",
> +				       led_tmp->chan_nr);
> +
> +		led_tmp++;
> +	}
> +
> +	ret = pos;
> +
> +exit:
> +	/* Disable LED Shorted Test */
> +	lp55xx_update_bits(chip, LP5569_REG_MISC2, LP5569_LED_SHORT_TEST,
> +			   0);

Nit: This line break seems unnecessary.

> +
> +	led_tmp = led;
> +	for (i = 0; i < pdata->num_channels; i++) {
> +		lp55xx_write(chip, LP5569_REG_LED_PWM_BASE + led_tmp->chan_nr,
> +			     0);

Nit: This too.

> +
> +		led_tmp++;
> +	}
> +
> +	return ret;
> +}
> +
> +static ssize_t lp5569_selftest(struct device *dev,
> +			       struct device_attribute *attr,
> +			       char *buf)
> +{
> +	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
> +	struct lp55xx_chip *chip = led->chip;
> +	int i, pos = 0;
> +
> +	mutex_lock(&chip->lock);
> +
> +	/* Test LED Open */
> +	pos = lp5569_led_open_test(led, buf);
> +	if (pos < 0)
> +		goto fail;
> +
> +	/* Test LED Shorted */
> +	pos = lp5569_led_short_test(led, buf);
> +	if (pos < 0)
> +		goto fail;
> +
> +	for (i = 0; i < chip->pdata->num_channels; i++) {
> +		/* Restore current */
> +		lp55xx_write(chip, LP5569_REG_LED_CURRENT_BASE + led->chan_nr,
> +			     led->led_current);
> +
> +		/* Restore brightness */
> +		lp55xx_write(chip, LP5569_REG_LED_PWM_BASE + led->chan_nr,
> +			     led->brightness);
> +		led++;
> +	}
> +
> +	if (pos == 0)
> +		pos = sprintf(buf, "OK\n");
> +	goto release_lock;
> +fail:
> +	pos = sprintf(buf, "FAIL\n");
> +
> +release_lock:
> +	mutex_unlock(&chip->lock);
> +
> +	return pos;
> +}
> +
> +LP55XX_DEV_ATTR_ENGINE_MODE(1);
> +LP55XX_DEV_ATTR_ENGINE_MODE(2);
> +LP55XX_DEV_ATTR_ENGINE_MODE(3);
> +LP55XX_DEV_ATTR_ENGINE_LEDS(1);
> +LP55XX_DEV_ATTR_ENGINE_LEDS(2);
> +LP55XX_DEV_ATTR_ENGINE_LEDS(3);
> +LP55XX_DEV_ATTR_ENGINE_LOAD(1);
> +LP55XX_DEV_ATTR_ENGINE_LOAD(2);
> +LP55XX_DEV_ATTR_ENGINE_LOAD(3);
> +static LP55XX_DEV_ATTR_RO(selftest, lp5569_selftest);
> +LP55XX_DEV_ATTR_MASTER_FADER(1);
> +LP55XX_DEV_ATTR_MASTER_FADER(2);
> +LP55XX_DEV_ATTR_MASTER_FADER(3);
> +static LP55XX_DEV_ATTR_RW(master_fader_leds, lp55xx_show_master_fader_leds,
> +			  lp55xx_store_master_fader_leds);
> +
> +static struct attribute *lp5569_attributes[] = {
> +	&dev_attr_engine1_mode.attr,
> +	&dev_attr_engine2_mode.attr,
> +	&dev_attr_engine3_mode.attr,
> +	&dev_attr_engine1_load.attr,
> +	&dev_attr_engine2_load.attr,
> +	&dev_attr_engine3_load.attr,
> +	&dev_attr_engine1_leds.attr,
> +	&dev_attr_engine2_leds.attr,
> +	&dev_attr_engine3_leds.attr,
> +	&dev_attr_selftest.attr,
> +	&dev_attr_master_fader1.attr,
> +	&dev_attr_master_fader2.attr,
> +	&dev_attr_master_fader3.attr,
> +	&dev_attr_master_fader_leds.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group lp5569_group = {
> +	.attrs = lp5569_attributes,
> +};
> +
> +/* Chip specific configurations */
> +static struct lp55xx_device_config lp5569_cfg = {
> +	.reg_op_mode = {
> +		.addr = LP5569_REG_OP_MODE,
> +		.shift = LP5569_MODE_ENG_SHIFT,
> +	},
> +	.reg_exec = {
> +		.addr = LP5569_REG_EXEC_CTRL,
> +		.shift = LP5569_EXEC_ENG_SHIFT,
> +	},
> +	.reset = {
> +		.addr = LP5569_REG_RESET,
> +		.val  = LP5569_RESET,
> +	},
> +	.enable = {
> +		.addr = LP5569_REG_ENABLE,
> +		.val  = LP5569_ENABLE,
> +	},
> +	.prog_mem_base = {
> +		.addr = LP5569_REG_PROG_MEM,
> +	},
> +	.reg_led_pwm_base = {
> +		.addr = LP5569_REG_LED_PWM_BASE,
> +	},
> +	.reg_led_current_base = {
> +		.addr = LP5569_REG_LED_CURRENT_BASE,
> +	},
> +	.pages_per_engine   = LP5569_PAGES_PER_ENGINE,
> +	.max_channel  = LP5569_MAX_LEDS,
> +	.post_init_device   = lp5569_post_init_device,
> +	.brightness_fn      = lp55xx_led_brightness,
> +	.multicolor_brightness_fn = lp55xx_multicolor_brightness,
> +	.set_led_current    = lp55xx_set_led_current,
> +	.firmware_cb        = lp55xx_firmware_loaded_cb,
> +	.run_engine         = lp5569_run_engine,
> +	.dev_attr_group     = &lp5569_group,
> +};
> +
> +static const struct i2c_device_id lp5569_id[] = {
> +	{ "lp5569",  .driver_data = (kernel_ulong_t)&lp5569_cfg, },
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, lp5569_id);
> +
> +static const struct of_device_id of_lp5569_leds_match[] = {
> +	{ .compatible = "ti,lp5569", .data = &lp5569_cfg, },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, of_lp5569_leds_match);
> +
> +static struct i2c_driver lp5569_driver = {
> +	.driver = {
> +		.name	= "lp5569x",
> +		.of_match_table = of_lp5569_leds_match,
> +	},
> +	.probe		= lp55xx_probe,
> +	.remove		= lp55xx_remove,
> +	.id_table	= lp5569_id,
> +};
> +
> +module_i2c_driver(lp5569_driver);
> +
> +MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
> +MODULE_DESCRIPTION("LP5569 LED engine");
> +MODULE_LICENSE("GPL");
> -- 
> 2.43.0
> 

-- 
Lee Jones [李琼斯]

  reply	other threads:[~2024-06-20 16:03 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-16 21:51 [PATCH v6 00/20] leds: leds-lp55xx: overhaul driver Christian Marangi
2024-06-16 21:52 ` [PATCH v6 01/20] dt-bindings: leds-lp55xx: limit pwr-sel property to ti,lp8501 Christian Marangi
2024-06-16 21:52 ` [PATCH v6 02/20] dt-bindings: leds-lp55xx: Add new ti,lp5569 compatible Christian Marangi
2024-06-16 21:52 ` [PATCH v6 03/20] leds: leds-lp55xx: generalize stop_all_engine OP Christian Marangi
2024-06-16 21:52 ` [PATCH v6 04/20] leds: leds-lp55xx: generalize probe/remove functions Christian Marangi
2024-06-20 15:38   ` Lee Jones
2024-06-16 21:52 ` [PATCH v6 05/20] leds: leds-lp55xx: generalize load_engine function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 06/20] leds: leds-lp55xx: generalize load_engine_and_select_page function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 07/20] leds: leds-lp55xx: generalize run_engine function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 08/20] leds: leds-lp55xx: generalize update_program_memory function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 09/20] leds: leds-lp55xx: generalize firmware_loaded function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 10/20] leds: leds-lp55xx: generalize led_brightness function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 11/20] leds: leds-lp55xx: generalize multicolor_brightness function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 12/20] leds: leds-lp55xx: generalize set_led_current function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 13/20] leds: leds-lp55xx: generalize turn_off_channels function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 14/20] leds: leds-lp55xx: generalize stop_engine function Christian Marangi
2024-06-16 21:52 ` [PATCH v6 15/20] leds: leds-lp55xx: generalize sysfs engine_load and engine_mode Christian Marangi
2024-06-16 21:52 ` [PATCH v6 16/20] leds: leds-lp55xx: generalize sysfs engine_leds Christian Marangi
2024-06-16 21:52 ` [PATCH v6 17/20] leds: leds-lp55xx: generalize sysfs master_fader Christian Marangi
2024-06-16 21:52 ` [PATCH v6 18/20] leds: leds-lp55xx: support ENGINE program up to 128 bytes Christian Marangi
2024-06-16 21:52 ` [PATCH v6 19/20] leds: leds-lp55xx: drop deprecated defines Christian Marangi
2024-06-16 21:52 ` [PATCH v6 20/20] leds: leds-lp5569: Add support for Texas Instruments LP5569 Christian Marangi
2024-06-20 16:03   ` Lee Jones [this message]
2024-06-20 16:09 ` [PATCH v6 00/20] leds: leds-lp55xx: overhaul driver Lee Jones
2024-06-20 15:15   ` Christian Marangi
2024-06-20 16:57     ` Lee Jones
2024-06-20 16:49 ` Lee Jones
2024-06-20 15:57   ` Christian Marangi
2024-06-20 17:30     ` Lee Jones

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=20240620160348.GO3029315@google.com \
    --to=lee@kernel.org \
    --cc=ansuelsmth@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=jacek.anaszewski@gmail.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=pavel@ucw.cz \
    --cc=robh@kernel.org \
    /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.