summaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
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