Commit a998a62b authored by Linus Torvalds's avatar Linus Torvalds

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

Pull LED updates from Pavel Machek:
 "Usual driver changes, some documentation that should hopefully get LED
  names standartized, and many fixes"

* tag 'leds-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds: (32 commits)
  leds: pca955x: Switch to i2c probe_new
  leds: pca955x: Let the core process the fwnode
  leds: pca955x: Implement the default-state property
  leds: pca955x: Add brightness_get function
  leds: pca955x: Clean up code formatting
  leds: leds-core: Implement the retain-state-shutdown property
  dt-bindings: leds: Add retain-state-shutdown boolean
  Documentation: leds: standartizing LED names
  leds: trigger: remove reference to obsolete CONFIG_IDE_GD_ATA
  leds: lp50xx: Fix chip name in KConfig
  leds: pwm: add support for default-state device property
  leds: move default_state read from fwnode to core
  leds: flash: Remove redundant initialization of variable ret
  leds: lgm-sso: Propagate error codes from callee to caller
  leds: trigger: audio: Add an activate callback to ensure the initial brightness is set
  leds: rt8515: Put fwnode in any case during ->probe()
  leds: lt3593: Put fwnode in any case during ->probe()
  leds: lm3697: Make error handling more robust
  leds: lm3697: Update header block to reflect reality
  leds: lm3692x: Correct headers (of*.h -> mod_devicetable.h)
  ...
parents e7c1bbcf 239f32b4
......@@ -128,6 +128,12 @@ properties:
as a panic indicator.
type: boolean
retain-state-shutdown:
description:
This property specifies that the LED should not be turned off or changed
when the system shuts down.
type: boolean
trigger-sources:
description: |
List of devices which should be used as a source triggering this LED
......
-*- org -*-
It is somehow important to provide consistent interface to the
userland. LED devices have one problem there, and that is naming of
directories in /sys/class/leds. It would be nice if userland would
just know right "name" for given LED function, but situation got more
complex.
Anyway, if backwards compatibility is not an issue, new code should
use one of the "good" names from this list, and you should extend the
list where applicable.
Legacy names are listed, too; in case you are writing application that
wants to use particular feature, you should probe for good name, first,
but then try the legacy ones, too.
Notice there's a list of functions in include/dt-bindings/leds/common.h .
* Keyboards
Good: "input*:*:capslock"
Good: "input*:*:scrolllock"
Good: "input*:*:numlock"
Legacy: "shift-key-light" (Motorola Droid 4, capslock)
Set of common keyboard LEDs, going back to PC AT or so.
Legacy: "tpacpi::thinklight" (IBM/Lenovo Thinkpads)
Legacy: "lp5523:kb{1,2,3,4,5,6}" (Nokia N900)
Frontlight/backlight of main keyboard.
Legacy: "button-backlight" (Motorola Droid 4)
Some phones have touch buttons below screen; it is different from main
keyboard. And this is their backlight.
* Sound subsystem
Good: "platform:*:mute"
Good: "platform:*:micmute"
LEDs on notebook body, indicating that sound input / output is muted.
* System notification
Legacy: "status-led:{red,green,blue}" (Motorola Droid 4)
Legacy: "lp5523:{r,g,b}" (Nokia N900)
Phones usually have multi-color status LED.
* Power management
Good: "platform:*:charging" (allwinner sun50i)
* Screen
Good: ":backlight" (Motorola Droid 4)
......@@ -2849,7 +2849,7 @@ AS3645A LED FLASH CONTROLLER DRIVER
M: Sakari Ailus <sakari.ailus@iki.fi>
L: linux-leds@vger.kernel.org
S: Maintained
F: drivers/leds/leds-as3645a.c
F: drivers/leds/flash/leds-as3645a.c
ASAHI KASEI AK7375 LENS VOICE COIL DRIVER
M: Tianshu Qiu <tian.shu.qiu@intel.com>
......
......@@ -59,16 +59,6 @@ config LEDS_88PM860X
This option enables support for on-chip LED drivers found on Marvell
Semiconductor 88PM8606 PMIC.
config LEDS_AAT1290
tristate "LED support for the AAT1290"
depends on LEDS_CLASS_FLASH
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
depends on GPIOLIB || COMPILE_TEST
depends on OF
depends on PINCTRL
help
This option enables support for the LEDs on the AAT1290.
config LEDS_AN30259A
tristate "LED support for Panasonic AN30259A"
depends on LEDS_CLASS && I2C && OF
......@@ -104,15 +94,6 @@ config LEDS_ARIEL
Say Y to if your machine is a Dell Wyse 3020 thin client.
config LEDS_AS3645A
tristate "AS3645A and LM3555 LED flash controllers support"
depends on I2C && LEDS_CLASS_FLASH
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
help
Enable LED flash class support for AS3645A LED flash
controller. V4L2 flash API is provided as well if
CONFIG_V4L2_FLASH_API is enabled.
config LEDS_AW2013
tristate "LED support for Awinic AW2013"
depends on LEDS_CLASS && I2C && OF
......@@ -239,15 +220,6 @@ config LEDS_LM3692X
This option enables support for the TI LM3692x family
of white LED string drivers used for backlighting.
config LEDS_LM3601X
tristate "LED support for LM3601x Chips"
depends on LEDS_CLASS && I2C
depends on LEDS_CLASS_FLASH
select REGMAP_I2C
help
This option enables support for the TI LM3601x family
of flash, torch and indicator classes.
config LEDS_LOCOMO
tristate "LED Support for Locomo device"
depends on LEDS_CLASS
......@@ -397,7 +369,7 @@ config LEDS_LP3952
module will be called leds-lp3952.
config LEDS_LP50XX
tristate "LED Support for TI LP5036/30/24/18/12/9 LED driver chip"
tristate "LED Support for TI LP5036/30/24/18/12/09 LED driver chip"
depends on LEDS_CLASS && REGMAP_I2C
depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
help
......@@ -699,17 +671,6 @@ config LEDS_MAX77650
help
LEDs driver for MAX77650 family of PMICs from Maxim Integrated.
config LEDS_MAX77693
tristate "LED support for MAX77693 Flash"
depends on LEDS_CLASS_FLASH
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
depends on MFD_MAX77693
depends on OF
help
This option enables support for the flash part of the MAX77693
multifunction device. It has build in control for two leds in flash
and torch mode.
config LEDS_MAX8997
tristate "LED support for MAX8997 PMIC"
depends on LEDS_CLASS && MFD_MAX8997
......@@ -741,16 +702,6 @@ config LEDS_MENF21BMC
This driver can also be built as a module. If so the module
will be called leds-menf21bmc.
config LEDS_KTD2692
tristate "LED support for KTD2692 flash LED controller"
depends on LEDS_CLASS_FLASH && OF
depends on GPIOLIB || COMPILE_TEST
help
This option enables support for KTD2692 LED flash connected
through ExpressWire interface.
Say Y to enable this driver.
config LEDS_IS31FL319X
tristate "LED Support for ISSI IS31FL319x I2C LED controller family"
depends on LEDS_CLASS && I2C && OF
......@@ -913,14 +864,6 @@ config LEDS_IP30
To compile this driver as a module, choose M here: the module
will be called leds-ip30.
config LEDS_SGM3140
tristate "LED support for the SGM3140"
depends on LEDS_CLASS_FLASH
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
help
This option enables support for the SGM3140 500mA Buck/Boost Charge
Pump LED Driver.
config LEDS_ACER_A500
tristate "Power button LED support for Acer Iconia Tab A500"
depends on LEDS_CLASS && MFD_ACER_A500_EC
......
......@@ -9,13 +9,11 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers (keep this sorted, M-| sort)
obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
obj-$(CONFIG_LEDS_ACER_A500) += leds-acer-a500.o
obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
obj-$(CONFIG_LEDS_AN30259A) += leds-an30259a.o
obj-$(CONFIG_LEDS_APU) += leds-apu.o
obj-$(CONFIG_LEDS_ARIEL) += leds-ariel.o
obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
obj-$(CONFIG_LEDS_AW2013) += leds-aw2013.o
obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
......@@ -37,12 +35,10 @@ obj-$(CONFIG_LEDS_IP30) += leds-ip30.o
obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o
obj-$(CONFIG_LEDS_IS31FL319X) += leds-is31fl319x.o
obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
obj-$(CONFIG_LEDS_LM3532) += leds-lm3532.o
obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o
obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o
obj-$(CONFIG_LEDS_LM3642) += leds-lm3642.o
obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o
......@@ -60,7 +56,6 @@ obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o
......@@ -82,7 +77,6 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o
obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
......
......@@ -611,9 +611,6 @@ static void sso_led_shutdown(struct sso_led *led)
if (led->desc.hw_trig)
regmap_update_bits(priv->mmap, SSO_CON3, BIT(led->desc.pin), 0);
if (led->gpiod)
devm_gpiod_put(priv->dev, led->gpiod);
led->priv = NULL;
}
......@@ -624,15 +621,16 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
struct device *dev = priv->dev;
struct sso_led_desc *desc;
struct sso_led *led;
struct list_head *p;
const char *tmp;
u32 prop;
int ret;
fwnode_for_each_child_node(fw_ssoled, fwnode_child) {
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
if (!led) {
ret = -ENOMEM;
goto __dt_err;
}
INIT_LIST_HEAD(&led->list);
led->priv = priv;
......@@ -642,7 +640,7 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
fwnode_child,
GPIOD_ASIS, NULL);
if (IS_ERR(led->gpiod)) {
dev_err(dev, "led: get gpio fail!\n");
ret = dev_err_probe(dev, PTR_ERR(led->gpiod), "led: get gpio fail!\n");
goto __dt_err;
}
......@@ -662,8 +660,11 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
desc->panic_indicator = 1;
ret = fwnode_property_read_u32(fwnode_child, "reg", &prop);
if (ret != 0 || prop >= SSO_LED_MAX_NUM) {
if (ret)
goto __dt_err;
if (prop >= SSO_LED_MAX_NUM) {
dev_err(dev, "invalid LED pin:%u\n", prop);
ret = -EINVAL;
goto __dt_err;
}
desc->pin = prop;
......@@ -699,21 +700,20 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
desc->brightness = LED_FULL;
}
if (sso_create_led(priv, led, fwnode_child))
ret = sso_create_led(priv, led, fwnode_child);
if (ret)
goto __dt_err;
}
fwnode_handle_put(fw_ssoled);
return 0;
__dt_err:
fwnode_handle_put(fw_ssoled);
fwnode_handle_put(fwnode_child);
/* unregister leds */
list_for_each(p, &priv->led_list) {
led = list_entry(p, struct sso_led, list);
list_for_each_entry(led, &priv->led_list, list)
sso_led_shutdown(led);
}
return -EINVAL;
return ret;
}
static int sso_led_dt_parse(struct sso_led_priv *priv)
......@@ -731,6 +731,7 @@ static int sso_led_dt_parse(struct sso_led_priv *priv)
fw_ssoled = fwnode_get_named_child_node(fwnode, "ssoled");
if (fw_ssoled) {
ret = __sso_led_dt_parse(priv, fw_ssoled);
fwnode_handle_put(fw_ssoled);
if (ret)
return ret;
}
......@@ -841,14 +842,12 @@ static int intel_sso_led_probe(struct platform_device *pdev)
static int intel_sso_led_remove(struct platform_device *pdev)
{
struct sso_led_priv *priv;
struct list_head *pos, *n;
struct sso_led *led;
struct sso_led *led, *n;
priv = platform_get_drvdata(pdev);
list_for_each_safe(pos, n, &priv->led_list) {
list_del(pos);
led = list_entry(pos, struct sso_led, list);
list_for_each_entry_safe(led, n, &priv->led_list, list) {
list_del(&led->list);
sso_led_shutdown(led);
}
......
......@@ -2,6 +2,52 @@
if LEDS_CLASS_FLASH
config LEDS_AAT1290
tristate "LED support for the AAT1290"
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
depends on GPIOLIB || COMPILE_TEST
depends on OF
depends on PINCTRL
help
This option enables support for the LEDs on the AAT1290.
config LEDS_AS3645A
tristate "AS3645A and LM3555 LED flash controllers support"
depends on I2C
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
help
Enable LED flash class support for AS3645A LED flash
controller. V4L2 flash API is provided as well if
CONFIG_V4L2_FLASH_API is enabled.
config LEDS_KTD2692
tristate "LED support for Kinetic KTD2692 flash LED controller"
depends on OF
depends on GPIOLIB || COMPILE_TEST
help
This option enables support for Kinetic KTD2692 LED flash connected
through ExpressWire interface.
Say Y to enable this driver.
config LEDS_LM3601X
tristate "LED support for LM3601x Chips"
depends on LEDS_CLASS && I2C
select REGMAP_I2C
help
This option enables support for the TI LM3601x family
of flash, torch and indicator classes.
config LEDS_MAX77693
tristate "LED support for MAX77693 Flash"
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
depends on MFD_MAX77693
depends on OF
help
This option enables support for the flash part of the MAX77693
multifunction device. It has build in control for two leds in flash
and torch mode.
config LEDS_RT4505
tristate "LED support for RT4505 flashlight controller"
depends on I2C && OF
......@@ -24,4 +70,11 @@ config LEDS_RT8515
To compile this driver as a module, choose M here: the module
will be called leds-rt8515.
config LEDS_SGM3140
tristate "LED support for the SGM3140"
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
help
This option enables support for the SGM3140 500mA Buck/Boost Charge
Pump LED Driver.
endif # LEDS_CLASS_FLASH
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o
obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o
obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o
obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o
obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o
......@@ -343,8 +343,9 @@ static int rt8515_probe(struct platform_device *pdev)
ret = devm_led_classdev_flash_register_ext(dev, fled, &init_data);
if (ret) {
dev_err(dev, "can't register LED %s\n", led->name);
fwnode_handle_put(child);
mutex_destroy(&rt->lock);
dev_err(dev, "can't register LED %s\n", led->name);
return ret;
}
......@@ -362,6 +363,7 @@ static int rt8515_probe(struct platform_device *pdev)
*/
}
fwnode_handle_put(child);
return 0;
}
......
......@@ -92,14 +92,12 @@ static ssize_t flash_strobe_store(struct device *dev,
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
unsigned long state;
ssize_t ret = -EINVAL;
ssize_t ret = -EBUSY;
mutex_lock(&led_cdev->led_access);
if (led_sysfs_is_disabled(led_cdev)) {
ret = -EBUSY;
if (led_sysfs_is_disabled(led_cdev))
goto unlock;
}
ret = kstrtoul(buf, 10, &state);
if (ret)
......
......@@ -350,10 +350,15 @@ int led_classdev_register_ext(struct device *parent,
if (ret < 0)
return ret;
if (init_data->fwnode)
if (init_data->fwnode) {
fwnode_property_read_string(init_data->fwnode,
"linux,default-trigger",
&led_cdev->default_trigger);
if (fwnode_property_present(init_data->fwnode,
"retain-state-shutdown"))
led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
}
} else {
proposed_name = led_cdev->name;
}
......@@ -444,6 +449,7 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
/* Stop blinking */
led_stop_software_blink(led_cdev);
if (!(led_cdev->flags & LED_RETAIN_AT_SHUTDOWN))
led_set_brightness(led_cdev, LED_OFF);
flush_work(&led_cdev->set_brightness_work);
......
......@@ -477,3 +477,18 @@ int led_compose_name(struct device *dev, struct led_init_data *init_data,
return 0;
}
EXPORT_SYMBOL_GPL(led_compose_name);
enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode)
{
const char *state = NULL;
if (!fwnode_property_read_string(fwnode, "default-state", &state)) {
if (!strcmp(state, "keep"))
return LEDS_DEFSTATE_KEEP;
if (!strcmp(state, "on"))
return LEDS_DEFSTATE_ON;
}
return LEDS_DEFSTATE_OFF;
}
EXPORT_SYMBOL_GPL(led_init_default_state_get);
......@@ -4,8 +4,9 @@
#include <linux/delay.h>
#include <linux/leds.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
/*
......
......@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include "leds.h"
struct gpio_led_data {
struct led_classdev cdev;
......@@ -144,7 +145,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
device_for_each_child_node(dev, child) {
struct gpio_led_data *led_dat = &priv->leds[priv->num_leds];
struct gpio_led led = {};
const char *state = NULL;
/*
* Acquire gpiod from DT with uninitialized label, which
......@@ -161,15 +161,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
led_dat->gpiod = led.gpiod;
if (!fwnode_property_read_string(child, "default-state",
&state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
led.default_state = LEDS_GPIO_DEFSTATE_ON;
else
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
led.default_state = led_init_default_state_get(child);
if (fwnode_property_present(child, "retain-state-suspended"))
led.retain_state_suspended = 1;
......
......@@ -386,6 +386,7 @@ static int is31fl32xx_parse_dt(struct device *dev,
dev_err(dev,
"Node %pOF 'reg' conflicts with another LED\n",
child);
ret = -EINVAL;
goto err;
}
......
......@@ -7,10 +7,9 @@
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/log2.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
......
......@@ -2,11 +2,16 @@
// TI LM3697 LED chip family driver
// Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
#include <linux/bits.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <linux/leds-ti-lmu-common.h>
#define LM3697_REV 0x0
......@@ -221,14 +226,12 @@ static int lm3697_probe_dt(struct lm3697 *priv)
ret = fwnode_property_read_u32(child, "reg", &control_bank);
if (ret) {
dev_err(dev, "reg property missing\n");
fwnode_handle_put(child);
goto child_out;
}
if (control_bank > LM3697_CONTROL_B) {
dev_err(dev, "reg property is invalid\n");
ret = -EINVAL;
fwnode_handle_put(child);
goto child_out;
}
......@@ -259,7 +262,6 @@ static int lm3697_probe_dt(struct lm3697 *priv)
led->num_leds);
if (ret) {
dev_err(dev, "led-sources property missing\n");
fwnode_handle_put(child);
goto child_out;
}
......@@ -284,14 +286,16 @@ static int lm3697_probe_dt(struct lm3697 *priv)
&init_data);
if (ret) {
dev_err(dev, "led register err: %d\n", ret);
fwnode_handle_put(child);
goto child_out;
}
i++;
}
return ret;
child_out:
fwnode_handle_put(child);
return ret;
}
......
......@@ -97,10 +97,9 @@ static int lt3593_led_probe(struct platform_device *pdev)
init_data.default_label = ":";
ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
if (ret < 0) {
fwnode_handle_put(child);
if (ret < 0)
return ret;
}
platform_set_drvdata(pdev, led_data);
......
......@@ -127,9 +127,9 @@ struct pca955x_led {
struct pca955x *pca955x;
struct led_classdev led_cdev;
int led_num; /* 0 .. 15 potentially */
char name[32];
u32 type;
const char *default_trigger;
int default_state;
struct fwnode_handle *fwnode;
};
struct pca955x_platform_data {
......@@ -166,11 +166,10 @@ static inline u8 pca955x_ledsel(u8 oldval, int led_num, int state)
static int pca955x_write_psc(struct i2c_client *client, int n, u8 val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + (2 * n);
int ret;
ret = i2c_smbus_write_byte_data(client,
pca95xx_num_input_regs(pca955x->chipdef->bits) + 2*n,
val);
ret = i2c_smbus_write_byte_data(client, cmd, val);
if (ret < 0)
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
__func__, n, val, ret);
......@@ -187,11 +186,10 @@ static int pca955x_write_psc(struct i2c_client *client, int n, u8 val)
static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n);
int ret;
ret = i2c_smbus_write_byte_data(client,
pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + 2*n,
val);
ret = i2c_smbus_write_byte_data(client, cmd, val);
if (ret < 0)
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
__func__, n, val, ret);
......@@ -205,11 +203,10 @@ static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val)
static int pca955x_write_ls(struct i2c_client *client, int n, u8 val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n;
int ret;
ret = i2c_smbus_write_byte_data(client,
pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n,
val);
ret = i2c_smbus_write_byte_data(client, cmd, val);
if (ret < 0)
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
__func__, n, val, ret);
......@@ -223,10 +220,10 @@ static int pca955x_write_ls(struct i2c_client *client, int n, u8 val)
static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n;
int ret;
ret = i2c_smbus_read_byte_data(client,
pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n);
ret = i2c_smbus_read_byte_data(client, cmd);
if (ret < 0) {
dev_err(&client->dev, "%s: reg 0x%x, err %d\n",
__func__, n, ret);
......@@ -236,6 +233,57 @@ static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val)
return 0;
}
static int pca955x_read_pwm(struct i2c_client *client, int n, u8 *val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n);
int ret;
ret = i2c_smbus_read_byte_data(client, cmd);
if (ret < 0) {
dev_err(&client->dev, "%s: reg 0x%x, err %d\n",
__func__, n, ret);
return ret;
}
*val = (u8)ret;
return 0;
}
static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev)
{
struct pca955x_led *pca955x_led = container_of(led_cdev,
struct pca955x_led,
led_cdev);
struct pca955x *pca955x = pca955x_led->pca955x;
u8 ls, pwm;
int ret;
ret = pca955x_read_ls(pca955x->client, pca955x_led->led_num / 4, &ls);
if (ret)
return ret;
ls = (ls >> ((pca955x_led->led_num % 4) << 1)) & 0x3;
switch (ls) {
case PCA955X_LS_LED_ON:
ret = LED_FULL;
break;
case PCA955X_LS_LED_OFF:
ret = LED_OFF;
break;
case PCA955X_LS_BLINK0:
ret = LED_HALF;
break;
case PCA955X_LS_BLINK1:
ret = pca955x_read_pwm(pca955x->client, 1, &pwm);
if (ret)
return ret;
ret = 255 - pwm;
break;
}
return ret;
}
static int pca955x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
......@@ -371,6 +419,7 @@ static struct pca955x_platform_data *
pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
{
struct pca955x_platform_data *pdata;
struct pca955x_led *led;
struct fwnode_handle *child;
int count;
......@@ -389,7 +438,7 @@ pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
return ERR_PTR(-ENOMEM);
device_for_each_child_node(&client->dev, child) {
const char *name;
const char *state;
u32 reg;
int res;
......@@ -397,17 +446,22 @@ pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
if ((res != 0) || (reg >= chip->bits))
continue;
res = fwnode_property_read_string(child, "label", &name);
if ((res != 0) && is_of_node(child))
name = to_of_node(child)->name;
snprintf(pdata->leds[reg].name, sizeof(pdata->leds[reg].name),
"%s", name);
pdata->leds[reg].type = PCA955X_TYPE_LED;
fwnode_property_read_u32(child, "type", &pdata->leds[reg].type);
fwnode_property_read_string(child, "linux,default-trigger",
&pdata->leds[reg].default_trigger);
led = &pdata->leds[reg];
led->type = PCA955X_TYPE_LED;
led->fwnode = child;
fwnode_property_read_u32(child, "type", &led->type);
if (!fwnode_property_read_string(child, "default-state",
&state)) {
if (!strcmp(state, "keep"))
led->default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
led->default_state = LEDS_GPIO_DEFSTATE_ON;
else
led->default_state = LEDS_GPIO_DEFSTATE_OFF;
} else {
led->default_state = LEDS_GPIO_DEFSTATE_OFF;
}
}
pdata->num_leds = chip->bits;
......@@ -425,18 +479,38 @@ static const struct of_device_id of_pca955x_match[] = {
};
MODULE_DEVICE_TABLE(of, of_pca955x_match);
static int pca955x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int pca955x_probe(struct i2c_client *client)
{
struct pca955x *pca955x;
struct pca955x_led *pca955x_led;
struct pca955x_chipdef *chip;
struct led_classdev *led;
struct led_init_data init_data;
struct i2c_adapter *adapter;
int i, err;
struct pca955x_platform_data *pdata;
int ngpios = 0;
bool set_default_label = false;
bool keep_pwm = false;
char default_label[8];
enum pca955x_type chip_type;
const void *md = device_get_match_data(&client->dev);
if (md) {
chip_type = (enum pca955x_type)md;
} else {
const struct i2c_device_id *id = i2c_match_id(pca955x_id,
client);
if (id) {
chip_type = (enum pca955x_type)id->driver_data;
} else {
dev_err(&client->dev, "unknown chip\n");
return -ENODEV;
}
}
chip = &pca955x_chipdefs[id->driver_data];
chip = &pca955x_chipdefs[chip_type];
adapter = client->adapter;
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
......@@ -454,8 +528,8 @@ static int pca955x_probe(struct i2c_client *client,
}
dev_info(&client->dev, "leds-pca955x: Using %s %d-bit LED driver at "
"slave address 0x%02x\n",
client->name, chip->bits, client->addr);
"slave address 0x%02x\n", client->name, chip->bits,
client->addr);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
......@@ -471,8 +545,8 @@ static int pca955x_probe(struct i2c_client *client,
if (!pca955x)
return -ENOMEM;
pca955x->leds = devm_kcalloc(&client->dev,
chip->bits, sizeof(*pca955x_led), GFP_KERNEL);
pca955x->leds = devm_kcalloc(&client->dev, chip->bits,
sizeof(*pca955x_led), GFP_KERNEL);
if (!pca955x->leds)
return -ENOMEM;
......@@ -482,6 +556,9 @@ static int pca955x_probe(struct i2c_client *client,
pca955x->client = client;
pca955x->chipdef = chip;
init_data.devname_mandatory = false;
init_data.devicename = "pca955x";
for (i = 0; i < chip->bits; i++) {
pca955x_led = &pca955x->leds[i];
pca955x_led->led_num = i;
......@@ -495,35 +572,60 @@ static int pca955x_probe(struct i2c_client *client,
ngpios++;
break;
case PCA955X_TYPE_LED:
/*
* Platform data can specify LED names and
* default triggers
*/
if (pdata->leds[i].name[0] == '\0')
snprintf(pdata->leds[i].name,
sizeof(pdata->leds[i].name), "%d", i);
led = &pca955x_led->led_cdev;
led->brightness_set_blocking = pca955x_led_set;
led->brightness_get = pca955x_led_get;
snprintf(pca955x_led->name,
sizeof(pca955x_led->name), "pca955x:%s",
pdata->leds[i].name);
if (pdata->leds[i].default_state ==
LEDS_GPIO_DEFSTATE_OFF) {
err = pca955x_led_set(led, LED_OFF);
if (err)
return err;
} else if (pdata->leds[i].default_state ==
LEDS_GPIO_DEFSTATE_ON) {
err = pca955x_led_set(led, LED_FULL);
if (err)
return err;
}
if (pdata->leds[i].default_trigger)
pca955x_led->led_cdev.default_trigger =
pdata->leds[i].default_trigger;
init_data.fwnode = pdata->leds[i].fwnode;
pca955x_led->led_cdev.name = pca955x_led->name;
pca955x_led->led_cdev.brightness_set_blocking =
pca955x_led_set;
if (is_of_node(init_data.fwnode)) {
if (to_of_node(init_data.fwnode)->name[0] ==
'\0')
set_default_label = true;
else
set_default_label = false;
} else {
set_default_label = true;
}
err = devm_led_classdev_register(&client->dev,
&pca955x_led->led_cdev);
if (err)
return err;
if (set_default_label) {
snprintf(default_label, sizeof(default_label),
"%d", i);
init_data.default_label = default_label;
} else {
init_data.default_label = NULL;
}
/* Turn off LED */
err = pca955x_led_set(&pca955x_led->led_cdev, LED_OFF);
err = devm_led_classdev_register_ext(&client->dev, led,
&init_data);
if (err)
return err;
/*
* For default-state == "keep", let the core update the
* brightness from the hardware, then check the
* brightness to see if it's using PWM1. If so, PWM1
* should not be written below.
*/
if (pdata->leds[i].default_state ==
LEDS_GPIO_DEFSTATE_KEEP) {
if (led->brightness != LED_FULL &&
led->brightness != LED_OFF &&
led->brightness != LED_HALF)
keep_pwm = true;
}
}
}
......@@ -532,10 +634,12 @@ static int pca955x_probe(struct i2c_client *client,
if (err)
return err;
if (!keep_pwm) {
/* PWM1 is used for variable brightness, default to OFF */
err = pca955x_write_pwm(client, 1, 0);
if (err)
return err;
}
/* Set to fast frequency so we do not see flashing */
err = pca955x_write_psc(client, 0, 0);
......@@ -581,7 +685,7 @@ static struct i2c_driver pca955x_driver = {
.name = "leds-pca955x",
.of_match_table = of_pca955x_match,
},
.probe = pca955x_probe,
.probe_new = pca955x_probe,
.id_table = pca955x_id,
};
......
......@@ -17,10 +17,12 @@
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include "leds.h"
struct led_pwm {
const char *name;
u8 active_low;
u8 default_state;
unsigned int max_brightness;
};
......@@ -77,7 +79,38 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
led_data->cdev.brightness_set_blocking = led_pwm_set;
/* init PWM state */
switch (led->default_state) {
case LEDS_DEFSTATE_KEEP:
pwm_get_state(led_data->pwm, &led_data->pwmstate);
if (led_data->pwmstate.period)
break;
led->default_state = LEDS_DEFSTATE_OFF;
dev_warn(dev,
"failed to read period for %s, default to off",
led->name);
fallthrough;
default:
pwm_init_state(led_data->pwm, &led_data->pwmstate);
break;
}
/* set brightness */
switch (led->default_state) {
case LEDS_DEFSTATE_ON:
led_data->cdev.brightness = led->max_brightness;
break;
case LEDS_DEFSTATE_KEEP:
{
uint64_t brightness;
brightness = led->max_brightness;
brightness *= led_data->pwmstate.duty_cycle;
do_div(brightness, led_data->pwmstate.period);
led_data->cdev.brightness = brightness;
}
break;
}
ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
if (ret) {
......@@ -86,12 +119,14 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
return ret;
}
if (led->default_state != LEDS_DEFSTATE_KEEP) {
ret = led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
if (ret) {
dev_err(dev, "failed to set led PWM value for %s: %d",
led->name, ret);
return ret;
}
}
priv->num_leds++;
return 0;
......@@ -120,6 +155,8 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
fwnode_property_read_u32(fwnode, "max-brightness",
&led.max_brightness);
led.default_state = led_init_default_state_get(fwnode);
ret = led_pwm_add(dev, priv, &led, fwnode);
if (ret)
goto err_child_out;
......
......@@ -27,6 +27,7 @@ ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t pos, size_t count);
enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
......
......@@ -34,7 +34,7 @@ config LEDS_TRIGGER_ONESHOT
config LEDS_TRIGGER_DISK
bool "LED Disk Trigger"
depends on IDE_GD_ATA || ATA
depends on ATA
help
This allows LEDs to be controlled by disk activity.
If unsure, say Y.
......
......@@ -6,10 +6,33 @@
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
#include "../leds.h"
static struct led_trigger *ledtrig_audio[NUM_AUDIO_LEDS];
static enum led_brightness audio_state[NUM_AUDIO_LEDS];
static int ledtrig_audio_mute_activate(struct led_classdev *led_cdev)
{
led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MUTE]);
return 0;
}
static int ledtrig_audio_micmute_activate(struct led_classdev *led_cdev)
{
led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MICMUTE]);
return 0;
}
static struct led_trigger ledtrig_audio[NUM_AUDIO_LEDS] = {
[LED_AUDIO_MUTE] = {
.name = "audio-mute",
.activate = ledtrig_audio_mute_activate,
},
[LED_AUDIO_MICMUTE] = {
.name = "audio-micmute",
.activate = ledtrig_audio_micmute_activate,
},
};
enum led_brightness ledtrig_audio_get(enum led_audio type)
{
return audio_state[type];
......@@ -19,24 +42,22 @@ EXPORT_SYMBOL_GPL(ledtrig_audio_get);
void ledtrig_audio_set(enum led_audio type, enum led_brightness state)
{
audio_state[type] = state;
led_trigger_event(ledtrig_audio[type], state);
led_trigger_event(&ledtrig_audio[type], state);
}
EXPORT_SYMBOL_GPL(ledtrig_audio_set);
static int __init ledtrig_audio_init(void)
{
led_trigger_register_simple("audio-mute",
&ledtrig_audio[LED_AUDIO_MUTE]);
led_trigger_register_simple("audio-micmute",
&ledtrig_audio[LED_AUDIO_MICMUTE]);
led_trigger_register(&ledtrig_audio[LED_AUDIO_MUTE]);
led_trigger_register(&ledtrig_audio[LED_AUDIO_MICMUTE]);
return 0;
}
module_init(ledtrig_audio_init);
static void __exit ledtrig_audio_exit(void)
{
led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MUTE]);
led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MICMUTE]);
led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MUTE]);
led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MICMUTE]);
}
module_exit(ledtrig_audio_exit);
......
......@@ -33,6 +33,12 @@ enum led_brightness {
LED_FULL = 255,
};
enum led_default_state {
LEDS_DEFSTATE_OFF = 0,
LEDS_DEFSTATE_ON = 1,
LEDS_DEFSTATE_KEEP = 2,
};
struct led_init_data {
/* device fwnode handle */
struct fwnode_handle *fwnode;
......@@ -520,9 +526,9 @@ struct gpio_led {
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
struct gpio_desc *gpiod;
};
#define LEDS_GPIO_DEFSTATE_OFF 0
#define LEDS_GPIO_DEFSTATE_ON 1
#define LEDS_GPIO_DEFSTATE_KEEP 2
#define LEDS_GPIO_DEFSTATE_OFF LEDS_DEFSTATE_OFF
#define LEDS_GPIO_DEFSTATE_ON LEDS_DEFSTATE_ON
#define LEDS_GPIO_DEFSTATE_KEEP LEDS_DEFSTATE_KEEP
struct gpio_led_platform_data {
int num_leds;
......
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