linux-leds.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jacek Anaszewski <jacek.anaszewski@gmail.com>
To: Oleh Kravchenko <oleg@kaa.org.ua>, linux-leds@vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>, Pavel Machek <pavel@ucw.cz>
Subject: Re: [PATCH v2] leds: add LED driver for CR0014114 board
Date: Tue, 15 Aug 2017 19:42:46 +0200	[thread overview]
Message-ID: <33519a27-a953-ac36-283e-13dff019082f@gmail.com> (raw)
In-Reply-To: <e1d38ada-2413-90ac-c297-890429385862@kaa.org.ua>

Hi Oleh,

On 08/15/2017 02:28 PM, Oleh Kravchenko wrote:
> Hi Jacek,
> 
> Thanks for your comments, please see my replies below.
> 
> On 14.08.17 22:44, Jacek Anaszewski wrote:
>> Hi Oleh,
>>
>> Thanks for the patch. Please see my comments below.
>>
>> On 08/14/2017 01: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.
>>>
>>> Driver creates LED devices with name written using the following
>>> pattern "LABEL-{N}:{red,green,blue}:".
>> LED device naming is already defined to "devicename:colour:function"
>> in Documentation/leds/leds-class.txt. Please stick to this scheme.
> 
> I tried to follow this rule with this pattern "LABEL-{N}:{red,green,blue}:".
> What is wrong with it?
> 
> Can I use this pattern?
> cr0014114:red:0
> cr0014114:green:0
> cr0014114:blue:0
> cr0014114:red:1
> cr0014114:green:1
> cr0014114:blue:1
> cr0014114:red:2
> cr0014114:green:2
> cr0014114:blue:2
> ...

This pattern looks fine. How "LABEL-(N)" corresponds with cr0014114?
This description is misleading.

