Skip to content

Commit e98a860

Browse files
anderssonpavelmachek
authored andcommitted
leds: qcom-lpg: Require pattern to follow documentation
The leds-trigger-pattern documentation describes how the brightness of the LED should transition linearly from one brightness value to the next, over the given delta_t. But the pattern engine in the Qualcomm LPG hardware only supports holding the brightness for each entry for the period. This subset of patterns can be represented in the leds-trigger-pattern by injecting zero-time transitions after each entry in the pattern, resulting in a pattern that pattern that can be rendered by the LPG. Rework LPG pattern interface to require these zero-time transitions, to make it comply with this subset of patterns and reject the patterns it can't render. Fixes: 24e2d05 ("leds: Add driver for Qualcomm LPG") Signed-off-by: Bjorn Andersson <[email protected]> Signed-off-by: Pavel Machek <[email protected]>
1 parent 73bce57 commit e98a860

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

Documentation/leds/leds-qcom-lpg.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ Specify a hardware pattern for a Qualcomm LPG LED.
3535
The pattern is a series of brightness and hold-time pairs, with the hold-time
3636
expressed in milliseconds. The hold time is a property of the pattern and must
3737
therefor be identical for each element in the pattern (except for the pauses
38-
described below).
38+
described below). As the LPG hardware is not able to perform the linear
39+
transitions expected by the leds-trigger-pattern format, each entry in the
40+
pattern must be followed a zero-length entry of the same brightness.
3941

4042
Simple pattern::
4143

42-
"255 500 0 500"
44+
"255 500 255 0 0 500 0 0"
4345

4446
^
4547
|
@@ -54,7 +56,7 @@ in the pattern, the so called "low pause" and "high pause".
5456

5557
Low-pause pattern::
5658

57-
"255 1000 0 500 255 500 0 500"
59+
"255 1000 255 0 0 500 0 0 255 500 255 0 0 500 0 0"
5860

5961
^
6062
|

drivers/leds/rgb/leds-qcom-lpg.c

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -704,11 +704,12 @@ static int lpg_blink_mc_set(struct led_classdev *cdev,
704704
return ret;
705705
}
706706

707-
static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *pattern,
707+
static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *led_pattern,
708708
u32 len, int repeat)
709709
{
710710
struct lpg_channel *chan;
711711
struct lpg *lpg = led->lpg;
712+
struct led_pattern *pattern;
712713
unsigned int brightness_a;
713714
unsigned int brightness_b;
714715
unsigned int actual_len;
@@ -719,18 +720,48 @@ static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *pattern,
719720
unsigned int hi_idx;
720721
unsigned int i;
721722
bool ping_pong = true;
722-
int ret;
723+
int ret = -EINVAL;
723724

724725
/* Hardware only support oneshot or indefinite loops */
725726
if (repeat != -1 && repeat != 1)
726727
return -EINVAL;
727728

729+
/*
730+
* The standardized leds-trigger-pattern format defines that the
731+
* brightness of the LED follows a linear transition from one entry
732+
* in the pattern to the next, over the given delta_t time. It
733+
* describes that the way to perform instant transitions a zero-length
734+
* entry should be added following a pattern entry.
735+
*
736+
* The LPG hardware is only able to perform the latter (no linear
737+
* transitions), so require each entry in the pattern to be followed by
738+
* a zero-length transition.
739+
*/
740+
if (len % 2)
741+
return -EINVAL;
742+
743+
pattern = kcalloc(len / 2, sizeof(*pattern), GFP_KERNEL);
744+
if (!pattern)
745+
return -ENOMEM;
746+
747+
for (i = 0; i < len; i += 2) {
748+
if (led_pattern[i].brightness != led_pattern[i + 1].brightness)
749+
goto out_free_pattern;
750+
if (led_pattern[i + 1].delta_t != 0)
751+
goto out_free_pattern;
752+
753+
pattern[i / 2].brightness = led_pattern[i].brightness;
754+
pattern[i / 2].delta_t = led_pattern[i].delta_t;
755+
}
756+
757+
len /= 2;
758+
728759
/*
729760
* Specifying a pattern of length 1 causes the hardware to iterate
730761
* through the entire LUT, so prohibit this.
731762
*/
732763
if (len < 2)
733-
return -EINVAL;
764+
goto out_free_pattern;
734765

735766
/*
736767
* The LPG plays patterns with at a fixed pace, a "low pause" can be
@@ -781,13 +812,13 @@ static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *pattern,
781812
* specify hi pause. Reject other variations.
782813
*/
783814
if (i != actual_len - 1)
784-
return -EINVAL;
815+
goto out_free_pattern;
785816
}
786817
}
787818

788819
/* LPG_RAMP_DURATION_REG is a 9bit */
789820
if (delta_t >= BIT(9))
790-
return -EINVAL;
821+
goto out_free_pattern;
791822

792823
/* Find "low pause" and "high pause" in the pattern */
793824
lo_pause = pattern[0].delta_t;
@@ -814,6 +845,8 @@ static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *pattern,
814845

815846
out_unlock:
816847
mutex_unlock(&lpg->lock);
848+
out_free_pattern:
849+
kfree(pattern);
817850

818851
return ret;
819852
}

0 commit comments

Comments
 (0)