提交 db3ecdee 编写于 作者: L Linus Torvalds

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds

Pull LED subsystem update from Bryan Wu:
 "The big change of LED subsystem is introducing a new LED class for
  Flash type LEDs which will be used for V4L2 subsystem.

  Also we got some cleanup and fixes"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds:
  leds: leds-gpio: Pass on error codes unmodified
  DT: leds: Add led-sources property
  leds: Add LED Flash class extension to the LED subsystem
  leds: leds-mc13783: Use of_get_child_by_name() instead of refcount hack
  leds: Use setup_timer
  leds: Don't allow brightness values greater than max_brightness
  DT: leds: Add flash LED devices related properties
Common leds properties. Common leds properties.
LED and flash LED devices provide the same basic functionality as current
regulators, but extended with LED and flash LED specific features like
blinking patterns, flash timeout, flash faults and external flash strobe mode.
Many LED devices expose more than one current output that can be connected
to one or more discrete LED component. Since the arrangement of connections
can influence the way of the LED device initialization, the LED components
have to be tightly coupled with the LED device binding. They are represented
by child nodes of the parent LED device binding.
Optional properties for child nodes: Optional properties for child nodes:
- led-sources : List of device current outputs the LED is connected to. The
outputs are identified by the numbers that must be defined
in the LED device binding documentation.
- label : The label for this LED. If omitted, the label is - label : The label for this LED. If omitted, the label is
taken from the node name (excluding the unit address). taken from the node name (excluding the unit address).
...@@ -14,6 +27,15 @@ Optional properties for child nodes: ...@@ -14,6 +27,15 @@ Optional properties for child nodes:
"ide-disk" - LED indicates disk activity "ide-disk" - LED indicates disk activity
"timer" - LED flashes at a fixed, configurable rate "timer" - LED flashes at a fixed, configurable rate
- max-microamp : maximum intensity in microamperes of the LED
(torch LED for flash devices)
- flash-max-microamp : maximum intensity in microamperes of the
flash LED; it is mandatory if the LED should
support the flash mode
- flash-timeout-us : timeout in microseconds after which the flash
LED is turned off
Examples: Examples:
system-status { system-status {
...@@ -21,3 +43,11 @@ system-status { ...@@ -21,3 +43,11 @@ system-status {
linux,default-trigger = "heartbeat"; linux,default-trigger = "heartbeat";
... ...
}; };
camera-flash {
label = "Flash";
led-sources = <0>, <1>;
max-microamp = <50000>;
flash-max-microamp = <320000>;
flash-timeout-us = <500000>;
};
...@@ -22,6 +22,16 @@ config LEDS_CLASS ...@@ -22,6 +22,16 @@ config LEDS_CLASS
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. need this to do anything useful with LEDs. If unsure, say N.
config LEDS_CLASS_FLASH
tristate "LED Flash Class Support"
depends on LEDS_CLASS
help
This option enables the flash led sysfs class in /sys/class/leds.
It wrapps LED Class and adds flash LEDs specific sysfs attributes
and kernel internal API to it. You'll need this to provide support
for the flash related features of a LED device. It can be built
as a module.
comment "LED drivers" comment "LED drivers"
config LEDS_88PM860X config LEDS_88PM860X
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# LED Core # LED Core
obj-$(CONFIG_NEW_LEDS) += led-core.o obj-$(CONFIG_NEW_LEDS) += led-core.o
obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_CLASS) += led-class.o
obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o
obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers # LED Platform Drivers
......
/*
* LED Flash class interface
*
* Copyright (C) 2015 Samsung Electronics Co., Ltd.
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/led-class-flash.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "leds.h"
#define has_flash_op(fled_cdev, op) \
(fled_cdev && fled_cdev->ops->op)
#define call_flash_op(fled_cdev, op, args...) \
((has_flash_op(fled_cdev, op)) ? \
(fled_cdev->ops->op(fled_cdev, args)) : \
-EINVAL)
static const char * const led_flash_fault_names[] = {
"led-over-voltage",
"flash-timeout-exceeded",
"controller-over-temperature",
"controller-short-circuit",
"led-power-supply-over-current",
"indicator-led-fault",
"led-under-voltage",
"controller-under-voltage",
"led-over-temperature",
};
static ssize_t flash_brightness_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
unsigned long state;
ssize_t ret;
mutex_lock(&led_cdev->led_access);
if (led_sysfs_is_disabled(led_cdev)) {
ret = -EBUSY;
goto unlock;
}
ret = kstrtoul(buf, 10, &state);
if (ret)
goto unlock;
ret = led_set_flash_brightness(fled_cdev, state);
if (ret < 0)
goto unlock;
ret = size;
unlock:
mutex_unlock(&led_cdev->led_access);
return ret;
}
static ssize_t flash_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
/* no lock needed for this */
led_update_flash_brightness(fled_cdev);
return sprintf(buf, "%u\n", fled_cdev->brightness.val);
}
static DEVICE_ATTR_RW(flash_brightness);
static ssize_t max_flash_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
return sprintf(buf, "%u\n", fled_cdev->brightness.max);
}
static DEVICE_ATTR_RO(max_flash_brightness);
static ssize_t flash_strobe_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
unsigned long state;
ssize_t ret = -EINVAL;
mutex_lock(&led_cdev->led_access);
if (led_sysfs_is_disabled(led_cdev)) {
ret = -EBUSY;
goto unlock;
}
ret = kstrtoul(buf, 10, &state);
if (ret)
goto unlock;
if (state < 0 || state > 1) {
ret = -EINVAL;
goto unlock;
}
ret = led_set_flash_strobe(fled_cdev, state);
if (ret < 0)
goto unlock;
ret = size;
unlock:
mutex_unlock(&led_cdev->led_access);
return ret;
}
static ssize_t flash_strobe_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
bool state;
int ret;
/* no lock needed for this */
ret = led_get_flash_strobe(fled_cdev, &state);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", state);
}
static DEVICE_ATTR_RW(flash_strobe);
static ssize_t flash_timeout_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
unsigned long flash_timeout;
ssize_t ret;
mutex_lock(&led_cdev->led_access);
if (led_sysfs_is_disabled(led_cdev)) {
ret = -EBUSY;
goto unlock;
}
ret = kstrtoul(buf, 10, &flash_timeout);
if (ret)
goto unlock;
ret = led_set_flash_timeout(fled_cdev, flash_timeout);
if (ret < 0)
goto unlock;
ret = size;
unlock:
mutex_unlock(&led_cdev->led_access);
return ret;
}
static ssize_t flash_timeout_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
return sprintf(buf, "%u\n", fled_cdev->timeout.val);
}
static DEVICE_ATTR_RW(flash_timeout);
static ssize_t max_flash_timeout_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
return sprintf(buf, "%u\n", fled_cdev->timeout.max);
}
static DEVICE_ATTR_RO(max_flash_timeout);
static ssize_t flash_fault_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
u32 fault, mask = 0x1;
char *pbuf = buf;
int i, ret, buf_len;
ret = led_get_flash_fault(fled_cdev, &fault);
if (ret < 0)
return -EINVAL;
*buf = '\0';
for (i = 0; i < LED_NUM_FLASH_FAULTS; ++i) {
if (fault & mask) {
buf_len = sprintf(pbuf, "%s ",
led_flash_fault_names[i]);
pbuf += buf_len;
}
mask <<= 1;
}
return sprintf(buf, "%s\n", buf);
}
static DEVICE_ATTR_RO(flash_fault);
static ssize_t available_sync_leds_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
char *pbuf = buf;
int i, buf_len;
buf_len = sprintf(pbuf, "[0: none] ");
pbuf += buf_len;
for (i = 0; i < fled_cdev->num_sync_leds; ++i) {
buf_len = sprintf(pbuf, "[%d: %s] ", i + 1,
fled_cdev->sync_leds[i]->led_cdev.name);
pbuf += buf_len;
}
return sprintf(buf, "%s\n", buf);
}
static DEVICE_ATTR_RO(available_sync_leds);
static ssize_t flash_sync_strobe_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
unsigned long led_id;
ssize_t ret;
mutex_lock(&led_cdev->led_access);
if (led_sysfs_is_disabled(led_cdev)) {
ret = -EBUSY;
goto unlock;
}
ret = kstrtoul(buf, 10, &led_id);
if (ret)
goto unlock;
if (led_id > fled_cdev->num_sync_leds) {
ret = -ERANGE;
goto unlock;
}
fled_cdev->sync_led_id = led_id;
ret = size;
unlock:
mutex_unlock(&led_cdev->led_access);
return ret;
}
static ssize_t flash_sync_strobe_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
int sled_id = fled_cdev->sync_led_id;
char *sync_led_name = "none";
if (fled_cdev->sync_led_id > 0)
sync_led_name = (char *)
fled_cdev->sync_leds[sled_id - 1]->led_cdev.name;
return sprintf(buf, "[%d: %s]\n", sled_id, sync_led_name);
}
static DEVICE_ATTR_RW(flash_sync_strobe);
static struct attribute *led_flash_strobe_attrs[] = {
&dev_attr_flash_strobe.attr,
NULL,
};
static struct attribute *led_flash_timeout_attrs[] = {
&dev_attr_flash_timeout.attr,
&dev_attr_max_flash_timeout.attr,
NULL,
};
static struct attribute *led_flash_brightness_attrs[] = {
&dev_attr_flash_brightness.attr,
&dev_attr_max_flash_brightness.attr,
NULL,
};
static struct attribute *led_flash_fault_attrs[] = {
&dev_attr_flash_fault.attr,
NULL,
};
static struct attribute *led_flash_sync_strobe_attrs[] = {
&dev_attr_available_sync_leds.attr,
&dev_attr_flash_sync_strobe.attr,
NULL,
};
static const struct attribute_group led_flash_strobe_group = {
.attrs = led_flash_strobe_attrs,
};
static const struct attribute_group led_flash_timeout_group = {
.attrs = led_flash_timeout_attrs,
};
static const struct attribute_group led_flash_brightness_group = {
.attrs = led_flash_brightness_attrs,
};
static const struct attribute_group led_flash_fault_group = {
.attrs = led_flash_fault_attrs,
};
static const struct attribute_group led_flash_sync_strobe_group = {
.attrs = led_flash_sync_strobe_attrs,
};
static void led_flash_resume(struct led_classdev *led_cdev)
{
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
call_flash_op(fled_cdev, flash_brightness_set,
fled_cdev->brightness.val);
call_flash_op(fled_cdev, timeout_set, fled_cdev->timeout.val);
}
static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev)
{
struct led_classdev *led_cdev = &fled_cdev->led_cdev;
const struct led_flash_ops *ops = fled_cdev->ops;
const struct attribute_group **flash_groups = fled_cdev->sysfs_groups;
int num_sysfs_groups = 0;
flash_groups[num_sysfs_groups++] = &led_flash_strobe_group;
if (ops->flash_brightness_set)
flash_groups[num_sysfs_groups++] = &led_flash_brightness_group;
if (ops->timeout_set)
flash_groups[num_sysfs_groups++] = &led_flash_timeout_group;
if (ops->fault_get)
flash_groups[num_sysfs_groups++] = &led_flash_fault_group;
if (led_cdev->flags & LED_DEV_CAP_SYNC_STROBE)
flash_groups[num_sysfs_groups++] = &led_flash_sync_strobe_group;
led_cdev->groups = flash_groups;
}
int led_classdev_flash_register(struct device *parent,
struct led_classdev_flash *fled_cdev)
{
struct led_classdev *led_cdev;
const struct led_flash_ops *ops;
int ret;
if (!fled_cdev)
return -EINVAL;
led_cdev = &fled_cdev->led_cdev;
if (led_cdev->flags & LED_DEV_CAP_FLASH) {
if (!led_cdev->brightness_set_sync)
return -EINVAL;
ops = fled_cdev->ops;
if (!ops || !ops->strobe_set)
return -EINVAL;
led_cdev->flash_resume = led_flash_resume;
/* Select the sysfs attributes to be created for the device */
led_flash_init_sysfs_groups(fled_cdev);
}
/* Register led class device */
ret = led_classdev_register(parent, led_cdev);
if (ret < 0)
return ret;
/* Setting a torch brightness needs to have immediate effect */
led_cdev->flags &= ~SET_BRIGHTNESS_ASYNC;
led_cdev->flags |= SET_BRIGHTNESS_SYNC;
return 0;
}
EXPORT_SYMBOL_GPL(led_classdev_flash_register);
void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
{
if (!fled_cdev)
return;
led_classdev_unregister(&fled_cdev->led_cdev);
}
EXPORT_SYMBOL_GPL(led_classdev_flash_unregister);
static void led_clamp_align(struct led_flash_setting *s)
{
u32 v, offset;
v = s->val + s->step / 2;
v = clamp(v, s->min, s->max);
offset = v - s->min;
offset = s->step * (offset / s->step);
s->val = s->min + offset;
}
int led_set_flash_timeout(struct led_classdev_flash *fled_cdev, u32 timeout)
{
struct led_classdev *led_cdev = &fled_cdev->led_cdev;
struct led_flash_setting *s = &fled_cdev->timeout;
s->val = timeout;
led_clamp_align(s);
if (!(led_cdev->flags & LED_SUSPENDED))
return call_flash_op(fled_cdev, timeout_set, s->val);
return 0;
}
EXPORT_SYMBOL_GPL(led_set_flash_timeout);
int led_get_flash_fault(struct led_classdev_flash *fled_cdev, u32 *fault)
{
return call_flash_op(fled_cdev, fault_get, fault);
}
EXPORT_SYMBOL_GPL(led_get_flash_fault);
int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
u32 brightness)
{
struct led_classdev *led_cdev = &fled_cdev->led_cdev;
struct led_flash_setting *s = &fled_cdev->brightness;
s->val = brightness;
led_clamp_align(s);
if (!(led_cdev->flags & LED_SUSPENDED))
return call_flash_op(fled_cdev, flash_brightness_set, s->val);
return 0;
}
EXPORT_SYMBOL_GPL(led_set_flash_brightness);
int led_update_flash_brightness(struct led_classdev_flash *fled_cdev)
{
struct led_flash_setting *s = &fled_cdev->brightness;
u32 brightness;
if (has_flash_op(fled_cdev, flash_brightness_get)) {
int ret = call_flash_op(fled_cdev, flash_brightness_get,
&brightness);
if (ret < 0)
return ret;
s->val = brightness;
}
return 0;
}
EXPORT_SYMBOL_GPL(led_update_flash_brightness);
MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
MODULE_DESCRIPTION("LED Flash class interface");
MODULE_LICENSE("GPL v2");
...@@ -179,6 +179,10 @@ EXPORT_SYMBOL_GPL(led_classdev_suspend); ...@@ -179,6 +179,10 @@ EXPORT_SYMBOL_GPL(led_classdev_suspend);
void led_classdev_resume(struct led_classdev *led_cdev) void led_classdev_resume(struct led_classdev *led_cdev)
{ {
led_cdev->brightness_set(led_cdev, led_cdev->brightness); led_cdev->brightness_set(led_cdev, led_cdev->brightness);
if (led_cdev->flash_resume)
led_cdev->flash_resume(led_cdev);
led_cdev->flags &= ~LED_SUSPENDED; led_cdev->flags &= ~LED_SUSPENDED;
} }
EXPORT_SYMBOL_GPL(led_classdev_resume); EXPORT_SYMBOL_GPL(led_classdev_resume);
...@@ -239,9 +243,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) ...@@ -239,9 +243,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed); INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
init_timer(&led_cdev->blink_timer); setup_timer(&led_cdev->blink_timer, led_timer_function,
led_cdev->blink_timer.function = led_timer_function; (unsigned long)led_cdev);
led_cdev->blink_timer.data = (unsigned long)led_cdev;
#ifdef CONFIG_LEDS_TRIGGERS #ifdef CONFIG_LEDS_TRIGGERS
led_trigger_set_default(led_cdev); led_trigger_set_default(led_cdev);
......
...@@ -187,6 +187,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) ...@@ -187,6 +187,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
led.gpiod = devm_get_gpiod_from_child(dev, child); led.gpiod = devm_get_gpiod_from_child(dev, child);
if (IS_ERR(led.gpiod)) { if (IS_ERR(led.gpiod)) {
fwnode_handle_put(child); fwnode_handle_put(child);
ret = PTR_ERR(led.gpiod);
goto err; goto err;
} }
...@@ -229,7 +230,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) ...@@ -229,7 +230,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
err: err:
for (count = priv->num_leds - 2; count >= 0; count--) for (count = priv->num_leds - 2; count >= 0; count--)
delete_gpio_led(&priv->leds[count]); delete_gpio_led(&priv->leds[count]);
return ERR_PTR(-ENODEV); return ERR_PTR(ret);
} }
static const struct of_device_id of_gpio_leds_match[] = { static const struct of_device_id of_gpio_leds_match[] = {
......
...@@ -134,9 +134,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt( ...@@ -134,9 +134,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
if (!pdata) if (!pdata)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
of_node_get(dev->parent->of_node); parent = of_get_child_by_name(dev->parent->of_node, "leds");
parent = of_find_node_by_name(dev->parent->of_node, "leds");
if (!parent) if (!parent)
goto out_node_put; goto out_node_put;
......
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
static inline void led_set_brightness_async(struct led_classdev *led_cdev, static inline void led_set_brightness_async(struct led_classdev *led_cdev,
enum led_brightness value) enum led_brightness value)
{ {
led_cdev->brightness = min(value, led_cdev->max_brightness); value = min(value, led_cdev->max_brightness);
led_cdev->brightness = value;
if (!(led_cdev->flags & LED_SUSPENDED)) if (!(led_cdev->flags & LED_SUSPENDED))
led_cdev->brightness_set(led_cdev, value); led_cdev->brightness_set(led_cdev, value);
......
/*
* LED Flash class interface
*
* Copyright (C) 2015 Samsung Electronics Co., Ltd.
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __LINUX_FLASH_LEDS_H_INCLUDED
#define __LINUX_FLASH_LEDS_H_INCLUDED
#include <linux/leds.h>
#include <uapi/linux/v4l2-controls.h>
struct device_node;
struct led_classdev_flash;
/*
* Supported led fault bits - must be kept in synch
* with V4L2_FLASH_FAULT bits.
*/
#define LED_FAULT_OVER_VOLTAGE (1 << 0)
#define LED_FAULT_TIMEOUT (1 << 1)
#define LED_FAULT_OVER_TEMPERATURE (1 << 2)
#define LED_FAULT_SHORT_CIRCUIT (1 << 3)
#define LED_FAULT_OVER_CURRENT (1 << 4)
#define LED_FAULT_INDICATOR (1 << 5)
#define LED_FAULT_UNDER_VOLTAGE (1 << 6)
#define LED_FAULT_INPUT_VOLTAGE (1 << 7)
#define LED_FAULT_LED_OVER_TEMPERATURE (1 << 8)
#define LED_NUM_FLASH_FAULTS 9
#define LED_FLASH_MAX_SYSFS_GROUPS 7
struct led_flash_ops {
/* set flash brightness */
int (*flash_brightness_set)(struct led_classdev_flash *fled_cdev,
u32 brightness);
/* get flash brightness */
int (*flash_brightness_get)(struct led_classdev_flash *fled_cdev,
u32 *brightness);
/* set flash strobe state */
int (*strobe_set)(struct led_classdev_flash *fled_cdev, bool state);
/* get flash strobe state */
int (*strobe_get)(struct led_classdev_flash *fled_cdev, bool *state);
/* set flash timeout */
int (*timeout_set)(struct led_classdev_flash *fled_cdev, u32 timeout);
/* get the flash LED fault */
int (*fault_get)(struct led_classdev_flash *fled_cdev, u32 *fault);
};
/*
* Current value of a flash setting along
* with its constraints.
*/
struct led_flash_setting {
/* maximum allowed value */
u32 min;
/* maximum allowed value */
u32 max;
/* step value */
u32 step;
/* current value */
u32 val;
};
struct led_classdev_flash {
/* led class device */
struct led_classdev led_cdev;
/* flash led specific ops */
const struct led_flash_ops *ops;
/* flash brightness value in microamperes along with its constraints */
struct led_flash_setting brightness;
/* flash timeout value in microseconds along with its constraints */
struct led_flash_setting timeout;
/* LED Flash class sysfs groups */
const struct attribute_group *sysfs_groups[LED_FLASH_MAX_SYSFS_GROUPS];
/* LEDs available for flash strobe synchronization */
struct led_classdev_flash **sync_leds;
/* Number of LEDs available for flash strobe synchronization */
int num_sync_leds;
/*
* The identifier of the sub-led to synchronize the flash strobe with.
* Identifiers start from 1, which reflects the first element from the
* sync_leds array. 0 means that the flash strobe should not be
* synchronized.
*/
u32 sync_led_id;
};
static inline struct led_classdev_flash *lcdev_to_flcdev(
struct led_classdev *lcdev)
{
return container_of(lcdev, struct led_classdev_flash, led_cdev);
}
/**
* led_classdev_flash_register - register a new object of led_classdev class
* with support for flash LEDs
* @parent: the flash LED to register
* @fled_cdev: the led_classdev_flash structure for this device
*
* Returns: 0 on success or negative error value on failure
*/
extern int led_classdev_flash_register(struct device *parent,
struct led_classdev_flash *fled_cdev);
/**
* led_classdev_flash_unregister - unregisters an object of led_classdev class
* with support for flash LEDs
* @fled_cdev: the flash LED to unregister
*
* Unregister a previously registered via led_classdev_flash_register object
*/
extern void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev);
/**
* led_set_flash_strobe - setup flash strobe
* @fled_cdev: the flash LED to set strobe on
* @state: 1 - strobe flash, 0 - stop flash strobe
*
* Strobe the flash LED.
*
* Returns: 0 on success or negative error value on failure
*/
static inline int led_set_flash_strobe(struct led_classdev_flash *fled_cdev,
bool state)
{
return fled_cdev->ops->strobe_set(fled_cdev, state);
}
/**
* led_get_flash_strobe - get flash strobe status
* @fled_cdev: the flash LED to query
* @state: 1 - flash is strobing, 0 - flash is off
*
* Check whether the flash is strobing at the moment.
*
* Returns: 0 on success or negative error value on failure
*/
static inline int led_get_flash_strobe(struct led_classdev_flash *fled_cdev,
bool *state)
{
if (fled_cdev->ops->strobe_get)
return fled_cdev->ops->strobe_get(fled_cdev, state);
return -EINVAL;
}
/**
* led_set_flash_brightness - set flash LED brightness
* @fled_cdev: the flash LED to set
* @brightness: the brightness to set it to
*
* Set a flash LED's brightness.
*
* Returns: 0 on success or negative error value on failure
*/
extern int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
u32 brightness);
/**
* led_update_flash_brightness - update flash LED brightness
* @fled_cdev: the flash LED to query
*
* Get a flash LED's current brightness and update led_flash->brightness
* member with the obtained value.
*
* Returns: 0 on success or negative error value on failure
*/
extern int led_update_flash_brightness(struct led_classdev_flash *fled_cdev);
/**
* led_set_flash_timeout - set flash LED timeout
* @fled_cdev: the flash LED to set
* @timeout: the flash timeout to set it to
*
* Set the flash strobe duration.
*
* Returns: 0 on success or negative error value on failure
*/
extern int led_set_flash_timeout(struct led_classdev_flash *fled_cdev,
u32 timeout);
/**
* led_get_flash_fault - get the flash LED fault
* @fled_cdev: the flash LED to query
* @fault: bitmask containing flash faults
*
* Get the flash LED fault.
*
* Returns: 0 on success or negative error value on failure
*/
extern int led_get_flash_fault(struct led_classdev_flash *fled_cdev,
u32 *fault);
#endif /* __LINUX_FLASH_LEDS_H_INCLUDED */
...@@ -46,6 +46,8 @@ struct led_classdev { ...@@ -46,6 +46,8 @@ struct led_classdev {
#define LED_SYSFS_DISABLE (1 << 20) #define LED_SYSFS_DISABLE (1 << 20)
#define SET_BRIGHTNESS_ASYNC (1 << 21) #define SET_BRIGHTNESS_ASYNC (1 << 21)
#define SET_BRIGHTNESS_SYNC (1 << 22) #define SET_BRIGHTNESS_SYNC (1 << 22)
#define LED_DEV_CAP_FLASH (1 << 23)
#define LED_DEV_CAP_SYNC_STROBE (1 << 24)
/* Set LED brightness level */ /* Set LED brightness level */
/* Must not sleep, use a workqueue if needed */ /* Must not sleep, use a workqueue if needed */
...@@ -81,6 +83,7 @@ struct led_classdev { ...@@ -81,6 +83,7 @@ struct led_classdev {
unsigned long blink_delay_on, blink_delay_off; unsigned long blink_delay_on, blink_delay_off;
struct timer_list blink_timer; struct timer_list blink_timer;
int blink_brightness; int blink_brightness;
void (*flash_resume)(struct led_classdev *led_cdev);
struct work_struct set_brightness_work; struct work_struct set_brightness_work;
int delayed_set_value; int delayed_set_value;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册