Merge tag 'leds-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds
Pull LED updates from Pavel Machek: "This contains usual small updates to drivers, and removal of PAGE_SIZE limits on /sys/class/leds/<led>/trigger. We should not be really having that many triggers; but with cpu activity triggers we do, and we'll eventually need to fix it, but... remove the limit for now" * tag 'leds-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds: (26 commits) leds: trigger: netdev: fix handling on interface rename leds: an30259a: add a check for devm_regmap_init_i2c leds: mlxreg: Fix possible buffer overflow leds: pca953x: Use of_device_get_match_data() leds: core: Fix leds.h structure documentation leds: core: Fix devm_classdev_match to reference correct structure leds: core: Remove extern from header leds: lm3601x: Convert class registration to device managed leds: flash: Add devm_* functions to the flash class leds: flash: Remove extern from the header file leds: flash: Convert non extended registration to inline leds: Kconfig: Be consistent with the usage of "LED" leds: remove PAGE_SIZE limit of /sys/class/leds/<led>/trigger leds: tlc591xx: update the maximum brightness leds: lm3692x: Use flags from LM3692X_BRT_CTRL leds: lm3692x: Use flags from LM3692X_BOOST_CTRL leds: lm3692x: Handle failure to probe the regulator leds: lm3692x: Don't overwrite return value in error path leds: lm3692x: Print error value on dev_err leds: tlc591xx: use devm_led_classdev_register_ext() ...
This commit is contained in:
commit
304220b56e
|
@ -0,0 +1,139 @@
|
|||
What: /sys/class/leds/<led>/hw_pattern
|
||||
Date: September 2019
|
||||
KernelVersion: 5.5
|
||||
Description:
|
||||
Specify a hardware pattern for the EL15203000 LED.
|
||||
The LEDs board supports only predefined patterns by firmware
|
||||
for specific LEDs.
|
||||
|
||||
Breathing mode for Screen frame light tube:
|
||||
"0 4000 1 4000"
|
||||
|
||||
^
|
||||
|
|
||||
Max-| ---
|
||||
| / \
|
||||
| / \
|
||||
| / \ /
|
||||
| / \ /
|
||||
Min-|- ---
|
||||
|
|
||||
0------4------8--> time (sec)
|
||||
|
||||
Cascade mode for Pipe LED:
|
||||
"1 800 2 800 4 800 8 800 16 800"
|
||||
|
||||
^
|
||||
|
|
||||
0 On -|----+ +----+ +---
|
||||
| | | | |
|
||||
Off-| +-------------------+ +-------------------+
|
||||
|
|
||||
1 On -| +----+ +----+
|
||||
| | | | |
|
||||
Off |----+ +-------------------+ +------------------
|
||||
|
|
||||
2 On -| +----+ +----+
|
||||
| | | | |
|
||||
Off-|---------+ +-------------------+ +-------------
|
||||
|
|
||||
3 On -| +----+ +----+
|
||||
| | | | |
|
||||
Off-|--------------+ +-------------------+ +--------
|
||||
|
|
||||
4 On -| +----+ +----+
|
||||
| | | | |
|
||||
Off-|-------------------+ +-------------------+ +---
|
||||
|
|
||||
0---0.8--1.6--2.4--3.2---4---4.8--5.6--6.4--7.2---8--> time (sec)
|
||||
|
||||
Inverted cascade mode for Pipe LED:
|
||||
"30 800 29 800 27 800 23 800 15 800"
|
||||
|
||||
^
|
||||
|
|
||||
0 On -| +-------------------+ +-------------------+
|
||||
| | | | |
|
||||
Off-|----+ +----+ +---
|
||||
|
|
||||
1 On -|----+ +-------------------+ +------------------
|
||||
| | | | |
|
||||
Off | +----+ +----+
|
||||
|
|
||||
2 On -|---------+ +-------------------+ +-------------
|
||||
| | | | |
|
||||
Off-| +----+ +----+
|
||||
|
|
||||
3 On -|--------------+ +-------------------+ +--------
|
||||
| | | | |
|
||||
Off-| +----+ +----+
|
||||
|
|
||||
4 On -|-------------------+ +-------------------+ +---
|
||||
| | | | |
|
||||
Off-| +----+ +----+
|
||||
|
|
||||
0---0.8--1.6--2.4--3.2---4---4.8--5.6--6.4--7.2---8--> time (sec)
|
||||
|
||||
Bounce mode for Pipe LED:
|
||||
"1 800 2 800 4 800 8 800 16 800 16 800 8 800 4 800 2 800 1 800"
|
||||
|
||||
^
|
||||
|
|
||||
0 On -|----+ +--------
|
||||
| | |
|
||||
Off-| +---------------------------------------+
|
||||
|
|
||||
1 On -| +----+ +----+
|
||||
| | | | |
|
||||
Off |----+ +-----------------------------+ +--------
|
||||
|
|
||||
2 On -| +----+ +----+
|
||||
| | | | |
|
||||
Off-|---------+ +-------------------+ +-------------
|
||||
|
|
||||
3 On -| +----+ +----+
|
||||
| | | | |
|
||||
Off-|--------------+ +---------+ +------------------
|
||||
|
|
||||
4 On -| +---------+
|
||||
| | |
|
||||
Off-|-------------------+ +-----------------------
|
||||
|
|
||||
0---0.8--1.6--2.4--3.2---4---4.8--5.6--6.4--7.2---8--> time (sec)
|
||||
|
||||
Inverted bounce mode for Pipe LED:
|
||||
"30 800 29 800 27 800 23 800 15 800 15 800 23 800 27 800 29 800 30 800"
|
||||
|
||||
^
|
||||
|
|
||||
0 On -| +---------------------------------------+
|
||||
| | |
|
||||
Off-|----+ +--------
|
||||
|
|
||||
1 On -|----+ +-----------------------------+ +--------
|
||||
| | | | |
|
||||
Off | +----+ +----+
|
||||
|
|
||||
2 On -|---------+ +-------------------+ +-------------
|
||||
| | | | |
|
||||
Off-| +----+ +----+
|
||||
|
|
||||
3 On -|--------------+ +---------+ +------------------
|
||||
| | | | |
|
||||
Off-| +----+ +----+
|
||||
|
|
||||
4 On -|-------------------+ +-----------------------
|
||||
| | |
|
||||
Off-| +---------+
|
||||
|
|
||||
0---0.8--1.6--2.4--3.2---4---4.8--5.6--6.4--7.2---8--> time (sec)
|
||||
|
||||
What: /sys/class/leds/<led>/repeat
|
||||
Date: September 2019
|
||||
KernelVersion: 5.5
|
||||
Description:
|
||||
EL15203000 supports only indefinitely patterns,
|
||||
so this file should always store -1.
|
||||
|
||||
For more info, please see:
|
||||
Documentation/ABI/testing/sysfs-class-led-trigger-pattern
|
|
@ -0,0 +1,69 @@
|
|||
Crane Merchandising System - EL15203000 LED driver
|
||||
--------------------------------------------------
|
||||
|
||||
This LED Board (aka RED LEDs board) is widely used in
|
||||
coffee vending machines produced by Crane Merchandising Systems.
|
||||
The board manages 3 LEDs and supports predefined blinking patterns
|
||||
for specific leds.
|
||||
|
||||
Vending area LED encoded with symbol 'V' (hex code 0x56).
|
||||
Doesn't have any hardware blinking pattern.
|
||||
|
||||
Screen light tube LED which surrounds vending machine screen and
|
||||
encoded with symbol 'S' (hex code 0x53). Supports blinking breathing pattern.
|
||||
|
||||
Water Pipe LED encoded with symbol 'P' (hex code 0x50) and
|
||||
actually consists of 5 LEDs that exposed by protocol like one LED.
|
||||
Supports next patterns:
|
||||
- cascade pattern
|
||||
- inversed cascade pattern
|
||||
- bounce pattern
|
||||
- inversed bounce pattern
|
||||
|
||||
Required properties:
|
||||
- compatible : "crane,el15203000"
|
||||
- #address-cells : must be 1
|
||||
- #size-cells : must be 0
|
||||
|
||||
Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
apply. In particular, "reg" and "spi-max-frequency" properties must be given.
|
||||
|
||||
Optional LED sub-node properties:
|
||||
- function:
|
||||
see Documentation/devicetree/bindings/leds/common.txt
|
||||
- color:
|
||||
see Documentation/devicetree/bindings/leds/common.txt
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
led-controller@0 {
|
||||
compatible = "crane,el15203000";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* water pipe */
|
||||
led@50 {
|
||||
reg = <0x50>;
|
||||
function = "pipe";
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
};
|
||||
|
||||
/* screen frame */
|
||||
led@53 {
|
||||
reg = <0x53>;
|
||||
function = "screen";
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
};
|
||||
|
||||
/* vending area */
|
||||
led@56 {
|
||||
reg = <0x56>;
|
||||
function = "vend";
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
};
|
||||
};
|
|
@ -17,7 +17,7 @@ if NEW_LEDS
|
|||
config LEDS_CLASS
|
||||
tristate "LED Class Support"
|
||||
help
|
||||
This option enables the led sysfs class in /sys/class/leds. You'll
|
||||
This option enables the LED sysfs class in /sys/class/leds. You'll
|
||||
need this to do anything useful with LEDs. If unsure, say N.
|
||||
|
||||
config LEDS_CLASS_FLASH
|
||||
|
@ -35,7 +35,7 @@ config LEDS_BRIGHTNESS_HW_CHANGED
|
|||
depends on LEDS_CLASS
|
||||
help
|
||||
This option enables support for the brightness_hw_changed attribute
|
||||
for led sysfs class devices under /sys/class/leds.
|
||||
for LED sysfs class devices under /sys/class/leds.
|
||||
|
||||
See Documentation/ABI/testing/sysfs-class-led for details.
|
||||
|
||||
|
@ -132,6 +132,19 @@ config LEDS_CR0014114
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called leds-cr0014114.
|
||||
|
||||
config LEDS_EL15203000
|
||||
tristate "LED Support for Crane EL15203000"
|
||||
depends on LEDS_CLASS
|
||||
depends on SPI
|
||||
depends on OF
|
||||
help
|
||||
This option enables support for EL15203000 LED Board
|
||||
(aka RED LED board) which is widely used in coffee vending
|
||||
machines produced by Crane Merchandising Systems.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called leds-el15203000.
|
||||
|
||||
config LEDS_LM3530
|
||||
tristate "LCD Backlight driver for LM3530"
|
||||
depends on LEDS_CLASS
|
||||
|
|
|
@ -89,6 +89,7 @@ obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o
|
|||
# LED SPI Drivers
|
||||
obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
|
||||
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
|
||||
obj-$(CONFIG_LEDS_EL15203000) += leds-el15203000.o
|
||||
|
||||
# LED Userspace Drivers
|
||||
obj-$(CONFIG_LEDS_USER) += uleds.o
|
||||
|
|
|
@ -327,6 +327,56 @@ void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(led_classdev_flash_unregister);
|
||||
|
||||
static void devm_led_classdev_flash_release(struct device *dev, void *res)
|
||||
{
|
||||
led_classdev_flash_unregister(*(struct led_classdev_flash **)res);
|
||||
}
|
||||
|
||||
int devm_led_classdev_flash_register_ext(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
struct led_classdev_flash **dr;
|
||||
int ret;
|
||||
|
||||
dr = devres_alloc(devm_led_classdev_flash_release, sizeof(*dr),
|
||||
GFP_KERNEL);
|
||||
if (!dr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = led_classdev_flash_register_ext(parent, fled_cdev, init_data);
|
||||
if (ret) {
|
||||
devres_free(dr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*dr = fled_cdev;
|
||||
devres_add(parent, dr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_led_classdev_flash_register_ext);
|
||||
|
||||
static int devm_led_classdev_flash_match(struct device *dev,
|
||||
void *res, void *data)
|
||||
{
|
||||
struct led_classdev_flash **p = res;
|
||||
|
||||
if (WARN_ON(!p || !*p))
|
||||
return 0;
|
||||
|
||||
return *p == data;
|
||||
}
|
||||
|
||||
void devm_led_classdev_flash_unregister(struct device *dev,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{
|
||||
WARN_ON(devres_release(dev,
|
||||
devm_led_classdev_flash_release,
|
||||
devm_led_classdev_flash_match, fled_cdev));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_led_classdev_flash_unregister);
|
||||
|
||||
static void led_clamp_align(struct led_flash_setting *s)
|
||||
{
|
||||
u32 v, offset;
|
||||
|
|
|
@ -74,13 +74,13 @@ static ssize_t max_brightness_show(struct device *dev,
|
|||
static DEVICE_ATTR_RO(max_brightness);
|
||||
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
|
||||
static struct attribute *led_trigger_attrs[] = {
|
||||
&dev_attr_trigger.attr,
|
||||
static BIN_ATTR(trigger, 0644, led_trigger_read, led_trigger_write, 0);
|
||||
static struct bin_attribute *led_trigger_bin_attrs[] = {
|
||||
&bin_attr_trigger,
|
||||
NULL,
|
||||
};
|
||||
static const struct attribute_group led_trigger_group = {
|
||||
.attrs = led_trigger_attrs,
|
||||
.bin_attrs = led_trigger_bin_attrs,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -403,7 +403,7 @@ EXPORT_SYMBOL_GPL(devm_led_classdev_register_ext);
|
|||
|
||||
static int devm_led_classdev_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct led_cdev **p = res;
|
||||
struct led_classdev **p = res;
|
||||
|
||||
if (WARN_ON(!p || !*p))
|
||||
return 0;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/rwsem.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include "leds.h"
|
||||
|
||||
/*
|
||||
|
@ -26,9 +27,11 @@ LIST_HEAD(trigger_list);
|
|||
|
||||
/* Used by LED Class */
|
||||
|
||||
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t pos, size_t count)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_trigger *trig;
|
||||
int ret = count;
|
||||
|
@ -64,39 +67,82 @@ unlock:
|
|||
mutex_unlock(&led_cdev->led_access);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_trigger_store);
|
||||
EXPORT_SYMBOL_GPL(led_trigger_write);
|
||||
|
||||
ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
__printf(3, 4)
|
||||
static int led_trigger_snprintf(char *buf, ssize_t size, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
if (size <= 0)
|
||||
i = vsnprintf(NULL, 0, fmt, args);
|
||||
else
|
||||
i = vscnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int led_trigger_format(char *buf, size_t size,
|
||||
struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_trigger *trig;
|
||||
int len = 0;
|
||||
int len = led_trigger_snprintf(buf, size, "%s",
|
||||
led_cdev->trigger ? "none" : "[none]");
|
||||
|
||||
list_for_each_entry(trig, &trigger_list, next_trig) {
|
||||
bool hit = led_cdev->trigger &&
|
||||
!strcmp(led_cdev->trigger->name, trig->name);
|
||||
|
||||
len += led_trigger_snprintf(buf + len, size - len,
|
||||
" %s%s%s", hit ? "[" : "",
|
||||
trig->name, hit ? "]" : "");
|
||||
}
|
||||
|
||||
len += led_trigger_snprintf(buf + len, size - len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* It was stupid to create 10000 cpu triggers, but we are stuck with it now.
|
||||
* Don't make that mistake again. We work around it here by creating binary
|
||||
* attribute, which is not limited by length. This is _not_ good design, do not
|
||||
* copy it.
|
||||
*/
|
||||
ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t pos, size_t count)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
void *data;
|
||||
int len;
|
||||
|
||||
down_read(&triggers_list_lock);
|
||||
down_read(&led_cdev->trigger_lock);
|
||||
|
||||
if (!led_cdev->trigger)
|
||||
len += scnprintf(buf+len, PAGE_SIZE - len, "[none] ");
|
||||
else
|
||||
len += scnprintf(buf+len, PAGE_SIZE - len, "none ");
|
||||
|
||||
list_for_each_entry(trig, &trigger_list, next_trig) {
|
||||
if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
|
||||
trig->name))
|
||||
len += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ",
|
||||
trig->name);
|
||||
else
|
||||
len += scnprintf(buf+len, PAGE_SIZE - len, "%s ",
|
||||
trig->name);
|
||||
len = led_trigger_format(NULL, 0, led_cdev);
|
||||
data = kvmalloc(len + 1, GFP_KERNEL);
|
||||
if (!data) {
|
||||
up_read(&led_cdev->trigger_lock);
|
||||
up_read(&triggers_list_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
len = led_trigger_format(data, len + 1, led_cdev);
|
||||
|
||||
up_read(&led_cdev->trigger_lock);
|
||||
up_read(&triggers_list_lock);
|
||||
|
||||
len += scnprintf(len+buf, PAGE_SIZE - len, "\n");
|
||||
len = memory_read_from_buffer(buf, count, &pos, data, len);
|
||||
|
||||
kvfree(data);
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_trigger_show);
|
||||
EXPORT_SYMBOL_GPL(led_trigger_read);
|
||||
|
||||
/* Caller must ensure led_cdev->trigger_lock held */
|
||||
int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
||||
|
|
|
@ -305,6 +305,13 @@ static int an30259a_probe(struct i2c_client *client)
|
|||
|
||||
chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);
|
||||
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
err = PTR_ERR(chip->regmap);
|
||||
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||
err);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < chip->num_leds; i++) {
|
||||
struct led_init_data init_data = {};
|
||||
|
||||
|
|
|
@ -346,16 +346,11 @@ 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 *child;
|
||||
struct resource *mem_r;
|
||||
void __iomem *mem;
|
||||
spinlock_t *lock; /* memory lock */
|
||||
unsigned long val, *blink_leds, *blink_delay;
|
||||
|
||||
mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem_r)
|
||||
return -EINVAL;
|
||||
|
||||
mem = devm_ioremap_resource(dev, mem_r);
|
||||
mem = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mem))
|
||||
return PTR_ERR(mem);
|
||||
|
||||
|
|
|
@ -151,17 +151,12 @@ 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 *child;
|
||||
struct resource *mem_r;
|
||||
void __iomem *mem;
|
||||
spinlock_t *lock; /* memory lock */
|
||||
unsigned long val;
|
||||
u32 clk_div;
|
||||
|
||||
mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem_r)
|
||||
return -EINVAL;
|
||||
|
||||
mem = devm_ioremap_resource(dev, mem_r);
|
||||
mem = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mem))
|
||||
return PTR_ERR(mem);
|
||||
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Crane Merchandising Systems. All rights reserved.
|
||||
// Copyright (C) 2019 Oleh Kravchenko <oleg@kaa.org.ua>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
/*
|
||||
* EL15203000 SPI protocol description:
|
||||
* +-----+---------+
|
||||
* | LED | COMMAND |
|
||||
* +-----+---------+
|
||||
* | 1 | 1 |
|
||||
* +-----+---------+
|
||||
* (*) LEDs MCU board expects 20 msec delay per byte.
|
||||
*
|
||||
* LEDs:
|
||||
* +----------+--------------+-------------------------------------------+
|
||||
* | ID | NAME | DESCRIPTION |
|
||||
* +----------+--------------+-------------------------------------------+
|
||||
* | 'P' 0x50 | Pipe | Consists from 5 LEDs, controlled by board |
|
||||
* +----------+--------------+-------------------------------------------+
|
||||
* | 'S' 0x53 | Screen frame | Light tube around the screen |
|
||||
* +----------+--------------+-------------------------------------------+
|
||||
* | 'V' 0x56 | Vending area | Highlights a cup of coffee |
|
||||
* +----------+--------------+-------------------------------------------+
|
||||
*
|
||||
* COMMAND:
|
||||
* +----------+-----------------+--------------+--------------+
|
||||
* | VALUES | PIPE | SCREEN FRAME | VENDING AREA |
|
||||
* +----------+-----------------+--------------+--------------+
|
||||
* | '0' 0x30 | Off |
|
||||
* +----------+-----------------------------------------------+
|
||||
* | '1' 0x31 | On |
|
||||
* +----------+-----------------+--------------+--------------+
|
||||
* | '2' 0x32 | Cascade | Breathing |
|
||||
* +----------+-----------------+--------------+
|
||||
* | '3' 0x33 | Inverse cascade |
|
||||
* +----------+-----------------+
|
||||
* | '4' 0x34 | Bounce |
|
||||
* +----------+-----------------+
|
||||
* | '5' 0x35 | Inverse bounce |
|
||||
* +----------+-----------------+
|
||||
*/
|
||||
|
||||
/* EL15203000 default settings */
|
||||
#define EL_FW_DELAY_USEC 20000ul
|
||||
#define EL_PATTERN_DELAY_MSEC 800u
|
||||
#define EL_PATTERN_LEN 10u
|
||||
#define EL_PATTERN_HALF_LEN (EL_PATTERN_LEN / 2)
|
||||
|
||||
enum el15203000_command {
|
||||
/* for all LEDs */
|
||||
EL_OFF = '0',
|
||||
EL_ON = '1',
|
||||
|
||||
/* for Screen LED */
|
||||
EL_SCREEN_BREATHING = '2',
|
||||
|
||||
/* for Pipe LED */
|
||||
EL_PIPE_CASCADE = '2',
|
||||
EL_PIPE_INV_CASCADE = '3',
|
||||
EL_PIPE_BOUNCE = '4',
|
||||
EL_PIPE_INV_BOUNCE = '5',
|
||||
};
|
||||
|
||||
struct el15203000_led {
|
||||
struct el15203000 *priv;
|
||||
struct led_classdev ldev;
|
||||
u32 reg;
|
||||
};
|
||||
|
||||
struct el15203000 {
|
||||
struct device *dev;
|
||||
struct mutex lock;
|
||||
struct spi_device *spi;
|
||||
unsigned long delay;
|
||||
size_t count;
|
||||
struct el15203000_led leds[];
|
||||
};
|
||||
|
||||
static int el15203000_cmd(struct el15203000_led *led, u8 brightness)
|
||||
{
|
||||
int ret;
|
||||
u8 cmd[2];
|
||||
size_t i;
|
||||
|
||||
mutex_lock(&led->priv->lock);
|
||||
|
||||
dev_dbg(led->priv->dev, "Set brightness of 0x%02x(%c) to 0x%02x(%c)",
|
||||
led->reg, led->reg, brightness, brightness);
|
||||
|
||||
/* to avoid SPI mistiming with firmware we should wait some time */
|
||||
if (time_after(led->priv->delay, jiffies)) {
|
||||
dev_dbg(led->priv->dev, "Wait %luus to sync",
|
||||
EL_FW_DELAY_USEC);
|
||||
|
||||
usleep_range(EL_FW_DELAY_USEC,
|
||||
EL_FW_DELAY_USEC + 1);
|
||||
}
|
||||
|
||||
cmd[0] = led->reg;
|
||||
cmd[1] = brightness;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cmd); i++) {
|
||||
if (i)
|
||||
usleep_range(EL_FW_DELAY_USEC,
|
||||
EL_FW_DELAY_USEC + 1);
|
||||
|
||||
ret = spi_write(led->priv->spi, &cmd[i], sizeof(cmd[i]));
|
||||
if (ret) {
|
||||
dev_err(led->priv->dev,
|
||||
"spi_write() error %d", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
led->priv->delay = jiffies + usecs_to_jiffies(EL_FW_DELAY_USEC);
|
||||
|
||||
mutex_unlock(&led->priv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int el15203000_set_blocking(struct led_classdev *ldev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct el15203000_led *led = container_of(ldev,
|
||||
struct el15203000_led,
|
||||
ldev);
|
||||
|
||||
return el15203000_cmd(led, brightness == LED_OFF ? EL_OFF : EL_ON);
|
||||
}
|
||||
|
||||
static int el15203000_pattern_set_S(struct led_classdev *ldev,
|
||||
struct led_pattern *pattern,
|
||||
u32 len, int repeat)
|
||||
{
|
||||
struct el15203000_led *led = container_of(ldev,
|
||||
struct el15203000_led,
|
||||
ldev);
|
||||
|
||||
if (repeat > 0 || len != 2 ||
|
||||
pattern[0].delta_t != 4000 || pattern[0].brightness != 0 ||
|
||||
pattern[1].delta_t != 4000 || pattern[1].brightness != 1)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(led->priv->dev, "Breathing mode for 0x%02x(%c)",
|
||||
led->reg, led->reg);
|
||||
|
||||
return el15203000_cmd(led, EL_SCREEN_BREATHING);
|
||||
}
|
||||
|
||||
static bool is_cascade(const struct led_pattern *pattern, u32 len,
|
||||
bool inv, bool right)
|
||||
{
|
||||
int val, t;
|
||||
u32 i;
|
||||
|
||||
if (len != EL_PATTERN_HALF_LEN)
|
||||
return false;
|
||||
|
||||
val = right ? BIT(4) : BIT(0);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
t = inv ? ~val & GENMASK(4, 0) : val;
|
||||
|
||||
if (pattern[i].delta_t != EL_PATTERN_DELAY_MSEC ||
|
||||
pattern[i].brightness != t)
|
||||
return false;
|
||||
|
||||
val = right ? val >> 1 : val << 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_bounce(const struct led_pattern *pattern, u32 len, bool inv)
|
||||
{
|
||||
if (len != EL_PATTERN_LEN)
|
||||
return false;
|
||||
|
||||
return is_cascade(pattern, EL_PATTERN_HALF_LEN, inv, false) &&
|
||||
is_cascade(pattern + EL_PATTERN_HALF_LEN,
|
||||
EL_PATTERN_HALF_LEN, inv, true);
|
||||
}
|
||||
|
||||
static int el15203000_pattern_set_P(struct led_classdev *ldev,
|
||||
struct led_pattern *pattern,
|
||||
u32 len, int repeat)
|
||||
{
|
||||
u8 cmd;
|
||||
struct el15203000_led *led = container_of(ldev,
|
||||
struct el15203000_led,
|
||||
ldev);
|
||||
|
||||
if (repeat > 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (is_cascade(pattern, len, false, false)) {
|
||||
dev_dbg(led->priv->dev, "Cascade mode for 0x%02x(%c)",
|
||||
led->reg, led->reg);
|
||||
|
||||
cmd = EL_PIPE_CASCADE;
|
||||
} else if (is_cascade(pattern, len, true, false)) {
|
||||
dev_dbg(led->priv->dev, "Inverse cascade mode for 0x%02x(%c)",
|
||||
led->reg, led->reg);
|
||||
|
||||
cmd = EL_PIPE_INV_CASCADE;
|
||||
} else if (is_bounce(pattern, len, false)) {
|
||||
dev_dbg(led->priv->dev, "Bounce mode for 0x%02x(%c)",
|
||||
led->reg, led->reg);
|
||||
|
||||
cmd = EL_PIPE_BOUNCE;
|
||||
} else if (is_bounce(pattern, len, true)) {
|
||||
dev_dbg(led->priv->dev, "Inverse bounce mode for 0x%02x(%c)",
|
||||
led->reg, led->reg);
|
||||
|
||||
cmd = EL_PIPE_INV_BOUNCE;
|
||||
} else {
|
||||
dev_err(led->priv->dev, "Invalid hw_pattern for 0x%02x(%c)!",
|
||||
led->reg, led->reg);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return el15203000_cmd(led, cmd);
|
||||
}
|
||||
|
||||
static int el15203000_pattern_clear(struct led_classdev *ldev)
|
||||
{
|
||||
struct el15203000_led *led = container_of(ldev,
|
||||
struct el15203000_led,
|
||||
ldev);
|
||||
|
||||
return el15203000_cmd(led, EL_OFF);
|
||||
}
|
||||
|
||||
static int el15203000_probe_dt(struct el15203000 *priv)
|
||||
{
|
||||
struct el15203000_led *led = priv->leds;
|
||||
struct fwnode_handle *child;
|
||||
int ret;
|
||||
|
||||
device_for_each_child_node(priv->dev, child) {
|
||||
struct led_init_data init_data = {};
|
||||
|
||||
ret = fwnode_property_read_u32(child, "reg", &led->reg);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "LED without ID number");
|
||||
fwnode_handle_put(child);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (led->reg > U8_MAX) {
|
||||
dev_err(priv->dev, "LED value %d is invalid", led->reg);
|
||||
fwnode_handle_put(child);
|
||||
|
||||
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;
|
||||
|
||||
if (led->reg == 'S') {
|
||||
led->ldev.pattern_set = el15203000_pattern_set_S;
|
||||
led->ldev.pattern_clear = el15203000_pattern_clear;
|
||||
} else if (led->reg == 'P') {
|
||||
led->ldev.pattern_set = el15203000_pattern_set_P;
|
||||
led->ldev.pattern_clear = el15203000_pattern_clear;
|
||||
}
|
||||
|
||||
init_data.fwnode = child;
|
||||
ret = devm_led_classdev_register_ext(priv->dev, &led->ldev,
|
||||
&init_data);
|
||||
if (ret) {
|
||||
dev_err(priv->dev,
|
||||
"failed to register LED device %s, err %d",
|
||||
led->ldev.name, ret);
|
||||
fwnode_handle_put(child);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
led++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int el15203000_probe(struct spi_device *spi)
|
||||
{
|
||||
struct el15203000 *priv;
|
||||
size_t count;
|
||||
|
||||
count = device_get_child_node_count(&spi->dev);
|
||||
if (!count) {
|
||||
dev_err(&spi->dev, "LEDs are not defined in device tree!");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&spi->dev, struct_size(priv, leds, count),
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&priv->lock);
|
||||
priv->count = count;
|
||||
priv->dev = &spi->dev;
|
||||
priv->spi = spi;
|
||||
priv->delay = jiffies -
|
||||
usecs_to_jiffies(EL_FW_DELAY_USEC);
|
||||
|
||||
spi_set_drvdata(spi, priv);
|
||||
|
||||
return el15203000_probe_dt(priv);
|
||||
}
|
||||
|
||||
static int el15203000_remove(struct spi_device *spi)
|
||||
{
|
||||
struct el15203000 *priv = spi_get_drvdata(spi);
|
||||
|
||||
mutex_destroy(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id el15203000_dt_ids[] = {
|
||||
{ .compatible = "crane,el15203000", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, el15203000_dt_ids);
|
||||
|
||||
static struct spi_driver el15203000_driver = {
|
||||
.probe = el15203000_probe,
|
||||
.remove = el15203000_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = el15203000_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_spi_driver(el15203000_driver);
|
||||
|
||||
MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
|
||||
MODULE_DESCRIPTION("el15203000 LED driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("spi:el15203000");
|
|
@ -350,8 +350,7 @@ static int lm3601x_register_leds(struct lm3601x_led *led,
|
|||
init_data.devicename = led->client->name;
|
||||
init_data.default_label = (led->led_mode == LM3601X_LED_TORCH) ?
|
||||
"torch" : "infrared";
|
||||
|
||||
return led_classdev_flash_register_ext(&led->client->dev,
|
||||
return devm_led_classdev_flash_register_ext(&led->client->dev,
|
||||
&led->fled_cdev, &init_data);
|
||||
}
|
||||
|
||||
|
@ -445,7 +444,6 @@ static int lm3601x_remove(struct i2c_client *client)
|
|||
{
|
||||
struct lm3601x_led *led = i2c_get_clientdata(client);
|
||||
|
||||
led_classdev_flash_unregister(&led->fled_cdev);
|
||||
mutex_destroy(&led->lock);
|
||||
|
||||
return regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
|
||||
|
|
|
@ -174,19 +174,20 @@ static int lm3692x_brightness_set(struct led_classdev *led_cdev,
|
|||
|
||||
ret = lm3692x_fault_check(led);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "Cannot read/clear faults\n");
|
||||
dev_err(&led->client->dev, "Cannot read/clear faults: %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = regmap_write(led->regmap, LM3692X_BRT_MSB, brt_val);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "Cannot write MSB\n");
|
||||
dev_err(&led->client->dev, "Cannot write MSB: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = regmap_write(led->regmap, LM3692X_BRT_LSB, led_brightness_lsb);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "Cannot write LSB\n");
|
||||
dev_err(&led->client->dev, "Cannot write LSB: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
|
@ -197,13 +198,13 @@ out:
|
|||
static int lm3692x_init(struct lm3692x_led *led)
|
||||
{
|
||||
int enable_state;
|
||||
int ret;
|
||||
int ret, reg_ret;
|
||||
|
||||
if (led->regulator) {
|
||||
ret = regulator_enable(led->regulator);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev,
|
||||
"Failed to enable regulator\n");
|
||||
"Failed to enable regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +214,8 @@ static int lm3692x_init(struct lm3692x_led *led)
|
|||
|
||||
ret = lm3692x_fault_check(led);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "Cannot read/clear faults\n");
|
||||
dev_err(&led->client->dev, "Cannot read/clear faults: %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -248,9 +250,9 @@ static int lm3692x_init(struct lm3692x_led *led)
|
|||
goto out;
|
||||
|
||||
ret = regmap_write(led->regmap, LM3692X_BOOST_CTRL,
|
||||
LM3692X_BRHT_MODE_RAMP_MULTI |
|
||||
LM3692X_BL_ADJ_POL |
|
||||
LM3692X_RAMP_RATE_250us);
|
||||
LM3692X_BOOST_SW_1MHZ |
|
||||
LM3692X_BOOST_SW_NO_SHIFT |
|
||||
LM3692X_OCP_PROT_1_5A);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@ -267,7 +269,7 @@ static int lm3692x_init(struct lm3692x_led *led)
|
|||
goto out;
|
||||
|
||||
ret = regmap_write(led->regmap, LM3692X_BRT_CTRL,
|
||||
LM3692X_BL_ADJ_POL | LM3692X_PWM_HYSTER_4LSB);
|
||||
LM3692X_BL_ADJ_POL | LM3692X_RAMP_EN);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@ -311,14 +313,15 @@ out:
|
|||
gpiod_direction_output(led->enable_gpio, 0);
|
||||
|
||||
if (led->regulator) {
|
||||
ret = regulator_disable(led->regulator);
|
||||
if (ret)
|
||||
reg_ret = regulator_disable(led->regulator);
|
||||
if (reg_ret)
|
||||
dev_err(&led->client->dev,
|
||||
"Failed to disable regulator\n");
|
||||
"Failed to disable regulator: %d\n", reg_ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lm3692x_probe_dt(struct lm3692x_led *led)
|
||||
{
|
||||
struct fwnode_handle *child = NULL;
|
||||
|
@ -334,9 +337,18 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
|
|||
return ret;
|
||||
}
|
||||
|
||||
led->regulator = devm_regulator_get(&led->client->dev, "vled");
|
||||
if (IS_ERR(led->regulator))
|
||||
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;
|
||||
}
|
||||
led->regulator = NULL;
|
||||
}
|
||||
|
||||
child = device_get_next_child_node(&led->client->dev, child);
|
||||
if (!child) {
|
||||
|
@ -409,7 +421,8 @@ static int lm3692x_remove(struct i2c_client *client)
|
|||
|
||||
ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_DEVICE_EN, 0);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "Failed to disable regulator\n");
|
||||
dev_err(&led->client->dev, "Failed to disable regulator: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -420,7 +433,7 @@ static int lm3692x_remove(struct i2c_client *client)
|
|||
ret = regulator_disable(led->regulator);
|
||||
if (ret)
|
||||
dev_err(&led->client->dev,
|
||||
"Failed to disable regulator\n");
|
||||
"Failed to disable regulator: %d\n", ret);
|
||||
}
|
||||
|
||||
mutex_destroy(&led->lock);
|
||||
|
|
|
@ -228,8 +228,8 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv)
|
|||
brightness = LED_OFF;
|
||||
led_data->base_color = MLXREG_LED_GREEN_SOLID;
|
||||
}
|
||||
sprintf(led_data->led_cdev_name, "%s:%s", "mlxreg",
|
||||
data->label);
|
||||
snprintf(led_data->led_cdev_name, sizeof(led_data->led_cdev_name),
|
||||
"mlxreg:%s", data->label);
|
||||
led_cdev->name = led_data->led_cdev_name;
|
||||
led_cdev->brightness = brightness;
|
||||
led_cdev->max_brightness = LED_ON;
|
||||
|
|
|
@ -467,16 +467,11 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np)
|
|||
{
|
||||
struct pca9532_platform_data *pdata;
|
||||
struct device_node *child;
|
||||
const struct of_device_id *match;
|
||||
int devid, maxleds;
|
||||
int i = 0;
|
||||
const char *state;
|
||||
|
||||
match = of_match_device(of_pca9532_leds_match, dev);
|
||||
if (!match)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
devid = (int)(uintptr_t)match->data;
|
||||
devid = (int)(uintptr_t)of_device_get_match_data(dev);
|
||||
maxleds = pca9532_chip_info_tbl[devid].num_leds;
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
|
@ -509,7 +504,6 @@ static int pca9532_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
int devid;
|
||||
const struct of_device_id *of_id;
|
||||
struct pca9532_data *data = i2c_get_clientdata(client);
|
||||
struct pca9532_platform_data *pca9532_pdata =
|
||||
dev_get_platdata(&client->dev);
|
||||
|
@ -525,11 +519,7 @@ static int pca9532_probe(struct i2c_client *client,
|
|||
dev_err(&client->dev, "no platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
of_id = of_match_device(of_pca9532_leds_match,
|
||||
&client->dev);
|
||||
if (unlikely(!of_id))
|
||||
return -EINVAL;
|
||||
devid = (int)(uintptr_t) of_id->data;
|
||||
devid = (int)(uintptr_t)of_device_get_match_data(&client->dev);
|
||||
} else {
|
||||
devid = id->driver_data;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#define TLC591XX_MAX_LEDS 16
|
||||
#define TLC591XX_MAX_BRIGHTNESS 256
|
||||
|
||||
#define TLC591XX_REG_MODE1 0x00
|
||||
#define MODE1_RESPON_ADDR_MASK 0xF0
|
||||
|
@ -112,11 +113,11 @@ tlc591xx_brightness_set(struct led_classdev *led_cdev,
|
|||
struct tlc591xx_priv *priv = led->priv;
|
||||
int err;
|
||||
|
||||
switch (brightness) {
|
||||
switch ((int)brightness) {
|
||||
case 0:
|
||||
err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF);
|
||||
break;
|
||||
case LED_FULL:
|
||||
case TLC591XX_MAX_BRIGHTNESS:
|
||||
err = tlc591xx_set_ledout(priv, led, LEDOUT_ON);
|
||||
break;
|
||||
default:
|
||||
|
@ -128,51 +129,6 @@ tlc591xx_brightness_set(struct led_classdev *led_cdev,
|
|||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j)
|
||||
{
|
||||
int i = j;
|
||||
|
||||
while (--i >= 0) {
|
||||
if (priv->leds[i].active)
|
||||
led_classdev_unregister(&priv->leds[i].ldev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
tlc591xx_configure(struct device *dev,
|
||||
struct tlc591xx_priv *priv,
|
||||
const struct tlc591xx *tlc591xx)
|
||||
{
|
||||
unsigned int i;
|
||||
int err = 0;
|
||||
|
||||
tlc591xx_set_mode(priv->regmap, MODE2_DIM);
|
||||
for (i = 0; i < TLC591XX_MAX_LEDS; i++) {
|
||||
struct tlc591xx_led *led = &priv->leds[i];
|
||||
|
||||
if (!led->active)
|
||||
continue;
|
||||
|
||||
led->priv = priv;
|
||||
led->led_no = i;
|
||||
led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
|
||||
led->ldev.max_brightness = LED_FULL;
|
||||
err = led_classdev_register(dev, &led->ldev);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "couldn't register LED %s\n",
|
||||
led->ldev.name);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
tlc591xx_destroy_devices(priv, i);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct regmap_config tlc591xx_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
@ -225,7 +181,16 @@ tlc591xx_probe(struct i2c_client *client,
|
|||
|
||||
i2c_set_clientdata(client, priv);
|
||||
|
||||
err = tlc591xx_set_mode(priv->regmap, MODE2_DIM);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
struct tlc591xx_led *led;
|
||||
struct led_init_data init_data = {};
|
||||
|
||||
init_data.fwnode = of_fwnode_handle(child);
|
||||
|
||||
err = of_property_read_u32(child, "reg", ®);
|
||||
if (err) {
|
||||
of_node_put(child);
|
||||
|
@ -236,22 +201,24 @@ tlc591xx_probe(struct i2c_client *client,
|
|||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
priv->leds[reg].active = true;
|
||||
priv->leds[reg].ldev.name =
|
||||
of_get_property(child, "label", NULL) ? : child->name;
|
||||
priv->leds[reg].ldev.default_trigger =
|
||||
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;
|
||||
led->ldev.max_brightness = TLC591XX_MAX_BRIGHTNESS;
|
||||
err = devm_led_classdev_register_ext(dev, &led->ldev,
|
||||
&init_data);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "couldn't register LED %s\n",
|
||||
led->ldev.name);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return tlc591xx_configure(dev, priv, tlc591xx);
|
||||
}
|
||||
|
||||
static int
|
||||
tlc591xx_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tlc591xx_priv *priv = i2c_get_clientdata(client);
|
||||
|
||||
tlc591xx_destroy_devices(priv, TLC591XX_MAX_LEDS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -268,7 +235,6 @@ static struct i2c_driver tlc591xx_driver = {
|
|||
.of_match_table = of_match_ptr(of_tlc591xx_leds_match),
|
||||
},
|
||||
.probe = tlc591xx_probe,
|
||||
.remove = tlc591xx_remove,
|
||||
.id_table = tlc591xx_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,12 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,
|
|||
enum led_brightness value);
|
||||
void led_set_brightness_nosleep(struct led_classdev *led_cdev,
|
||||
enum led_brightness value);
|
||||
ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t pos, size_t count);
|
||||
ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t pos, size_t count);
|
||||
|
||||
extern struct rw_semaphore leds_list_lock;
|
||||
extern struct list_head leds_list;
|
||||
|
|
|
@ -302,10 +302,12 @@ static int netdev_trig_notify(struct notifier_block *nb,
|
|||
container_of(nb, struct led_netdev_data, notifier);
|
||||
|
||||
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
|
||||
&& evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
|
||||
&& evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
|
||||
&& evt != NETDEV_CHANGENAME)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (!(dev == trigger_data->net_dev ||
|
||||
(evt == NETDEV_CHANGENAME && !strcmp(dev->name, trigger_data->device_name)) ||
|
||||
(evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
|
@ -315,6 +317,7 @@ static int netdev_trig_notify(struct notifier_block *nb,
|
|||
|
||||
clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
switch (evt) {
|
||||
case NETDEV_CHANGENAME:
|
||||
case NETDEV_REGISTER:
|
||||
if (trigger_data->net_dev)
|
||||
dev_put(trigger_data->net_dev);
|
||||
|
|
|
@ -94,12 +94,15 @@ static inline struct led_classdev_flash *lcdev_to_flcdev(
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_classdev_flash_register_ext(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data);
|
||||
int led_classdev_flash_register_ext(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
#define led_classdev_flash_register(parent, fled_cdev) \
|
||||
led_classdev_flash_register_ext(parent, fled_cdev, NULL)
|
||||
static inline int led_classdev_flash_register(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{
|
||||
return led_classdev_flash_register_ext(parent, fled_cdev, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* led_classdev_flash_unregister - unregisters an object of led_classdev class
|
||||
|
@ -108,7 +111,21 @@ extern int led_classdev_flash_register_ext(struct device *parent,
|
|||
*
|
||||
* Unregister a previously registered via led_classdev_flash_register object
|
||||
*/
|
||||
extern void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev);
|
||||
void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev);
|
||||
|
||||
int devm_led_classdev_flash_register_ext(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
|
||||
static inline int devm_led_classdev_flash_register(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{
|
||||
return devm_led_classdev_flash_register_ext(parent, fled_cdev, NULL);
|
||||
}
|
||||
|
||||
void devm_led_classdev_flash_unregister(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev);
|
||||
|
||||
/**
|
||||
* led_set_flash_strobe - setup flash strobe
|
||||
|
@ -156,8 +173,8 @@ static inline int led_get_flash_strobe(struct led_classdev_flash *fled_cdev,
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
|
||||
u32 brightness);
|
||||
int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
|
||||
u32 brightness);
|
||||
|
||||
/**
|
||||
* led_update_flash_brightness - update flash LED brightness
|
||||
|
@ -168,7 +185,7 @@ extern int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_update_flash_brightness(struct led_classdev_flash *fled_cdev);
|
||||
int led_update_flash_brightness(struct led_classdev_flash *fled_cdev);
|
||||
|
||||
/**
|
||||
* led_set_flash_timeout - set flash LED timeout
|
||||
|
@ -179,8 +196,7 @@ extern int led_update_flash_brightness(struct led_classdev_flash *fled_cdev);
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_set_flash_timeout(struct led_classdev_flash *fled_cdev,
|
||||
u32 timeout);
|
||||
int led_set_flash_timeout(struct led_classdev_flash *fled_cdev, u32 timeout);
|
||||
|
||||
/**
|
||||
* led_get_flash_fault - get the flash LED fault
|
||||
|
@ -191,7 +207,6 @@ extern int led_set_flash_timeout(struct led_classdev_flash *fled_cdev,
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_get_flash_fault(struct led_classdev_flash *fled_cdev,
|
||||
u32 *fault);
|
||||
int led_get_flash_fault(struct led_classdev_flash *fled_cdev, u32 *fault);
|
||||
|
||||
#endif /* __LINUX_FLASH_LEDS_H_INCLUDED */
|
||||
|
|
|
@ -161,7 +161,7 @@ struct led_classdev {
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_classdev_register_ext(struct device *parent,
|
||||
int led_classdev_register_ext(struct device *parent,
|
||||
struct led_classdev *led_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
|
@ -181,7 +181,7 @@ static inline int led_classdev_register(struct device *parent,
|
|||
return led_classdev_register_ext(parent, led_cdev, NULL);
|
||||
}
|
||||
|
||||
extern int devm_led_classdev_register_ext(struct device *parent,
|
||||
int devm_led_classdev_register_ext(struct device *parent,
|
||||
struct led_classdev *led_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
|
@ -190,11 +190,11 @@ static inline int devm_led_classdev_register(struct device *parent,
|
|||
{
|
||||
return devm_led_classdev_register_ext(parent, led_cdev, NULL);
|
||||
}
|
||||
extern void led_classdev_unregister(struct led_classdev *led_cdev);
|
||||
extern void devm_led_classdev_unregister(struct device *parent,
|
||||
struct led_classdev *led_cdev);
|
||||
extern void led_classdev_suspend(struct led_classdev *led_cdev);
|
||||
extern void led_classdev_resume(struct led_classdev *led_cdev);
|
||||
void led_classdev_unregister(struct led_classdev *led_cdev);
|
||||
void devm_led_classdev_unregister(struct device *parent,
|
||||
struct led_classdev *led_cdev);
|
||||
void led_classdev_suspend(struct led_classdev *led_cdev);
|
||||
void led_classdev_resume(struct led_classdev *led_cdev);
|
||||
|
||||
/**
|
||||
* led_blink_set - set blinking with software fallback
|
||||
|
@ -211,9 +211,8 @@ extern void led_classdev_resume(struct led_classdev *led_cdev);
|
|||
* led_cdev->brightness_set() will not stop the blinking,
|
||||
* use led_classdev_brightness_set() instead.
|
||||
*/
|
||||
extern void led_blink_set(struct led_classdev *led_cdev,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off);
|
||||
void led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,
|
||||
unsigned long *delay_off);
|
||||
/**
|
||||
* led_blink_set_oneshot - do a oneshot software blink
|
||||
* @led_cdev: the LED to start blinking
|
||||
|
@ -228,10 +227,9 @@ extern void led_blink_set(struct led_classdev *led_cdev,
|
|||
* If invert is set, led blinks for delay_off first, then for
|
||||
* delay_on and leave the led on after the on-off cycle.
|
||||
*/
|
||||
extern void led_blink_set_oneshot(struct led_classdev *led_cdev,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off,
|
||||
int invert);
|
||||
void led_blink_set_oneshot(struct led_classdev *led_cdev,
|
||||
unsigned long *delay_on, unsigned long *delay_off,
|
||||
int invert);
|
||||
/**
|
||||
* led_set_brightness - set LED brightness
|
||||
* @led_cdev: the LED to set
|
||||
|
@ -241,8 +239,8 @@ extern void led_blink_set_oneshot(struct led_classdev *led_cdev,
|
|||
* software blink timer that implements blinking when the
|
||||
* hardware doesn't. This function is guaranteed not to sleep.
|
||||
*/
|
||||
extern void led_set_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness);
|
||||
void led_set_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness);
|
||||
|
||||
/**
|
||||
* led_set_brightness_sync - set LED brightness synchronously
|
||||
|
@ -255,8 +253,8 @@ extern void led_set_brightness(struct led_classdev *led_cdev,
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_set_brightness_sync(struct led_classdev *led_cdev,
|
||||
enum led_brightness value);
|
||||
int led_set_brightness_sync(struct led_classdev *led_cdev,
|
||||
enum led_brightness value);
|
||||
|
||||
/**
|
||||
* led_update_brightness - update LED brightness
|
||||
|
@ -267,7 +265,7 @@ extern int led_set_brightness_sync(struct led_classdev *led_cdev,
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_update_brightness(struct led_classdev *led_cdev);
|
||||
int led_update_brightness(struct led_classdev *led_cdev);
|
||||
|
||||
/**
|
||||
* led_get_default_pattern - return default pattern
|
||||
|
@ -279,8 +277,7 @@ extern int led_update_brightness(struct led_classdev *led_cdev);
|
|||
* Return: Allocated array of integers with default pattern from device tree
|
||||
* or NULL. Caller is responsible for kfree().
|
||||
*/
|
||||
extern u32 *led_get_default_pattern(struct led_classdev *led_cdev,
|
||||
unsigned int *size);
|
||||
u32 *led_get_default_pattern(struct led_classdev *led_cdev, unsigned int *size);
|
||||
|
||||
/**
|
||||
* led_sysfs_disable - disable LED sysfs interface
|
||||
|
@ -288,7 +285,7 @@ extern u32 *led_get_default_pattern(struct led_classdev *led_cdev,
|
|||
*
|
||||
* Disable the led_cdev's sysfs interface.
|
||||
*/
|
||||
extern void led_sysfs_disable(struct led_classdev *led_cdev);
|
||||
void led_sysfs_disable(struct led_classdev *led_cdev);
|
||||
|
||||
/**
|
||||
* led_sysfs_enable - enable LED sysfs interface
|
||||
|
@ -296,7 +293,7 @@ extern void led_sysfs_disable(struct led_classdev *led_cdev);
|
|||
*
|
||||
* Enable the led_cdev's sysfs interface.
|
||||
*/
|
||||
extern void led_sysfs_enable(struct led_classdev *led_cdev);
|
||||
void led_sysfs_enable(struct led_classdev *led_cdev);
|
||||
|
||||
/**
|
||||
* led_compose_name - compose LED class device name
|
||||
|
@ -310,8 +307,8 @@ extern void led_sysfs_enable(struct led_classdev *led_cdev);
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
extern int led_compose_name(struct device *dev, struct led_init_data *init_data,
|
||||
char *led_classdev_name);
|
||||
int led_compose_name(struct device *dev, struct led_init_data *init_data,
|
||||
char *led_classdev_name);
|
||||
|
||||
/**
|
||||
* led_sysfs_is_disabled - check if LED sysfs interface is disabled
|
||||
|
@ -360,33 +357,25 @@ struct led_trigger {
|
|||
#define led_trigger_get_led(dev) ((struct led_classdev *)dev_get_drvdata((dev)))
|
||||
#define led_trigger_get_drvdata(dev) (led_get_trigger_data(led_trigger_get_led(dev)))
|
||||
|
||||
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
|
||||
/* Registration functions for complex triggers */
|
||||
extern int led_trigger_register(struct led_trigger *trigger);
|
||||
extern void led_trigger_unregister(struct led_trigger *trigger);
|
||||
extern int devm_led_trigger_register(struct device *dev,
|
||||
int led_trigger_register(struct led_trigger *trigger);
|
||||
void led_trigger_unregister(struct led_trigger *trigger);
|
||||
int devm_led_trigger_register(struct device *dev,
|
||||
struct led_trigger *trigger);
|
||||
|
||||
extern void led_trigger_register_simple(const char *name,
|
||||
void led_trigger_register_simple(const char *name,
|
||||
struct led_trigger **trigger);
|
||||
extern void led_trigger_unregister_simple(struct led_trigger *trigger);
|
||||
extern void led_trigger_event(struct led_trigger *trigger,
|
||||
enum led_brightness event);
|
||||
extern void led_trigger_blink(struct led_trigger *trigger,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off);
|
||||
extern void led_trigger_blink_oneshot(struct led_trigger *trigger,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off,
|
||||
int invert);
|
||||
extern void led_trigger_set_default(struct led_classdev *led_cdev);
|
||||
extern int led_trigger_set(struct led_classdev *led_cdev,
|
||||
struct led_trigger *trigger);
|
||||
extern void led_trigger_remove(struct led_classdev *led_cdev);
|
||||
void led_trigger_unregister_simple(struct led_trigger *trigger);
|
||||
void led_trigger_event(struct led_trigger *trigger, enum led_brightness event);
|
||||
void led_trigger_blink(struct led_trigger *trigger, unsigned long *delay_on,
|
||||
unsigned long *delay_off);
|
||||
void led_trigger_blink_oneshot(struct led_trigger *trigger,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off,
|
||||
int invert);
|
||||
void led_trigger_set_default(struct led_classdev *led_cdev);
|
||||
int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger);
|
||||
void led_trigger_remove(struct led_classdev *led_cdev);
|
||||
|
||||
static inline void led_set_trigger_data(struct led_classdev *led_cdev,
|
||||
void *trigger_data)
|
||||
|
@ -414,8 +403,7 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
|
|||
* This is meant to be used on triggers with statically
|
||||
* allocated name.
|
||||
*/
|
||||
extern void led_trigger_rename_static(const char *name,
|
||||
struct led_trigger *trig);
|
||||
void led_trigger_rename_static(const char *name, struct led_trigger *trig);
|
||||
|
||||
#define module_led_trigger(__led_trigger) \
|
||||
module_driver(__led_trigger, led_trigger_register, \
|
||||
|
@ -457,20 +445,20 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
|
|||
|
||||
/* Trigger specific functions */
|
||||
#ifdef CONFIG_LEDS_TRIGGER_DISK
|
||||
extern void ledtrig_disk_activity(bool write);
|
||||
void ledtrig_disk_activity(bool write);
|
||||
#else
|
||||
static inline void ledtrig_disk_activity(bool write) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LEDS_TRIGGER_MTD
|
||||
extern void ledtrig_mtd_activity(void);
|
||||
void ledtrig_mtd_activity(void);
|
||||
#else
|
||||
static inline void ledtrig_mtd_activity(void) {}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_LEDS_TRIGGER_CAMERA) || defined(CONFIG_LEDS_TRIGGER_CAMERA_MODULE)
|
||||
extern void ledtrig_flash_ctrl(bool on);
|
||||
extern void ledtrig_torch_ctrl(bool on);
|
||||
void ledtrig_flash_ctrl(bool on);
|
||||
void ledtrig_torch_ctrl(bool on);
|
||||
#else
|
||||
static inline void ledtrig_flash_ctrl(bool on) {}
|
||||
static inline void ledtrig_torch_ctrl(bool on) {}
|
||||
|
@ -550,7 +538,7 @@ enum cpu_led_event {
|
|||
CPU_LED_HALTED, /* Machine shutdown */
|
||||
};
|
||||
#ifdef CONFIG_LEDS_TRIGGER_CPU
|
||||
extern void ledtrig_cpu(enum cpu_led_event evt);
|
||||
void ledtrig_cpu(enum cpu_led_event evt);
|
||||
#else
|
||||
static inline void ledtrig_cpu(enum cpu_led_event evt)
|
||||
{
|
||||
|
@ -559,7 +547,7 @@ static inline void ledtrig_cpu(enum cpu_led_event evt)
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
|
||||
extern void led_classdev_notify_brightness_hw_changed(
|
||||
void led_classdev_notify_brightness_hw_changed(
|
||||
struct led_classdev *led_cdev, enum led_brightness brightness);
|
||||
#else
|
||||
static inline void led_classdev_notify_brightness_hw_changed(
|
||||
|
|
Loading…
Reference in New Issue