Pull request for 5.10-rc1.

Quite a lot of stuff is going on here. Great cleanups/fixes from Marek
 and others are biggest part.
 
 I limited CPU LED trigger to 8 LEDs, because it was willing to
 register 1024 "triggers" on machine with 1024 CPUs. I don't believe it
 will cause any problems, but we can raise the limit if it does.
 -----BEGIN PGP SIGNATURE-----
 
 iF0EABECAB0WIQRPfPO7r0eAhk010v0w5/Bqldv68gUCX4bazAAKCRAw5/Bqldv6
 8tVrAJ4szXoDAwqphVAV1UBVDLfW8TmgogCgjLkj6bqMxBukSp2ynEVEoqyuPBQ=
 =a+Fi
 -----END PGP SIGNATURE-----

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

Pull LED updates from Pavel Machek:
 "Quite a lot of stuff is going on here. Great cleanups/fixes from Marek
  and others are biggest part.

  I limited CPU LED trigger to 8 LEDs, because it was willing to
  register 1024 'triggers' on machine with 1024 CPUs. I don't believe it
  will cause any problems, but we can raise the limit if it does"

* tag 'leds-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds: (84 commits)
  leds: pwm: Remove platform_data support
  leds: lm3697: Fix out-of-bound access
  leds: ns2: do not guard OF match pointer with of_match_ptr
  leds: ns2: convert to fwnode API
  leds: tlc591xx: fix leak of device node iterator
  leds: pca963x: use struct led_init_data when registering
  leds: pca963x: register LEDs immediately after parsing, get rid of platdata
  leds: tca6507: remove binding comment
  leds: tca6507: cosmetic change: use helper variable
  leds: tca6507: do not set GPIO names
  dt-bindings: leds: tca6507: convert to YAML
  ledtrig-cpu: Limit to 8 CPUs
  leds: TODO: Add documentation about possible subsystem improvements
  leds: pca9532: read pwm settings from device tree
  leds: pca9532: correct shift computation in pca9532_getled
  leds: lm36274: Fix warning for undefined parameters
  leds: lm3532: Fix warnings for undefined parameters
  leds: pca963x: use flexible array
  leds: pca963x: cosmetic: rename variables
  leds: pca963x: cosmetic: rename variables
  ...
This commit is contained in:
Linus Torvalds 2020-10-14 15:22:07 -07:00
commit 7fafb54c7d
61 changed files with 1789 additions and 1102 deletions

View File

@ -16,6 +16,7 @@ Optional properties:
- audio-gain-db : audio gain selection for external analog modulation input.
Valid values: 0 - 21, step by 3 (rounded down)
Default: 0
- shutdown-gpios : Specifier of the GPIO connected to SDB pin of the chip.
Each led is represented as a sub-node of the issi,is31fl319x device.
There can be less leds subnodes than the chip can support but not more.
@ -44,6 +45,7 @@ fancy_leds: leds@65 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x65>;
shutdown-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>;
red_aux: led@1 {
label = "red:aux";

View File

@ -0,0 +1,130 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/leds/leds-lp50xx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LED driver for LP50XX RGB LED from Texas Instruments.
maintainers:
- Dan Murphy <dmurphy@ti.com>
description: |
The LP50XX is multi-channel, I2C RGB LED Drivers that can group RGB LEDs into
a LED group or control them individually.
The difference in these RGB LED drivers is the number of supported RGB
modules.
For more product information please see the link below:
https://www.ti.com/lit/ds/symlink/lp5012.pdf
https://www.ti.com/lit/ds/symlink/lp5024.pdf
https://www.ti.com/lit/ds/symlink/lp5036.pdf
properties:
compatible:
enum:
- ti,lp5009
- ti,lp5012
- ti,lp5018
- ti,lp5024
- ti,lp5030
- ti,lp5036
reg:
maxItems: 1
description:
I2C slave address
lp5009/12 - 0x14, 0x15, 0x16, 0x17
lp5018/24 - 0x28, 0x29, 0x2a, 0x2b
lp5030/36 - 0x30, 0x31, 0x32, 0x33
enable-gpios:
maxItems: 1
description: GPIO pin to enable/disable the device.
vled-supply:
description: LED supply.
patternProperties:
'^multi-led@[0-9a-f]$':
type: object
allOf:
- $ref: leds-class-multicolor.yaml#
properties:
reg:
minItems: 1
maxItems: 12
description:
This property denotes the LED module number(s) that is used on the
for the child node. The LED modules can either be used stand alone
or grouped into a module bank.
patternProperties:
"(^led-[0-9a-f]$|led)":
type: object
$ref: common.yaml#
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
led-controller@14 {
compatible = "ti,lp5009";
reg = <0x14>;
#address-cells = <1>;
#size-cells = <0>;
enable-gpios = <&gpio1 16>;
multi-led@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x1>;
color = <LED_COLOR_ID_RGB>;
function = LED_FUNCTION_CHARGING;
led-0 {
color = <LED_COLOR_ID_RED>;
};
led-1 {
color = <LED_COLOR_ID_GREEN>;
};
led-2 {
color = <LED_COLOR_ID_BLUE>;
};
};
multi-led@2 {
#address-cells = <1>;
#size-cells = <2>;
reg = <0x2 0x3 0x5>;
color = <LED_COLOR_ID_RGB>;
function = LED_FUNCTION_STANDBY;
led-6 {
color = <LED_COLOR_ID_RED>;
};
led-7 {
color = <LED_COLOR_ID_GREEN>;
};
led-8 {
color = <LED_COLOR_ID_BLUE>;
};
};
};
};
...

View File

@ -189,7 +189,7 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
reg = <0x2>;
color = <LED_COLOR_ID_MULTI>;
color = <LED_COLOR_ID_RGB>;
function = LED_FUNCTION_STANDBY;
linux,default-trigger = "heartbeat";

View File

@ -9,6 +9,7 @@ Required properties:
"nxp,pca9550"
"nxp,pca9551"
"nxp,pca9552"
"ibm,pca9552"
"nxp,pca9553"
- #address-cells: must be 1
- #size-cells: must be 0

View File

@ -1,49 +0,0 @@
LEDs connected to tca6507
Required properties:
- compatible : should be : "ti,tca6507".
- #address-cells: must be 1
- #size-cells: must be 0
- reg: typically 0x45.
Optional properties:
- gpio-controller: allows lines to be used as output-only GPIOs.
- #gpio-cells: if present, must not be 0.
Each led is represented as a sub-node of the ti,tca6507 device.
LED sub-node properties:
- label : (optional) see Documentation/devicetree/bindings/leds/common.txt
- reg : number of LED line (could be from 0 to 6)
- linux,default-trigger : (optional)
see Documentation/devicetree/bindings/leds/common.txt
- compatible: either "led" (the default) or "gpio".
Examples:
tca6507@45 {
compatible = "ti,tca6507";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x45>;
gpio-controller;
#gpio-cells = <2>;
led0: red-aux@0 {
label = "red:aux";
reg = <0x0>;
};
led1: green-aux@1 {
label = "green:aux";
reg = <0x5>;
linux,default-trigger = "default-on";
};
wifi-reset@6 {
reg = <0x6>;
compatible = "gpio";
};
};

View File

@ -0,0 +1,134 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/leds/ti,tca6507.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TCA6507 LED and GPIO controller
maintainers:
- NeilBrown <neilb@suse.de>
description:
The TCA6507 is a programmable LED controller connected via I2C that can drive
7 separate lines either by holding them low, or by pulsing them with modulated
width.
properties:
compatible:
const: ti,tca6507
reg:
description: I2C slave address of the controller.
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 0
gpio-controller: true
"#gpio-cells":
const: 2
gpio-line-names: true
patternProperties:
"^led@[0-6]$":
type: object
$ref: common.yaml#
properties:
reg:
minimum: 0
maximum: 6
required:
- reg
"^gpio@[0-6]$":
type: object
properties:
compatible:
const: gpio
reg:
minimum: 0
maximum: 6
additionalProperties: false
required:
- reg
- compatible
if:
patternProperties:
"^gpio@[0-6]$":
properties:
compatible:
contains:
const: gpio
then:
required:
- gpio-controller
- "#gpio-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
led-controller@45 {
compatible = "ti,tca6507";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x45>;
gpio-controller;
#gpio-cells = <2>;
gpio-line-names = "wifi_reset@6";
led@0 {
label = "gta04:red:aux";
reg = <0x0>;
};
led@1 {
label = "gta04:green:aux";
reg = <0x1>;
};
led@3 {
reg = <0x3>;
color = <LED_COLOR_ID_RED>;
function = LED_FUNCTION_POWER;
linux,default-trigger = "default-on";
};
led@4 {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_POWER;
reg = <0x4>;
};
gpio@6 {
compatible = "gpio";
reg = <0x6>;
};
};
};
...

View File

@ -17,12 +17,6 @@ set a timer to hold a state, however when user space application crashes or
goes away without deactivating the timer, the hardware will be left in that
state permanently.
As a specific example of this use-case, let's look at vibrate feature on
phones. Vibrate function on phones is implemented using PWM pins on SoC or
PMIC. There is a need to activate one shot timer to control the vibrate
feature, to prevent user space crashes leaving the phone in vibrate mode
permanently causing the battery to drain.
Transient trigger addresses the need for one shot timer activation. The
transient trigger can be enabled and disabled just like the other leds
triggers.
@ -159,7 +153,6 @@ repeat the following step as needed::
This trigger is intended to be used for the following example use cases:
- Control of vibrate (phones, tablets etc.) hardware by user space app.
- Use of LED by user space app as activity indicator.
- Use of LED by user space app as a kind of watchdog indicator -- as
long as the app is alive, it can keep the LED illuminated, if it dies

View File

@ -274,7 +274,7 @@ config LEDS_MT6323
config LEDS_S3C24XX
tristate "LED Support for Samsung S3C24XX GPIO LEDs"
depends on LEDS_CLASS
depends on ARCH_S3C24XX
depends on ARCH_S3C24XX || COMPILE_TEST
help
This option enables support for LEDs connected to GPIO lines
on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440.
@ -304,13 +304,13 @@ config LEDS_WRAP
config LEDS_COBALT_QUBE
tristate "LED Support for the Cobalt Qube series front LED"
depends on LEDS_CLASS
depends on MIPS_COBALT
depends on MIPS_COBALT || COMPILE_TEST
help
This option enables support for the front LED on Cobalt Qube series
config LEDS_COBALT_RAQ
bool "LED Support for the Cobalt Raq series"
depends on LEDS_CLASS=y && MIPS_COBALT
depends on LEDS_CLASS=y && (MIPS_COBALT || COMPILE_TEST)
select LEDS_TRIGGERS
help
This option enables support for the Cobalt Raq series LEDs.
@ -395,8 +395,20 @@ config LEDS_LP3952
To compile this driver as a module, choose M here: the
module will be called leds-lp3952.
config LEDS_LP50XX
tristate "LED Support for TI LP5036/30/24/18/12/9 LED driver chip"
depends on LEDS_CLASS && REGMAP_I2C
depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
help
If you say yes here you get support for the Texas Instruments
LP5036, LP5030, LP5024, LP5018, LP5012 and LP5009 LED driver.
To compile this driver as a module, choose M here: the
module will be called leds-lp50xx.
config LEDS_LP55XX_COMMON
tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
depends on LEDS_CLASS
depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
depends on OF
depends on I2C
@ -632,7 +644,7 @@ config LEDS_MC13783
config LEDS_NS2
tristate "LED support for Network Space v2 GPIO LEDs"
depends on LEDS_CLASS
depends on MACH_KIRKWOOD || MACH_ARMADA_370
depends on MACH_KIRKWOOD || MACH_ARMADA_370 || COMPILE_TEST
default y
help
This option enables support for the dual-GPIO LEDs found on the
@ -646,7 +658,7 @@ config LEDS_NS2
config LEDS_NETXBIG
tristate "LED support for Big Network series LEDs"
depends on LEDS_CLASS
depends on MACH_KIRKWOOD
depends on MACH_KIRKWOOD || COMPILE_TEST
depends on OF_GPIO
default y
help
@ -893,7 +905,7 @@ config LEDS_TPS6105X
config LEDS_IP30
tristate "LED support for SGI Octane machines"
depends on LEDS_CLASS
depends on SGI_MFD_IOC3
depends on SGI_MFD_IOC3 || COMPILE_TEST
help
This option enables support for the Red and White LEDs of
SGI Octane machines.
@ -909,6 +921,13 @@ config LEDS_SGM3140
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
help
This option enables support for the Power Button LED of
Acer Iconia Tab A500.
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"

View File

@ -10,6 +10,7 @@ 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
@ -49,6 +50,7 @@ obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
obj-$(CONFIG_LEDS_LP3952) += leds-lp3952.o
obj-$(CONFIG_LEDS_LP50XX) += leds-lp50xx.o
obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o
obj-$(CONFIG_LEDS_LP5562) += leds-lp5562.o

75
drivers/leds/TODO Normal file
View File

@ -0,0 +1,75 @@
-*- org -*-
* On/off LEDs should have max_brightness of 1
* Get rid of enum led_brightness
It is really an integer, as maximum is configurable. Get rid of it, or
make it into typedef or something.
* Review atomicity requirements in LED subsystem
Calls that may and that may not block are mixed in same structure, and
semantics is sometimes non-intuitive. (For example blink callback may
not sleep.) Review the requirements for any bugs and document them
clearly.
* LED names are still a mess
No two LEDs have same name, so the names are probably unusable for the
userland. Nudge authors into creating common LED names for common
functionality.
? Perhaps check for known LED names during boot, and warn if there are
LEDs not on the list?
* Split drivers into subdirectories
The number of drivers is getting big, and driver for on/off LED on a
i/o port is really quite different from camera flash LED, which is
really different from driver for RGB color LED that can run its own
microcode. Split the drivers somehow.
* Figure out what to do with RGB leds
Multicolor is a bit too abstract. Yes, we can have
Green-Magenta-Ultraviolet LED, but so far all the LEDs we support are
RGB, and not even RGB-White or RGB-Yellow variants emerged.
Multicolor is not a good fit for RGB LED. It does not really know
about LED color. In particular, there's no way to make LED "white".
Userspace is interested in knowing "this LED can produce arbitrary
color", which not all multicolor LEDs can.
Proposal: let's add "rgb" to led_colors in drivers/leds/led-core.c,
add corresponding device tree defines, and use that, instead of
multicolor for RGB LEDs.
We really need to do that now; "white" stuff can wait.
RGB LEDs are quite common, and it would be good to be able to turn LED
white and to turn it into any arbitrary color. It is essential that
userspace is able to set arbitrary colors, and it might be good to
have that ability from kernel, too... to allow full-color triggers.
* Command line utility to manipulate the LEDs?
/sys interface is not really suitable to use by hand, should we have
an utility to perform LED control?
In particular, LED names are still a mess (see above) and utility
could help there by presenting both old and new names while we clean
them up.
In future, I'd like utility to accept both old and new names while we
clean them up.
It would be also nice to have useful listing mode -- name, type,
current brightness/trigger...
In future, it would be good to be able to set rgb led to particular
color.
And probably user-friendly interface to access LEDs for particular
ethernet interface would be nice.

View File

@ -354,6 +354,11 @@ int led_classdev_register_ext(struct device *parent,
ret = led_compose_name(parent, init_data, composed_name);
if (ret < 0)
return ret;
if (init_data->fwnode)
fwnode_property_read_string(init_data->fwnode,
"linux,default-trigger",
&led_cdev->default_trigger);
} else {
proposed_name = led_cdev->name;
}

View File

