Commit 945433be authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'leds-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds

Pull LED updates from Pavel Machek:
 "Small cleanups/fixes mostly thanks to Marek, nothing major made it in
  this time"

* tag 'leds-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds:
  leds: turris-omnia: check for LED_COLOR_ID_RGB instead LED_COLOR_ID_MULTI
  leds: turris-omnia: fix checkpatch warning
  leds: turris-omnia: wrap to 80 columns
  leds: turris-omnia: use constants instead of macros for color command
  dt-bindings: leds: Convert pwm to yaml
  leds: lp50xx: Fix an error handling path in 'lp50xx_probe_dt()'
  leds: netxbig: add missing put_device() call in netxbig_leds_get_of_pdata()
  Documentation: leds: remove invalidated information
parents f67d6620 98650b08
LED connected to PWM
Required properties:
- compatible : should be "pwm-leds".
Each LED is represented as a sub-node of the pwm-leds device. Each
node's name represents the name of the corresponding LED.
LED sub-node properties:
- pwms : PWM property to point to the PWM device (phandle)/port (id) and to
specify the period time to be used: <&phandle id period_ns>;
- pwm-names : (optional) Name to be used by the PWM subsystem for the PWM device
For the pwms and pwm-names property please refer to:
Documentation/devicetree/bindings/pwm/pwm.txt
- max-brightness : Maximum brightness possible for the LED
- active-low : (optional) For PWMs where the LED is wired to supply
rather than ground.
- label : (optional)
see Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger : (optional)
see Documentation/devicetree/bindings/leds/common.txt
Example:
twl_pwm: pwm {
/* provides two PWMs (id 0, 1 for PWM1 and PWM2) */
compatible = "ti,twl6030-pwm";
#pwm-cells = <2>;
};
twl_pwmled: pwmled {
/* provides one PWM (id 0 for Charing indicator LED) */
compatible = "ti,twl6030-pwmled";
#pwm-cells = <2>;
};
pwmleds {
compatible = "pwm-leds";
kpad {
label = "omap4::keypad";
pwms = <&twl_pwm 0 7812500>;
max-brightness = <127>;
};
charging {
label = "omap4:green:chrg";
pwms = <&twl_pwmled 0 7812500>;
max-brightness = <255>;
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/leds/leds-pwm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LEDs connected to PWM
maintainers:
- Pavel Machek <pavel@ucw.cz>
description:
Each LED is represented as a sub-node of the pwm-leds device. Each
node's name represents the name of the corresponding LED.
properties:
compatible:
const: pwm-leds
patternProperties:
"^led(-[0-9a-f]+)?$":
type: object
$ref: common.yaml#
properties:
pwms:
maxItems: 1
pwm-names: true
max-brightness:
description:
Maximum brightness possible for the LED
$ref: /schemas/types.yaml#/definitions/uint32
active-low:
description:
For PWMs where the LED is wired to supply rather than ground.
type: boolean
required:
- pwms
- max-brightness
additionalProperties: false
examples:
- |
#include <dt-bindings/leds/common.h>
led-controller {
compatible = "pwm-leds";
led-1 {
label = "omap4::keypad";
pwms = <&twl_pwm 0 7812500>;
max-brightness = <127>;
};
led-2 {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_CHARGING;
pwms = <&twl_pwmled 0 7812500>;
max-brightness = <255>;
};
};
...
......@@ -177,13 +177,3 @@ The LED Trigger core cannot be a module as the simple trigger functions
would cause nightmare dependency issues. I see this as a minor issue
compared to the benefits the simple trigger functionality brings. The
rest of the LED subsystem can be modular.
Future Development
==================
At the moment, a trigger can't be created specifically for a single LED.
There are a number of cases where a trigger might only be mappable to a
particular LED (ACPI?). The addition of triggers provided by the LED driver
should cover this option and be possible to add without breaking the
current interface.
......@@ -487,8 +487,10 @@ static int lp50xx_probe_dt(struct lp50xx *priv)
*/
mc_led_info = devm_kcalloc(priv->dev, LP50XX_LEDS_PER_MODULE,
sizeof(*mc_led_info), GFP_KERNEL);
if (!mc_led_info)
return -ENOMEM;
if (!mc_led_info) {
ret = -ENOMEM;
goto child_out;
}
fwnode_for_each_child_node(child, led_node) {
ret = fwnode_property_read_u32(led_node, "color",
......
......@@ -448,31 +448,39 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL);
if (!gpio_ext) {
of_node_put(gpio_ext_np);
return -ENOMEM;
ret = -ENOMEM;
goto put_device;
}
ret = netxbig_gpio_ext_get(dev, gpio_ext_dev, gpio_ext);
of_node_put(gpio_ext_np);
if (ret)
return ret;
goto put_device;
pdata->gpio_ext = gpio_ext;
/* Timers (optional) */
ret = of_property_count_u32_elems(np, "timers");
if (ret > 0) {
if (ret % 3)
return -EINVAL;
if (ret % 3) {
ret = -EINVAL;
goto put_device;
}
num_timers = ret / 3;
timers = devm_kcalloc(dev, num_timers, sizeof(*timers),
GFP_KERNEL);
if (!timers)
return -ENOMEM;
if (!timers) {
ret = -ENOMEM;
goto put_device;
}
for (i = 0; i < num_timers; i++) {
u32 tmp;
of_property_read_u32_index(np, "timers", 3 * i,
&timers[i].mode);
if (timers[i].mode >= NETXBIG_LED_MODE_NUM)
return -EINVAL;
if (timers[i].mode >= NETXBIG_LED_MODE_NUM) {
ret = -EINVAL;
goto put_device;
}
of_property_read_u32_index(np, "timers",
3 * i + 1, &tmp);
timers[i].delay_on = tmp;
......@@ -488,12 +496,15 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
num_leds = of_get_available_child_count(np);
if (!num_leds) {
dev_err(dev, "No LED subnodes found in DT\n");
return -ENODEV;
ret = -ENODEV;
goto put_device;
}
leds = devm_kcalloc(dev, num_leds, sizeof(*leds), GFP_KERNEL);
if (!leds)
return -ENOMEM;
if (!leds) {
ret = -ENOMEM;
goto put_device;
}
led = leds;
for_each_available_child_of_node(np, child) {
......@@ -574,6 +585,8 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
err_node_put:
of_node_put(child);
put_device:
put_device(gpio_ext_dev);
return ret;
}
......
......@@ -12,28 +12,20 @@
#include <linux/of.h>
#include "leds.h"
#define OMNIA_BOARD_LEDS 12
#define OMNIA_LED_NUM_CHANNELS 3
#define OMNIA_BOARD_LEDS 12
#define OMNIA_LED_NUM_CHANNELS 3
#define CMD_LED_MODE 3
#define CMD_LED_MODE_LED(l) ((l) & 0x0f)
#define CMD_LED_MODE_USER 0x10
#define CMD_LED_MODE 3
#define CMD_LED_MODE_LED(l) ((l) & 0x0f)
#define CMD_LED_MODE_USER 0x10
#define CMD_LED_STATE 4
#define CMD_LED_STATE_LED(l) ((l) & 0x0f)
#define CMD_LED_STATE_ON 0x10
#define CMD_LED_STATE 4
#define CMD_LED_STATE_LED(l) ((l) & 0x0f)
#define CMD_LED_STATE_ON 0x10
#define CMD_LED_COLOR 5
#define CMD_LED_SET_BRIGHTNESS 7
#define CMD_LED_GET_BRIGHTNESS 8
#define OMNIA_CMD 0
#define OMNIA_CMD_LED_COLOR_LED 1
#define OMNIA_CMD_LED_COLOR_R 2
#define OMNIA_CMD_LED_COLOR_G 3
#define OMNIA_CMD_LED_COLOR_B 4
#define OMNIA_CMD_LED_COLOR_LEN 5
#define CMD_LED_COLOR 5
#define CMD_LED_SET_BRIGHTNESS 7
#define CMD_LED_GET_BRIGHTNESS 8
struct omnia_led {
struct led_classdev_mc mc_cdev;
......@@ -41,7 +33,7 @@ struct omnia_led {
int reg;
};
#define to_omnia_led(l) container_of(l, struct omnia_led, mc_cdev)
#define to_omnia_led(l) container_of(l, struct omnia_led, mc_cdev)
struct omnia_leds {
struct i2c_client *client;
......@@ -55,21 +47,21 @@ static int omnia_led_brightness_set_blocking(struct led_classdev *cdev,
struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent);
struct omnia_led *led = to_omnia_led(mc_cdev);
u8 buf[OMNIA_CMD_LED_COLOR_LEN], state;
u8 buf[5], state;
int ret;
mutex_lock(&leds->lock);
led_mc_calc_color_components(&led->mc_cdev, brightness);
buf[OMNIA_CMD] = CMD_LED_COLOR;
buf[OMNIA_CMD_LED_COLOR_LED] = led->reg;
buf[OMNIA_CMD_LED_COLOR_R] = mc_cdev->subled_info[0].brightness;
buf[OMNIA_CMD_LED_COLOR_G] = mc_cdev->subled_info[1].brightness;
buf[OMNIA_CMD_LED_COLOR_B] = mc_cdev->subled_info[2].brightness;
buf[0] = CMD_LED_COLOR;
buf[1] = led->reg;
buf[2] = mc_cdev->subled_info[0].brightness;
buf[3] = mc_cdev->subled_info[1].brightness;
buf[4] = mc_cdev->subled_info[2].brightness;
state = CMD_LED_STATE_LED(led->reg);
if (buf[OMNIA_CMD_LED_COLOR_R] || buf[OMNIA_CMD_LED_COLOR_G] || buf[OMNIA_CMD_LED_COLOR_B])
if (buf[2] || buf[3] || buf[4])
state |= CMD_LED_STATE_ON;
ret = i2c_smbus_write_byte_data(leds->client, CMD_LED_STATE, state);
......@@ -98,9 +90,9 @@ static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,
}
ret = of_property_read_u32(np, "color", &color);
if (ret || color != LED_COLOR_ID_MULTI) {
if (ret || color != LED_COLOR_ID_RGB) {
dev_warn(dev,
"Node %pOF: must contain 'color' property with value LED_COLOR_ID_MULTI\n",
"Node %pOF: must contain 'color' property with value LED_COLOR_ID_RGB\n",
np);
return 0;
}
......@@ -126,18 +118,21 @@ static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,
CMD_LED_MODE_LED(led->reg) |
CMD_LED_MODE_USER);
if (ret < 0) {
dev_err(dev, "Cannot set LED %pOF to software mode: %i\n", np, ret);
dev_err(dev, "Cannot set LED %pOF to software mode: %i\n", np,
ret);
return ret;
}
/* disable the LED */
ret = i2c_smbus_write_byte_data(client, CMD_LED_STATE, CMD_LED_STATE_LED(led->reg));
ret = i2c_smbus_write_byte_data(client, CMD_LED_STATE,
CMD_LED_STATE_LED(led->reg));
if (ret < 0) {
dev_err(dev, "Cannot set LED %pOF brightness: %i\n", np, ret);
return ret;
}
ret = devm_led_classdev_multicolor_register_ext(dev, &led->mc_cdev, &init_data);
ret = devm_led_classdev_multicolor_register_ext(dev, &led->mc_cdev,
&init_data);
if (ret < 0) {
dev_err(dev, "Cannot register LED %pOF: %i\n", np, ret);
return ret;
......@@ -157,7 +152,8 @@ static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,
* file lives in the device directory of the LED controller, not an individual
* LED, so it should not confuse users.
*/
static ssize_t brightness_show(struct device *dev, struct device_attribute *a, char *buf)
static ssize_t brightness_show(struct device *dev, struct device_attribute *a,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct omnia_leds *leds = i2c_get_clientdata(client);
......@@ -173,22 +169,23 @@ static ssize_t brightness_show(struct device *dev, struct device_attribute *a, c
return sprintf(buf, "%d\n", ret);
}
static ssize_t brightness_store(struct device *dev, struct device_attribute *a, const char *buf,
size_t count)
static ssize_t brightness_store(struct device *dev, struct device_attribute *a,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct omnia_leds *leds = i2c_get_clientdata(client);
unsigned int brightness;
unsigned long brightness;
int ret;
if (sscanf(buf, "%u", &brightness) != 1)
if (kstrtoul(buf, 10, &brightness))
return -EINVAL;
if (brightness > 100)
return -EINVAL;
mutex_lock(&leds->lock);
ret = i2c_smbus_write_byte_data(client, CMD_LED_SET_BRIGHTNESS, (u8) brightness);
ret = i2c_smbus_write_byte_data(client, CMD_LED_SET_BRIGHTNESS,
(u8)brightness);
mutex_unlock(&leds->lock);
if (ret < 0)
......@@ -250,18 +247,18 @@ static int omnia_leds_probe(struct i2c_client *client,
static int omnia_leds_remove(struct i2c_client *client)
{
u8 buf[OMNIA_CMD_LED_COLOR_LEN];
u8 buf[5];
/* put all LEDs into default (HW triggered) mode */
i2c_smbus_write_byte_data(client, CMD_LED_MODE,
CMD_LED_MODE_LED(OMNIA_BOARD_LEDS));
/* set all LEDs color to [255, 255, 255] */
buf[OMNIA_CMD] = CMD_LED_COLOR;
buf[OMNIA_CMD_LED_COLOR_LED] = OMNIA_BOARD_LEDS;
buf[OMNIA_CMD_LED_COLOR_R] = 255;
buf[OMNIA_CMD_LED_COLOR_G] = 255;
buf[OMNIA_CMD_LED_COLOR_B] = 255;
buf[0] = CMD_LED_COLOR;
buf[1] = OMNIA_BOARD_LEDS;
buf[2] = 255;
buf[3] = 255;
buf[4] = 255;
i2c_master_send(client, buf, 5);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment