Linux LED subsystem development
 help / color / mirror / Atom feed
From: Matthias Fend <matthias.fend@emfend.at>
To: Lee Jones <lee@kernel.org>
Cc: Pavel Machek <pavel@ucw.cz>, Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	linux-leds@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	bsp-development.geo@leica-geosystems.com
Subject: Re: [PATCH 2/2] leds: tps6131x: add support for Texas Instruments TPS6131X flash LED driver
Date: Fri, 14 Mar 2025 12:27:33 +0100	[thread overview]
Message-ID: <8a16c018-8466-4dea-8f1e-e8a65e3ed950@emfend.at> (raw)
In-Reply-To: <20250314105257.GD3890718@google.com>

Hi Lee,

Am 14.03.2025 um 11:52 schrieb Lee Jones:
> On Fri, 14 Mar 2025, Matthias Fend wrote:
> 
>> Hi Lee,
>>
>> thanks a lot for your feedback!
>>
>> Am 10.03.2025 um 15:49 schrieb Lee Jones:
>>> On Fri, 28 Feb 2025, Matthias Fend wrote:
>>>
>>>> The TPS61310/TPS61311 is a flash LED driver with I2C interface. Its power
>>>> stage is capable of supplying a maximum total current of roughly 1500mA.
>>>> The TPS6131x provides three constant-current sinks, capable of sinking up
>>>> to 2 × 400mA (LED1 and LED3) and 800mA (LED2) in flash mode. In torch mode
>>>> each sink (LED1, LED2, LED3) supports currents up to 175mA.
>>>>
>>>> Signed-off-by: Matthias Fend <matthias.fend@emfend.at>
>>>> ---
>>>>    MAINTAINERS                        |   7 +
>>>>    drivers/leds/flash/Kconfig         |  11 +
>>>>    drivers/leds/flash/Makefile        |   1 +
>>>>    drivers/leds/flash/leds-tps6131x.c | 798 +++++++++++++++++++++++++++++++++++++
>>>>    4 files changed, 817 insertions(+)
> 
> [...]
> 
>>>> +static int tps6131x_led_class_setup(struct tps6131x *tps6131x)
>>>> +{
>>>> +	struct led_classdev *led_cdev;
>>>> +	struct led_flash_setting *setting;
>>>> +	struct led_init_data init_data = {};
>>>> +	static const struct tps6131x_timer_config *timer_config;
>>>> +	int ret;
>>>> +
>>>> +	tps6131x->fled_cdev.ops = &flash_ops;
>>>> +
>>>> +	setting = &tps6131x->fled_cdev.timeout;
>>>> +	timer_config = tps6131x_find_closest_timer_config(0);
>>>> +	setting->min = timer_config->time_us;
>>>> +	setting->max = tps6131x->max_timeout_us;
>>>> +	setting->step = 1; /* Only some specific time periods are supported. No fixed step size. */
>>>> +	setting->val = setting->min;
>>>> +
>>>> +	setting = &tps6131x->fled_cdev.brightness;
>>>> +	setting->min = tps6131x->step_flash_current_ma;
>>>> +	setting->max = tps6131x->max_flash_current_ma;
>>>> +	setting->step = tps6131x->step_flash_current_ma;
>>>> +	setting->val = setting->min;
>>>> +
>>>> +	led_cdev = &tps6131x->fled_cdev.led_cdev;
>>>> +	led_cdev->brightness_set_blocking = tps6131x_brightness_set;
>>>> +	led_cdev->max_brightness = tps6131x->max_torch_current_ma;
>>>> +	led_cdev->flags |= LED_DEV_CAP_FLASH;
>>>> +
>>>> +	init_data.fwnode = tps6131x->led_node;
>>>> +	init_data.devicename = NULL;
>>>> +	init_data.default_label = NULL;
>>>> +	init_data.devname_mandatory = false;
>>>> +
>>>> +	ret = devm_led_classdev_flash_register_ext(&tps6131x->client->dev, &tps6131x->fled_cdev,
>>>> +						   &init_data);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
>>>
>>> Not keen on #ifery in C files.
>>>
>>> Can you use is_defined() and return early instead?
>>>
>>> I see that there is a precedent for this already. :(
>>
>> Me neither, but since it is done this way in about 9 out of 10 flash
>> controllers, I wanted to continue doing it consistently.
>> But since the required v4l2_flash_* functions are also available as dummies
>> if this option is not activated, I could do it like this:
>>
>> if (!IS_BUILTIN(CONFIG_V4L2_FLASH_LED_CLASS))
>>    return 0;
>>
>> Would you prefer this solution?
> 
> I would, yes.  Thank you.

Sure, then I'll change that.

> 
>>>> +static int tps6131x_flash_external_strobe_set(struct v4l2_flash *v4l2_flash, bool enable)
>>>> +{
>>>> +	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
>>>> +	struct tps6131x *tps6131x = fled_cdev_to_tps6131x(fled_cdev);
>>>> +
>>>> +	guard(mutex)(&tps6131x->lock);
>>>> +
>>> /> +	return tps6131x_set_mode(tps6131x, enable ? TPS6131X_MODE_FLASH : TPS6131X_MODE_SHUTDOWN,
>>>> +				 false);
>>>> +}
>>>> +
>>>> +static const struct v4l2_flash_ops tps6131x_v4l2_flash_ops = {
>>>> +	.external_strobe_set = tps6131x_flash_external_strobe_set,
>>>> +};
>>>> +
>>>> +static int tps6131x_v4l2_setup(struct tps6131x *tps6131x)
>>>> +{
>>>> +	struct v4l2_flash_config v4l2_cfg = { 0 };
>>>> +	struct led_flash_setting *intensity = &v4l2_cfg.intensity;
>>>> +
>>>> +	intensity->min = tps6131x->step_torch_current_ma;
>>>> +	intensity->max = tps6131x->max_torch_current_ma;
>>>> +	intensity->step = tps6131x->step_torch_current_ma;
>>>> +	intensity->val = intensity->min;
>>>> +
>>>> +	strscpy(v4l2_cfg.dev_name, tps6131x->fled_cdev.led_cdev.dev->kobj.name,
>>>
>>> tps6131x->client->dev?
>>
>> Do you mean the name should be taken from the I2C device?
>> The current name, for example, is 'white:flash-0', while the I2C device name
>> would be '4-0033'. So I think the current version is appropriate, don't you
>> think?
> 
> No, I'm implying that:
> 
>    tps6131x->client->dev == tps6131x->fled_cdev.led_cdev.dev
> 
> ... and that the former is shorter / neater.

Hmm. That's interesting. I thought these were two different devices, 
which seems to be actually the case for me. Hence the different names in 
the kobj.
Are the devices really supposed to be identical?

> 
>>>> +		sizeof(v4l2_cfg.dev_name));
>>>> +
>>>> +	v4l2_cfg.has_external_strobe = true;
>>>> +	v4l2_cfg.flash_faults = LED_FAULT_TIMEOUT | LED_FAULT_OVER_TEMPERATURE |
>>>> +				LED_FAULT_SHORT_CIRCUIT | LED_FAULT_UNDER_VOLTAGE |
>>>> +				LED_FAULT_LED_OVER_TEMPERATURE;
>>>> +
>>>> +	tps6131x->v4l2_flash = v4l2_flash_init(&tps6131x->client->dev, tps6131x->led_node,
>>>> +					       &tps6131x->fled_cdev, &tps6131x_v4l2_flash_ops,
>>>> +					       &v4l2_cfg);
>>>> +	if (IS_ERR(tps6131x->v4l2_flash)) {
>>>> +		dev_err(&tps6131x->client->dev, "v4l2_flash_init failed\n");
>>>
>>> "Failed to initialise V4L2 flash LED" ?
>>
>> ACK
>>
>>>
>>>> +		return PTR_ERR(tps6131x->v4l2_flash);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#else
>>>> +
>>>> +static int tps6131x_v4l2_setup(struct tps6131x *tps6131x)
>>>> +{
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#endif
>>>> +
>>>> +static int tps6131x_probe(struct i2c_client *client)
>>>> +{
>>>> +	struct tps6131x *tps6131x;
>>>> +	int ret;
>>>> +
>>>> +	tps6131x = devm_kzalloc(&client->dev, sizeof(*tps6131x), GFP_KERNEL);
>>>> +	if (!tps6131x)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	tps6131x->client = client;
>>>
>>> What are you planning on using client for?
>>>
>>>> +	i2c_set_clientdata(client, tps6131x);
>>>
>>> How are you going to _get_ this without client?
>>
>> Maybe I didn't understand the question correctly, but in tps6131x_remove() I
>> get the device data via the client.
> 
> Right, which uses 'client' to obtain it, so you don't need to save 'client'.

Okay, now I understand. Since I'm now saving 'dev' instead of 'client,' 
as you suggested, that's no longer an issue.

> 
>>> Why not save dev and reduce the amount of dereferencing levels required.
>>
>> Absolutely. Good idea.
>>
>>>
>>>> +	mutex_init(&tps6131x->lock);
>>>> +	INIT_DELAYED_WORK(&tps6131x->torch_refresh_work, tps6131x_torch_refresh_handler);
>>>> +
>>>> +	ret = tps6131x_parse_node(tps6131x);
>>>> +	if (ret)
>>>> +		return -ENODEV;
>>>> +
>>>> +	tps6131x->regmap = devm_regmap_init_i2c(client, &tps6131x_regmap);
>>>> +	if (IS_ERR(tps6131x->regmap)) {
>>>> +		ret = PTR_ERR(tps6131x->regmap);
>>>> +		dev_err(&client->dev, "Failed to allocate register map\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	tps6131x->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH);
>>>> +	ret = tps6131x_reset_chip(tps6131x);
>>>> +	if (ret)
>>>> +		return dev_err_probe(&client->dev, ret, "Failed to reset LED controller\n");
>>>
>>> How do you manage the optional part?
>>
>> If there is a reset line, then tps6131x_reset_chip() uses it to reset the
>> chip. If there is none, the software reset (via an I2C register) is used.
>> Therefore the reset pin can be optional.
> 
> Right, but didn't you just fail if one is not provided, or is that
> accounted for in tps6131x_reset_chip()?

Yes, tps6131x_reset_chip() selects the appropriate reset method 
depending on the circumstances. Something like this:

if (IS_ERR_OR_NULL(tps6131x->reset_gpio))
   sofware reset via i2c
else
   hardware reset via gpio

So there's no error just because the reset GPIO isn't present.

Thanks
  ~Matthias

> 


  reply	other threads:[~2025-03-14 11:27 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-28 10:31 [PATCH 0/2] Support for Texas Instruments TPS6131X flash LED driver Matthias Fend
2025-02-28 10:31 ` [PATCH 1/2] dt-bindings: leds: add Texas Instruments TPS6131x " Matthias Fend
2025-02-28 18:24   ` Conor Dooley
2025-03-10  7:20     ` Matthias Fend
2025-03-10  7:43       ` Krzysztof Kozlowski
2025-03-10  7:49   ` Krzysztof Kozlowski
2025-03-10  8:40     ` Matthias Fend
2025-03-10 11:45       ` Krzysztof Kozlowski
2025-02-28 10:31 ` [PATCH 2/2] leds: tps6131x: add support for Texas Instruments TPS6131X " Matthias Fend
2025-03-10  7:46   ` Krzysztof Kozlowski
2025-03-10  8:04     ` Matthias Fend
2025-03-10 11:46       ` Krzysztof Kozlowski
2025-03-10 14:49   ` Lee Jones
2025-03-14  8:28     ` Matthias Fend
2025-03-14 10:52       ` Lee Jones
2025-03-14 11:27         ` Matthias Fend [this message]
2025-03-14 11:45           ` Lee Jones
2025-03-14 12:38             ` Matthias Fend
2025-03-14 14:13               ` 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=8a16c018-8466-4dea-8f1e-e8a65e3ed950@emfend.at \
    --to=matthias.fend@emfend.at \
    --cc=bsp-development.geo@leica-geosystems.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=lee@kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox