Skip to content

Commit

Permalink
Merge tag 'leds-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/pavel/linux-leds

Pull LED updates from Pavel Machek:

 - New driver for TI TPS6105X

 - Add managed API to get a LED from a device driver

 - Misc fixes and updates

* tag 'leds-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds: (22 commits)
  leds: lm3692x: Disable chip on brightness 0
  leds: lm3692x: Split out lm3692x_leds_disable
  leds: lm3692x: Move lm3692x_init and rename to lm3692x_leds_enable
  leds: lm3692x: Make sure we don't exceed the maximum LED current
  dt: bindings: lm3692x: Add led-max-microamp property
  leds: lm3692x: Allow to configure over voltage protection
  dt: bindings: lm3692x: Add ti,ovp-microvolt property
  leds: populate the device's of_node
  leds: Add managed API to get a LED from a device driver
  leds: Add of_led_get() and led_put()
  leds: lm3532: add pointer to documentation and fix typo
  leds: lm3532: use extended registration so that LED can be used for backlight
  leds: lm3642: remove warnings for bad strtol, cleanup gotos
  leds: rb532: cleanup whitespace
  ledtrig-pattern: fix email address quoting in MODULE_AUTHOR()
  dt-bindings: mfd: update TI tps6105x chip bindings
  leds: tps6105x: add driver for MFD chip LED mode
  led: max77650: add of_match table
  leds: bd2802: Convert to use GPIO descriptors
  leds: pca963x: Fix open-drain initialization
  ...
  • Loading branch information
Linus Torvalds committed Feb 2, 2020
2 parents 15f8e73 + 260718b commit 545ae66
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 94 deletions.
8 changes: 8 additions & 0 deletions Documentation/devicetree/bindings/leds/leds-lm3692x.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Required properties:
Optional properties:
- enable-gpios : gpio pin to enable/disable the device.
- vled-supply : LED supply
- ti,ovp-microvolt: Overvoltage protection in
micro-volt, can be 17000000, 21000000, 25000000 or
29000000. If ti,ovp-microvolt is not specified it
defaults to 29000000.

Required child properties:
- reg : 0 - Will enable all LED sync paths
Expand All @@ -31,6 +35,8 @@ Optional child properties:
- label : see Documentation/devicetree/bindings/leds/common.txt (deprecated)
- linux,default-trigger :
see Documentation/devicetree/bindings/leds/common.txt
- led-max-microamp :
see Documentation/devicetree/bindings/leds/common.txt

Example:

Expand All @@ -44,12 +50,14 @@ led-controller@36 {

enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
vled-supply = <&vbatt>;
ti,ovp-microvolt = <29000000>;

led@0 {
reg = <0>;
function = LED_FUNCTION_BACKLIGHT;
color = <LED_COLOR_ID_WHITE>;
linux,default-trigger = "backlight";
led-max-microamp = <20000>;
};
}

Expand Down
47 changes: 46 additions & 1 deletion Documentation/devicetree/bindings/mfd/tps6105x.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,56 @@ Required properties:
- compatible: "ti,tps61050" or "ti,tps61052"
- reg: Specifies the I2C slave address

Example:
Optional sub-node:

This subnode selects the chip's operational mode.
There can be at most one single available subnode.

- regulator: presence of this sub-node puts the chip in regulator mode.
see ../regulator/regulator.yaml

- led: presence of this sub-node puts the chip in led mode.
Optional properties:
- function : see ../leds/common.txt
- color : see ../leds/common.txt
- label : see ../leds/common.txt
(deprecated)

Example (GPIO operation only):

i2c0 {
tps61052@33 {
compatible = "ti,tps61052";
reg = <0x33>;
};
};

Example (GPIO + regulator operation):

i2c0 {
tps61052@33 {
compatible = "ti,tps61052";
reg = <0x33>;

regulator {
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-always-on;
};
};
};

Example (GPIO + led operation):

#include <dt-bindings/leds/common.h>

i2c0 {
tps61052@33 {
compatible = "ti,tps61052";
reg = <0x33>;

led {
color = <LED_COLOR_ID_WHITE>;
};
};
};
10 changes: 10 additions & 0 deletions drivers/leds/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,16 @@ config LEDS_LM36274
Say Y to enable the LM36274 LED driver for TI LMU devices.
This supports the LED device LM36274.

config LEDS_TPS6105X
tristate "LED support for TI TPS6105X"
depends on LEDS_CLASS
depends on TPS6105X
default y if TPS6105X
help
This driver supports TPS61050/TPS61052 LED chips.
It is a single boost converter primarily for white LEDs and
audio amplifiers.

comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"

Expand Down
1 change: 1 addition & 0 deletions drivers/leds/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o
obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o
obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o
obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o

# LED SPI Drivers
obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
Expand Down
97 changes: 96 additions & 1 deletion drivers/leds/led-class.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <uapi/linux/uleds.h>
#include <linux/of.h>
#include "leds.h"

static struct class *leds_class;
Expand Down Expand Up @@ -214,6 +215,98 @@ static int led_resume(struct device *dev)

static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);

/**
* of_led_get() - request a LED device via the LED framework
* @np: device node to get the LED device from
* @index: the index of the LED
*
* Returns the LED device parsed from the phandle specified in the "leds"
* property of a device tree node or a negative error-code on failure.
*/
struct led_classdev *of_led_get(struct device_node *np, int index)
{
struct device *led_dev;
struct led_classdev *led_cdev;
struct device_node *led_node;

led_node = of_parse_phandle(np, "leds", index);
if (!led_node)
return ERR_PTR(-ENOENT);

led_dev = class_find_device_by_of_node(leds_class, led_node);
of_node_put(led_node);

if (!led_dev)
return ERR_PTR(-EPROBE_DEFER);

led_cdev = dev_get_drvdata(led_dev);

if (!try_module_get(led_cdev->dev->parent->driver->owner))
return ERR_PTR(-ENODEV);

return led_cdev;
}
EXPORT_SYMBOL_GPL(of_led_get);

/**
* led_put() - release a LED device
* @led_cdev: LED device
*/
void led_put(struct led_classdev *led_cdev)
{
module_put(led_cdev->dev->parent->driver->owner);
}
EXPORT_SYMBOL_GPL(led_put);

static void devm_led_release(struct device *dev, void *res)
{
struct led_classdev **p = res;

led_put(*p);
}

/**
* devm_of_led_get - Resource-managed request of a LED device
* @dev: LED consumer
* @index: index of the LED to obtain in the consumer
*
* The device node of the device is parse to find the request LED device.
* The LED device returned from this function is automatically released
* on driver detach.
*
* @return a pointer to a LED device or ERR_PTR(errno) on failure.
*/
struct led_classdev *__must_check devm_of_led_get(struct device *dev,
int index)
{
struct led_classdev *led;
struct led_classdev **dr;

if (!dev)
return ERR_PTR(-EINVAL);

/* Not using device tree? */
if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
return ERR_PTR(-ENOTSUPP);

led = of_led_get(dev->of_node, index);
if (IS_ERR(led))
return led;

dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *),
GFP_KERNEL);
if (!dr) {
led_put(led);
return ERR_PTR(-ENOMEM);
}

*dr = led;
devres_add(dev, dr);

return led;
}
EXPORT_SYMBOL_GPL(devm_of_led_get);

static int led_classdev_next_name(const char *init_name, char *name,
size_t len)
{
Expand Down Expand Up @@ -276,8 +369,10 @@ int led_classdev_register_ext(struct device *parent,
mutex_unlock(&led_cdev->led_access);
return PTR_ERR(led_cdev->dev);
}
if (init_data && init_data->fwnode)
if (init_data && init_data->fwnode) {
led_cdev->dev->fwnode = init_data->fwnode;
led_cdev->dev->of_node = to_of_node(init_data->fwnode);
}

if (ret)
dev_warn(parent, "Led %s renamed to %s due to name collision",
Expand Down
27 changes: 18 additions & 9 deletions drivers/leds/leds-bd2802.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/leds.h>
#include <linux/leds-bd2802.h>
Expand Down Expand Up @@ -67,6 +67,7 @@ struct led_state {
struct bd2802_led {
struct bd2802_led_platform_data *pdata;
struct i2c_client *client;
struct gpio_desc *reset;
struct rw_semaphore rwsem;

struct led_state led[2];
Expand Down Expand Up @@ -200,7 +201,7 @@ static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
return;

if (bd2802_is_all_off(led) && !led->adf_on) {
gpio_set_value(led->pdata->reset_gpio, 0);
gpiod_set_value(led->reset, 1);
return;
}

Expand All @@ -226,7 +227,7 @@ static void bd2802_configure(struct bd2802_led *led)

static void bd2802_reset_cancel(struct bd2802_led *led)
{
gpio_set_value(led->pdata->reset_gpio, 1);
gpiod_set_value(led->reset, 0);
udelay(100);
bd2802_configure(led);
}
Expand Down Expand Up @@ -420,7 +421,7 @@ static void bd2802_disable_adv_conf(struct bd2802_led *led)
bd2802_addr_attributes[i]);

if (bd2802_is_all_off(led))
gpio_set_value(led->pdata->reset_gpio, 0);
gpiod_set_value(led->reset, 1);

led->adf_on = 0;
}
Expand Down Expand Up @@ -670,8 +671,16 @@ static int bd2802_probe(struct i2c_client *client,
pdata = led->pdata = dev_get_platdata(&client->dev);
i2c_set_clientdata(client, led);

/* Configure RESET GPIO (L: RESET, H: RESET cancel) */
gpio_request_one(pdata->reset_gpio, GPIOF_OUT_INIT_HIGH, "RGB_RESETB");
/*
* Configure RESET GPIO (L: RESET, H: RESET cancel)
*
* We request the reset GPIO as OUT_LOW which means de-asserted,
* board files specifying this GPIO line in a machine descriptor
* table should take care to specify GPIO_ACTIVE_LOW for this line.
*/
led->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(led->reset))
return PTR_ERR(led->reset);

/* Tacss = min 0.1ms */
udelay(100);
Expand All @@ -685,7 +694,7 @@ static int bd2802_probe(struct i2c_client *client,
dev_info(&client->dev, "return 0x%02x\n", ret);

/* To save the power, reset BD2802 after detecting */
gpio_set_value(led->pdata->reset_gpio, 0);
gpiod_set_value(led->reset, 1);

/* Default attributes */
led->wave_pattern = BD2802_PATTERN_HALF;
Expand Down Expand Up @@ -720,7 +729,7 @@ static int bd2802_remove(struct i2c_client *client)
struct bd2802_led *led = i2c_get_clientdata(client);
int i;

gpio_set_value(led->pdata->reset_gpio, 0);
gpiod_set_value(led->reset, 1);
bd2802_unregister_led_classdev(led);
if (led->adf_on)
bd2802_disable_adv_conf(led);
Expand Down Expand Up @@ -750,7 +759,7 @@ static int bd2802_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct bd2802_led *led = i2c_get_clientdata(client);

gpio_set_value(led->pdata->reset_gpio, 0);
gpiod_set_value(led->reset, 1);

return 0;
}
Expand Down
8 changes: 7 additions & 1 deletion drivers/leds/leds-lm3532.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,12 @@ static int lm3532_parse_node(struct lm3532_data *priv)
priv->runtime_ramp_down = lm3532_get_ramp_index(ramp_time);

device_for_each_child_node(priv->dev, child) {
struct led_init_data idata = {
.fwnode = child,
.default_label = ":",
.devicename = priv->client->name,
};

led = &priv->leds[i];

ret = fwnode_property_read_u32(child, "reg", &control_bank);
Expand Down Expand Up @@ -652,7 +658,7 @@ static int lm3532_parse_node(struct lm3532_data *priv)
led->led_dev.name = led->label;
led->led_dev.brightness_set_blocking = lm3532_brightness_set;

ret = devm_led_classdev_register(priv->dev, &led->led_dev);
ret = devm_led_classdev_register_ext(priv->dev, &led->led_dev, &idata);
if (ret) {
dev_err(&priv->client->dev, "led register err: %d\n",
ret);
Expand Down
Loading

0 comments on commit 545ae66

Please sign in to comment.