>>> +static void cr0014114_calc_crc(u8 *buf, const size_t len)
>>> +{
>>> +	u8	crc;
>>> +	size_t	i;
>>> +
>>> +	for (i = 1, crc = 1; i < len - 1; i++)
>>> +		crc += buf[i];
>>> +
>>> +	crc |= BIT(7);
>>> +
>>> +	/* special case when CRC matches to SPI commands */
>>> +	switch (crc) {
>>> +	case CMD_SET_BRIGHTNESS:
>>> +	case CMD_INIT_REENUMERATE:
>>> +	case CMD_NEXT_REENUMERATE:
>>> +		crc = 0xfe;
>>> +		break;
>>> +	}
>> Wouldn't "if" fit better here?
> 
> I tried it's looks ugly for me, but if you insist I will use "if".
> 
>     if (crc == CMD_SET_BRIGHTNESS ||
>         crc == CMD_INIT_REENUMERATE ||
>         crc == CMD_NEXT_REENUMERATE)
>             crc = 0xfe;

It better reflects what is going on here. switch suggests
the need to differentiate actions depending on multiple possible
states, which is not the case here.

>>> +
>>> +	buf[len - 1] = crc;
>>> +}
>>> +
>>> +static void cr0014114_leds_work(struct work_struct *work)
>>> +{
>>> +	int			ret;
>>> +	size_t			i;
>>> +	struct cr0014114	*priv = container_of(work,
>>> +					struct cr0014114, leds_work);
>>> +	u8			data[priv->leds_count + 2];
>>> +	unsigned long		udelay, now = jiffies;
>>> +
>>> +	/* to avoid SPI mistiming with firmware we should wait some time */
>>> +	if (time_after(priv->leds_delay, now)) {
>>> +		udelay = jiffies_to_usecs(priv->leds_delay - now);
>>> +		usleep_range(udelay, udelay + 1);
>>> +	}
>>> +
>>> +	data[0] = CMD_SET_BRIGHTNESS;
>>> +	for (i = 0; i < priv->leds_count; i++)
>>> +		data[i + 1] = priv->leds[i].brightness;
>> Why do you set three LEDs at once? We expose each LED as a single
>> LED class device in the LED subsystem.
> 
> Unfortunately board should receive brightness
> for all 18 LEDs (or 6 RGB LEDs) at one time.
> 
> On CR0014114 you can't update only one LED, you should update them all :)

Ack.

>>> +	cr0014114_calc_crc(data, sizeof(data));
>>> +
>>> +	ret = spi_write(priv->spi, data, sizeof(data));
>> Could you please describe the layout of registers driving the brightness
>> of each LED ?
> 
> +----+-----------------------------------+----+
> | 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                       |
> +---------------------------------------------+
> 
> Boards can be connected to the chain:
>     SPI -> board0 -> board1 -> board2 ..
> 
> in this case only BRIGHTNESS length (18 -> 36 -> 54) will be increased.

Thanks for the description.

> 
>>> +	if (ret)
>>> +		dev_err(priv->dev, "spi_write() error %d\n", ret);
>>> +
>>> +	priv->leds_delay = jiffies + msecs_to_jiffies(DEF_FW_DELAY_MSEC);
>>> +}
>>> +
>>> +static void cr0014114_test(struct cr0014114 *priv)
>>> +{
>>> +	unsigned int		mdelay;
>>> +	size_t			i;
>>> +	struct led_classdev	*ldev;
>>> +
>>> +	/* blink all LEDs in 500 milliseconds */
>>> +	mdelay = 500 / priv->leds_count - DEF_FW_DELAY_MSEC;
>>> +	if (mdelay < DEF_FW_DELAY_MSEC)
>>> +		mdelay = DEF_FW_DELAY_MSEC;
>>> +
>>> +	for (i = 0; i < priv->leds_count; i++) {
>>> +		ldev = &priv->leds[i].ldev;
>>> +
>>> +		ldev->brightness_set(ldev, DEF_MAX_BRIGHTNESS);
>>> +		msleep(mdelay);
>>> +		ldev->brightness_set(ldev, LED_OFF);
>>> +	}
>>> +}
>> Is this function really required? It seems to mimic timer trigger.
> 
> No, this function is not really needed.
> I will remove it.
> 
>>> +	queue_work(led->priv->wq, &led->priv->leds_work);
>>> +}
>>> +
>>> +static int cr0014114_led_create(struct cr0014114 *priv,
>>> +				struct cr0014114_led *led,
>>> +				size_t id,
>>> +				const char *color)
>>> +{
>>> +	int ret;
>>> +
>>> +	led->priv = priv;
>>> +	snprintf(led->name, sizeof(led->name), "%s-%zd:%s:",
>>> +		 priv->label, id, color);
>>> +
>>> +	led->ldev.name			= led->name;
>>> +	led->ldev.brightness		= LED_OFF;
>>> +	led->ldev.max_brightness	= DEF_MAX_BRIGHTNESS;
>>> +	led->ldev.brightness_set	= cr0014114_set_brightness;
>> Please use brightness_set_blocking op and remove workqueue.
> 
> If driver will send data often than 10 ms, board will hangs up.
> How I can workaround it with brightness_set_blocking?

brightness_set_blocking op is executed in the workqueue internally
by the LED core, so you can sleep in it safely.

>>> +
>>> +	/* setup recount timer to workaround buggy firmware */
>>> +	mod_timer(&priv->recount_timer, jiffies + DEF_RECOUNT_DELAY);
>> Could you share some details on why it is needed?
> 
> Board (or boards if they in chain) time to time losing synchronization
> with SPI.
> So we should recount LEDs on them to avoid this.

Is it recommended way to fix the issue?
Is there an openly available documentation for this LED controller?

>From the code it looks like the recount can result in spurious
LED blinks.

-- 
Best regards,
Jacek Anaszewski

      reply	other threads:[~2017-08-15 17:43 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-14 11:53 [PATCH v2] leds: add LED driver for CR0014114 board Oleh Kravchenko
     [not found] ` <20170814115355.9437-1-oleg-CGGh1czddphUq1AO9QMCaQ@public.gmane.org>
2017-08-14 14:28   ` Rob Herring
2017-08-15 11:37     ` Oleh Kravchenko
2017-08-14 19:44 ` Jacek Anaszewski
2017-08-15 12:28   ` Oleh Kravchenko
2017-08-15 17:42     ` Jacek Anaszewski [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=33519a27-a953-ac36-283e-13dff019082f@gmail.com \
    --to=jacek.anaszewski@gmail.com \
    --cc=linux-leds@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=oleg@kaa.org.ua \
    --cc=pavel@ucw.cz \
    --cc=robh+dt@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;
as well as URLs for NNTP newsgroup(s).