Commit 447bbf76 authored by Sebastian Reichel's avatar Sebastian Reichel
Browse files

Merge tag 'ib-leds-platform-power-v6.11'



Immutable branch between LEDs, Power and RGB due for the v6.11 merge
window.

Merge it to provide functionality required by power-supply specific
LED handler cleanups depending on the newly added (multi-colour) LED
features.

Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
parents ebacfa1f 9af12f57
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ int led_classdev_multicolor_register_ext(struct device *parent,
		return -EINVAL;

	led_cdev = &mcled_cdev->led_cdev;
	led_cdev->flags |= LED_MULTI_COLOR;
	mcled_cdev->led_cdev.groups = led_multicolor_groups;

	return led_classdev_register_ext(parent, led_cdev, init_data);
+31 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 */

#include <linux/kernel.h>
#include <linux/led-class-multicolor.h>
#include <linux/leds.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -362,6 +363,36 @@ int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value)
}
EXPORT_SYMBOL_GPL(led_set_brightness_sync);

/*
 * This is a led-core function because just like led_set_brightness()
 * it is used in the kernel by e.g. triggers.
 */
void led_mc_set_brightness(struct led_classdev *led_cdev,
			   unsigned int *intensity_value, unsigned int num_colors,
			   unsigned int brightness)
{
	struct led_classdev_mc *mcled_cdev;
	unsigned int i;

	if (!(led_cdev->flags & LED_MULTI_COLOR)) {
		dev_err_once(led_cdev->dev, "error not a multi-color LED\n");
		return;
	}

	mcled_cdev = lcdev_to_mccdev(led_cdev);
	if (num_colors != mcled_cdev->num_colors) {
		dev_err_once(led_cdev->dev, "error num_colors mismatch %u != %u\n",
			     num_colors, mcled_cdev->num_colors);
		return;
	}

	for (i = 0; i < mcled_cdev->num_colors; i++)
		mcled_cdev->subled_info[i].intensity = intensity_value[i];

	led_set_brightness(led_cdev, brightness);
}
EXPORT_SYMBOL_GPL(led_mc_set_brightness);

int led_update_brightness(struct led_classdev *led_cdev)
{
	int ret;
+20 −0
Original line number Diff line number Diff line
@@ -396,6 +396,26 @@ void led_trigger_event(struct led_trigger *trig,
}
EXPORT_SYMBOL_GPL(led_trigger_event);

void led_mc_trigger_event(struct led_trigger *trig,
			  unsigned int *intensity_value, unsigned int num_colors,
			  enum led_brightness brightness)
{
	struct led_classdev *led_cdev;

	if (!trig)
		return;

	rcu_read_lock();
	list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) {
		if (!(led_cdev->flags & LED_MULTI_COLOR))
			continue;

		led_mc_set_brightness(led_cdev, intensity_value, num_colors, brightness);
	}
	rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(led_mc_trigger_event);

static void led_trigger_blink_setup(struct led_trigger *trig,
			     unsigned long delay_on,
			     unsigned long delay_off,
+0 −1
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ config LEDS_GROUP_MULTICOLOR
config LEDS_KTD202X
	tristate "LED support for KTD202x Chips"
	depends on I2C
	depends on OF
	select REGMAP_I2C
	help
	  This option enables support for the Kinetic KTD2026/KTD2027
+46 −34
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ struct ktd202x {
	struct device *dev;
	struct regmap *regmap;
	bool enabled;
	int num_leds;
	unsigned long num_leds;
	struct ktd202x_led leds[] __counted_by(num_leds);
};

@@ -381,16 +381,19 @@ static int ktd202x_blink_mc_set(struct led_classdev *cdev,
				 mc->num_colors);
}

static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np,
static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct fwnode_handle *fwnode,
				 struct ktd202x_led *led, struct led_init_data *init_data)
{
	struct fwnode_handle *child;
	struct led_classdev *cdev;
	struct device_node *child;
	struct mc_subled *info;
	int num_channels;
	int i = 0;

	num_channels = of_get_available_child_count(np);
	num_channels = 0;
	fwnode_for_each_available_child_node(fwnode, child)
		num_channels++;

	if (!num_channels || num_channels > chip->num_leds)
		return -EINVAL;

@@ -398,22 +401,22 @@ static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np,
	if (!info)
		return -ENOMEM;