@ -118,14 +118,14 @@ static int pm860x_led_dt_init(struct platform_device *pdev,
struct device_node *nproot, *np;
int iset = 0;
if (!pdev->dev.parent->of_node)
if (!dev_of_node(pdev->dev.parent))
return -ENODEV;
nproot = of_get_child_by_name(pdev->dev.parent->of_node, "leds");
nproot = of_get_child_by_name(dev_of_node(pdev->dev.parent), "leds");
if (!nproot) {
dev_err(&pdev->dev, "failed to find leds node\n");
return -ENODEV;
}
for_each_child_of_node(nproot, np) {
for_each_available_child_of_node(nproot, np) {
if (of_node_name_eq(np, data->name)) {
of_property_read_u32(np, "marvell,88pm860x-iset",
&iset);

View File

@ -248,7 +248,7 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
}
#endif
child_node = of_get_next_available_child(dev->of_node, NULL);
child_node = of_get_next_available_child(dev_of_node(dev), NULL);
if (!child_node) {
dev_err(dev, "No DT child node found for connected LED.\n");
return -EINVAL;

View File

@ -0,0 +1,129 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define A500_EC_LED_DELAY_USEC (100 * 1000)
enum {
REG_RESET_LEDS = 0x40,
REG_POWER_LED_ON = 0x42,
REG_CHARGE_LED_ON = 0x43,
REG_ANDROID_LEDS_OFF = 0x5a,
};
struct a500_led {
struct led_classdev cdev;
const struct reg_sequence *enable_seq;
struct a500_led *other;
struct regmap *rmap;
};
static const struct reg_sequence a500_ec_leds_reset_seq[] = {
REG_SEQ(REG_RESET_LEDS, 0x0, A500_EC_LED_DELAY_USEC),
REG_SEQ(REG_ANDROID_LEDS_OFF, 0x0, A500_EC_LED_DELAY_USEC),
};
static const struct reg_sequence a500_ec_white_led_enable_seq[] = {
REG_SEQ(REG_POWER_LED_ON, 0x0, A500_EC_LED_DELAY_USEC),
};
static const struct reg_sequence a500_ec_orange_led_enable_seq[] = {
REG_SEQ(REG_CHARGE_LED_ON, 0x0, A500_EC_LED_DELAY_USEC),
};
static int a500_ec_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct a500_led *led = container_of(led_cdev, struct a500_led, cdev);
struct reg_sequence control_seq[2];
unsigned int num_regs = 1;
if (value) {
control_seq[0] = led->enable_seq[0];
} else {
/*
* There is no separate controls which can disable LEDs
* individually, there is only RESET_LEDS command that turns
* off both LEDs.
*
* RESET_LEDS turns off both LEDs, thus restore other LED if
* it's turned ON.
*/
if (led->other->cdev.brightness)
num_regs = 2;
control_seq[0] = a500_ec_leds_reset_seq[0];
control_seq[1] = led->other->enable_seq[0];
}
return regmap_multi_reg_write(led->rmap, control_seq, num_regs);
}
static int a500_ec_leds_probe(struct platform_device *pdev)
{
struct a500_led *white_led, *orange_led;
struct regmap *rmap;
int err;
rmap = dev_get_regmap(pdev->dev.parent, "KB930");
if (!rmap)
return -EINVAL;
/* reset and turn off LEDs */
regmap_multi_reg_write(rmap, a500_ec_leds_reset_seq, 2);
white_led = devm_kzalloc(&pdev->dev, sizeof(*white_led), GFP_KERNEL);
if (!white_led)
return -ENOMEM;
white_led->cdev.name = "power:white";
white_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
white_led->cdev.flags = LED_CORE_SUSPENDRESUME;
white_led->cdev.max_brightness = 1;
white_led->enable_seq = a500_ec_white_led_enable_seq;
white_led->rmap = rmap;
orange_led = devm_kzalloc(&pdev->dev, sizeof(*orange_led), GFP_KERNEL);
if (!orange_led)
return -ENOMEM;
orange_led->cdev.name = "power:orange";
orange_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
orange_led->cdev.flags = LED_CORE_SUSPENDRESUME;
orange_led->cdev.max_brightness = 1;
orange_led->enable_seq = a500_ec_orange_led_enable_seq;
orange_led->rmap = rmap;
white_led->other = orange_led;
orange_led->other = white_led;
err = devm_led_classdev_register(&pdev->dev, &white_led->cdev);
if (err) {
dev_err(&pdev->dev, "failed to register white LED\n");
return err;
}
err = devm_led_classdev_register(&pdev->dev, &orange_led->cdev);
if (err) {
dev_err(&pdev->dev, "failed to register orange LED\n");
return err;
}
return 0;
}
static struct platform_driver a500_ec_leds_driver = {
.driver = {
.name = "acer-a500-iconia-leds",
},
.probe = a500_ec_leds_probe,
};
module_platform_driver(a500_ec_leds_driver);
MODULE_DESCRIPTION("LED driver for Acer Iconia Tab A500 Power Button");
MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
MODULE_ALIAS("platform:acer-a500-iconia-leds");
MODULE_LICENSE("GPL");

View File

@ -202,13 +202,13 @@ static int an30259a_blink_set(struct led_classdev *cdev,
static int an30259a_dt_init(struct i2c_client *client,
struct an30259a *chip)
{
struct device_node *np = client->dev.of_node, *child;
struct device_node *np = dev_of_node(&client->dev), *child;
int count, ret;
int i = 0;
const char *str;
struct an30259a_led *led;
count = of_get_child_count(np);
count = of_get_available_child_count(np);
if (!count || count > AN30259A_MAX_LEDS)
return -EINVAL;
@ -238,9 +238,6 @@ static int an30259a_dt_init(struct i2c_client *client,
led->default_state = STATE_OFF;
}
of_property_read_string(child, "linux,default-trigger",
&led->cdev.default_trigger);
i++;
}

View File

@ -261,11 +261,11 @@ static int aw2013_blink_set(struct led_classdev *cdev,
static int aw2013_probe_dt(struct aw2013 *chip)
{
struct device_node *np = chip->client->dev.of_node, *child;
struct device_node *np = dev_of_node(&chip->client->dev), *child;
int count, ret = 0, i = 0;
struct aw2013_led *led;
count = of_get_child_count(np);
count = of_get_available_child_count(np);
if (!count || count > AW2013_MAX_LEDS)
return -EINVAL;
@ -297,16 +297,15 @@ static int aw2013_probe_dt(struct aw2013 *chip)
"DT property led-max-microamp is missing\n");
}
of_property_read_string(child, "linux,default-trigger",
&led->cdev.default_trigger);
led->cdev.brightness_set_blocking = aw2013_brightness_set;
led->cdev.blink_set = aw2013_blink_set;
ret = devm_led_classdev_register_ext(&chip->client->dev,
&led->cdev, &init_data);
if (ret < 0)
if (ret < 0) {
of_node_put(child);
return ret;
}
i++;
}

View File

@ -328,6 +328,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
void __iomem *mem, spinlock_t *lock,
unsigned long *blink_leds, unsigned long *blink_delay)
{
struct led_init_data init_data = {};
struct bcm6328_led *led;
const char *state;
int rc;
@ -345,11 +346,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
if (of_property_read_bool(nc, "active-low"))
led->active_low = true;
led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name;
led->cdev.default_trigger = of_get_property(nc,
"linux,default-trigger",
NULL);
if (!of_property_read_string(nc, "default-state", &state)) {
if (!strcmp(state, "on")) {
led->cdev.brightness = LED_FULL;
@ -382,8 +378,9 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
led->cdev.brightness_set = bcm6328_led_set;
led->cdev.blink_set = bcm6328_blink_set;
init_data.fwnode = of_fwnode_handle(nc);
rc = led_classdev_register(dev, &led->cdev);
rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
if (rc < 0)
return rc;
@ -395,7 +392,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
static int bcm6328_leds_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct device_node *np = dev_of_node(&pdev->dev);
struct device_node *child;
void __iomem *mem;
spinlock_t *lock; /* memory lock */

View File

@ -94,6 +94,7 @@ static void bcm6358_led_set(struct led_classdev *led_cdev,
static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
void __iomem *mem, spinlock_t *lock)
{
struct led_init_data init_data = {};
struct bcm6358_led *led;
const char *state;
int rc;
@ -109,11 +110,6 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
if (of_property_read_bool(nc, "active-low"))
led->active_low = true;
led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name;
led->cdev.default_trigger = of_get_property(nc,
"linux,default-trigger",
NULL);
if (!of_property_read_string(nc, "default-state", &state)) {
if (!strcmp(state, "on")) {
led->cdev.brightness = LED_FULL;
@ -136,8 +132,9 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
bcm6358_led_set(&led->cdev, led->cdev.brightness);
led->cdev.brightness_set = bcm6358_led_set;
init_data.fwnode = of_fwnode_handle(nc);
rc = led_classdev_register(dev, &led->cdev);
rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
if (rc < 0)
return rc;
@ -149,7 +146,7 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
static int bcm6358_leds_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct device_node *np = dev_of_node(&pdev->dev);
struct device_node *child;
void __iomem *mem;
spinlock_t *lock; /* memory lock */

View File

@ -158,19 +158,14 @@ MODULE_DEVICE_TABLE(of, cpcap_led_of_match);
static int cpcap_led_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct cpcap_led *led;
int err;
match = of_match_device(of_match_ptr(cpcap_led_of_match), &pdev->dev);
if (!match || !match->data)
return -EINVAL;
led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
platform_set_drvdata(pdev, led);
led->info = match->data;
led->info = device_get_match_data(&pdev->dev);
led->dev = &pdev->dev;
if (led->info->reg == 0x0000) {

View File

@ -188,9 +188,6 @@ static int cr0014114_probe_dt(struct cr0014114 *priv)
device_for_each_child_node(priv->dev, child) {
led = &priv->leds[i];
fwnode_property_read_string(child, "linux,default-trigger",
&led->ldev.default_trigger);
led->priv = priv;
led->ldev.max_brightness = CR_MAX_BRIGHTNESS;
led->ldev.brightness_set_blocking = cr0014114_set_sync;

View File

@ -263,9 +263,6 @@ static int el15203000_probe_dt(struct el15203000 *priv)
return -EINVAL;
}
fwnode_property_read_string(child, "linux,default-trigger",
&led->ldev.default_trigger);
led->priv = priv;
led->ldev.max_brightness = LED_ON;
led->ldev.brightness_set_blocking = el15203000_set_blocking;

View File

@ -160,9 +160,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
led_dat->gpiod = led.gpiod;
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
if (!fwnode_property_read_string(child, "default-state",
&state)) {
if (!strcmp(state, "keep"))

View File

@ -3,6 +3,7 @@
* LED Driver for SGI Octane machines
*/
#include <asm/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>

View File

@ -16,6 +16,8 @@
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
/* register numbers */
#define IS31FL319X_SHUTDOWN 0x00
@ -61,6 +63,7 @@
struct is31fl319x_chip {
const struct is31fl319x_chipdef *cdef;
struct i2c_client *client;
struct gpio_desc *shutdown_gpio;
struct regmap *regmap;
struct mutex lock;
u32 audio_gain_db;
@ -199,26 +202,27 @@ static int is31fl319x_parse_child_dt(const struct device *dev,
static int is31fl319x_parse_dt(struct device *dev,
struct is31fl319x_chip *is31)
{
struct device_node *np = dev->of_node, *child;
const struct of_device_id *of_dev_id;
struct device_node *np = dev_of_node(dev), *child;
int count;
int ret;
if (!np)
return -ENODEV;
of_dev_id = of_match_device(of_is31fl319x_match, dev);
if (!of_dev_id) {
dev_err(dev, "Failed to match device with supported chips\n");
return -EINVAL;
is31->shutdown_gpio = devm_gpiod_get_optional(dev,
"shutdown",
GPIOD_OUT_HIGH);
if (IS_ERR(is31->shutdown_gpio)) {
ret = PTR_ERR(is31->shutdown_gpio);
dev_err(dev, "Failed to get shutdown gpio: %d\n", ret);
return ret;
}
is31->cdef = of_dev_id->data;
is31->cdef = device_get_match_data(dev);
count = of_get_child_count(np);
count = of_get_available_child_count(np);
dev_dbg(dev, "probe %s with %d leds defined in DT\n",
of_dev_id->compatible, count);
dev_dbg(dev, "probing with %d leds defined in DT\n", count);
if (!count || count > is31->cdef->num_leds) {
dev_err(dev, "Number of leds defined must be between 1 and %u\n",
@ -226,7 +230,7 @@ static int is31fl319x_parse_dt(struct device *dev,
return -ENODEV;
}
for_each_child_of_node(np, child) {
for_each_available_child_of_node(np, child) {
struct is31fl319x_led *led;
u32 reg;
@ -350,6 +354,12 @@ static int is31fl319x_probe(struct i2c_client *client,
if (err)
goto free_mutex;
if (is31->shutdown_gpio) {
gpiod_direction_output(is31->shutdown_gpio, 0);
mdelay(5);
gpiod_direction_output(is31->shutdown_gpio, 1);
}
is31->client = client;
is31->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(is31->regmap)) {

View File

@ -332,9 +332,6 @@ static int is31fl32xx_parse_child_dt(const struct device *dev,
int ret = 0;
u32 reg;
if (of_property_read_string(child, "label", &cdev->name))
cdev->name = child->name;
ret = of_property_read_u32(child, "reg", &reg);
if (ret || reg < 1 || reg > led_data->priv->cdef->channels) {
dev_err(dev,
@ -344,9 +341,6 @@ static int is31fl32xx_parse_child_dt(const struct device *dev,
}
led_data->channel = reg;
of_property_read_string(child, "linux,default-trigger",
&cdev->default_trigger);
cdev->brightness_set_blocking = is31fl32xx_brightness_set;
return 0;
@ -372,7 +366,8 @@ static int is31fl32xx_parse_dt(struct device *dev,
struct device_node *child;
int ret = 0;
for_each_child_of_node(dev->of_node, child) {
for_each_available_child_of_node(dev_of_node(dev), child) {
struct led_init_data init_data = {};
struct is31fl32xx_led_data *led_data =
&priv->leds[priv->num_leds];
const struct is31fl32xx_led_data *other_led_data;
@ -388,17 +383,18 @@ static int is31fl32xx_parse_dt(struct device *dev,
led_data->channel);
if (other_led_data) {
dev_err(dev,
"%s and %s both attempting to use channel %d\n",
led_data->cdev.name,
other_led_data->cdev.name,
led_data->channel);
"Node %pOF 'reg' conflicts with another LED\n",
child);
goto err;
}
ret = devm_led_classdev_register(dev, &led_data->cdev);
init_data.fwnode = of_fwnode_handle(child);
ret = devm_led_classdev_register_ext(dev, &led_data->cdev,
&init_data);
if (ret) {
dev_err(dev, "failed to register PWM led for %s: %d\n",
led_data->cdev.name, ret);
dev_err(dev, "Failed to register LED for %pOF: %d\n",
child, ret);
goto err;
}
@ -428,19 +424,14 @@ static int is31fl32xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct is31fl32xx_chipdef *cdef;
const struct of_device_id *of_dev_id;
struct device *dev = &client->dev;
struct is31fl32xx_priv *priv;
int count;
int ret = 0;
of_dev_id = of_match_device(of_is31fl32xx_match, dev);
if (!of_dev_id)
return -EINVAL;
cdef = device_get_match_data(dev);
cdef = of_dev_id->data;
count = of_get_child_count(dev->of_node);
count = of_get_available_child_count(dev_of_node(dev));
if (!count)
return -EINVAL;

View File

@ -259,11 +259,11 @@ static void ktd2692_setup(struct ktd2692_context *led)
static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
struct ktd2692_led_config_data *cfg)
{
struct device_node *np = dev->of_node;
struct device_node *np = dev_of_node(dev);
struct device_node *child_node;
int ret;
if (!dev->of_node)
if (!dev_of_node(dev))
return -ENXIO;
led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);

View File

@ -96,15 +96,15 @@
/*
* struct lm3532_als_data
* @config - value of ALS configuration register
* @als1_imp_sel - value of ALS1 resistor select register
* @als2_imp_sel - value of ALS2 resistor select register
* @als_avrg_time - ALS averaging time
* @als_input_mode - ALS input mode for brightness control
* @als_vmin - Minimum ALS voltage
* @als_vmax - Maximum ALS voltage
* @zone_lo - values of ALS lo ZB(Zone Boundary) registers
* @zone_hi - values of ALS hi ZB(Zone Boundary) registers
* @config: value of ALS configuration register
* @als1_imp_sel: value of ALS1 resistor select register
* @als2_imp_sel: value of ALS2 resistor select register
* @als_avrg_time: ALS averaging time
* @als_input_mode: ALS input mode for brightness control
* @als_vmin: Minimum ALS voltage
* @als_vmax: Maximum ALS voltage
* @zone_lo: values of ALS lo ZB(Zone Boundary) registers
* @zone_hi: values of ALS hi ZB(Zone Boundary) registers
*/
struct lm3532_als_data {
u8 config;
@ -121,15 +121,14 @@ struct lm3532_als_data {
/**
* struct lm3532_led
* @led_dev: led class device
* @priv - Pointer the device data structure
* @control_bank - Control bank the LED is associated to
* @mode - Mode of the LED string
* @ctrl_brt_pointer - Zone target register that controls the sink
* @num_leds - Number of LED strings are supported in this array
* @full_scale_current - The full-scale current setting for the current sink.
* @led_strings - The LED strings supported in this array
* @enabled - Enabled status
* @label - LED label
* @priv: Pointer the device data structure
* @control_bank: Control bank the LED is associated to
* @mode: Mode of the LED string
* @ctrl_brt_pointer: Zone target register that controls the sink
* @num_leds: Number of LED strings are supported in this array
* @full_scale_current: The full-scale current setting for the current sink.
* @led_strings: The LED strings supported in this array
* @enabled: Enabled status
*/
struct lm3532_led {
struct led_classdev led_dev;
@ -142,21 +141,20 @@ struct lm3532_led {
int full_scale_current;
unsigned int enabled:1;
u32 led_strings[LM3532_MAX_CONTROL_BANKS];
char label[LED_MAX_NAME_SIZE];
};
/**
* struct lm3532_data
* @enable_gpio - Hardware enable gpio
* @enable_gpio: Hardware enable gpio
* @regulator: regulator
* @client: i2c client
* @regmap - Devices register map
* @dev - Pointer to the devices device struct
* @lock - Lock for reading/writing the device
* @als_data - Pointer to the als data struct
* @runtime_ramp_up - Runtime ramp up setting
* @runtime_ramp_down - Runtime ramp down setting
* @leds - Array of LED strings
* @regmap: Devices register map
* @dev: Pointer to the devices device struct
* @lock: Lock for reading/writing the device
* @als_data: Pointer to the als data struct
* @runtime_ramp_up: Runtime ramp up setting
* @runtime_ramp_down: Runtime ramp down setting
* @leds: Array of LED strings
*/
struct lm3532_data {
struct gpio_desc *enable_gpio;
@ -548,7 +546,6 @@ static int lm3532_parse_node(struct lm3532_data *priv)
{
struct fwnode_handle *child = NULL;
struct lm3532_led *led;
const char *name;
int control_bank;
u32 ramp_time;
size_t i = 0;
@ -643,19 +640,7 @@ static int lm3532_parse_node(struct lm3532_data *priv)
goto child_out;
}
fwnode_property_read_string(child, "linux,default-trigger",
&led->led_dev.default_trigger);
ret = fwnode_property_read_string(child, "label", &name);
if (ret)
snprintf(led->label, sizeof(led->label),
"%s::", priv->client->name);
else
snprintf(led->label, sizeof(led->label),
"%s:%s", priv->client->name, name);
led->priv = priv;
led->led_dev.name = led->label;
led->led_dev.brightness_set_blocking = lm3532_brightness_set;
ret = devm_led_classdev_register_ext(priv->dev, &led->led_dev, &idata);

View File

@ -26,8 +26,8 @@
* @lmu_data: Register and setting values for common code
* @regmap: Devices register map
* @dev: Pointer to the devices device struct
* @led_sources - The LED strings supported in this array
* @num_leds - Number of LED strings are supported in this array
* @led_sources: The LED strings supported in this array
* @num_leds: Number of LED strings are supported in this array
*/
struct lm36274 {
struct platform_device *pdev;
@ -41,122 +41,113 @@ struct lm36274 {
};
static int lm36274_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brt_val)
enum led_brightness brt_val)
{
struct lm36274 *led = container_of(led_cdev, struct lm36274, led_dev);
struct lm36274 *chip = container_of(led_cdev, struct lm36274, led_dev);
return ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
return ti_lmu_common_set_brightness(&chip->lmu_data, brt_val);
}
static int lm36274_init(struct lm36274 *lm36274_data)
static int lm36274_init(struct lm36274 *chip)
{
int enable_val = 0;
int i;
for (i = 0; i < lm36274_data->num_leds; i++)
enable_val |= (1 << lm36274_data->led_sources[i]);
for (i = 0; i < chip->num_leds; i++)
enable_val |= (1 << chip->led_sources[i]);
if (!enable_val) {
dev_err(lm36274_data->dev, "No LEDs were enabled\n");
dev_err(chip->dev, "No LEDs were enabled\n");
return -EINVAL;
}
enable_val |= LM36274_BL_EN;
return regmap_write(lm36274_data->regmap, LM36274_REG_BL_EN,
enable_val);
return regmap_write(chip->regmap, LM36274_REG_BL_EN, enable_val);
}
static int lm36274_parse_dt(struct lm36274 *lm36274_data)
static int lm36274_parse_dt(struct lm36274 *chip,
struct led_init_data *init_data)
{
struct fwnode_handle *child = NULL;
char label[LED_MAX_NAME_SIZE];
struct device *dev = &lm36274_data->pdev->dev;
const char *name;
int child_cnt;
int ret = -EINVAL;
struct device *dev = chip->dev;
struct fwnode_handle *child;
int ret;
/* There should only be 1 node */
child_cnt = device_get_child_node_count(dev);
if (child_cnt != 1)
if (device_get_child_node_count(dev) != 1)
return -EINVAL;
device_for_each_child_node(dev, child) {
ret = fwnode_property_read_string(child, "label", &name);
if (ret)
snprintf(label, sizeof(label),
"%s::", lm36274_data->pdev->name);
else
snprintf(label, sizeof(label),
"%s:%s", lm36274_data->pdev->name, name);
child = device_get_next_child_node(dev, NULL);
lm36274_data->num_leds = fwnode_property_count_u32(child, "led-sources");
if (lm36274_data->num_leds <= 0)
return -ENODEV;
ret = fwnode_property_read_u32_array(child, "led-sources",
lm36274_data->led_sources,
lm36274_data->num_leds);
if (ret) {
dev_err(dev, "led-sources property missing\n");
return ret;
}
fwnode_property_read_string(child, "linux,default-trigger",
&lm36274_data->led_dev.default_trigger);
init_data->fwnode = child;
init_data->devicename = chip->pdev->name;
/* for backwards compatibility when `label` property is not present */
init_data->default_label = ":";
chip->num_leds = fwnode_property_count_u32(child, "led-sources");
if (chip->num_leds <= 0) {
ret = -ENODEV;
goto err;
}
lm36274_data->lmu_data.regmap = lm36274_data->regmap;
lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
lm36274_data->led_dev.name = label;
lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set;
ret = fwnode_property_read_u32_array(child, "led-sources",
chip->led_sources, chip->num_leds);
if (ret) {
dev_err(dev, "led-sources property missing\n");
goto err;
}
return 0;
err:
fwnode_handle_put(child);
return ret;
}
static int lm36274_probe(struct platform_device *pdev)
{
struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
struct lm36274 *lm36274_data;
struct led_init_data init_data = {};
struct lm36274 *chip;
int ret;
lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data),
GFP_KERNEL);
if (!lm36274_data)
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
lm36274_data->pdev = pdev;
lm36274_data->dev = lmu->dev;
lm36274_data->regmap = lmu->regmap;
platform_set_drvdata(pdev, lm36274_data);
chip->pdev = pdev;
chip->dev = &pdev->dev;
chip->regmap = lmu->regmap;
platform_set_drvdata(pdev, chip);
ret = lm36274_parse_dt(lm36274_data);
ret = lm36274_parse_dt(chip, &init_data);
if (ret) {
dev_err(lm36274_data->dev, "Failed to parse DT node\n");
dev_err(chip->dev, "Failed to parse DT node\n");
return ret;
}
ret = lm36274_init(lm36274_data);
ret = lm36274_init(chip);
if (ret) {
dev_err(lm36274_data->dev, "Failed to init the device\n");
dev_err(chip->dev, "Failed to init the device\n");
return ret;
}
return led_classdev_register(lm36274_data->dev, &lm36274_data->led_dev);
}
chip->lmu_data.regmap = chip->regmap;
chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
static int lm36274_remove(struct platform_device *pdev)
{
struct lm36274 *lm36274_data = platform_get_drvdata(pdev);
chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
chip->led_dev.brightness_set_blocking = lm36274_brightness_set;
led_classdev_unregister(&lm36274_data->led_dev);
ret = devm_led_classdev_register_ext(chip->dev, &chip->led_dev,
&init_data);
if (ret)
dev_err(chip->dev, "Failed to register LED for node %pfw\n",
init_data.fwnode);
return 0;
fwnode_handle_put(init_data.fwnode);
return ret;
}
static const struct of_device_id of_lm36274_leds_match[] = {
@ -167,9 +158,9 @@ MODULE_DEVICE_TABLE(of, of_lm36274_leds_match);
static struct platform_driver lm36274_driver = {
.probe = lm36274_probe,
.remove = lm36274_remove,
.driver = {
.name = "lm36274-leds",
.of_match_table = of_lm36274_leds_match,
},
};
module_platform_driver(lm36274_driver)

View File

@ -394,13 +394,10 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
led->regulator = devm_regulator_get_optional(&led->client->dev, "vled");
if (IS_ERR(led->regulator)) {
ret = PTR_ERR(led->regulator);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(&led->client->dev,
"Failed to get vled regulator: %d\n",
ret);
return ret;
}
if (ret != -ENODEV)
return dev_err_probe(&led->client->dev, ret,
"Failed to get vled regulator\n");
led->regulator = NULL;
}
@ -436,9 +433,6 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
return -ENODEV;
}
fwnode_property_read_string(child, "linux,default-trigger",
&led->led_dev.default_trigger);
ret = fwnode_property_read_u32(child, "reg", &led->led_enable);
if (ret) {
dev_err(&led->client->dev, "reg DT property missing\n");

View File

@ -78,6 +78,7 @@ struct lm3697 {
struct mutex lock;
int bank_cfg;
int num_banks;
struct lm3697_led leds[];
};
@ -115,6 +116,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
struct lm3697_led *led = container_of(led_cdev, struct lm3697_led,
led_dev);
int ctrl_en_val = (1 << led->control_bank);
struct device *dev = led->priv->dev;
int ret;
mutex_lock(&led->priv->lock);
@ -123,7 +125,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE,
ctrl_en_val, ~ctrl_en_val);
if (ret) {
dev_err(&led->priv->client->dev, "Cannot write ctrl register\n");
dev_err(dev, "Cannot write ctrl register\n");
goto brightness_out;
}
@ -131,8 +133,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
} else {
ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
if (ret) {
dev_err(&led->priv->client->dev,
"Cannot write brightness\n");
dev_err(dev, "Cannot write brightness\n");
goto brightness_out;
}
@ -141,8 +142,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
LM3697_CTRL_ENABLE,
ctrl_en_val, ctrl_en_val);
if (ret) {
dev_err(&led->priv->client->dev,
"Cannot enable the device\n");
dev_err(dev, "Cannot enable the device\n");
goto brightness_out;
}
@ -157,6 +157,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
static int lm3697_init(struct lm3697 *priv)
{
struct device *dev = priv->dev;
struct lm3697_led *led;
int i, ret;
@ -165,26 +166,26 @@ static int lm3697_init(struct lm3697 *priv)
} else {
ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET);
if (ret) {
dev_err(&priv->client->dev, "Cannot reset the device\n");
dev_err(dev, "Cannot reset the device\n");
goto out;
}
}
ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0);
if (ret) {
dev_err(&priv->client->dev, "Cannot write ctrl enable\n");
dev_err(dev, "Cannot write ctrl enable\n");
goto out;
}
ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg);
if (ret)
dev_err(&priv->client->dev, "Cannot write OUTPUT config\n");
dev_err(dev, "Cannot write OUTPUT config\n");
for (i = 0; i < LM3697_MAX_CONTROL_BANKS; i++) {
for (i = 0; i < priv->num_banks; i++) {
led = &priv->leds[i];
ret = ti_lmu_common_set_ramp(&led->lmu_data);
if (ret)
dev_err(&priv->client->dev, "Setting the ramp rate failed\n");
dev_err(dev, "Setting the ramp rate failed\n");
}
out:
return ret;
@ -193,36 +194,37 @@ static int lm3697_init(struct lm3697 *priv)
static int lm3697_probe_dt(struct lm3697 *priv)
{
struct fwnode_handle *child = NULL;
struct device *dev = priv->dev;
struct lm3697_led *led;
const char *name;
int ret = -EINVAL;
int control_bank;
size_t i = 0;
int ret = -EINVAL;
int j;
priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev,
"enable", GPIOD_OUT_LOW);
priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(priv->enable_gpio)) {
ret = PTR_ERR(priv->enable_gpio);
dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n",
ret);
dev_err(dev, "Failed to get enable gpio: %d\n", ret);
return ret;
}
priv->regulator = devm_regulator_get(&priv->client->dev, "vled");
priv->regulator = devm_regulator_get(dev, "vled");
if (IS_ERR(priv->regulator))
priv->regulator = NULL;
device_for_each_child_node(priv->dev, child) {
device_for_each_child_node(dev, child) {
struct led_init_data init_data = {};
ret = fwnode_property_read_u32(child, "reg", &control_bank);
if (ret) {
dev_err(&priv->client->dev, "reg property missing\n");
dev_err(dev, "reg property missing\n");
fwnode_handle_put(child);
goto child_out;
}
if (control_bank > LM3697_CONTROL_B) {
dev_err(&priv->client->dev, "reg property is invalid\n");
dev_err(dev, "reg property is invalid\n");
ret = -EINVAL;
fwnode_handle_put(child);
goto child_out;
@ -230,10 +232,10 @@ static int lm3697_probe_dt(struct lm3697 *priv)
led = &priv->leds[i];
ret = ti_lmu_common_get_brt_res(&priv->client->dev,
child, &led->lmu_data);
ret = ti_lmu_common_get_brt_res(dev, child, &led->lmu_data);
if (ret)
dev_warn(&priv->client->dev, "brightness resolution property missing\n");
dev_warn(dev,
"brightness resolution property missing\n");
led->control_bank = control_bank;
led->lmu_data.regmap = priv->regmap;
@ -246,7 +248,7 @@ static int lm3697_probe_dt(struct lm3697 *priv)
led->num_leds = fwnode_property_count_u32(child, "led-sources");
if (led->num_leds > LM3697_MAX_LED_STRINGS) {
dev_err(&priv->client->dev, "Too many LED strings defined\n");
dev_err(dev, "Too many LED strings defined\n");
continue;
}
@ -254,7 +256,7 @@ static int lm3697_probe_dt(struct lm3697 *priv)
led->hvled_strings,
led->num_leds);
if (ret) {
dev_err(&priv->client->dev, "led-sources property missing\n");
dev_err(dev, "led-sources property missing\n");
fwnode_handle_put(child);
goto child_out;
}
@ -263,31 +265,23 @@ static int lm3697_probe_dt(struct lm3697 *priv)
priv->bank_cfg |=
(led->control_bank << led->hvled_strings[j]);
ret = ti_lmu_common_get_ramp_params(&priv->client->dev,
child, &led->lmu_data);
ret = ti_lmu_common_get_ramp_params(dev, child, &led->lmu_data);
if (ret)
dev_warn(&priv->client->dev, "runtime-ramp properties missing\n");
dev_warn(dev, "runtime-ramp properties missing\n");
fwnode_property_read_string(child, "linux,default-trigger",
&led->led_dev.default_trigger);
ret = fwnode_property_read_string(child, "label", &name);
if (ret)
snprintf(led->label, sizeof(led->label),
"%s::", priv->client->name);
else
snprintf(led->label, sizeof(led->label),
"%s:%s", priv->client->name, name);
init_data.fwnode = child;
init_data.devicename = priv->client->name;
/* for backwards compatibility if `label` is not present */
init_data.default_label = ":";
led->priv = priv;
led->led_dev.name = led->label;
led->led_dev.max_brightness = led->lmu_data.max_brightness;
led->led_dev.brightness_set_blocking = lm3697_brightness_set;
ret = devm_led_classdev_register(priv->dev, &led->led_dev);
ret = devm_led_classdev_register_ext(dev, &led->led_dev,
&init_data);
if (ret) {
dev_err(&priv->client->dev, "led register err: %d\n",
ret);
dev_err(dev, "led register err: %d\n", ret);
fwnode_handle_put(child);
goto child_out;
}
@ -302,18 +296,18 @@ static int lm3697_probe_dt(struct lm3697 *priv)
static int lm3697_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct lm3697 *led;
int count;
int ret;
count = device_get_child_node_count(&client->dev);
if (!count) {
dev_err(&client->dev, "LEDs are not defined in device tree!");
count = device_get_child_node_count(dev);
if (!count || count > LM3697_MAX_CONTROL_BANKS) {
dev_err(dev, "Strange device tree!");
return -ENODEV;
}
led = devm_kzalloc(&client->dev, struct_size(led, leds, count),
GFP_KERNEL);
led = devm_kzalloc(dev, struct_size(led, leds, count), GFP_KERNEL);
if (!led)
return -ENOMEM;
@ -321,12 +315,12 @@ static int lm3697_probe(struct i2c_client *client,
i2c_set_clientdata(client, led);
led->client = client;
led->dev = &client->dev;
led->dev = dev;
led->num_banks = count;
led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config);
if (IS_ERR(led->regmap)) {
ret = PTR_ERR(led->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
dev_err(dev, "Failed to allocate register map: %d\n", ret);
return ret;
}
@ -340,12 +334,13 @@ static int lm3697_probe(struct i2c_client *client,
static int lm3697_remove(struct i2c_client *client)
{
struct lm3697 *led = i2c_get_clientdata(client);
struct device *dev = &led->client->dev;
int ret;
ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE,
LM3697_CTRL_A_B_EN, 0);
if (ret) {
dev_err(&led->client->dev, "Failed to disable the device\n");
dev_err(dev, "Failed to disable the device\n");
return ret;
}
@ -355,8 +350,7 @@ static int lm3697_remove(struct i2c_client *client)
if (led->regulator) {
ret = regulator_disable(led->regulator);
if (ret)
dev_err(&led->client->dev,
"Failed to disable regulator\n");
dev_err(dev, "Failed to disable regulator\n");
}
mutex_destroy(&led->lock);

631
drivers/leds/leds-lp50xx.c Normal file
View File

@ -0,0 +1,631 @@
// SPDX-License-Identifier: GPL-2.0
// TI LP50XX LED chip family driver
// Copyright (C) 2018-20 Texas Instruments Incorporated - https://www.ti.com/
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.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>
#include <uapi/linux/uleds.h>
#include <linux/led-class-multicolor.h>
#include "leds.h"
#define LP50XX_DEV_CFG0 0x00
#define LP50XX_DEV_CFG1 0x01
#define LP50XX_LED_CFG0 0x02
/* LP5009 and LP5012 registers */
#define LP5012_BNK_BRT 0x03
#define LP5012_BNKA_CLR 0x04
#define LP5012_BNKB_CLR 0x05
#define LP5012_BNKC_CLR 0x06
#define LP5012_LED0_BRT 0x07
#define LP5012_OUT0_CLR 0x0b
#define LP5012_RESET 0x17
/* LP5018 and LP5024 registers */
#define LP5024_BNK_BRT 0x03
#define LP5024_BNKA_CLR 0x04
#define LP5024_BNKB_CLR 0x05
#define LP5024_BNKC_CLR 0x06
#define LP5024_LED0_BRT 0x07
#define LP5024_OUT0_CLR 0x0f
#define LP5024_RESET 0x27
/* LP5030 and LP5036 registers */
#define LP5036_LED_CFG1 0x03
#define LP5036_BNK_BRT 0x04
#define LP5036_BNKA_CLR 0x05
#define LP5036_BNKB_CLR 0x06
#define LP5036_BNKC_CLR 0x07
#define LP5036_LED0_BRT 0x08
#define LP5036_OUT0_CLR 0x14
#define LP5036_RESET 0x38
#define LP50XX_SW_RESET 0xff
#define LP50XX_CHIP_EN BIT(6)
/* There are 3 LED outputs per bank */
#define LP50XX_LEDS_PER_MODULE 3
#define LP5009_MAX_LED_MODULES 2
#define LP5012_MAX_LED_MODULES 4
#define LP5018_MAX_LED_MODULES 6
#define LP5024_MAX_LED_MODULES 8
#define LP5030_MAX_LED_MODULES 10
#define LP5036_MAX_LED_MODULES 12
static const struct reg_default lp5012_reg_defs[] = {
{LP50XX_DEV_CFG0, 0x0},
{LP50XX_DEV_CFG1, 0x3c},
{LP50XX_LED_CFG0, 0x0},
{LP5012_BNK_BRT, 0xff},
{LP5012_BNKA_CLR, 0x0f},
{LP5012_BNKB_CLR, 0x0f},
{LP5012_BNKC_CLR, 0x0f},
{LP5012_LED0_BRT, 0x0f},
/* LEDX_BRT registers are all 0xff for defaults */
{0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff},
{LP5012_OUT0_CLR, 0x0f},
/* OUTX_CLR registers are all 0x0 for defaults */
{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00}, {0x10, 0x00},
{0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, {0x14, 0x00}, {0x15, 0x00},
{0x16, 0x00},
{LP5012_RESET, 0x00}
};
static const struct reg_default lp5024_reg_defs[] = {
{LP50XX_DEV_CFG0, 0x0},
{LP50XX_DEV_CFG1, 0x3c},
{LP50XX_LED_CFG0, 0x0},
{LP5024_BNK_BRT, 0xff},
{LP5024_BNKA_CLR, 0x0f},
{LP5024_BNKB_CLR, 0x0f},
{LP5024_BNKC_CLR, 0x0f},
{LP5024_LED0_BRT, 0x0f},
/* LEDX_BRT registers are all 0xff for defaults */
{0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff}, {0x0b, 0xff}, {0x0c, 0xff},
{0x0d, 0xff}, {0x0e, 0xff},
{LP5024_OUT0_CLR, 0x0f},
/* OUTX_CLR registers are all 0x0 for defaults */
{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, {0x14, 0x00},
{0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, {0x18, 0x00}, {0x19, 0x00},
{0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00},
{0x1f, 0x00}, {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00},
{LP5024_RESET, 0x00}
};
static const struct reg_default lp5036_reg_defs[] = {
{LP50XX_DEV_CFG0, 0x0},
{LP50XX_DEV_CFG1, 0x3c},
{LP50XX_LED_CFG0, 0x0},
{LP5036_LED_CFG1, 0x0},
{LP5036_BNK_BRT, 0xff},
{LP5036_BNKA_CLR, 0x0f},
{LP5036_BNKB_CLR, 0x0f},
{LP5036_BNKC_CLR, 0x0f},
{LP5036_LED0_BRT, 0x0f},
/* LEDX_BRT registers are all 0xff for defaults */
{0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff}, {0x0b, 0xff}, {0x0c, 0xff},
{0x0d, 0xff}, {0x0e, 0xff}, {0x0f, 0xff}, {0x10, 0xff}, {0x11, 0xff},
{0x12, 0xff}, {0x13, 0xff},
{LP5036_OUT0_CLR, 0x0f},
/* OUTX_CLR registers are all 0x0 for defaults */
{0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, {0x18, 0x00}, {0x19, 0x00},
{0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00},
{0x1f, 0x00}, {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
{0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, {0x2c, 0x00}, {0x2d, 0x00},
{0x2e, 0x00}, {0x2f, 0x00}, {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00},
{0x33, 0x00}, {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
{LP5036_RESET, 0x00}
};
static const struct regmap_config lp5012_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = LP5012_RESET,
.reg_defaults = lp5012_reg_defs,
.num_reg_defaults = ARRAY_SIZE(lp5012_reg_defs),
.cache_type = REGCACHE_FLAT,
};
static const struct regmap_config lp5024_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = LP5024_RESET,
.reg_defaults = lp5024_reg_defs,
.num_reg_defaults = ARRAY_SIZE(lp5024_reg_defs),
.cache_type = REGCACHE_FLAT,
};
static const struct regmap_config lp5036_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = LP5036_RESET,
.reg_defaults = lp5036_reg_defs,
.num_reg_defaults = ARRAY_SIZE(lp5036_reg_defs),
.cache_type = REGCACHE_FLAT,
};
enum lp50xx_model {
LP5009,
LP5012,
LP5018,
LP5024,
LP5030,
LP5036,
};
/**
* struct lp50xx_chip_info -
* @lp50xx_regmap_config: regmap register configuration
* @model_id: LED device model
* @max_modules: total number of supported LED modules
* @num_leds: number of LED outputs available on the device
* @led_brightness0_reg: first brightness register of the device
* @mix_out0_reg: first color mix register of the device
* @bank_brt_reg: bank brightness register
* @bank_mix_reg: color mix register
* @reset_reg: device reset register
*/
struct lp50xx_chip_info {
const struct regmap_config *lp50xx_regmap_config;
int model_id;
u8 max_modules;
u8 num_leds;
u8 led_brightness0_reg;
u8 mix_out0_reg;
u8 bank_brt_reg;
u8 bank_mix_reg;
u8 reset_reg;
};
static const struct lp50xx_chip_info lp50xx_chip_info_tbl[] = {
[LP5009] = {
.model_id = LP5009,
.max_modules = LP5009_MAX_LED_MODULES,
.num_leds = LP5009_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
.led_brightness0_reg = LP5012_LED0_BRT,
.mix_out0_reg = LP5012_OUT0_CLR,
.bank_brt_reg = LP5012_BNK_BRT,
.bank_mix_reg = LP5012_BNKA_CLR,
.reset_reg = LP5012_RESET,
.lp50xx_regmap_config = &lp5012_regmap_config,
},
[LP5012] = {
.model_id = LP5012,
.max_modules = LP5012_MAX_LED_MODULES,
.num_leds = LP5012_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
.led_brightness0_reg = LP5012_LED0_BRT,
.mix_out0_reg = LP5012_OUT0_CLR,
.bank_brt_reg = LP5012_BNK_BRT,
.bank_mix_reg = LP5012_BNKA_CLR,
.reset_reg = LP5012_RESET,
.lp50xx_regmap_config = &lp5012_regmap_config,
},
[LP5018] = {
.model_id = LP5018,
.max_modules = LP5018_MAX_LED_MODULES,
.num_leds = LP5018_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
.led_brightness0_reg = LP5024_LED0_BRT,
.mix_out0_reg = LP5024_OUT0_CLR,
.bank_brt_reg = LP5024_BNK_BRT,
.bank_mix_reg = LP5024_BNKA_CLR,
.reset_reg = LP5024_RESET,
.lp50xx_regmap_config = &lp5024_regmap_config,
},
[LP5024] = {
.model_id = LP5024,
.max_modules = LP5024_MAX_LED_MODULES,
.num_leds = LP5024_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
.led_brightness0_reg = LP5024_LED0_BRT,
.mix_out0_reg = LP5024_OUT0_CLR,
.bank_brt_reg = LP5024_BNK_BRT,
.bank_mix_reg = LP5024_BNKA_CLR,
.reset_reg = LP5024_RESET,
.lp50xx_regmap_config = &lp5024_regmap_config,
},
[LP5030] = {
.model_id = LP5030,
.max_modules = LP5030_MAX_LED_MODULES,
.num_leds = LP5030_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
.led_brightness0_reg = LP5036_LED0_BRT,
.mix_out0_reg = LP5036_OUT0_CLR,
.bank_brt_reg = LP5036_BNK_BRT,
.bank_mix_reg = LP5036_BNKA_CLR,
.reset_reg = LP5036_RESET,
.lp50xx_regmap_config = &lp5036_regmap_config,
},
[LP5036] = {
.model_id = LP5036,
.max_modules = LP5036_MAX_LED_MODULES,
.num_leds = LP5036_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
.led_brightness0_reg = LP5036_LED0_BRT,
.mix_out0_reg = LP5036_OUT0_CLR,
.bank_brt_reg = LP5036_BNK_BRT,
.bank_mix_reg = LP5036_BNKA_CLR,
.reset_reg = LP5036_RESET,
.lp50xx_regmap_config = &lp5036_regmap_config,
},
};
struct lp50xx_led {
struct led_classdev_mc mc_cdev;
struct lp50xx *priv;
unsigned long bank_modules;
int led_intensity[LP50XX_LEDS_PER_MODULE];
u8 ctrl_bank_enabled;
int led_number;
};
/**
* struct lp50xx -
* @enable_gpio: hardware enable gpio
* @regulator: LED supply regulator pointer
* @client: pointer to the I2C client
* @regmap: device register map
* @dev: pointer to the devices device struct
* @lock: lock for reading/writing the device
* @chip_info: chip specific information (ie num_leds)
* @num_of_banked_leds: holds the number of banked LEDs
* @leds: array of LED strings
*/
struct lp50xx {
struct gpio_desc *enable_gpio;
struct regulator *regulator;
struct i2c_client *client;
struct regmap *regmap;
struct device *dev;
struct mutex lock;
const struct lp50xx_chip_info *chip_info;
int num_of_banked_leds;
/* This needs to be at the end of the struct */
struct lp50xx_led leds[];
};
static struct lp50xx_led *mcled_cdev_to_led(struct led_classdev_mc *mc_cdev)
{
return container_of(mc_cdev, struct lp50xx_led, mc_cdev);
}
static int lp50xx_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct led_classdev_mc *mc_dev = lcdev_to_mccdev(cdev);
struct lp50xx_led *led = mcled_cdev_to_led(mc_dev);
const struct lp50xx_chip_info *led_chip = led->priv->chip_info;
u8 led_offset, reg_val;
int ret = 0;
int i;
mutex_lock(&led->priv->lock);
if (led->ctrl_bank_enabled)
reg_val = led_chip->bank_brt_reg;
else
reg_val = led_chip->led_brightness0_reg +
led->led_number;
ret = regmap_write(led->priv->regmap, reg_val, brightness);
if (ret) {
dev_err(&led->priv->client->dev,
"Cannot write brightness value %d\n", ret);
goto out;
}
for (i = 0; i < led->mc_cdev.num_colors; i++) {
if (led->ctrl_bank_enabled) {
reg_val = led_chip->bank_mix_reg + i;
} else {
led_offset = (led->led_number * 3) + i;
reg_val = led_chip->mix_out0_reg + led_offset;
}
ret = regmap_write(led->priv->regmap, reg_val,
mc_dev->subled_info[i].intensity);
if (ret) {
dev_err(&led->priv->client->dev,
"Cannot write intensity value %d\n", ret);
goto out;
}
}
out:
mutex_unlock(&led->priv->lock);
return ret;
}
static int lp50xx_set_banks(struct lp50xx *priv, u32 led_banks[])
{
u8 led_config_lo, led_config_hi;
u32 bank_enable_mask = 0;
int ret;
int i;
for (i = 0; i < priv->chip_info->max_modules; i++) {
if (led_banks[i])
bank_enable_mask |= (1 << led_banks[i]);
}
led_config_lo = (u8)(bank_enable_mask & 0xff);
led_config_hi = (u8)(bank_enable_mask >> 8) & 0xff;
ret = regmap_write(priv->regmap, LP50XX_LED_CFG0, led_config_lo);
if (ret)
return ret;
if (priv->chip_info->model_id >= LP5030)
ret = regmap_write(priv->regmap, LP5036_LED_CFG1, led_config_hi);
return ret;
}
static int lp50xx_reset(struct lp50xx *priv)
{
return regmap_write(priv->regmap, priv->chip_info->reset_reg, LP50XX_SW_RESET);
}
static int lp50xx_enable_disable(struct lp50xx *priv, int enable_disable)
{
int ret;
if (priv->enable_gpio) {
ret = gpiod_direction_output(priv->enable_gpio, enable_disable);
if (ret)
return ret;
}
if (enable_disable)
return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN);
else
return regmap_write(priv->regmap, LP50XX_DEV_CFG0, 0);
}
static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv,
struct lp50xx_led *led, int num_leds)
{
u32 led_banks[LP5036_MAX_LED_MODULES] = {0};
int led_number;
int ret;
if (num_leds > 1) {
if (num_leds > priv->chip_info->max_modules) {
dev_err(&priv->client->dev, "reg property is invalid\n");
return -EINVAL;
}
priv->num_of_banked_leds = num_leds;
ret = fwnode_property_read_u32_array(child, "reg", led_banks, num_leds);
if (ret) {
dev_err(&priv->client->dev, "reg property is missing\n");
return ret;
}
ret = lp50xx_set_banks(priv, led_banks);
if (ret) {
dev_err(&priv->client->dev, "Cannot setup banked LEDs\n");
return ret;
}
led->ctrl_bank_enabled = 1;
} else {
ret = fwnode_property_read_u32(child, "reg", &led_number);
if (ret) {
dev_err(&priv->client->dev, "led reg property missing\n");
return ret;
}
if (led_number > priv->chip_info->num_leds) {
dev_err(&priv->client->dev, "led-sources property is invalid\n");
return -EINVAL;
}
led->led_number = led_number;
}
return 0;
}
static int lp50xx_probe_dt(struct lp50xx *priv)
{
struct fwnode_handle *child = NULL;
struct fwnode_handle *led_node = NULL;
struct led_init_data init_data = {};
struct led_classdev *led_cdev;
struct mc_subled *mc_led_info;
struct lp50xx_led *led;
int ret = -EINVAL;
int num_colors;
u32 color_id;
int i = 0;
priv->enable_gpio = devm_gpiod_get_optional(priv->dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(priv->enable_gpio)) {
ret = PTR_ERR(priv->enable_gpio);
dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n",
ret);
return ret;
}
priv->regulator = devm_regulator_get(priv->dev, "vled");
if (IS_ERR(priv->regulator))
priv->regulator = NULL;
device_for_each_child_node(priv->dev, child) {
led = &priv->leds[i];
ret = fwnode_property_count_u32(child, "reg");
if (ret < 0) {
dev_err(&priv->client->dev, "reg property is invalid\n");
goto child_out;
}
ret = lp50xx_probe_leds(child, priv, led, ret);
if (ret)
goto child_out;
init_data.fwnode = child;
num_colors = 0;
/*
* There are only 3 LEDs per module otherwise they should be
* banked which also is presented as 3 LEDs.
*/
mc_led_info = devm_kcalloc(priv->dev, LP50XX_LEDS_PER_MODULE,
sizeof(*mc_led_info), GFP_KERNEL);
if (!mc_led_info)
return -ENOMEM;
fwnode_for_each_child_node(child, led_node) {
ret = fwnode_property_read_u32(led_node, "color",
&color_id);
if (ret) {
dev_err(priv->dev, "Cannot read color\n");
goto child_out;
}
mc_led_info[num_colors].color_index = color_id;
num_colors++;
}
led->priv = priv;
led->mc_cdev.num_colors = num_colors;
led->mc_cdev.subled_info = mc_led_info;
led_cdev = &led->mc_cdev.led_cdev;
led_cdev->brightness_set_blocking = lp50xx_brightness_set;
ret = devm_led_classdev_multicolor_register_ext(&priv->client->dev,
&led->mc_cdev,
&init_data);
if (ret) {
dev_err(&priv->client->dev, "led register err: %d\n",
ret);
goto child_out;
}
i++;
fwnode_handle_put(child);
}
return 0;
child_out:
fwnode_handle_put(child);
return ret;
}
static int lp50xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lp50xx *led;
int count;
int ret;
count = device_get_child_node_count(&client->dev);
if (!count) {
dev_err(&client->dev, "LEDs are not defined in device tree!");
return -ENODEV;
}
led = devm_kzalloc(&client->dev, struct_size(led, leds, count),
GFP_KERNEL);
if (!led)
return -ENOMEM;
mutex_init(&led->lock);
led->client = client;
led->dev = &client->dev;
led->chip_info = &lp50xx_chip_info_tbl[id->driver_data];
i2c_set_clientdata(client, led);
led->regmap = devm_regmap_init_i2c(client,
led->chip_info->lp50xx_regmap_config);
if (IS_ERR(led->regmap)) {
ret = PTR_ERR(led->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
ret = lp50xx_reset(led);
if (ret)
return ret;
ret = lp50xx_enable_disable(led, 1);
if (ret)
return ret;
return lp50xx_probe_dt(led);
}
static int lp50xx_remove(struct i2c_client *client)
{
struct lp50xx *led = i2c_get_clientdata(client);
int ret;
ret = lp50xx_enable_disable(led, 0);
if (ret) {
dev_err(&led->client->dev, "Failed to disable chip\n");
return ret;
}
if (led->regulator) {
ret = regulator_disable(led->regulator);
if (ret)
dev_err(&led->client->dev,
"Failed to disable regulator\n");
}
mutex_destroy(&led->lock);
return 0;
}
static const struct i2c_device_id lp50xx_id[] = {
{ "lp5009", LP5009 },
{ "lp5012", LP5012 },
{ "lp5018", LP5018 },
{ "lp5024", LP5024 },
{ "lp5030", LP5030 },
{ "lp5036", LP5036 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lp50xx_id);
static const struct of_device_id of_lp50xx_leds_match[] = {
{ .compatible = "ti,lp5009", .data = (void *)LP5009 },
{ .compatible = "ti,lp5012", .data = (void *)LP5012 },
{ .compatible = "ti,lp5018", .data = (void *)LP5018 },
{ .compatible = "ti,lp5024", .data = (void *)LP5024 },
{ .compatible = "ti,lp5030", .data = (void *)LP5030 },
{ .compatible = "ti,lp5036", .data = (void *)LP5036 },
{},
};
MODULE_DEVICE_TABLE(of, of_lp50xx_leds_match);
static struct i2c_driver lp50xx_driver = {
.driver = {
.name = "lp50xx",
.of_match_table = of_lp50xx_leds_match,
},
.probe = lp50xx_probe,
.remove = lp50xx_remove,
.id_table = lp50xx_id,
};
module_i2c_driver(lp50xx_driver);
MODULE_DESCRIPTION("Texas Instruments LP50XX LED driver");
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
MODULE_LICENSE("GPL v2");

View File

@ -523,7 +523,7 @@ static int lp5521_probe(struct i2c_client *client,
struct lp55xx_chip *chip;
struct lp55xx_led *led;
struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *np = client->dev.of_node;
struct device_node *np = dev_of_node(&client->dev);
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)

View File

@ -891,7 +891,7 @@ static int lp5523_probe(struct i2c_client *client,
struct lp55xx_chip *chip;
struct lp55xx_led *led;
struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *np = client->dev.of_node;
struct device_node *np = dev_of_node(&client->dev);
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)

View File

@ -518,7 +518,7 @@ static int lp5562_probe(struct i2c_client *client,
struct lp55xx_chip *chip;
struct lp55xx_led *led;
struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *np = client->dev.of_node;
struct device_node *np = dev_of_node(&client->dev);
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)

View File

@ -611,11 +611,13 @@ static int lp55xx_parse_multi_led(struct device_node *np,
struct device_node *child;
int num_colors = 0, ret;
for_each_child_of_node(np, child) {
for_each_available_child_of_node(np, child) {
ret = lp55xx_parse_multi_led_child(child, cfg, child_number,
num_colors);
if (ret)
if (ret) {
of_node_put(child);
return ret;
}
num_colors++;
}
@ -665,7 +667,7 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev,
if (!pdata)
return ERR_PTR(-ENOMEM);
num_channels = of_get_child_count(np);
num_channels = of_get_available_child_count(np);
if (num_channels == 0) {
dev_err(dev, "no LED channels\n");
return ERR_PTR(-EINVAL);
@ -679,10 +681,12 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev,
pdata->num_channels = num_channels;
cfg->max_channel = chip->cfg->max_channel;
for_each_child_of_node(np, child) {
for_each_available_child_of_node(np, child) {
ret = lp55xx_parse_logical_led(child, cfg, i);
if (ret)
if (ret) {
of_node_put(child);
return ERR_PTR(-EINVAL);
}
i++;
}

View File

@ -306,7 +306,7 @@ static int lp8501_probe(struct i2c_client *client,
struct lp55xx_chip *chip;
struct lp55xx_led *led;
struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *np = client->dev.of_node;
struct device_node *np = dev_of_node(&client->dev);
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)

View File

@ -380,7 +380,7 @@ static int lp8860_probe(struct i2c_client *client,
{
int ret;
struct lp8860_led *led;
struct device_node *np = client->dev.of_node;
struct device_node *np = dev_of_node(&client->dev);
struct device_node *child_node;
struct led_init_data init_data = {};
@ -392,10 +392,6 @@ static int lp8860_probe(struct i2c_client *client,
if (!child_node)
return -EINVAL;
led->led_dev.default_trigger = of_get_property(child_node,
"linux,default-trigger",
NULL);
led->enable_gpio = devm_gpiod_get_optional(&client->dev,
"enable", GPIOD_OUT_LOW);
if (IS_ERR(led->enable_gpio)) {

View File

@ -68,7 +68,7 @@ static int lt3593_led_probe(struct platform_device *pdev)
struct led_init_data init_data = {};
const char *tmp;
if (!dev->of_node)
if (!dev_of_node(dev))
return -ENODEV;
led_data = devm_kzalloc(dev, sizeof(*led_data), GFP_KERNEL);
@ -86,9 +86,6 @@ static int lt3593_led_probe(struct platform_device *pdev)
child = device_get_next_child_node(dev, NULL);
fwnode_property_read_string(child, "linux,default-trigger",
&led_data->cdev.default_trigger);
if (!fwnode_property_read_string(child, "default-state", &tmp)) {
if (!strcmp(tmp, "on"))
state = LEDS_GPIO_DEFSTATE_ON;
@ -107,7 +104,6 @@ static int lt3593_led_probe(struct platform_device *pdev)
return ret;
}
led_data->cdev.dev->of_node = dev->of_node;
platform_set_drvdata(pdev, led_data);
return 0;

View File

@ -66,7 +66,6 @@ static int max77650_led_probe(struct platform_device *pdev)
struct max77650_led *leds, *led;
struct device *dev;
struct regmap *map;
const char *label;
int rv, num_leds;
u32 reg;
@ -86,6 +85,8 @@ static int max77650_led_probe(struct platform_device *pdev)
return -ENODEV;
device_for_each_child_node(dev, child) {
struct led_init_data init_data = {};
rv = fwnode_property_read_u32(child, "reg", &reg);
if (rv || reg >= MAX77650_LED_NUM_LEDS) {
rv = -EINVAL;
@ -99,22 +100,13 @@ static int max77650_led_probe(struct platform_device *pdev)
led->cdev.brightness_set_blocking = max77650_led_brightness_set;
led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS;
rv = fwnode_property_read_string(child, "label", &label);
if (rv) {
led->cdev.name = "max77650::";
} else {
led->cdev.name = devm_kasprintf(dev, GFP_KERNEL,
"max77650:%s", label);
if (!led->cdev.name) {
rv = -ENOMEM;
goto err_node_put;
}
}
init_data.fwnode = child;
init_data.devicename = "max77650";
/* for backwards compatibility if `label` is not present */
init_data.default_label = ":";
fwnode_property_read_string(child, "linux,default-trigger",
&led->cdev.default_trigger);
rv = devm_led_classdev_register(dev, &led->cdev);
rv = devm_led_classdev_register_ext(dev, &led->cdev,
&init_data);
if (rv)
goto err_node_put;

View File

@ -599,7 +599,7 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
{
struct device *dev = &led->pdev->dev;
struct max77693_sub_led *sub_leds = led->sub_leds;
struct device_node *node = dev->of_node, *child_node;
struct device_node *node = dev_of_node(dev), *child_node;
struct property *prop;
u32 led_sources[2];
int i, ret, fled_id;

View File

@ -121,7 +121,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
if (!pdata)
return ERR_PTR(-ENOMEM);
parent = of_get_child_by_name(dev->parent->of_node, "leds");
parent = of_get_child_by_name(dev_of_node(dev->parent), "leds");
if (!parent)
goto out_node_put;
@ -131,7 +131,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
if (ret)
goto out_node_put;
pdata->num_leds = of_get_child_count(parent);
pdata->num_leds = of_get_available_child_count(parent);
pdata->led = devm_kcalloc(dev, pdata->num_leds, sizeof(*pdata->led),
GFP_KERNEL);
@ -140,7 +140,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
goto out_node_put;
}
for_each_child_of_node(parent, child) {
for_each_available_child_of_node(parent, child) {
const char *str;
u32 tmp;
@ -192,7 +192,7 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
leds->master = mcdev;
platform_set_drvdata(pdev, leds);
if (dev->parent->of_node) {
if (dev_of_node(dev->parent)) {
pdata = mc13xxx_led_probe_dt(pdev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);

View File

@ -248,15 +248,6 @@ static int mt6323_led_set_blink(struct led_classdev *cdev,
u8 duty_hw;
int ret;
/*
* Units are in ms, if over the hardware able
* to support, fallback into software blink
*/
period = *delay_on + *delay_off;
if (period > MT6323_MAX_PERIOD)
return -EINVAL;
/*
* LED subsystem requires a default user
* friendly blink pattern for the LED so using
@ -268,6 +259,15 @@ static int mt6323_led_set_blink(struct led_classdev *cdev,
*delay_off = 500;
}
/*
* Units are in ms, if over the hardware able
* to support, fallback into software blink
*/
period = *delay_on + *delay_off;
if (period > MT6323_MAX_PERIOD)
return -EINVAL;
/*
* Calculate duty_hw based on the percentage of period during
* which the led is ON.
@ -342,11 +342,6 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev,
const char *state;
int ret = 0;
led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
led->cdev.default_trigger = of_get_property(np,
"linux,default-trigger",
NULL);
state = of_get_property(np, "default-state", NULL);
if (state) {
if (!strcmp(state, "keep")) {
@ -369,9 +364,9 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev,
static int mt6323_led_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct device_node *np = dev_of_node(dev);
struct device_node *child;
struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent);
struct mt6397_chip *hw = dev_get_drvdata(dev->parent);
struct mt6323_leds *leds;
struct mt6323_led *led;
int ret;
@ -402,6 +397,8 @@ static int mt6323_led_probe(struct platform_device *pdev)
}
for_each_available_child_of_node(np, child) {
struct led_init_data init_data = {};
ret = of_property_read_u32(child, "reg", &reg);
if (ret) {
dev_err(dev, "Failed to read led 'reg' property\n");
@ -437,13 +434,14 @@ static int mt6323_led_probe(struct platform_device *pdev)
goto put_child_node;
}
ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev);
init_data.fwnode = of_fwnode_handle(child);
ret = devm_led_classdev_register_ext(dev, &leds->led[reg]->cdev,
&init_data);
if (ret) {
dev_err(&pdev->dev, "Failed to register LED: %d\n",
ret);
dev_err(dev, "Failed to register LED: %d\n", ret);
goto put_child_node;
}
leds->led[reg]->cdev.dev->of_node = child;
}
return 0;

View File

@ -419,7 +419,7 @@ static int netxbig_gpio_ext_get(struct device *dev,
static int netxbig_leds_get_of_pdata(struct device *dev,
struct netxbig_led_platform_data *pdata)
{
struct device_node *np = dev->of_node;
struct device_node *np = dev_of_node(dev);
struct device_node *gpio_ext_np;
struct platform_device *gpio_ext_pdev;
struct device *gpio_ext_dev;
@ -485,7 +485,7 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
}
/* LEDs */
num_leds = of_get_child_count(np);
num_leds = of_get_available_child_count(np);
if (!num_leds) {
dev_err(dev, "No LED subnodes found in DT\n");
return -ENODEV;
@ -496,7 +496,7 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
return -ENOMEM;
led = leds;
for_each_child_of_node(np, child) {
for_each_available_child_of_node(np, child) {
const char *string;
int *mode_val;
int num_modes;

View File

@ -24,25 +24,16 @@ enum ns2_led_modes {
NS_V2_LED_SATA,
};
/*
* If the size of this structure or types of its members is changed,
* the filling of array modval in function ns2_led_register must be changed
* accordingly.
*/
struct ns2_led_modval {
enum ns2_led_modes mode;
int cmd_level;
int slow_level;
};
struct ns2_led {
const char *name;
const char *default_trigger;
struct gpio_desc *cmd;
struct gpio_desc *slow;
int num_modes;
struct ns2_led_modval *modval;
};
struct ns2_led_platform_data {
int num_leds;
struct ns2_led *leds;
};
u32 mode;
u32 cmd_level;
u32 slow_level;
} __packed;
/*
* The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED
@ -51,7 +42,7 @@ struct ns2_led_platform_data {
* for the command/slow GPIOs corresponds to a LED mode.
*/
struct ns2_led_data {
struct ns2_led {
struct led_classdev cdev;
struct gpio_desc *cmd;
struct gpio_desc *slow;
@ -62,77 +53,67 @@ struct ns2_led_data {
struct ns2_led_modval *modval;
};
static int ns2_led_get_mode(struct ns2_led_data *led_dat,
enum ns2_led_modes *mode)
static int ns2_led_get_mode(struct ns2_led *led, enum ns2_led_modes *mode)
{
int i;
int ret = -EINVAL;
int cmd_level;
int slow_level;
cmd_level = gpiod_get_value_cansleep(led_dat->cmd);
slow_level = gpiod_get_value_cansleep(led_dat->slow);
cmd_level = gpiod_get_value_cansleep(led->cmd);
slow_level = gpiod_get_value_cansleep(led->slow);
for (i = 0; i < led_dat->num_modes; i++) {
if (cmd_level == led_dat->modval[i].cmd_level &&
slow_level == led_dat->modval[i].slow_level) {
*mode = led_dat->modval[i].mode;
ret = 0;
break;
for (i = 0; i < led->num_modes; i++) {
if (cmd_level == led->modval[i].cmd_level &&
slow_level == led->modval[i].slow_level) {
*mode = led->modval[i].mode;
return 0;
}
}
return ret;
return -EINVAL;
}
static void ns2_led_set_mode(struct ns2_led_data *led_dat,
enum ns2_led_modes mode)
static void ns2_led_set_mode(struct ns2_led *led, enum ns2_led_modes mode)
{
int i;
bool found = false;
unsigned long flags;
for (i = 0; i < led_dat->num_modes; i++)
if (mode == led_dat->modval[i].mode) {
found = true;
for (i = 0; i < led->num_modes; i++)
if (mode == led->modval[i].mode)
break;
}
if (!found)
if (i == led->num_modes)
return;
write_lock_irqsave(&led_dat->rw_lock, flags);
write_lock_irqsave(&led->rw_lock, flags);
if (!led_dat->can_sleep) {
gpiod_set_value(led_dat->cmd,
led_dat->modval[i].cmd_level);
gpiod_set_value(led_dat->slow,
led_dat->modval[i].slow_level);
if (!led->can_sleep) {
gpiod_set_value(led->cmd, led->modval[i].cmd_level);
gpiod_set_value(led->slow, led->modval[i].slow_level);
goto exit_unlock;
}
gpiod_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
gpiod_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
gpiod_set_value_cansleep(led->cmd, led->modval[i].cmd_level);
gpiod_set_value_cansleep(led->slow, led->modval[i].slow_level);
exit_unlock:
write_unlock_irqrestore(&led_dat->rw_lock, flags);
write_unlock_irqrestore(&led->rw_lock, flags);
}
static void ns2_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct ns2_led_data *led_dat =
container_of(led_cdev, struct ns2_led_data, cdev);
struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
enum ns2_led_modes mode;
if (value == LED_OFF)
mode = NS_V2_LED_OFF;
else if (led_dat->sata)
else if (led->sata)
mode = NS_V2_LED_SATA;
else
mode = NS_V2_LED_ON;
ns2_led_set_mode(led_dat, mode);
ns2_led_set_mode(led, mode);
}
static int ns2_led_set_blocking(struct led_classdev *led_cdev,
@ -147,8 +128,7 @@ static ssize_t ns2_led_sata_store(struct device *dev,
const char *buff, size_t count)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct ns2_led_data *led_dat =
container_of(led_cdev, struct ns2_led_data, cdev);
struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
int ret;
unsigned long enable;
@ -158,18 +138,18 @@ static ssize_t ns2_led_sata_store(struct device *dev,
enable = !!enable;
if (led_dat->sata == enable)
if (led->sata == enable)
goto exit;
led_dat->sata = enable;
led->sata = enable;
if (!led_get_brightness(led_cdev))
goto exit;
if (enable)
ns2_led_set_mode(led_dat, NS_V2_LED_SATA);
ns2_led_set_mode(led, NS_V2_LED_SATA);
else
ns2_led_set_mode(led_dat, NS_V2_LED_ON);
ns2_led_set_mode(led, NS_V2_LED_ON);
exit:
return count;
@ -179,10 +159,9 @@ static ssize_t ns2_led_sata_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct ns2_led_data *led_dat =
container_of(led_cdev, struct ns2_led_data, cdev);
struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
return sprintf(buf, "%d\n", led_dat->sata);
return sprintf(buf, "%d\n", led->sata);
}
static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store);
@ -193,147 +172,94 @@ static struct attribute *ns2_led_attrs[] = {
};
ATTRIBUTE_GROUPS(ns2_led);
static int
create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
const struct ns2_led *template)
static int ns2_led_register(struct device *dev, struct fwnode_handle *node,
struct ns2_led *led)
{
int ret;
struct led_init_data init_data = {};
struct ns2_led_modval *modval;
enum ns2_led_modes mode;
int nmodes, ret;
rwlock_init(&led_dat->rw_lock);
led->cmd = devm_fwnode_gpiod_get_index(dev, node, "cmd", 0, GPIOD_ASIS,
fwnode_get_name(node));
if (IS_ERR(led->cmd))
return PTR_ERR(led->cmd);
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->cdev.blink_set = NULL;
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
led_dat->cdev.groups = ns2_led_groups;
led_dat->cmd = template->cmd;
led_dat->slow = template->slow;
led_dat->can_sleep = gpiod_cansleep(led_dat->cmd) |
gpiod_cansleep(led_dat->slow);
if (led_dat->can_sleep)
led_dat->cdev.brightness_set_blocking = ns2_led_set_blocking;
led->slow = devm_fwnode_gpiod_get_index(dev, node, "slow", 0,
GPIOD_ASIS,
fwnode_get_name(node));
if (IS_ERR(led->slow))
return PTR_ERR(led->slow);
ret = fwnode_property_count_u32(node, "modes-map");
if (ret < 0 || ret % 3) {
dev_err(dev, "Missing or malformed modes-map for %pfw\n", node);
return -EINVAL;
}
nmodes = ret / 3;
modval = devm_kcalloc(dev, nmodes, sizeof(*modval), GFP_KERNEL);
if (!modval)
return -ENOMEM;
fwnode_property_read_u32_array(node, "modes-map", (void *)modval,
nmodes * 3);
rwlock_init(&led->rw_lock);
led->cdev.blink_set = NULL;
led->cdev.flags |= LED_CORE_SUSPENDRESUME;
led->cdev.groups = ns2_led_groups;
led->can_sleep = gpiod_cansleep(led->cmd) || gpiod_cansleep(led->slow);
if (led->can_sleep)
led->cdev.brightness_set_blocking = ns2_led_set_blocking;
else
led_dat->cdev.brightness_set = ns2_led_set;
led_dat->modval = template->modval;
led_dat->num_modes = template->num_modes;
led->cdev.brightness_set = ns2_led_set;
led->num_modes = nmodes;
led->modval = modval;
ret = ns2_led_get_mode(led_dat, &mode);
ret = ns2_led_get_mode(led, &mode);
if (ret < 0)
return ret;
/* Set LED initial state. */
led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
led_dat->cdev.brightness =
(mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
if (ret < 0)
return ret;
init_data.fwnode = node;
return 0;
ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
if (ret)
dev_err(dev, "Failed to register LED for node %pfw\n", node);
return ret;
}
static void delete_ns2_led(struct ns2_led_data *led_dat)
static int ns2_led_probe(struct platform_device *pdev)
{
led_classdev_unregister(&led_dat->cdev);
}
struct device *dev = &pdev->dev;
struct fwnode_handle *child;
struct ns2_led *leds;
int count;
int ret;
#ifdef CONFIG_OF_GPIO
/*
* Translate OpenFirmware node properties into platform_data.
*/
static int
ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
{
struct device_node *np = dev->of_node;
struct device_node *child;
struct ns2_led *led, *leds;
int ret, num_leds = 0;
num_leds = of_get_child_count(np);
if (!num_leds)
count = device_get_child_node_count(dev);
if (!count)
return -ENODEV;
leds = devm_kcalloc(dev, num_leds, sizeof(struct ns2_led),
GFP_KERNEL);
leds = devm_kzalloc(dev, array_size(sizeof(*leds), count), GFP_KERNEL);
if (!leds)
return -ENOMEM;
led = leds;
for_each_child_of_node(np, child) {
const char *string;
int i, num_modes;
struct ns2_led_modval *modval;
struct gpio_desc *gd;
ret = of_property_read_string(child, "label", &string);
led->name = (ret == 0) ? string : child->name;
gd = gpiod_get_from_of_node(child, "cmd-gpio", 0,
GPIOD_ASIS, led->name);
if (IS_ERR(gd)) {
ret = PTR_ERR(gd);
goto err_node_put;
device_for_each_child_node(dev, child) {
ret = ns2_led_register(dev, child, leds++);
if (ret) {
fwnode_handle_put(child);
return ret;
}
led->cmd = gd;
gd = gpiod_get_from_of_node(child, "slow-gpio", 0,
GPIOD_ASIS, led->name);
if (IS_ERR(gd)) {
ret = PTR_ERR(gd);
goto err_node_put;
}
led->slow = gd;
ret = of_property_read_string(child, "linux,default-trigger",
&string);
if (ret == 0)
led->default_trigger = string;
ret = of_property_count_u32_elems(child, "modes-map");
if (ret < 0 || ret % 3) {
dev_err(dev,
"Missing or malformed modes-map property\n");
ret = -EINVAL;
goto err_node_put;
}
num_modes = ret / 3;
modval = devm_kcalloc(dev,
num_modes,
sizeof(struct ns2_led_modval),
GFP_KERNEL);
if (!modval) {
ret = -ENOMEM;
goto err_node_put;
}
for (i = 0; i < num_modes; i++) {
of_property_read_u32_index(child,
"modes-map", 3 * i,
(u32 *) &modval[i].mode);
of_property_read_u32_index(child,
"modes-map", 3 * i + 1,
(u32 *) &modval[i].cmd_level);
of_property_read_u32_index(child,
"modes-map", 3 * i + 2,
(u32 *) &modval[i].slow_level);
}
led->num_modes = num_modes;
led->modval = modval;
led++;
}
pdata->leds = leds;
pdata->num_leds = num_leds;
return 0;
err_node_put:
of_node_put(child);
return ret;
}
static const struct of_device_id of_ns2_leds_match[] = {
@ -341,76 +267,12 @@ static const struct of_device_id of_ns2_leds_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, of_ns2_leds_match);
#endif /* CONFIG_OF_GPIO */
struct ns2_led_priv {
int num_leds;
struct ns2_led_data leds_data[];
};
static int ns2_led_probe(struct platform_device *pdev)
{
struct ns2_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct ns2_led_priv *priv;
int i;
int ret;
#ifdef CONFIG_OF_GPIO
if (!pdata) {
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct ns2_led_platform_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
ret = ns2_leds_get_of_pdata(&pdev->dev, pdata);
if (ret)
return ret;
}
#else
if (!pdata)
return -EINVAL;
#endif /* CONFIG_OF_GPIO */
priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds_data, pdata->num_leds), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->num_leds = pdata->num_leds;
for (i = 0; i < priv->num_leds; i++) {
ret = create_ns2_led(pdev, &priv->leds_data[i],
&pdata->leds[i]);
if (ret < 0) {
for (i = i - 1; i >= 0; i--)
delete_ns2_led(&priv->leds_data[i]);
return ret;
}
}
platform_set_drvdata(pdev, priv);
return 0;
}
static int ns2_led_remove(struct platform_device *pdev)
{
int i;
struct ns2_led_priv *priv;
priv = platform_get_drvdata(pdev);
for (i = 0; i < priv->num_leds; i++)
delete_ns2_led(&priv->leds_data[i]);
return 0;
}
static struct platform_driver ns2_led_driver = {
.probe = ns2_led_probe,
.remove = ns2_led_remove,
.driver = {
.name = "leds-ns2",
.of_match_table = of_match_ptr(of_ns2_leds_match),
.of_match_table = of_ns2_leds_match,
},
};

View File

@ -27,6 +27,8 @@
#define PCA9532_REG_PWM(m, i) (PCA9532_REG_OFFSET(m) + 0x2 + (i) * 2)
#define LED_REG(m, led) (PCA9532_REG_OFFSET(m) + 0x5 + (led >> 2))
#define LED_NUM(led) (led & 0x3)
#define LED_SHIFT(led) (LED_NUM(led) * 2)
#define LED_MASK(led) (0x3 << LED_SHIFT(led))
#define ldev_to_led(c) container_of(c, struct pca9532_led, ldev)
@ -162,9 +164,9 @@ static void pca9532_setled(struct pca9532_led *led)
mutex_lock(&data->update_lock);
reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
/* zero led bits */
reg = reg & ~(0x3<<LED_NUM(led->id)*2);
reg = reg & ~LED_MASK(led->id);
/* set the new value */
reg = reg | (led->state << LED_NUM(led->id)*2);
reg = reg | (led->state << LED_SHIFT(led->id));
i2c_smbus_write_byte_data(client, LED_REG(maxleds, led->id), reg);
mutex_unlock(&data->update_lock);
}
@ -260,7 +262,7 @@ static enum pca9532_state pca9532_getled(struct pca9532_led *led)
mutex_lock(&data->update_lock);
reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
ret = reg >> LED_NUM(led->id)/2;
ret = (reg & LED_MASK(led->id)) >> LED_SHIFT(led->id);
mutex_unlock(&data->update_lock);
return ret;
}
@ -478,7 +480,12 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np)
if (!pdata)
return ERR_PTR(-ENOMEM);
for_each_child_of_node(np, child) {
of_property_read_u8_array(np, "nxp,pwm", &pdata->pwm[0],
ARRAY_SIZE(pdata->pwm));
of_property_read_u8_array(np, "nxp,psc", &pdata->psc[0],
ARRAY_SIZE(pdata->psc));
for_each_available_child_of_node(np, child) {
if (of_property_read_string(child, "label",
&pdata->leds[i].name))
pdata->leds[i].name = child->name;
@ -507,7 +514,7 @@ static int pca9532_probe(struct i2c_client *client,
struct pca9532_data *data = i2c_get_clientdata(client);
struct pca9532_platform_data *pca9532_pdata =
dev_get_platdata(&client->dev);
struct device_node *np = client->dev.of_node;
struct device_node *np = dev_of_node(&client->dev);
if (!pca9532_pdata) {
if (np) {
@ -545,13 +552,8 @@ static int pca9532_probe(struct i2c_client *client,
static int pca9532_remove(struct i2c_client *client)
{
struct pca9532_data *data = i2c_get_clientdata(client);
int err;
err = pca9532_destroy_devices(data, data->chip_info->num_leds);
if (err)
return err;
return 0;
return pca9532_destroy_devices(data, data->chip_info->num_leds);
}
module_i2c_driver(pca9532_driver);

View File

@ -65,6 +65,7 @@ enum pca955x_type {
pca9550,
pca9551,
pca9552,
ibm_pca9552,
pca9553,
};
@ -90,6 +91,11 @@ static struct pca955x_chipdef pca955x_chipdefs[] = {
.slv_addr = /* 1100xxx */ 0x60,
.slv_addr_shift = 3,
},
[ibm_pca9552] = {
.bits = 16,
.slv_addr = /* 0110xxx */ 0x30,
.slv_addr_shift = 3,
},
[pca9553] = {
.bits = 4,
.slv_addr = /* 110001x */ 0x62,
@ -101,6 +107,7 @@ static const struct i2c_device_id pca955x_id[] = {
{ "pca9550", pca9550 },
{ "pca9551", pca9551 },
{ "pca9552", pca9552 },
{ "ibm-pca9552", ibm_pca9552 },
{ "pca9553", pca9553 },
{ }
};
@ -412,6 +419,7 @@ static const struct of_device_id of_pca955x_match[] = {
{ .compatible = "nxp,pca9550", .data = (void *)pca9550 },
{ .compatible = "nxp,pca9551", .data = (void *)pca9551 },
{ .compatible = "nxp,pca9552", .data = (void *)pca9552 },
{ .compatible = "ibm,pca9552", .data = (void *)ibm_pca9552 },
{ .compatible = "nxp,pca9553", .data = (void *)pca9553 },
{},
};

View File

@ -32,7 +32,6 @@
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/platform_data/leds-pca963x.h>
/* LED select registers determine the source that drives LED outputs */
#define PCA963X_LED_OFF 0x0 /* LED driver off */
@ -96,142 +95,148 @@ static const struct i2c_device_id pca963x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pca963x_id);
struct pca963x_led;
struct pca963x {
struct pca963x_chipdef *chipdef;
struct mutex mutex;
struct i2c_client *client;
struct pca963x_led *leds;
unsigned long leds_on;
};
struct pca963x;
struct pca963x_led {
struct pca963x *chip;
struct led_classdev led_cdev;
int led_num; /* 0 .. 15 potentially */
char name[32];
u8 gdc;
u8 gfrq;
};
static int pca963x_brightness(struct pca963x_led *pca963x,
enum led_brightness brightness)
struct pca963x {
struct pca963x_chipdef *chipdef;
struct mutex mutex;
struct i2c_client *client;
unsigned long leds_on;
struct pca963x_led leds[];
};
static int pca963x_brightness(struct pca963x_led *led,
enum led_brightness brightness)
{
u8 ledout_addr = pca963x->chip->chipdef->ledout_base
+ (pca963x->led_num / 4);
u8 ledout;
int shift = 2 * (pca963x->led_num % 4);
u8 mask = 0x3 << shift;
struct i2c_client *client = led->chip->client;
struct pca963x_chipdef *chipdef = led->chip->chipdef;
u8 ledout_addr, ledout, mask, val;
int shift;
int ret;
ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
ledout_addr = chipdef->ledout_base + (led->led_num / 4);
shift = 2 * (led->led_num % 4);
mask = 0x3 << shift;
ledout = i2c_smbus_read_byte_data(client, ledout_addr);
switch (brightness) {
case LED_FULL:
ret = i2c_smbus_write_byte_data(pca963x->chip->client,
ledout_addr,
(ledout & ~mask) | (PCA963X_LED_ON << shift));
val = (ledout & ~mask) | (PCA963X_LED_ON << shift);
ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
break;
case LED_OFF:
ret = i2c_smbus_write_byte_data(pca963x->chip->client,
ledout_addr, ledout & ~mask);
val = ledout & ~mask;
ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
break;
default:
ret = i2c_smbus_write_byte_data(pca963x->chip->client,
PCA963X_PWM_BASE + pca963x->led_num,
brightness);
ret = i2c_smbus_write_byte_data(client,
PCA963X_PWM_BASE +
led->led_num,
brightness);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(pca963x->chip->client,
ledout_addr,
(ledout & ~mask) | (PCA963X_LED_PWM << shift));
val = (ledout & ~mask) | (PCA963X_LED_PWM << shift);
ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
break;
}
return ret;
}
static void pca963x_blink(struct pca963x_led *pca963x)
static void pca963x_blink(struct pca963x_led *led)
{
u8 ledout_addr = pca963x->chip->chipdef->ledout_base +
(pca963x->led_num / 4);
u8 ledout;
u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client,
PCA963X_MODE2);
int shift = 2 * (pca963x->led_num % 4);
u8 mask = 0x3 << shift;
struct i2c_client *client = led->chip->client;
struct pca963x_chipdef *chipdef = led->chip->chipdef;
u8 ledout_addr, ledout, mask, val, mode2;
int shift;
i2c_smbus_write_byte_data(pca963x->chip->client,
pca963x->chip->chipdef->grppwm, pca963x->gdc);
ledout_addr = chipdef->ledout_base + (led->led_num / 4);
shift = 2 * (led->led_num % 4);
mask = 0x3 << shift;
mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2);
i2c_smbus_write_byte_data(pca963x->chip->client,
pca963x->chip->chipdef->grpfreq, pca963x->gfrq);
i2c_smbus_write_byte_data(client, chipdef->grppwm, led->gdc);
i2c_smbus_write_byte_data(client, chipdef->grpfreq, led->gfrq);
if (!(mode2 & PCA963X_MODE2_DMBLNK))
i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
mode2 | PCA963X_MODE2_DMBLNK);
i2c_smbus_write_byte_data(client, PCA963X_MODE2,
mode2 | PCA963X_MODE2_DMBLNK);
mutex_lock(&pca963x->chip->mutex);
ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift))
i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
(ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift));
mutex_unlock(&pca963x->chip->mutex);
mutex_lock(&led->chip->mutex);
ledout = i2c_smbus_read_byte_data(client, ledout_addr);
if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) {
val = (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift);
i2c_smbus_write_byte_data(client, ledout_addr, val);
}
mutex_unlock(&led->chip->mutex);
}
static int pca963x_power_state(struct pca963x_led *pca963x)
static int pca963x_power_state(struct pca963x_led *led)
{
unsigned long *leds_on = &pca963x->chip->leds_on;
unsigned long cached_leds = pca963x->chip->leds_on;
struct i2c_client *client = led->chip->client;
unsigned long *leds_on = &led->chip->leds_on;
unsigned long cached_leds = *leds_on;
if (pca963x->led_cdev.brightness)
set_bit(pca963x->led_num, leds_on);
if (led->led_cdev.brightness)
set_bit(led->led_num, leds_on);
else
clear_bit(pca963x->led_num, leds_on);
clear_bit(led->led_num, leds_on);
if (!(*leds_on) != !cached_leds)
return i2c_smbus_write_byte_data(pca963x->chip->client,
PCA963X_MODE1, *leds_on ? 0 : BIT(4));
return i2c_smbus_write_byte_data(client, PCA963X_MODE1,
*leds_on ? 0 : BIT(4));
return 0;
}
static int pca963x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
enum led_brightness value)
{
struct pca963x_led *pca963x;
struct pca963x_led *led;
int ret;
pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
led = container_of(led_cdev, struct pca963x_led, led_cdev);
mutex_lock(&pca963x->chip->mutex);
mutex_lock(&led->chip->mutex);
ret = pca963x_brightness(pca963x, value);
ret = pca963x_brightness(led, value);
if (ret < 0)
goto unlock;
ret = pca963x_power_state(pca963x);
ret = pca963x_power_state(led);
unlock:
mutex_unlock(&pca963x->chip->mutex);
mutex_unlock(&led->chip->mutex);
return ret;
}
static unsigned int pca963x_period_scale(struct pca963x_led *pca963x,
unsigned int val)
static unsigned int pca963x_period_scale(struct pca963x_led *led,
unsigned int val)
{
unsigned int scaling = pca963x->chip->chipdef->scaling;
unsigned int scaling = led->chip->chipdef->scaling;
return scaling ? DIV_ROUND_CLOSEST(val * scaling, 1000) : val;
}
static int pca963x_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
unsigned long *delay_on, unsigned long *delay_off)
{
struct pca963x_led *pca963x;
unsigned long time_on, time_off, period;
struct pca963x_led *led;
u8 gdc, gfrq;
pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
led = container_of(led_cdev, struct pca963x_led, led_cdev);
time_on = *delay_on;
time_off = *delay_off;
@ -242,14 +247,14 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
time_off = 500;
}
period = pca963x_period_scale(pca963x, time_on + time_off);
period = pca963x_period_scale(led, time_on + time_off);
/* If period not supported by hardware, default to someting sane. */
if ((period < PCA963X_BLINK_PERIOD_MIN) ||
(period > PCA963X_BLINK_PERIOD_MAX)) {
time_on = 500;
time_off = 500;
period = pca963x_period_scale(pca963x, 1000);
period = pca963x_period_scale(led, 1000);
}
/*
@ -257,7 +262,7 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
* (time_on / period) = (GDC / 256) ->
* GDC = ((time_on * 256) / period)
*/
gdc = (pca963x_period_scale(pca963x, time_on) * 256) / period;
gdc = (pca963x_period_scale(led, time_on) * 256) / period;
/*
* From manual: period = ((GFRQ + 1) / 24) in seconds.
@ -266,10 +271,10 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
*/
gfrq = (period * 24 / 1000) - 1;
pca963x->gdc = gdc;
pca963x->gfrq = gfrq;
led->gdc = gdc;
led->gfrq = gfrq;
pca963x_blink(pca963x);
pca963x_blink(led);
*delay_on = time_on;
*delay_off = time_off;
@ -277,72 +282,84 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
return 0;
}
static struct pca963x_platform_data *
pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip)
static int pca963x_register_leds(struct i2c_client *client,
struct pca963x *chip)
{
struct pca963x_platform_data *pdata;
struct led_info *pca963x_leds;
struct pca963x_chipdef *chipdef = chip->chipdef;
struct pca963x_led *led = chip->leds;
struct device *dev = &client->dev;
struct fwnode_handle *child;
int count;
bool hw_blink;
s32 mode2;
u32 reg;
int ret;
count = device_get_child_node_count(&client->dev);
if (!count || count > chip->n_leds)
return ERR_PTR(-ENODEV);
if (device_property_read_u32(dev, "nxp,period-scale",
&chipdef->scaling))
chipdef->scaling = 1000;
pca963x_leds = devm_kcalloc(&client->dev,
chip->n_leds, sizeof(struct led_info), GFP_KERNEL);
if (!pca963x_leds)
return ERR_PTR(-ENOMEM);
hw_blink = device_property_read_bool(dev, "nxp,hw-blink");
device_for_each_child_node(&client->dev, child) {
struct led_info led = {};
u32 reg;
int res;
res = fwnode_property_read_u32(child, "reg", &reg);
if ((res != 0) || (reg >= chip->n_leds))
continue;
res = fwnode_property_read_string(child, "label", &led.name);
if ((res != 0) && is_of_node(child))
led.name = to_of_node(child)->name;
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
pca963x_leds[reg] = led;
}
pdata = devm_kzalloc(&client->dev,
sizeof(struct pca963x_platform_data), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->leds.leds = pca963x_leds;
pdata->leds.num_leds = chip->n_leds;
mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2);
if (mode2 < 0)
return mode2;
/* default to open-drain unless totem pole (push-pull) is specified */
if (device_property_read_bool(&client->dev, "nxp,totem-pole"))
pdata->outdrv = PCA963X_TOTEM_POLE;
if (device_property_read_bool(dev, "nxp,totem-pole"))
mode2 |= PCA963X_MODE2_OUTDRV;
else
pdata->outdrv = PCA963X_OPEN_DRAIN;
/* default to software blinking unless hardware blinking is specified */
if (device_property_read_bool(&client->dev, "nxp,hw-blink"))
pdata->blink_type = PCA963X_HW_BLINK;
else
pdata->blink_type = PCA963X_SW_BLINK;
if (device_property_read_u32(&client->dev, "nxp,period-scale",
&chip->scaling))
chip->scaling = 1000;
mode2 &= ~PCA963X_MODE2_OUTDRV;
/* default to non-inverted output, unless inverted is specified */
if (device_property_read_bool(&client->dev, "nxp,inverted-out"))
pdata->dir = PCA963X_INVERTED;
if (device_property_read_bool(dev, "nxp,inverted-out"))
mode2 |= PCA963X_MODE2_INVRT;
else
pdata->dir = PCA963X_NORMAL;
mode2 &= ~PCA963X_MODE2_INVRT;
return pdata;
ret = i2c_smbus_write_byte_data(client, PCA963X_MODE2, mode2);
if (ret < 0)
return ret;
device_for_each_child_node(dev, child) {
struct led_init_data init_data = {};
char default_label[32];
ret = fwnode_property_read_u32(child, "reg", &reg);
if (ret || reg >= chipdef->n_leds) {
dev_err(dev, "Invalid 'reg' property for node %pfw\n",
child);
ret = -EINVAL;
goto err;
}
led->led_num = reg;
led->chip = chip;
led->led_cdev.brightness_set_blocking = pca963x_led_set;
if (hw_blink)
led->led_cdev.blink_set = pca963x_blink_set;
init_data.fwnode = child;
/* for backwards compatibility */
init_data.devicename = "pca963x";
snprintf(default_label, sizeof(default_label), "%d:%.2x:%u",
client->adapter->nr, client->addr, reg);
init_data.default_label = default_label;
ret = devm_led_classdev_register_ext(dev, &led->led_cdev,
&init_data);
if (ret) {
dev_err(dev, "Failed to register LED for node %pfw\n",
child);
goto err;
}
++led;
}
return 0;
err:
fwnode_handle_put(child);
return ret;
}
static const struct of_device_id of_pca963x_match[] = {
@ -355,119 +372,40 @@ static const struct of_device_id of_pca963x_match[] = {
MODULE_DEVICE_TABLE(of, of_pca963x_match);
static int pca963x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
const struct i2c_device_id *id)
{
struct pca963x *pca963x_chip;
struct pca963x_led *pca963x;
struct pca963x_platform_data *pdata;
struct pca963x_chipdef *chip;
int i, err;
struct device *dev = &client->dev;
struct pca963x_chipdef *chipdef;
struct pca963x *chip;
int i, count;
chip = &pca963x_chipdefs[id->driver_data];
pdata = dev_get_platdata(&client->dev);
chipdef = &pca963x_chipdefs[id->driver_data];
if (!pdata) {
pdata = pca963x_get_pdata(client, chip);
if (IS_ERR(pdata)) {
dev_warn(&client->dev, "could not parse configuration\n");
pdata = NULL;
}
}
if (pdata && (pdata->leds.num_leds < 1 ||
pdata->leds.num_leds > chip->n_leds)) {
dev_err(&client->dev, "board info must claim 1-%d LEDs",
chip->n_leds);
count = device_get_child_node_count(dev);
if (!count || count > chipdef->n_leds) {
dev_err(dev, "Node %pfw must define between 1 and %d LEDs\n",
dev_fwnode(dev), chipdef->n_leds);
return -EINVAL;
}
pca963x_chip = devm_kzalloc(&client->dev, sizeof(*pca963x_chip),
GFP_KERNEL);
if (!pca963x_chip)
return -ENOMEM;
pca963x = devm_kcalloc(&client->dev, chip->n_leds, sizeof(*pca963x),
GFP_KERNEL);
if (!pca963x)
chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL);
if (!chip)
return -ENOMEM;
i2c_set_clientdata(client, pca963x_chip);
i2c_set_clientdata(client, chip);
mutex_init(&pca963x_chip->mutex);
pca963x_chip->chipdef = chip;
pca963x_chip->client = client;
pca963x_chip->leds = pca963x;
mutex_init(&chip->mutex);
chip->chipdef = chipdef;
chip->client = client;
/* Turn off LEDs by default*/
for (i = 0; i < chip->n_leds / 4; i++)
i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00);
for (i = 0; i < chip->n_leds; i++) {
pca963x[i].led_num = i;
pca963x[i].chip = pca963x_chip;
/* Platform data can specify LED names and default triggers */
if (pdata && i < pdata->leds.num_leds) {
if (pdata->leds.leds[i].name)
snprintf(pca963x[i].name,
sizeof(pca963x[i].name), "pca963x:%s",
pdata->leds.leds[i].name);
if (pdata->leds.leds[i].default_trigger)
pca963x[i].led_cdev.default_trigger =
pdata->leds.leds[i].default_trigger;
}
if (!pdata || i >= pdata->leds.num_leds ||
!pdata->leds.leds[i].name)
snprintf(pca963x[i].name, sizeof(pca963x[i].name),
"pca963x:%d:%.2x:%d", client->adapter->nr,
client->addr, i);
pca963x[i].led_cdev.name = pca963x[i].name;
pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set;
if (pdata && pdata->blink_type == PCA963X_HW_BLINK)
pca963x[i].led_cdev.blink_set = pca963x_blink_set;
err = led_classdev_register(&client->dev, &pca963x[i].led_cdev);
if (err < 0)
goto exit;
}
for (i = 0; i < chipdef->n_leds / 4; i++)
i2c_smbus_write_byte_data(client, chipdef->ledout_base + i, 0x00);
/* Disable LED all-call address, and power down initially */
i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4));
if (pdata) {
u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client,
PCA963X_MODE2);
/* Configure output: open-drain or totem pole (push-pull) */
if (pdata->outdrv == PCA963X_OPEN_DRAIN)
mode2 &= ~PCA963X_MODE2_OUTDRV;
else
mode2 |= PCA963X_MODE2_OUTDRV;
/* Configure direction: normal or inverted */
if (pdata->dir == PCA963X_INVERTED)
mode2 |= PCA963X_MODE2_INVRT;
i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
mode2);
}
return 0;
exit:
while (i--)
led_classdev_unregister(&pca963x[i].led_cdev);
return err;
}
static int pca963x_remove(struct i2c_client *client)
{
struct pca963x *pca963x = i2c_get_clientdata(client);
int i;
for (i = 0; i < pca963x->chipdef->n_leds; i++)
led_classdev_unregister(&pca963x->leds[i].led_cdev);
return 0;
return pca963x_register_leds(client, chip);
}
static struct i2c_driver pca963x_driver = {
@ -476,7 +414,6 @@ static struct i2c_driver pca963x_driver = {
.of_match_table = of_pca963x_match,
},
.probe = pca963x_probe,
.remove = pca963x_remove,
.id_table = pca963x_id,
};

View File

@ -87,36 +87,36 @@ static enum led_brightness pm8058_led_get(struct led_classdev *cled)
static int pm8058_led_probe(struct platform_device *pdev)
{
struct led_init_data init_data = {};
struct device *dev = &pdev->dev;
struct pm8058_led *led;
struct device_node *np = pdev->dev.of_node;
struct device_node *np;
int ret;
struct regmap *map;
const char *state;
enum led_brightness maxbright;
led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
led->ledtype = (u32)(unsigned long)of_device_get_match_data(&pdev->dev);
led->ledtype = (u32)(unsigned long)of_device_get_match_data(dev);
map = dev_get_regmap(pdev->dev.parent, NULL);
map = dev_get_regmap(dev->parent, NULL);
if (!map) {
dev_err(&pdev->dev, "Parent regmap unavailable.\n");
dev_err(dev, "Parent regmap unavailable.\n");
return -ENXIO;
}
led->map = map;
np = dev_of_node(dev);
ret = of_property_read_u32(np, "reg", &led->reg);
if (ret) {
dev_err(&pdev->dev, "no register offset specified\n");
dev_err(dev, "no register offset specified\n");
return -EINVAL;
}
/* Use label else node name */
led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
led->cdev.default_trigger =
of_get_property(np, "linux,default-trigger", NULL);
led->cdev.brightness_set = pm8058_led_set;
led->cdev.brightness_get = pm8058_led_get;
if (led->ledtype == PM8058_LED_TYPE_COMMON)
@ -142,14 +142,13 @@ static int pm8058_led_probe(struct platform_device *pdev)
led->ledtype == PM8058_LED_TYPE_FLASH)
led->cdev.flags = LED_CORE_SUSPENDRESUME;
ret = devm_led_classdev_register(&pdev->dev, &led->cdev);
if (ret) {
dev_err(&pdev->dev, "unable to register led \"%s\"\n",
led->cdev.name);
return ret;
}
init_data.fwnode = of_fwnode_handle(np);
return 0;
ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
if (ret)
dev_err(dev, "Failed to register LED for %pOF\n", np);
return ret;
}
static const struct of_device_id pm8058_leds_id_table[] = {

View File

@ -250,7 +250,7 @@ static int powernv_led_classdev(struct platform_device *pdev,
struct powernv_led_data *powernv_led;
struct device *dev = &pdev->dev;
for_each_child_of_node(led_node, np) {
for_each_available_child_of_node(led_node, np) {
p = of_find_property(np, "led-types", NULL);
while ((cur = of_prop_next_string(p, cur)) != NULL) {

View File

@ -20,16 +20,10 @@
struct led_pwm {
const char *name;
const char *default_trigger;
u8 active_low;
unsigned int max_brightness;
};
struct led_pwm_platform_data {
int num_leds;
struct led_pwm *leds;
};
struct led_pwm_data {
struct led_classdev cdev;
struct pwm_device *pwm;
@ -61,36 +55,31 @@ static int led_pwm_set(struct led_classdev *led_cdev,
return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate);
}
__attribute__((nonnull))
static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
struct led_pwm *led, struct fwnode_handle *fwnode)
{
struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
struct led_init_data init_data = { .fwnode = fwnode };
int ret;
led_data->active_low = led->active_low;
led_data->cdev.name = led->name;
led_data->cdev.default_trigger = led->default_trigger;
led_data->cdev.brightness = LED_OFF;
led_data->cdev.max_brightness = led->max_brightness;
led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
if (fwnode)
led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
else
led_data->pwm = devm_pwm_get(dev, led->name);
if (IS_ERR(led_data->pwm)) {
ret = PTR_ERR(led_data->pwm);
if (ret != -EPROBE_DEFER)
dev_err(dev, "unable to request PWM for %s: %d\n",
led->name, ret);
return ret;
}
led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
if (IS_ERR(led_data->pwm))
return dev_err_probe(dev, PTR_ERR(led_data->pwm),
"unable to request PWM for %s\n",
led->name);
led_data->cdev.brightness_set_blocking = led_pwm_set;
pwm_init_state(led_data->pwm, &led_data->pwmstate);
ret = devm_led_classdev_register(dev, &led_data->cdev);
ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
if (ret) {
dev_err(dev, "failed to register PWM led for %s: %d\n",
led->name, ret);
@ -126,9 +115,6 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
return -EINVAL;
}
fwnode_property_read_string(fwnode, "linux,default-trigger",
&led.default_trigger);
led.active_low = fwnode_property_read_bool(fwnode,
"active-low");
fwnode_property_read_u32(fwnode, "max-brightness",
@ -146,15 +132,11 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
static int led_pwm_probe(struct platform_device *pdev)
{
struct led_pwm_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct led_pwm_priv *priv;
int count, i;
int ret = 0;
int count;
if (pdata)
count = pdata->num_leds;
else
count = device_get_child_node_count(&pdev->dev);
count = device_get_child_node_count(&pdev->dev);
if (!count)
return -EINVAL;
@ -164,16 +146,7 @@ static int led_pwm_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
if (pdata) {
for (i = 0; i < count; i++) {
ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i],
NULL);
if (ret)
break;
}
} else {
ret = led_pwm_create_fwnode(&pdev->dev, priv);
}
ret = led_pwm_create_fwnode(&pdev->dev, priv);
if (ret)
return ret;

View File

@ -16,8 +16,6 @@
#include <linux/module.h>
#include <linux/platform_data/leds-s3c24xx.h>
#include <mach/regs-gpio.h>
/* our context */
struct s3c24xx_gpio_led {

View File

@ -276,12 +276,12 @@ static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)
static int sc27xx_led_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node, *child;
struct device_node *np = dev_of_node(dev), *child;
struct sc27xx_led_priv *priv;
u32 base, count, reg;
int err;
count = of_get_child_count(np);
count = of_get_available_child_count(np);
if (!count || count > SC27XX_LEDS_MAX)
return -EINVAL;
@ -305,7 +305,7 @@ static int sc27xx_led_probe(struct platform_device *pdev)
return err;
}
for_each_child_of_node(np, child) {
for_each_available_child_of_node(np, child) {
err = of_property_read_u32(child, "reg", &reg);
if (err) {
of_node_put(child);

View File

@ -195,30 +195,21 @@ static int sgm3140_probe(struct platform_device *pdev)
priv->flash_gpio = devm_gpiod_get(&pdev->dev, "flash", GPIOD_OUT_LOW);
ret = PTR_ERR_OR_ZERO(priv->flash_gpio);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"Failed to request flash gpio: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(&pdev->dev, ret,
"Failed to request flash gpio\n");
priv->enable_gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW);
ret = PTR_ERR_OR_ZERO(priv->enable_gpio);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"Failed to request enable gpio: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(&pdev->dev, ret,
"Failed to request enable gpio\n");
priv->vin_regulator = devm_regulator_get(&pdev->dev, "vin");
ret = PTR_ERR_OR_ZERO(priv->vin_regulator);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"Failed to request regulator: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(&pdev->dev, ret,
"Failed to request regulator\n");
child_node = fwnode_get_next_available_child_node(pdev->dev.fwnode,
NULL);
@ -316,5 +307,5 @@ static struct platform_driver sgm3140_driver = {
module_platform_driver(sgm3140_driver);
MODULE_AUTHOR("Luca Weiss <luca@z3ntu.xyz>");
MODULE_DESCRIPTION("SG Micro SGM3140 charge pump led driver");
MODULE_DESCRIPTION("SG Micro SGM3140 charge pump LED driver");
MODULE_LICENSE("GPL v2");

View File

@ -80,7 +80,6 @@ static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
static int spi_byte_probe(struct spi_device *spi)
{
const struct of_device_id *of_dev_id;
struct device_node *child;
struct device *dev = &spi->dev;
struct spi_byte_led *led;
@ -88,15 +87,11 @@ static int spi_byte_probe(struct spi_device *spi)
const char *state;
int ret;
of_dev_id = of_match_device(spi_byte_dt_ids, dev);
if (!of_dev_id)
return -EINVAL;
if (of_get_child_count(dev->of_node) != 1) {
if (of_get_available_child_count(dev_of_node(dev)) != 1) {
dev_err(dev, "Device must have exactly one LED sub-node.");
return -EINVAL;
}
child = of_get_next_child(dev->of_node, NULL);
child = of_get_next_available_child(dev_of_node(dev), NULL);
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
if (!led)
@ -106,7 +101,7 @@ static int spi_byte_probe(struct spi_device *spi)
strlcpy(led->name, name, sizeof(led->name));
led->spi = spi;
mutex_init(&led->mutex);
led->cdef = of_dev_id->data;
led->cdef = device_get_match_data(dev);
led->ldev.name = led->name;
led->ldev.brightness = LED_OFF;
led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value;

View File

@ -55,8 +55,9 @@ static void syscon_led_set(struct led_classdev *led_cdev,
static int syscon_led_probe(struct platform_device *pdev)
{
struct led_init_data init_data = {};
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *np = dev_of_node(dev);
struct device *parent;
struct regmap *map;
struct syscon_led *sled;
@ -68,7 +69,7 @@ static int syscon_led_probe(struct platform_device *pdev)
dev_err(dev, "no parent for syscon LED\n");
return -ENODEV;
}
map = syscon_node_to_regmap(parent->of_node);
map = syscon_node_to_regmap(dev_of_node(parent));
if (IS_ERR(map)) {
dev_err(dev, "no regmap for syscon LED parent\n");
return PTR_ERR(map);
@ -84,10 +85,6 @@ static int syscon_led_probe(struct platform_device *pdev)
return -EINVAL;
if (of_property_read_u32(np, "mask", &sled->mask))
return -EINVAL;
sled->cdev.name =
of_get_property(np, "label", NULL) ? : np->name;
sled->cdev.default_trigger =
of_get_property(np, "linux,default-trigger", NULL);
state = of_get_property(np, "default-state", NULL);
if (state) {
@ -115,7 +112,9 @@ static int syscon_led_probe(struct platform_device *pdev)
}
sled->cdev.brightness_set = syscon_led_set;
ret = devm_led_classdev_register(dev, &sled->cdev);
init_data.fwnode = of_fwnode_handle(np);
ret = devm_led_classdev_register_ext(dev, &sled->cdev, &init_data);
if (ret < 0)
return ret;

View File

@ -69,23 +69,6 @@
* defaulted. Similarly the banks know if each time was explicit or a
* default. Defaults are permitted to be changed freely - they are
* not recognised when matching.
*
*
* An led-tca6507 device must be provided with platform data or
* configured via devicetree.
*
* The platform-data lists for each output: the name, default trigger,
* and whether the signal is being used as a GPIO rather than an LED.
* 'struct led_plaform_data' is used for this. If 'name' is NULL, the
* output isn't used. If 'flags' is TCA6507_MAKE_GPIO, the output is
* a GPO. The "struct led_platform_data" can be embedded in a "struct
* tca6507_platform_data" which adds a 'gpio_base' for the GPIOs, and
* a 'setup' callback which is called once the GPIOs are available.
*
* When configured via devicetree there is one child for each output.
* The "reg" determines the output number and "compatible" determines
* whether it is an LED or a GPIO. "linux,default-trigger" can set a
* default trigger.
*/
#include <linux/module.h>
@ -94,9 +77,8 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/gpio/driver.h>
#include <linux/property.h>
#include <linux/workqueue.h>
#include <linux/leds-tca6507.h>
#include <linux/of.h>
/* LED select registers determine the source that drives LED outputs */
#define TCA6507_LS_LED_OFF 0x0 /* Output HI-Z (off) */
@ -108,6 +90,15 @@
#define TCA6507_LS_BLINK0 0x6 /* Blink at Bank0 rate */
#define TCA6507_LS_BLINK1 0x7 /* Blink at Bank1 rate */
struct tca6507_platform_data {
struct led_platform_data leds;
#ifdef CONFIG_GPIOLIB
int gpio_base;
#endif
};
#define TCA6507_MAKE_GPIO 1
enum {
BANK0,
BANK1,
@ -189,7 +180,6 @@ struct tca6507_chip {
} leds[NUM_LEDS];
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio;
const char *gpio_name[NUM_LEDS];
int gpio_map[NUM_LEDS];
#endif
};
@ -628,7 +618,7 @@ static int tca6507_gpio_direction_output(struct gpio_chip *gc,
return 0;
}
static int tca6507_probe_gpios(struct i2c_client *client,
static int tca6507_probe_gpios(struct device *dev,
struct tca6507_chip *tca,
struct tca6507_platform_data *pdata)
{
@ -639,7 +629,6 @@ static int tca6507_probe_gpios(struct i2c_client *client,
for (i = 0; i < NUM_LEDS; i++)
if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) {
/* Configure as a gpio */
tca->gpio_name[gpios] = pdata->leds.leds[i].name;
tca->gpio_map[gpios] = i;
gpios++;
}
@ -648,23 +637,20 @@ static int tca6507_probe_gpios(struct i2c_client *client,
return 0;
tca->gpio.label = "gpio-tca6507";
tca->gpio.names = tca->gpio_name;
tca->gpio.ngpio = gpios;
tca->gpio.base = pdata->gpio_base;
tca->gpio.owner = THIS_MODULE;
tca->gpio.direction_output = tca6507_gpio_direction_output;
tca->gpio.set = tca6507_gpio_set_value;
tca->gpio.parent = &client->dev;
tca->gpio.parent = dev;
#ifdef CONFIG_OF_GPIO
tca->gpio.of_node = of_node_get(client->dev.of_node);
tca->gpio.of_node = of_node_get(dev_of_node(dev));
#endif
err = gpiochip_add_data(&tca->gpio, tca);
if (err) {
tca->gpio.ngpio = 0;
return err;
}
if (pdata->setup)
pdata->setup(tca->gpio.base, tca->gpio.ngpio);
return 0;
}
@ -674,7 +660,7 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca)
gpiochip_remove(&tca->gpio);
}
#else /* CONFIG_GPIOLIB */
static int tca6507_probe_gpios(struct i2c_client *client,
static int tca6507_probe_gpios(struct device *dev,
struct tca6507_chip *tca,
struct tca6507_platform_data *pdata)
{
@ -685,44 +671,50 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca)
}
#endif /* CONFIG_GPIOLIB */
#ifdef CONFIG_OF
static struct tca6507_platform_data *
tca6507_led_dt_init(struct i2c_client *client)
tca6507_led_dt_init(struct device *dev)
{
struct device_node *np = client->dev.of_node, *child;
struct tca6507_platform_data *pdata;
struct fwnode_handle *child;
struct led_info *tca_leds;
int count;
count = of_get_child_count(np);
count = device_get_child_node_count(dev);
if (!count || count > NUM_LEDS)
return ERR_PTR(-ENODEV);
tca_leds = devm_kcalloc(&client->dev,
NUM_LEDS, sizeof(struct led_info), GFP_KERNEL);
tca_leds = devm_kcalloc(dev, NUM_LEDS, sizeof(struct led_info),
GFP_KERNEL);
if (!tca_leds)
return ERR_PTR(-ENOMEM);
for_each_child_of_node(np, child) {
device_for_each_child_node(dev, child) {
struct led_info led;
u32 reg;
int ret;
led.name =
of_get_property(child, "label", NULL) ? : child->name;
led.default_trigger =
of_get_property(child, "linux,default-trigger", NULL);
if (fwnode_property_read_string(child, "label", &led.name))
led.name = fwnode_get_name(child);
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
led.flags = 0;
if (of_property_match_string(child, "compatible", "gpio") >= 0)
if (fwnode_property_match_string(child, "compatible",
"gpio") >= 0)
led.flags |= TCA6507_MAKE_GPIO;
ret = of_property_read_u32(child, "reg", &reg);
if (ret != 0 || reg >= NUM_LEDS)
continue;
ret = fwnode_property_read_u32(child, "reg", &reg);
if (ret || reg >= NUM_LEDS) {
fwnode_handle_put(child);
return ERR_PTR(ret ? : -EINVAL);
}
tca_leds[reg] = led;
}
pdata = devm_kzalloc(&client->dev,
sizeof(struct tca6507_platform_data), GFP_KERNEL);
pdata = devm_kzalloc(dev, sizeof(struct tca6507_platform_data),
GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
@ -731,48 +723,37 @@ tca6507_led_dt_init(struct i2c_client *client)
#ifdef CONFIG_GPIOLIB
pdata->gpio_base = -1;
#endif
return pdata;
}
static const struct of_device_id of_tca6507_leds_match[] = {
static const struct of_device_id __maybe_unused of_tca6507_leds_match[] = {
{ .compatible = "ti,tca6507", },
{},
};
MODULE_DEVICE_TABLE(of, of_tca6507_leds_match);
#else
static struct tca6507_platform_data *
tca6507_led_dt_init(struct i2c_client *client)
{
return ERR_PTR(-ENODEV);
}
#endif
static int tca6507_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tca6507_chip *tca;
struct device *dev = &client->dev;
struct i2c_adapter *adapter;
struct tca6507_chip *tca;
struct tca6507_platform_data *pdata;
int err;
int i = 0;
adapter = client->adapter;
pdata = dev_get_platdata(&client->dev);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return -EIO;
if (!pdata || pdata->leds.num_leds != NUM_LEDS) {
pdata = tca6507_led_dt_init(client);
if (IS_ERR(pdata)) {
dev_err(&client->dev, "Need %d entries in platform-data list\n",
NUM_LEDS);
return PTR_ERR(pdata);
}
pdata = tca6507_led_dt_init(dev);
if (IS_ERR(pdata)) {
dev_err(dev, "Need %d entries in platform-data list\n", NUM_LEDS);
return PTR_ERR(pdata);
}
tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL);
tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL);
if (!tca)
return -ENOMEM;
@ -793,13 +774,12 @@ static int tca6507_probe(struct i2c_client *client,
l->led_cdev.brightness_set = tca6507_brightness_set;
l->led_cdev.blink_set = tca6507_blink_set;
l->bank = -1;
err = led_classdev_register(&client->dev,
&l->led_cdev);
err = led_classdev_register(dev, &l->led_cdev);
if (err < 0)
goto exit;
}
}
err = tca6507_probe_gpios(client, tca, pdata);
err = tca6507_probe_gpios(dev, tca, pdata);
if (err)
goto exit;
/* set all registers to known state - zero */

View File

@ -148,22 +148,17 @@ static int
tlc591xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device_node *np = client->dev.of_node, *child;
struct device_node *np = dev_of_node(&client->dev), *child;
struct device *dev = &client->dev;
const struct of_device_id *match;
const struct tlc591xx *tlc591xx;
struct tlc591xx_priv *priv;
int err, count, reg;
match = of_match_device(of_tlc591xx_leds_match, dev);
if (!match)
return -ENODEV;
tlc591xx = match->data;
tlc591xx = device_get_match_data(dev);
if (!np)
return -ENODEV;
count = of_get_child_count(np);
count = of_get_available_child_count(np);
if (!count || count > tlc591xx->max_leds)
return -EINVAL;
@ -185,7 +180,7 @@ tlc591xx_probe(struct i2c_client *client,
if (err < 0)
return err;
for_each_child_of_node(np, child) {
for_each_available_child_of_node(np, child) {
struct tlc591xx_led *led;
struct led_init_data init_data = {};
@ -204,9 +199,6 @@ tlc591xx_probe(struct i2c_client *client,
led = &priv->leds[reg];
led->active = true;
led->ldev.default_trigger =
of_get_property(child, "linux,default-trigger", NULL);
led->priv = priv;
led->led_no = reg;
led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
@ -214,10 +206,10 @@ tlc591xx_probe(struct i2c_client *client,
err = devm_led_classdev_register_ext(dev, &led->ldev,
&init_data);
if (err < 0) {
if (err != -EPROBE_DEFER)
dev_err(dev, "couldn't register LED %s\n",
led->ldev.name);
return err;
of_node_put(child);
return dev_err_probe(dev, err,
"couldn't register LED %s\n",
led->ldev.name);
}
}
return 0;

View File

@ -121,8 +121,6 @@ static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,
cdev->max_brightness = 255;
cdev->brightness_set_blocking = omnia_led_brightness_set_blocking;
of_property_read_string(np, "linux,default-trigger", &cdev->default_trigger);
/* put the LED into software mode */
ret = i2c_smbus_write_byte_data(client, CMD_LED_MODE,
CMD_LED_MODE_LED(led->reg) |
@ -210,7 +208,7 @@ static int omnia_leds_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *np = dev->of_node, *child;
struct device_node *np = dev_of_node(dev), *child;
struct omnia_leds *leds;
struct omnia_led *led;
int ret, count;
@ -236,8 +234,10 @@ static int omnia_leds_probe(struct i2c_client *client,
led = &leds->leds[0];
for_each_available_child_of_node(np, child) {
ret = omnia_led_register(client, led, child);
if (ret < 0)
if (ret < 0) {
of_node_put(child);
return ret;
}
led += ret;
}

View File

@ -2,14 +2,18 @@
/*
* ledtrig-cpu.c - LED trigger based on CPU activity
*
* This LED trigger will be registered for each possible CPU and named as
* cpu0, cpu1, cpu2, cpu3, etc.
* This LED trigger will be registered for first 8 CPUs and named
* as cpu0..cpu7. There's additional trigger called cpu that
* is on when any CPU is active.
*
* If you want support for arbitrary number of CPUs, make it one trigger,
* with additional sysfs file selecting which CPU to watch.
*
* It can be bound to any LED just like other triggers using either a
* board file or via sysfs interface.
*
* An API named ledtrig_cpu is exported for any user, who want to add CPU
* activity indication in their code
* activity indication in their code.
*
* Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
* Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com>
@ -145,6 +149,9 @@ static int __init ledtrig_cpu_init(void)
for_each_possible_cpu(cpu) {
struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
if (cpu >= 8)
continue;
snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
led_trigger_register_simple(trig->name, &trig->_trig);

View File

@ -1,21 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* TCA6507 LED chip driver.
*
* Copyright (C) 2011 Neil Brown <neil@brown.name>
*/
#ifndef __LINUX_TCA6507_H
#define __LINUX_TCA6507_H
#include <linux/leds.h>
struct tca6507_platform_data {
struct led_platform_data leds;
#ifdef CONFIG_GPIOLIB
int gpio_base;
void (*setup)(unsigned gpio_base, unsigned ngpio);
#endif
};
#define TCA6507_MAKE_GPIO 1
#endif /* __LINUX_TCA6507_H*/

View File

@ -1,35 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* PCA963X LED chip driver.
*
* Copyright 2012 bct electronic GmbH
* Copyright 2013 Qtechnology A/S
*/
#ifndef __LINUX_PCA963X_H
#define __LINUX_PCA963X_H
#include <linux/leds.h>
enum pca963x_outdrv {
PCA963X_OPEN_DRAIN,
PCA963X_TOTEM_POLE, /* aka push-pull */
};
enum pca963x_blink_type {
PCA963X_SW_BLINK,
PCA963X_HW_BLINK,
};
enum pca963x_direction {
PCA963X_NORMAL,
PCA963X_INVERTED,
};
struct pca963x_platform_data {
struct led_platform_data leds;
enum pca963x_outdrv outdrv;
enum pca963x_blink_type blink_type;
enum pca963x_direction dir;
};
#endif /* __LINUX_PCA963X_H*/