Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa6fd104 authored by Krzysztof Kozlowski's avatar Krzysztof Kozlowski Committed by Jacek Anaszewski
Browse files

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: default avatarKrzysztof Kozlowski <krzk@kernel.org>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarJacek Anaszewski <jacek.anaszewski@gmail.com>
parent 8e1f4561
Loading
Loading
Loading
Loading
+80 −19
Original line number Diff line number Diff line
@@ -220,12 +220,48 @@ static ssize_t pattern_trig_show_patterns(struct pattern_trig_data *data,
	return count;
}

static int pattern_trig_store_patterns_string(struct pattern_trig_data *data,
					      const char *buf, size_t count)
{
	int ccount, cr, offset = 0;

	while (offset < count - 1 && data->npatterns < MAX_PATTERNS) {
		cr = 0;
		ccount = sscanf(buf + offset, "%d %u %n",
				&data->patterns[data->npatterns].brightness,
				&data->patterns[data->npatterns].delta_t, &cr);
		if (ccount != 2) {
			data->npatterns = 0;
			return -EINVAL;
		}

		offset += cr;
		data->npatterns++;
	}

	return 0;
}

static int pattern_trig_store_patterns_int(struct pattern_trig_data *data,
					   const u32 *buf, size_t count)
{
	unsigned int i;

	for (i = 0; i < count; i += 2) {
		data->patterns[data->npatterns].brightness = buf[i];
		data->patterns[data->npatterns].delta_t = buf[i + 1];
		data->npatterns++;
	}

	return 0;
}

static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
					   const char *buf, size_t count,
					   bool hw_pattern)
					   const char *buf, const u32 *buf_int,
					   size_t count, bool hw_pattern)
{
	struct pattern_trig_data *data = led_cdev->trigger_data;
	int ccount, cr, offset = 0, err = 0;
	int err = 0;

	mutex_lock(&data->lock);

@@ -237,20 +273,12 @@ static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
	data->is_hw_pattern = hw_pattern;
	data->npatterns = 0;

	while (offset < count - 1 && data->npatterns < MAX_PATTERNS) {
		cr = 0;
		ccount = sscanf(buf + offset, "%d %u %n",
				&data->patterns[data->npatterns].brightness,
				&data->patterns[data->npatterns].delta_t, &cr);
		if (ccount != 2) {
			data->npatterns = 0;
			err = -EINVAL;
	if (buf)
		err = pattern_trig_store_patterns_string(data, buf, count);
	else
		err = pattern_trig_store_patterns_int(data, buf_int, count);
	if (err)
		goto out;
		}

		offset += cr;
		data->npatterns++;
	}

	err = pattern_trig_start_pattern(led_cdev);
	if (err)
@@ -275,7 +303,7 @@ static ssize_t pattern_store(struct device *dev, struct device_attribute *attr,
{
	struct led_classdev *led_cdev = dev_get_drvdata(dev);

	return pattern_trig_store_patterns(led_cdev, buf, count, false);
	return pattern_trig_store_patterns(led_cdev, buf, NULL, count, false);
}

static DEVICE_ATTR_RW(pattern);
@@ -295,7 +323,7 @@ static ssize_t hw_pattern_store(struct device *dev,
{
	struct led_classdev *led_cdev = dev_get_drvdata(dev);

	return pattern_trig_store_patterns(led_cdev, buf, count, true);
	return pattern_trig_store_patterns(led_cdev, buf, NULL, count, true);
}

static DEVICE_ATTR_RW(hw_pattern);
@@ -331,6 +359,30 @@ static const struct attribute_group *pattern_trig_groups[] = {
	NULL,
};

static void pattern_init(struct led_classdev *led_cdev)
{
	unsigned int size = 0;
	u32 *pattern;
	int err;

	pattern = led_get_default_pattern(led_cdev, &size);
	if (!pattern)
		return;

	if (size % 2) {
		dev_warn(led_cdev->dev, "Expected pattern of tuples\n");
		goto out;
	}

	err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, false);
	if (err < 0)
		dev_warn(led_cdev->dev,
			 "Pattern initialization failed with error %d\n", err);

out:
	kfree(pattern);
}

static int pattern_trig_activate(struct led_classdev *led_cdev)
{
	struct pattern_trig_data *data;
@@ -354,6 +406,15 @@ static int pattern_trig_activate(struct led_classdev *led_cdev)
	timer_setup(&data->timer, pattern_trig_timer_function, 0);
	led_cdev->activated = true;

	if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) {
		pattern_init(led_cdev);
		/*
		 * Mark as initialized even on pattern_init() error because
		 * any consecutive call to it would produce the same error.
		 */
		led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER;
	}

	return 0;
}