	for_each_available_child_of_node(np, child) {
	fwnode_for_each_available_child_node(fwnode, child) {
		u32 mono_color;
		u32 reg;
		int ret;

		ret = of_property_read_u32(child, "reg", &reg);
		ret = fwnode_property_read_u32(child, "reg", &reg);
		if (ret != 0 || reg >= chip->num_leds) {
			dev_err(chip->dev, "invalid 'reg' of %pOFn\n", child);
			of_node_put(child);
			return -EINVAL;
			dev_err(chip->dev, "invalid 'reg' of %pfw\n", child);
			fwnode_handle_put(child);
			return ret;
		}

		ret = of_property_read_u32(child, "color", &mono_color);
		ret = fwnode_property_read_u32(child, "color", &mono_color);
		if (ret < 0 && ret != -EINVAL) {
			dev_err(chip->dev, "failed to parse 'color' of %pOF\n", child);
			of_node_put(child);
			dev_err(chip->dev, "failed to parse 'color' of %pfw\n", child);
			fwnode_handle_put(child);
			return ret;
		}

@@ -433,16 +436,16 @@ static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np,
	return devm_led_classdev_multicolor_register_ext(chip->dev, &led->mcdev, init_data);
}

static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np,
static int ktd202x_setup_led_single(struct ktd202x *chip, struct fwnode_handle *fwnode,
				    struct ktd202x_led *led, struct led_init_data *init_data)
{
	struct led_classdev *cdev;
	u32 reg;
	int ret;

	ret = of_property_read_u32(np, "reg", &reg);
	ret = fwnode_property_read_u32(fwnode, "reg", &reg);
	if (ret != 0 || reg >= chip->num_leds) {
		dev_err(chip->dev, "invalid 'reg' of %pOFn\n", np);
		dev_err(chip->dev, "invalid 'reg' of %pfw\n", fwnode);
		return -EINVAL;
	}
	led->index = reg;
@@ -454,7 +457,7 @@ static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np
	return devm_led_classdev_register_ext(chip->dev, &led->cdev, init_data);
}

static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigned int index)
static int ktd202x_add_led(struct ktd202x *chip, struct fwnode_handle *fwnode, unsigned int index)
{
	struct ktd202x_led *led = &chip->leds[index];
	struct led_init_data init_data = {};
@@ -463,21 +466,21 @@ static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigne
	int ret;

	/* Color property is optional in single color case */
	ret = of_property_read_u32(np, "color", &color);
	ret = fwnode_property_read_u32(fwnode, "color", &color);
	if (ret < 0 && ret != -EINVAL) {
		dev_err(chip->dev, "failed to parse 'color' of %pOF\n", np);
		dev_err(chip->dev, "failed to parse 'color' of %pfw\n", fwnode);
		return ret;
	}

	led->chip = chip;
	init_data.fwnode = of_fwnode_handle(np);
	init_data.fwnode = fwnode;

	if (color == LED_COLOR_ID_RGB) {
		cdev = &led->mcdev.led_cdev;
		ret = ktd202x_setup_led_rgb(chip, np, led, &init_data);
		ret = ktd202x_setup_led_rgb(chip, fwnode, led, &init_data);
	} else {
		cdev = &led->cdev;
		ret = ktd202x_setup_led_single(chip, np, led, &init_data);
		ret = ktd202x_setup_led_single(chip, fwnode, led, &init_data);
	}

	if (ret) {
@@ -490,15 +493,14 @@ static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigne
	return 0;
}

static int ktd202x_probe_dt(struct ktd202x *chip)
static int ktd202x_probe_fw(struct ktd202x *chip)
{
	struct device_node *np = dev_of_node(chip->dev), *child;
	struct fwnode_handle *child;
	struct device *dev = chip->dev;
	int count;
	int i = 0;

	chip->num_leds = (int)(unsigned long)of_device_get_match_data(chip->dev);

	count = of_get_available_child_count(np);
	count = device_get_child_node_count(dev);
	if (!count || count > chip->num_leds)
		return -EINVAL;

@@ -507,11 +509,11 @@ static int ktd202x_probe_dt(struct ktd202x *chip)
	/* Allow the device to execute the complete reset */
	usleep_range(200, 300);

	for_each_available_child_of_node(np, child) {
	device_for_each_child_node(dev, child) {
		int ret = ktd202x_add_led(chip, child, i);

		if (ret) {
			of_node_put(child);
			fwnode_handle_put(child);
			return ret;
		}
		i++;
@@ -554,6 +556,12 @@ static int ktd202x_probe(struct i2c_client *client)
		return ret;
	}

	ret = devm_mutex_init(dev, &chip->mutex);
	if (ret)
		return ret;

	chip->num_leds = (unsigned long)i2c_get_match_data(client);

	chip->regulators[0].supply = "vin";
	chip->regulators[1].supply = "vio";
	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(chip->regulators), chip->regulators);
@@ -568,7 +576,7 @@ static int ktd202x_probe(struct i2c_client *client)
		return ret;
	}

	ret = ktd202x_probe_dt(chip);
	ret = ktd202x_probe_fw(chip);
	if (ret < 0) {
		regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);
		return ret;
@@ -580,8 +588,6 @@ static int ktd202x_probe(struct i2c_client *client)
		return ret;
	}

	mutex_init(&chip->mutex);

	return 0;
}

@@ -590,8 +596,6 @@ static void ktd202x_remove(struct i2c_client *client)
	struct ktd202x *chip = i2c_get_clientdata(client);

	ktd202x_chip_disable(chip);

	mutex_destroy(&chip->mutex);
}

static void ktd202x_shutdown(struct i2c_client *client)
@@ -602,10 +606,17 @@ static void ktd202x_shutdown(struct i2c_client *client)
	regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET);
}

static const struct i2c_device_id ktd202x_id[] = {
	{"ktd2026", KTD2026_NUM_LEDS},
	{"ktd2027", KTD2027_NUM_LEDS},
	{}
};
MODULE_DEVICE_TABLE(i2c, ktd202x_id);

static const struct of_device_id ktd202x_match_table[] = {
	{ .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS },
	{ .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS },
	{},
	{}
};
MODULE_DEVICE_TABLE(of, ktd202x_match_table);

@@ -617,6 +628,7 @@ static struct i2c_driver ktd202x_driver = {
	.probe = ktd202x_probe,
	.remove = ktd202x_remove,
	.shutdown = ktd202x_shutdown,
	.id_table = ktd202x_id,
};
module_i2c_driver(ktd202x_driver);

Loading