summaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <krzk@kernel.org>2019-01-09 09:44:47 -0500
committerJacek Anaszewski <jacek.anaszewski@gmail.com>2019-01-16 16:08:47 -0500
commitaa6fd10481bdb1af2d4a4b5975e23674e989cd81 (patch)
treeb4a949c3d934b1a0dd84e6c6795f7fba6c89b5fd /drivers/leds
parent8e1f456129e61371fb190c71ea182a9f6e21282e (diff)
leds: trigger: pattern: Add pattern initialization from Device Tree
Allow initialization of pattern used in pattern trigger from Device Tree property. This is especially useful for embedded systems where the pattern trigger would be used to indicate the process of boot status in a nice, user-friendly blinking way. This initialization pattern will be used till user-space is brought up and sets its own pattern, indicating the boot status is for example finished. Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/trigger/ledtrig-pattern.c99
1 files changed, 80 insertions, 19 deletions
diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c
index 1870cf87afe1..718729c89440 100644
--- a/drivers/leds/trigger/ledtrig-pattern.c
+++ b/drivers/leds/trigger/ledtrig-pattern.c
@@ -220,22 +220,10 @@ out:
220 return count; 220 return count;
221} 221}
222 222
223static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, 223static int pattern_trig_store_patterns_string(struct pattern_trig_data *data,
224 const char *buf, size_t count, 224 const char *buf, size_t count)
225 bool hw_pattern)
226{ 225{
227 struct pattern_trig_data *data = led_cdev->trigger_data; 226 int ccount, cr, offset = 0;
228 int ccount, cr, offset = 0, err = 0;
229
230 mutex_lock(&data->lock);
231
232 del_timer_sync(&data->timer);
233
234 if (data->is_hw_pattern)
235 led_cdev->pattern_clear(led_cdev);
236
237 data->is_hw_pattern = hw_pattern;
238 data->npatterns = 0;
239 227
240 while (offset < count - 1 && data->npatterns < MAX_PATTERNS) { 228 while (offset < count - 1 && data->npatterns < MAX_PATTERNS) {
241 cr = 0; 229 cr = 0;
@@ -244,14 +232,54 @@ static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
244 &data->patterns[data->npatterns].delta_t, &cr); 232 &data->patterns[data->npatterns].delta_t, &cr);
245 if (ccount != 2) { 233 if (ccount != 2) {
246 data->npatterns = 0; 234 data->npatterns = 0;
247 err = -EINVAL; 235 return -EINVAL;
248 goto out;
249 } 236 }
250 237
251 offset += cr; 238 offset += cr;
252 data->npatterns++; 239 data->npatterns++;
253 } 240 }
254 241
242 return 0;
243}
244
245static int pattern_trig_store_patterns_int(struct pattern_trig_data *data,
246 const u32 *buf, size_t count)
247{
248 unsigned int i;
249
250 for (i = 0; i < count; i += 2) {
251 data->patterns[data->npatterns].brightness = buf[i];
252 data->patterns[data->npatterns].delta_t = buf[i + 1];
253 data->npatterns++;
254 }
255
256 return 0;
257}
258
259static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
260 const char *buf, const u32 *buf_int,
261 size_t count, bool hw_pattern)
262{
263 struct pattern_trig_data *data = led_cdev->trigger_data;
264 int err = 0;
265
266 mutex_lock(&data->lock);
267
268 del_timer_sync(&data->timer);
269
270 if (data->is_hw_pattern)
271 led_cdev->pattern_clear(led_cdev);
272
273 data->is_hw_pattern = hw_pattern;
274 data->npatterns = 0;
275
276 if (buf)
277 err = pattern_trig_store_patterns_string(data, buf, count);
278 else
279 err = pattern_trig_store_patterns_int(data, buf_int, count);
280 if (err)
281 goto out;
282
255 err = pattern_trig_start_pattern(led_cdev); 283 err = pattern_trig_start_pattern(led_cdev);
256 if (err) 284 if (err)
257 data->npatterns = 0; 285 data->npatterns = 0;
@@ -275,7 +303,7 @@ static ssize_t pattern_store(struct device *dev, struct device_attribute *attr,
275{ 303{
276 struct led_classdev *led_cdev = dev_get_drvdata(dev); 304 struct led_classdev *led_cdev = dev_get_drvdata(dev);
277 305
278 return pattern_trig_store_patterns(led_cdev, buf, count, false); 306 return pattern_trig_store_patterns(led_cdev, buf, NULL, count, false);
279} 307}
280 308
281static DEVICE_ATTR_RW(pattern); 309static DEVICE_ATTR_RW(pattern);
@@ -295,7 +323,7 @@ static ssize_t hw_pattern_store(struct device *dev,
295{ 323{
296 struct led_classdev *led_cdev = dev_get_drvdata(dev); 324 struct led_classdev *led_cdev = dev_get_drvdata(dev);
297 325
298 return pattern_trig_store_patterns(led_cdev, buf, count, true); 326 return pattern_trig_store_patterns(led_cdev, buf, NULL, count, true);
299} 327}
300 328
301static DEVICE_ATTR_RW(hw_pattern); 329static DEVICE_ATTR_RW(hw_pattern);
@@ -331,6 +359,30 @@ static const struct attribute_group *pattern_trig_groups[] = {
331 NULL, 359 NULL,
332}; 360};
333 361
362static void pattern_init(struct led_classdev *led_cdev)
363{
364 unsigned int size = 0;
365 u32 *pattern;
366 int err;
367
368 pattern = led_get_default_pattern(led_cdev, &size);
369 if (!pattern)
370 return;
371
372 if (size % 2) {
373 dev_warn(led_cdev->dev, "Expected pattern of tuples\n");
374 goto out;
375 }
376
377 err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, false);
378 if (err < 0)
379 dev_warn(led_cdev->dev,
380 "Pattern initialization failed with error %d\n", err);
381
382out:
383 kfree(pattern);
384}
385
334static int pattern_trig_activate(struct led_classdev *led_cdev) 386static int pattern_trig_activate(struct led_classdev *led_cdev)
335{ 387{
336 struct pattern_trig_data *data; 388 struct pattern_trig_data *data;
@@ -354,6 +406,15 @@ static int pattern_trig_activate(struct led_classdev *led_cdev)
354 timer_setup(&data->timer, pattern_trig_timer_function, 0); 406 timer_setup(&data->timer, pattern_trig_timer_function, 0);
355 led_cdev->activated = true; 407 led_cdev->activated = true;
356 408
409 if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) {
410 pattern_init(led_cdev);
411 /*
412 * Mark as initialized even on pattern_init() error because
413 * any consecutive call to it would produce the same error.
414 */
415 led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER;
416 }
417
357 return 0; 418 return 0;
358} 419}
359 420