Commit 13d45f79 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull LED subsystem updates from Bryan Wu:
 "In this cycle, we finished to merge patches for LED Flash class
  driver.

  Other than that we have some bug fixes and new drivers for LED
  controllers"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds: (33 commits)
  leds:lp55xx: fix firmware loading error
  leds: fix max77693-led build errors
  leds: fix aat1290 build errors
  leds: aat1290: pass flags parameter to devm_gpiod_get
  leds: ktd2692: pass flags parameter to devm_gpiod_get
  drivers/leds: don't use module_init in non-modular leds-cobalt-raq.c
  leds: aat1290: add support for V4L2 Flash sub-device
  DT: aat1290: Document handling external strobe sources
  leds: max77693: add support for V4L2 Flash sub-device
  media: Add registration helpers for V4L2 flash sub-devices
  v4l: async: Add a pointer to of_node to struct v4l2_subdev, match it
  Documentation: leds: Add description of v4l2-flash sub-device
  leds: add BCM6358 LED driver
  leds: add DT binding for BCM6358 LED controller
  leds: fix brightness changing when software blinking is active
  Documentation: leds-lp5523: describe master fader attributes
  leds: lp5523: add master_fader support
  leds: leds-gpio: Allow compile test if !GPIOLIB
  leds: leds-gpio: Add missing #include <linux/of.h>
  gpiolib: Add missing dummies for the unified device properties interface
  ...
parents 05fde26a b6789320
* Skyworks Solutions, Inc. AAT1290 Current Regulator for Flash LEDs
The device is controlled through two pins: FL_EN and EN_SET. The pins when,
asserted high, enable flash strobe and movie mode (max 1/2 of flash current)
respectively. In order to add a capability of selecting the strobe signal source
(e.g. CPU or camera sensor) there is an additional switch required, independent
of the flash chip. The switch is controlled with pin control.
Required properties:
- compatible : Must be "skyworks,aat1290".
- flen-gpios : Must be device tree identifier of the flash device FL_EN pin.
- enset-gpios : Must be device tree identifier of the flash device EN_SET pin.
Optional properties:
- pinctrl-names : Must contain entries: "default", "host", "isp". Entries
"default" and "host" must refer to the same pin configuration
node, which sets the host as a strobe signal provider. Entry
"isp" must refer to the pin configuration node, which sets the
ISP as a strobe signal provider.
A discrete LED element connected to the device must be represented by a child
node - see Documentation/devicetree/bindings/leds/common.txt.
Required properties of the LED child node:
- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
Maximum flash LED supply current can be calculated using
following formula: I = 1A * 162kohm / Rset.
- flash-timeout-us : see Documentation/devicetree/bindings/leds/common.txt
Maximum flash timeout can be calculated using following
formula: T = 8.82 * 10^9 * Ct.
Optional properties of the LED child node:
- label : see Documentation/devicetree/bindings/leds/common.txt
Example (by Ct = 220nF, Rset = 160kohm and exynos4412-trats2 board with
a switch that allows for routing strobe signal either from the host or from
the camera sensor):
#include "exynos4412.dtsi"
aat1290 {
compatible = "skyworks,aat1290";
flen-gpios = <&gpj1 1 GPIO_ACTIVE_HIGH>;
enset-gpios = <&gpj1 2 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default", "host", "isp";
pinctrl-0 = <&camera_flash_host>;
pinctrl-1 = <&camera_flash_host>;
pinctrl-2 = <&camera_flash_isp>;
camera_flash: flash-led {
label = "aat1290-flash";
led-max-microamp = <520833>;
flash-max-microamp = <1012500>;
flash-timeout-us = <1940000>;
};
};
&pinctrl_0 {
camera_flash_host: camera-flash-host {
samsung,pins = "gpj1-0";
samsung,pin-function = <1>;
samsung,pin-val = <0>;
};
camera_flash_isp: camera-flash-isp {
samsung,pins = "gpj1-0";
samsung,pin-function = <1>;
samsung,pin-val = <1>;
};
};
LEDs connected to Broadcom BCM6328 controller
This controller is present on BCM6318, BCM6328, BCM6362 and BCM63268.
In these SoCs it's possible to control LEDs both as GPIOs or by hardware.
However, on some devices there are Serial LEDs (LEDs connected to a 74x164
controller), which can either be controlled by software (exporting the 74x164
as spi-gpio. See Documentation/devicetree/bindings/gpio/gpio-74x164.txt), or
by hardware using this driver.
Some of these Serial LEDs are hardware controlled (e.g. ethernet LEDs) and
exporting the 74x164 as spi-gpio prevents those LEDs to be hardware
controlled, so the only chance to keep them working is by using this driver.
BCM6328 LED controller has a HWDIS register, which controls whether a LED
should be controlled by a hardware signal instead of the MODE register value,
with 0 meaning hardware control enabled and 1 hardware control disabled. This
is usually 1:1 for hardware to LED signals, but through the activity/link
registers you have some limited control over rerouting the LEDs (as
explained later in brcm,link-signal-sources). Even if a LED is hardware
controlled you are still able to make it blink or light it up if it isn't,
but you can't turn it off if the hardware decides to light it up. For this
reason, hardware controlled LEDs aren't registered as LED class devices.
Required properties:
- compatible : should be "brcm,bcm6328-leds".
- #address-cells : must be 1.
- #size-cells : must be 0.
- reg : BCM6328 LED controller address and size.
Optional properties:
- brcm,serial-leds : Boolean, enables Serial LEDs.
Default : false
Each LED is represented as a sub-node of the brcm,bcm6328-leds device.
LED sub-node required properties:
- reg : LED pin number (only LEDs 0 to 23 are valid).
LED sub-node optional properties:
a) Optional properties for sub-nodes related to software controlled LEDs:
- label : see Documentation/devicetree/bindings/leds/common.txt
- active-low : Boolean, makes LED active low.
Default : false
- default-state : see
Documentation/devicetree/bindings/leds/leds-gpio.txt
- linux,default-trigger : see
Documentation/devicetree/bindings/leds/common.txt
b) Optional properties for sub-nodes related to hardware controlled LEDs:
- brcm,hardware-controlled : Boolean, makes this LED hardware controlled.
Default : false
- brcm,link-signal-sources : An array of hardware link
signal sources. Up to four link hardware signals can get muxed into
these LEDs. Only valid for LEDs 0 to 7, where LED signals 0 to 3 may
be muxed to LEDs 0 to 3, and signals 4 to 7 may be muxed to LEDs
4 to 7. A signal can be muxed to more than one LED, and one LED can
have more than one source signal.
- brcm,activity-signal-sources : An array of hardware activity
signal sources. Up to four activity hardware signals can get muxed into
these LEDs. Only valid for LEDs 0 to 7, where LED signals 0 to 3 may
be muxed to LEDs 0 to 3, and signals 4 to 7 may be muxed to LEDs
4 to 7. A signal can be muxed to more than one LED, and one LED can
have more than one source signal.
Examples:
Scenario 1 : BCM6328 with 4 EPHY LEDs
leds0: led-controller@10000800 {
compatible = "brcm,bcm6328-leds";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10000800 0x24>;
alarm_red@2 {
reg = <2>;
active-low;
label = "red:alarm";
};
inet_green@3 {
reg = <3>;
active-low;
label = "green:inet";
};
power_green@4 {
reg = <4>;
active-low;
label = "green:power";
default-state = "on";
};
ephy0_spd@17 {
reg = <17>;
brcm,hardware-controlled;
};
ephy1_spd@18 {
reg = <18>;
brcm,hardware-controlled;
};
ephy2_spd@19 {
reg = <19>;
brcm,hardware-controlled;
};
ephy3_spd@20 {
reg = <20>;
brcm,hardware-controlled;
};
};
Scenario 2 : BCM63268 with Serial/GPHY0 LEDs
leds0: led-controller@10001900 {
compatible = "brcm,bcm6328-leds";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10001900 0x24>;
brcm,serial-leds;
gphy0_spd0@0 {
reg = <0>;
brcm,hardware-controlled;
brcm,link-signal-sources = <0>;
};
gphy0_spd1@1 {
reg = <1>;
brcm,hardware-controlled;
brcm,link-signal-sources = <1>;
};
inet_red@2 {
reg = <2>;
active-low;
label = "red:inet";
};
dsl_green@3 {
reg = <3>;
active-low;
label = "green:dsl";
};
usb_green@4 {
reg = <4>;
active-low;
label = "green:usb";
};
wps_green@7 {
reg = <7>;
active-low;
label = "green:wps";
};
inet_green@8 {
reg = <8>;
active-low;
label = "green:inet";
};
ephy0_act@9 {
reg = <9>;
brcm,hardware-controlled;
};
ephy1_act@10 {
reg = <10>;
brcm,hardware-controlled;
};
ephy2_act@11 {
reg = <11>;
brcm,hardware-controlled;
};
gphy0_act@12 {
reg = <12>;
brcm,hardware-controlled;
};
ephy0_spd@13 {
reg = <13>;
brcm,hardware-controlled;
};
ephy1_spd@14 {
reg = <14>;
brcm,hardware-controlled;
};
ephy2_spd@15 {
reg = <15>;
brcm,hardware-controlled;
};
power_green@20 {
reg = <20>;
active-low;
label = "green:power";
default-state = "on";
};
};
Scenario 3 : BCM6362 with 1 LED for each EPHY
leds0: led-controller@10001900 {
compatible = "brcm,bcm6328-leds";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10001900 0x24>;
usb@0 {
reg = <0>;
brcm,hardware-controlled;
brcm,link-signal-sources = <0>;
brcm,activity-signal-sources = <0>;
/* USB link/activity routed to USB LED */
};
inet@1 {
reg = <1>;
brcm,hardware-controlled;
brcm,activity-signal-sources = <1>;
/* INET activity routed to INET LED */
};
ephy0@4 {
reg = <4>;
brcm,hardware-controlled;
brcm,link-signal-sources = <4>;
/* EPHY0 link routed to EPHY0 LED */
};
ephy1@5 {
reg = <5>;
brcm,hardware-controlled;
brcm,link-signal-sources = <5>;
/* EPHY1 link routed to EPHY1 LED */
};
ephy2@6 {
reg = <6>;
brcm,hardware-controlled;
brcm,link-signal-sources = <6>;
/* EPHY2 link routed to EPHY2 LED */
};
ephy3@7 {
reg = <7>;
brcm,hardware-controlled;
brcm,link-signal-sources = <7>;
/* EPHY3 link routed to EPHY3 LED */
};
power_green@20 {
reg = <20>;
active-low;
label = "green:power";
default-state = "on";
};
};
Scenario 4 : BCM6362 with 1 LED for all EPHYs
leds0: led-controller@10001900 {
compatible = "brcm,bcm6328-leds";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10001900 0x24>;
usb@0 {
reg = <0>;
brcm,hardware-controlled;
brcm,link-signal-sources = <0 1>;
brcm,activity-signal-sources = <0 1>;
/* USB/INET link/activity routed to USB LED */
};
ephy@4 {
reg = <4>;
brcm,hardware-controlled;
brcm,link-signal-sources = <4 5 6 7>;
/* EPHY0/1/2/3 link routed to EPHY0 LED */
};
power_green@20 {
reg = <20>;
active-low;
label = "green:power";
default-state = "on";
};
};
Scenario 5 : BCM6362 with EPHY LEDs swapped
leds0: led-controller@10001900 {
compatible = "brcm,bcm6328-leds";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10001900 0x24>;
usb@0 {
reg = <0>;
brcm,hardware-controlled;
brcm,link-signal-sources = <0>;
brcm,activity-signal-sources = <0 1>;
/* USB link/act and INET act routed to USB LED */
};
ephy0@4 {
reg = <4>;
brcm,hardware-controlled;
brcm,link-signal-sources = <7>;
/* EPHY3 link routed to EPHY0 LED */
};
ephy1@5 {
reg = <5>;
brcm,hardware-controlled;
brcm,link-signal-sources = <6>;
/* EPHY2 link routed to EPHY1 LED */
};
ephy2@6 {
reg = <6>;
brcm,hardware-controlled;
brcm,link-signal-sources = <5>;
/* EPHY1 link routed to EPHY2 LED */
};
ephy3@7 {
reg = <7>;
brcm,hardware-controlled;
brcm,link-signal-sources = <4>;
/* EPHY0 link routed to EPHY3 LED */
};
power_green@20 {
reg = <20>;
active-low;
label = "green:power";
default-state = "on";
};
};
LEDs connected to Broadcom BCM6358 controller
This controller is present on BCM6358 and BCM6368.
In these SoCs there are Serial LEDs (LEDs connected to a 74x164 controller),
which can either be controlled by software (exporting the 74x164 as spi-gpio.
See Documentation/devicetree/bindings/gpio/gpio-74x164.txt), or
by hardware using this driver.
Required properties:
- compatible : should be "brcm,bcm6358-leds".
- #address-cells : must be 1.
- #size-cells : must be 0.
- reg : BCM6358 LED controller address and size.
Optional properties:
- brcm,clk-div : SCK signal divider. Possible values are 1, 2, 4 and 8.
Default : 1
- brcm,clk-dat-low : Boolean, makes clock and data signals active low.
Default : false
Each LED is represented as a sub-node of the brcm,bcm6358-leds device.
LED sub-node required properties:
- reg : LED pin number (only LEDs 0 to 31 are valid).
LED sub-node optional properties:
- label : see Documentation/devicetree/bindings/leds/common.txt
- active-low : Boolean, makes LED active low.
Default : false
- default-state : see
Documentation/devicetree/bindings/leds/leds-gpio.txt
- linux,default-trigger : see
Documentation/devicetree/bindings/leds/common.txt
Examples:
Scenario 1 : BCM6358
leds0: led-controller@fffe00d0 {
compatible = "brcm,bcm6358-leds";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xfffe00d0 0x8>;
alarm_white {
reg = <0>;
active-low;
label = "white:alarm";
};
tv_white {
reg = <2>;
active-low;
label = "white:tv";
};
tel_white {
reg = <3>;
active-low;
label = "white:tel";
};
adsl_white {
reg = <4>;
active-low;
label = "white:adsl";
};
};
Scenario 2 : BCM6368
leds0: led-controller@100000d0 {
compatible = "brcm,bcm6358-leds";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x100000d0 0x8>;
brcm,pol-low;
brcm,clk-div = <4>;
power_red {
reg = <0>;
active-low;
label = "red:power";
};
power_green {
reg = <1>;
active-low;
label = "green:power";
default-state = "on";
};
power_blue {
reg = <2>;
label = "blue:power";
};
broadband_red {
reg = <3>;
active-low;
label = "red:broadband";
};
broadband_green {
reg = <4>;
label = "green:broadband";
};
broadband_blue {
reg = <5>;
active-low;
label = "blue:broadband";
};
wireless_red {
reg = <6>;
active-low;
label = "red:wireless";
};
wireless_green {
reg = <7>;
active-low;
label = "green:wireless";
};
wireless_blue {
reg = <8>;
label = "blue:wireless";
};
phone_red {
reg = <9>;
active-low;
label = "red:phone";
};
phone_green {
reg = <10>;
active-low;
label = "green:phone";
};
phone_blue {
reg = <11>;
label = "blue:phone";
};
upgrading_red {
reg = <12>;
active-low;
label = "red:upgrading";
};
upgrading_green {
reg = <13>;
active-low;
label = "green:upgrading";
};
upgrading_blue {
reg = <14>;
label = "blue:upgrading";
};
};
* Kinetic Technologies - KTD2692 Flash LED Driver
KTD2692 is the ideal power solution for high-power flash LEDs.
It uses ExpressWire single-wire programming for maximum flexibility.
The ExpressWire interface through CTRL pin can control LED on/off and
enable/disable the IC, Movie(max 1/3 of Flash current) / Flash mode current,
Flash timeout, LVP(low voltage protection).
Also, When the AUX pin is pulled high while CTRL pin is high,
LED current will be ramped up to the flash-mode current level.
Required properties:
- compatible : Should be "kinetic,ktd2692".
- ctrl-gpios : Specifier of the GPIO connected to CTRL pin.
- aux-gpios : Specifier of the GPIO connected to AUX pin.
Optional properties:
- vin-supply : "vin" LED supply (2.7V to 5.5V).
See Documentation/devicetree/bindings/regulator/regulator.txt
A discrete LED element connected to the device must be represented by a child
node - See Documentation/devicetree/bindings/leds/common.txt
Required properties for flash LED child nodes:
See Documentation/devicetree/bindings/leds/common.txt
- led-max-microamp : Minimum Threshold for Timer protection
is defined internally (Maximum 300mA).
- flash-max-microamp : Flash LED maximum current
Formula : I(mA) = 15000 / Rset.
- flash-max-timeout-us : Flash LED maximum timeout.
Optional properties for flash LED child nodes:
- label : See Documentation/devicetree/bindings/leds/common.txt
Example:
ktd2692 {
compatible = "kinetic,ktd2692";
ctrl-gpios = <&gpc0 1 0>;
aux-gpios = <&gpc0 2 0>;
vin-supply = <&vbat>;
flash-led {
label = "ktd2692-flash";
led-max-microamp = <300000>;
flash-max-microamp = <1500000>;
flash-max-timeout-us = <1835000>;
};
};
LEDs connected to tlc59116 or tlc59108
Required properties
- compatible: should be "ti,tlc59116" or "ti,tlc59108"
- #address-cells: must be 1
- #size-cells: must be 0
- reg: typically 0x68
Each led is represented as a sub-node of the ti,tlc59116.
See Documentation/devicetree/bindings/leds/common.txt
LED sub-node properties:
- reg: number of LED line, 0 to 15 or 0 to 7
- label: (optional) name of LED
- linux,default-trigger : (optional)
Examples:
tlc59116@68 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "ti,tlc59116";
reg = <0x68>;
wan@0 {
label = "wrt1900ac:amber:wan";
reg = <0x0>;
};
2g@2 {
label = "wrt1900ac:white:2g";
reg = <0x2>;
};
alive@9 {
label = "wrt1900ac:green:alive";
reg = <0x9>;
linux,default_trigger = "heartbeat";
};
};
......@@ -114,6 +114,7 @@ isee ISEE 2007 S.L.
isil Intersil
karo Ka-Ro electronics GmbH
keymile Keymile GmbH
kinetic Kinetic Technologies
lacie LaCie
lantiq Lantiq Semiconductor
lenovo Lenovo Group Ltd.
......
......@@ -20,3 +20,54 @@ Following sysfs attributes are exposed for controlling flash LED devices:
- max_flash_timeout
- flash_strobe
- flash_fault
V4L2 flash wrapper for flash LEDs
=================================
A LED subsystem driver can be controlled also from the level of VideoForLinux2
subsystem. In order to enable this CONFIG_V4L2_FLASH_LED_CLASS symbol has to
be defined in the kernel config.
The driver must call the v4l2_flash_init function to get registered in the
V4L2 subsystem. The function takes six arguments:
- dev : flash device, e.g. an I2C device
- of_node : of_node of the LED, may be NULL if the same as device's
- fled_cdev : LED flash class device to wrap
- iled_cdev : LED flash class device representing indicator LED associated with
fled_cdev, may be NULL
- ops : V4L2 specific ops
* external_strobe_set - defines the source of the flash LED strobe -
V4L2_CID_FLASH_STROBE control or external source, typically
a sensor, which makes it possible to synchronise the flash
strobe start with exposure start,
* intensity_to_led_brightness and led_brightness_to_intensity - perform
enum led_brightness <-> V4L2 intensity conversion in a device
specific manner - they can be used for devices with non-linear
LED current scale.
- config : configuration for V4L2 Flash sub-device
* dev_name - the name of the media entity, unique in the system,
* flash_faults - bitmask of flash faults that the LED flash class
device can report; corresponding LED_FAULT* bit definitions are
available in <linux/led-class-flash.h>,
* torch_intensity - constraints for the LED in TORCH mode
in microamperes,
* indicator_intensity - constraints for the indicator LED
in microamperes,
* has_external_strobe - determines whether the flash strobe source
can be switched to external,
On remove the v4l2_flash_release function has to be called, which takes one
argument - struct v4l2_flash pointer returned previously by v4l2_flash_init.
This function can be safely called with NULL or error pointer argument.
Please refer to drivers/leds/leds-max77693.c for an exemplary usage of the
v4l2 flash wrapper.
Once the V4L2 sub-device is registered by the driver which created the Media
controller device, the sub-device node acts just as a node of a native V4L2
flash API device would. The calls are simply routed to the LED flash API.
Opening the V4L2 flash sub-device makes the LED subsystem sysfs interface
unavailable. The interface is re-enabled after the V4L2 flash sub-device
is closed.
......@@ -49,6 +49,36 @@ There are two ways to run LED patterns.
2) Firmware interface - LP55xx common interface
For the details, please refer to 'firmware' section in leds-lp55xx.txt
LP5523 has three master faders. If a channel is mapped to one of
the master faders, its output is dimmed based on the value of the master
fader.
For example,
echo "123000123" > master_fader_leds
creates the following channel-fader mappings:
channel 0,6 to master_fader1
channel 1,7 to master_fader2
channel 2,8 to master_fader3
Then, to have 25% of the original output on channel 0,6:
echo 64 > master_fader1
To have 0% of the original output (i.e. no output) channel 1,7:
echo 0 > master_fader2
To have 100% of the original output (i.e. no dimming) on channel 2,8:
echo 255 > master_fader3
To clear all master fader controls:
echo "000000000" > master_fader_leds
Selftest uses always the current from the platform data.
Each channel contains led current settings.
......
......@@ -39,6 +39,32 @@ config LEDS_88PM860X
This option enables support for on-chip LED drivers found on Marvell
Semiconductor 88PM8606 PMIC.
config LEDS_AAT1290
tristate "LED support for the AAT1290"
depends on LEDS_CLASS_FLASH
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
depends on GPIOLIB
depends on OF
depends on PINCTRL
help
This option enables support for the LEDs on the AAT1290.
config LEDS_BCM6328
tristate "LED Support for Broadcom BCM6328"
depends on LEDS_CLASS
depends on OF
help
This option enables support for LEDs connected to the BCM6328
LED HW controller accessed via MMIO registers.
config LEDS_BCM6358
tristate "LED Support for Broadcom BCM6358"
depends on LEDS_CLASS
depends on OF
help
This option enables support for LEDs connected to the BCM6358
LED HW controller accessed via MMIO registers.
config LEDS_LM3530
tristate "LCD Backlight driver for LM3530"
depends on LEDS_CLASS
......@@ -179,7 +205,7 @@ config LEDS_PCA9532_GPIO
config LEDS_GPIO
tristate "LED Support for GPIO connected LEDs"
depends on LEDS_CLASS
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
This option enables support for the LEDs connected to GPIO
outputs. To be useful the particular board must have LEDs
......@@ -203,6 +229,7 @@ config LEDS_LP55XX_COMMON
tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501
select FW_LOADER
select FW_LOADER_USER_HELPER_FALLBACK
help
This option supports common operations for LP5521/5523/55231/5562/8501
devices.
......@@ -464,6 +491,25 @@ config LEDS_TCA6507
LED driver chips accessed via the I2C bus.
Driver support brightness control and hardware-assisted blinking.
config LEDS_TLC591XX
tristate "LED driver for TLC59108 and TLC59116 controllers"
depends on LEDS_CLASS && I2C
select REGMAP_I2C
help
This option enables support for Texas Instruments TLC59108
and TLC59116 LED controllers.
config LEDS_MAX77693
tristate "LED support for MAX77693 Flash"
depends on LEDS_CLASS_FLASH
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
depends on MFD_MAX77693
depends on OF
help
This option enables support for the flash part of the MAX77693
multifunction device. It has build in control for two leds in flash
and torch mode.
config LEDS_MAX8997
tristate "LED support for MAX8997 PMIC"
depends on LEDS_CLASS && MFD_MAX8997
......@@ -495,6 +541,15 @@ config LEDS_MENF21BMC
This driver can also be built as a module. If so the module
will be called leds-menf21bmc.
config LEDS_KTD2692
tristate "LED support for KTD2692 flash LED controller"
depends on LEDS_CLASS_FLASH && GPIOLIB && OF
help
This option enables support for KTD2692 LED flash connected
through ExpressWire interface.
Say Y to enable this driver.
comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
config LEDS_BLINKM
......
......@@ -7,6 +7,9 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers
obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
......@@ -31,6 +34,7 @@ obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o
obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
......@@ -52,6 +56,7 @@ obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o
......@@ -59,6 +64,7 @@ obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o
obj-$(CONFIG_LEDS_VERSATILE) += leds-versatile.o
obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o
obj-$(CONFIG_LEDS_PM8941_WLED) += leds-pm8941-wled.o
obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
......
......@@ -121,6 +121,11 @@ static void led_timer_function(unsigned long data)
brightness = led_get_brightness(led_cdev);
if (!brightness) {
/* Time to switch the LED on. */
if (led_cdev->delayed_set_value) {
led_cdev->blink_brightness =
led_cdev->delayed_set_value;
led_cdev->delayed_set_value = 0;
}
brightness = led_cdev->blink_brightness;
delay = led_cdev->blink_delay_on;
} else {
......
......@@ -119,9 +119,10 @@ void led_set_brightness(struct led_classdev *led_cdev,
{
int ret = 0;
/* delay brightness setting if need to stop soft-blink timer */
/* delay brightness if soft-blink is active */
if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
led_cdev->delayed_set_value = brightness;
if (brightness == LED_OFF)
schedule_work(&led_cdev->set_brightness_work);
return;
}
......
This diff is collapsed.
This diff is collapsed.
/*
* Driver for BCM6358 memory-mapped LEDs, based on leds-syscon.c
*
* Copyright 2015 Álvaro Fernández Rojas <noltari@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#define BCM6358_REG_MODE 0x0
#define BCM6358_REG_CTRL 0x4
#define BCM6358_SLED_CLKDIV_MASK 3
#define BCM6358_SLED_CLKDIV_1 0
#define BCM6358_SLED_CLKDIV_2 1
#define BCM6358_SLED_CLKDIV_4 2
#define BCM6358_SLED_CLKDIV_8 3
#define BCM6358_SLED_POLARITY BIT(2)
#define BCM6358_SLED_BUSY BIT(3)
#define BCM6358_SLED_MAX_COUNT 32
#define BCM6358_SLED_WAIT 100
/**
* struct bcm6358_led - state container for bcm6358 based LEDs
* @cdev: LED class device for this LED
* @mem: memory resource
* @lock: memory lock
* @pin: LED pin number
* @active_low: LED is active low
*/
struct bcm6358_led {
struct led_classdev cdev;
void __iomem *mem;
spinlock_t *lock;
unsigned long pin;
bool active_low;
};
static void bcm6358_led_write(void __iomem *reg, unsigned long data)
{
iowrite32be(data, reg);
}
static unsigned long bcm6358_led_read(void __iomem *reg)
{
return ioread32be(reg);
}
static unsigned long bcm6358_led_busy(void __iomem *mem)
{
unsigned long val;
while ((val = bcm6358_led_read(mem + BCM6358_REG_CTRL)) &
BCM6358_SLED_BUSY)
udelay(BCM6358_SLED_WAIT);
return val;
}
static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value)
{
unsigned long val;
bcm6358_led_busy(led->mem);
val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
if ((led->active_low && value == LED_OFF) ||
(!led->active_low && value != LED_OFF))
val |= BIT(led->pin);
else
val &= ~(BIT(led->pin));
bcm6358_led_write(led->mem + BCM6358_REG_MODE, val);
}
static void bcm6358_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct bcm6358_led *led =
container_of(led_cdev, struct bcm6358_led, cdev);
unsigned long flags;
spin_lock_irqsave(led->lock, flags);
bcm6358_led_mode(led, value);
spin_unlock_irqrestore(led->lock, flags);
}
static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
void __iomem *mem, spinlock_t *lock)
{
struct bcm6358_led *led;
unsigned long flags;
const char *state;
int rc;
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
led->pin = reg;
led->mem = mem;
led->lock = lock;
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);
spin_lock_irqsave(lock, flags);
if (!of_property_read_string(nc, "default-state", &state)) {
if (!strcmp(state, "on")) {
led->cdev.brightness = LED_FULL;
} else if (!strcmp(state, "keep")) {
unsigned long val;
bcm6358_led_busy(led->mem);
val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
val &= BIT(led->pin);
if ((led->active_low && !val) ||
(!led->active_low && val))
led->cdev.brightness = LED_FULL;
else
led->cdev.brightness = LED_OFF;
} else {
led->cdev.brightness = LED_OFF;
}
} else {
led->cdev.brightness = LED_OFF;
}
bcm6358_led_mode(led, led->cdev.brightness);
spin_unlock_irqrestore(lock, flags);
led->cdev.brightness_set = bcm6358_led_set;
rc = led_classdev_register(dev, &led->cdev);
if (rc < 0)
return rc;
dev_dbg(dev, "registered LED %s\n", led->cdev.name);
return 0;
}
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);
if (IS_ERR(mem))
return PTR_ERR(mem);
lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
if (!lock)
return -ENOMEM;
spin_lock_init(lock);
val = bcm6358_led_busy(mem);
val &= ~(BCM6358_SLED_POLARITY | BCM6358_SLED_CLKDIV_MASK);
if (of_property_read_bool(np, "brcm,clk-dat-low"))
val |= BCM6358_SLED_POLARITY;
of_property_read_u32(np, "brcm,clk-div", &clk_div);
switch (clk_div) {
case 8:
val |= BCM6358_SLED_CLKDIV_8;
break;
case 4:
val |= BCM6358_SLED_CLKDIV_4;
break;
case 2:
val |= BCM6358_SLED_CLKDIV_2;
break;
default:
val |= BCM6358_SLED_CLKDIV_1;
break;
}
bcm6358_led_write(mem + BCM6358_REG_CTRL, val);
for_each_available_child_of_node(np, child) {
int rc;
u32 reg;
if (of_property_read_u32(child, "reg", &reg))
continue;
if (reg >= BCM6358_SLED_MAX_COUNT) {
dev_err(dev, "invalid LED (%u >= %d)\n", reg,
BCM6358_SLED_MAX_COUNT);
continue;
}
rc = bcm6358_led(dev, child, reg, mem, lock);
if (rc < 0)
return rc;
}
return 0;
}
static const struct of_device_id bcm6358_leds_of_match[] = {
{ .compatible = "brcm,bcm6358-leds", },
{ },
};
static struct platform_driver bcm6358_leds_driver = {
.probe = bcm6358_leds_probe,
.driver = {
.name = "leds-bcm6358",
.of_match_table = bcm6358_leds_of_match,
},
};
module_platform_driver(bcm6358_leds_driver);
MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>");
MODULE_DESCRIPTION("LED driver for BCM6358 controllers");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:leds-bcm6358");
......@@ -108,20 +108,8 @@ static int cobalt_raq_led_probe(struct platform_device *pdev)
return retval;
}
static int cobalt_raq_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&raq_power_off_led);
led_classdev_unregister(&raq_web_led);
if (led_port)
led_port = NULL;
return 0;
}
static struct platform_driver cobalt_raq_led_driver = {
.probe = cobalt_raq_led_probe,
.remove = cobalt_raq_led_remove,
.driver = {
.name = "cobalt-raq-leds",
},
......@@ -131,5 +119,4 @@ static int __init cobalt_raq_led_init(void)
{
return platform_driver_register(&cobalt_raq_led_driver);
}
module_init(cobalt_raq_led_init);
device_initcall(cobalt_raq_led_init);
......@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
......@@ -198,8 +199,10 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
} else {
if (IS_ENABLED(CONFIG_OF) && !led.name && np)
led.name = np->name;
if (!led.name)
return ERR_PTR(-EINVAL);
if (!led.name) {
ret = -EINVAL;
goto err;
}
}
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
......@@ -217,18 +220,19 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
if (fwnode_property_present(child, "retain-state-suspended"))
led.retain_state_suspended = 1;
ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
ret = create_gpio_led(&led, &priv->leds[priv->num_leds],
dev, NULL);
if (ret < 0) {
fwnode_handle_put(child);
goto err;
}
priv->num_leds++;
}
return priv;
err:
for (count = priv->num_leds - 2; count >= 0; count--)
for (count = priv->num_leds - 1; count >= 0; count--)
delete_gpio_led(&priv->leds[count]);
return ERR_PTR(ret);
}
......
This diff is collapsed.
......@@ -50,6 +50,7 @@
#define LP5523_REG_OP_MODE 0x01
#define LP5523_REG_ENABLE_LEDS_MSB 0x04
#define LP5523_REG_ENABLE_LEDS_LSB 0x05
#define LP5523_REG_LED_CTRL_BASE 0x06
#define LP5523_REG_LED_PWM_BASE 0x16
#define LP5523_REG_LED_CURRENT_BASE 0x26
#define LP5523_REG_CONFIG 0x36
......@@ -57,6 +58,7 @@
#define LP5523_REG_RESET 0x3D
#define LP5523_REG_LED_TEST_CTRL 0x41
#define LP5523_REG_LED_TEST_ADC 0x42
#define LP5523_REG_MASTER_FADER_BASE 0x48
#define LP5523_REG_CH1_PROG_START 0x4C
#define LP5523_REG_CH2_PROG_START 0x4D
#define LP5523_REG_CH3_PROG_START 0x4E
......@@ -78,6 +80,9 @@
#define LP5523_EXT_CLK_USED 0x08
#define LP5523_ENG_STATUS_MASK 0x07
#define LP5523_FADER_MAPPING_MASK 0xC0
#define LP5523_FADER_MAPPING_SHIFT 6
/* Memory Page Selection */
#define LP5523_PAGE_ENG1 0
#define LP5523_PAGE_ENG2 1
......@@ -666,6 +671,137 @@ static ssize_t lp5523_selftest(struct device *dev,
return pos;
}
#define show_fader(nr) \
static ssize_t show_master_fader##nr(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
return show_master_fader(dev, attr, buf, nr); \
}
#define store_fader(nr) \
static ssize_t store_master_fader##nr(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t len) \
{ \
return store_master_fader(dev, attr, buf, len, nr); \
}
static ssize_t show_master_fader(struct device *dev,
struct device_attribute *attr,
char *buf, int nr)
{
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
struct lp55xx_chip *chip = led->chip;
int ret;
u8 val;
mutex_lock(&chip->lock);
ret = lp55xx_read(chip, LP5523_REG_MASTER_FADER_BASE + nr - 1, &val);
mutex_unlock(&chip->lock);
if (ret == 0)
ret = sprintf(buf, "%u\n", val);
return ret;
}
show_fader(1)
show_fader(2)
show_fader(3)
static ssize_t store_master_fader(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len, int nr)
{
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
struct lp55xx_chip *chip = led->chip;
int ret;
unsigned long val;
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val > 0xff)
return -EINVAL;
mutex_lock(&chip->lock);
ret = lp55xx_write(chip, LP5523_REG_MASTER_FADER_BASE + nr - 1,
(u8)val);
mutex_unlock(&chip->lock);
if (ret == 0)
ret = len;
return ret;
}
store_fader(1)
store_fader(2)
store_fader(3)
static ssize_t show_master_fader_leds(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
struct lp55xx_chip *chip = led->chip;
int i, ret, pos = 0;
u8 val;
mutex_lock(&chip->lock);
for (i = 0; i < LP5523_MAX_LEDS; i++) {
ret = lp55xx_read(chip, LP5523_REG_LED_CTRL_BASE + i, &val);
if (ret)
goto leave;
val = (val & LP5523_FADER_MAPPING_MASK)
>> LP5523_FADER_MAPPING_SHIFT;
if (val > 3) {
ret = -EINVAL;
goto leave;
}
buf[pos++] = val + '0';
}
buf[pos++] = '\n';
ret = pos;
leave:
mutex_unlock(&chip->lock);
return ret;
}
static ssize_t store_master_fader_leds(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
struct lp55xx_chip *chip = led->chip;
int i, n, ret;
u8 val;
n = min_t(int, len, LP5523_MAX_LEDS);
mutex_lock(&chip->lock);
for (i = 0; i < n; i++) {
if (buf[i] >= '0' && buf[i] <= '3') {
val = (buf[i] - '0') << LP5523_FADER_MAPPING_SHIFT;
ret = lp55xx_update_bits(chip,
LP5523_REG_LED_CTRL_BASE + i,
LP5523_FADER_MAPPING_MASK,
val);
if (ret)
goto leave;
} else {
ret = -EINVAL;
goto leave;
}
}
ret = len;
leave:
mutex_unlock(&chip->lock);
return ret;
}
static void lp5523_led_brightness_work(struct work_struct *work)
{
struct lp55xx_led *led = container_of(work, struct lp55xx_led,
......@@ -688,6 +824,14 @@ static LP55XX_DEV_ATTR_WO(engine1_load, store_engine1_load);
static LP55XX_DEV_ATTR_WO(engine2_load, store_engine2_load);
static LP55XX_DEV_ATTR_WO(engine3_load, store_engine3_load);
static LP55XX_DEV_ATTR_RO(selftest, lp5523_selftest);
static LP55XX_DEV_ATTR_RW(master_fader1, show_master_fader1,
store_master_fader1);
static LP55XX_DEV_ATTR_RW(master_fader2, show_master_fader2,
store_master_fader2);
static LP55XX_DEV_ATTR_RW(master_fader3, show_master_fader3,
store_master_fader3);
static LP55XX_DEV_ATTR_RW(master_fader_leds, show_master_fader_leds,
store_master_fader_leds);
static struct attribute *lp5523_attributes[] = {
&dev_attr_engine1_mode.attr,
......@@ -700,6 +844,10 @@ static struct attribute *lp5523_attributes[] = {
&dev_attr_engine2_leds.attr,
&dev_attr_engine3_leds.attr,
&dev_attr_selftest.attr,
&dev_attr_master_fader1.attr,
&dev_attr_master_fader2.attr,
&dev_attr_master_fader3.attr,
&dev_attr_master_fader_leds.attr,
NULL,
};
......
......@@ -223,7 +223,7 @@ static int lp55xx_request_firmware(struct lp55xx_chip *chip)
const char *name = chip->cl->name;
struct device *dev = &chip->cl->dev;
return request_firmware_nowait(THIS_MODULE, true, name, dev,
return request_firmware_nowait(THIS_MODULE, false, name, dev,
GFP_KERNEL, chip, lp55xx_firmware_loaded);
}
......
This diff is collapsed.
/*
* Copyright 2014 Belkin Inc.
* Copyright 2015 Andrew Lunn <andrew@lunn.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#define TLC591XX_MAX_LEDS 16
#define TLC591XX_REG_MODE1 0x00
#define MODE1_RESPON_ADDR_MASK 0xF0
#define MODE1_NORMAL_MODE (0 << 4)
#define MODE1_SPEED_MODE (1 << 4)
#define TLC591XX_REG_MODE2 0x01
#define MODE2_DIM (0 << 5)
#define MODE2_BLINK (1 << 5)
#define MODE2_OCH_STOP (0 << 3)
#define MODE2_OCH_ACK (1 << 3)
#define TLC591XX_REG_PWM(x) (0x02 + (x))
#define TLC591XX_REG_GRPPWM 0x12
#define TLC591XX_REG_GRPFREQ 0x13
/* LED Driver Output State, determine the source that drives LED outputs */
#define LEDOUT_OFF 0x0 /* Output LOW */
#define LEDOUT_ON 0x1 /* Output HI-Z */
#define LEDOUT_DIM 0x2 /* Dimming */
#define LEDOUT_BLINK 0x3 /* Blinking */
#define LEDOUT_MASK 0x3
#define ldev_to_led(c) container_of(c, struct tlc591xx_led, ldev)
#define work_to_led(work) container_of(work, struct tlc591xx_led, work)
struct tlc591xx_led {
bool active;
unsigned int led_no;
struct led_classdev ldev;
struct work_struct work;
struct tlc591xx_priv *priv;
};
struct tlc591xx_priv {
struct tlc591xx_led leds[TLC591XX_MAX_LEDS];
struct regmap *regmap;
unsigned int reg_ledout_offset;
};
struct tlc591xx {
unsigned int max_leds;
unsigned int reg_ledout_offset;
};
static const struct tlc591xx tlc59116 = {
.max_leds = 16,
.reg_ledout_offset = 0x14,
};
static const struct tlc591xx tlc59108 = {
.max_leds = 8,
.reg_ledout_offset = 0x0c,
};
static int
tlc591xx_set_mode(struct regmap *regmap, u8 mode)
{
int err;
u8 val;
err = regmap_write(regmap, TLC591XX_REG_MODE1, MODE1_NORMAL_MODE);
if (err)
return err;
val = MODE2_OCH_STOP | mode;
return regmap_write(regmap, TLC591XX_REG_MODE2, val);
}
static int
tlc591xx_set_ledout(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
u8 val)
{
unsigned int i = (led->led_no % 4) * 2;
unsigned int mask = LEDOUT_MASK << i;
unsigned int addr = priv->reg_ledout_offset + (led->led_no >> 2);
val = val << i;
return regmap_update_bits(priv->regmap, addr, mask, val);
}
static int
tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
u8 brightness)
{
u8 pwm = TLC591XX_REG_PWM(led->led_no);
return regmap_write(priv->regmap, pwm, brightness);
}
static void
tlc591xx_led_work(struct work_struct *work)
{
struct tlc591xx_led *led = work_to_led(work);
struct tlc591xx_priv *priv = led->priv;
enum led_brightness brightness = led->ldev.brightness;
int err;
switch (brightness) {
case 0:
err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF);
break;
case LED_FULL:
err = tlc591xx_set_ledout(priv, led, LEDOUT_ON);
break;
default:
err = tlc591xx_set_ledout(priv, led, LEDOUT_DIM);
if (!err)
err = tlc591xx_set_pwm(priv, led, brightness);
}
if (err)
dev_err(led->ldev.dev, "Failed setting brightness\n");
}
static void
tlc591xx_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct tlc591xx_led *led = ldev_to_led(led_cdev);
led->ldev.brightness = brightness;
schedule_work(&led->work);
}
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);
cancel_work_sync(&priv->leds[i].work);
}
}
}
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 = tlc591xx_brightness_set;
led->ldev.max_brightness = LED_FULL;
INIT_WORK(&led->work, tlc591xx_led_work);
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,
.max_register = 0x1e,
};
static const struct of_device_id of_tlc591xx_leds_match[] = {
{ .compatible = "ti,tlc59116",
.data = &tlc59116 },
{ .compatible = "ti,tlc59108",
.data = &tlc59108 },
{},
};
MODULE_DEVICE_TABLE(of, of_tlc591xx_leds_match);
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 *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;
if (!np)
return -ENODEV;
count = of_get_child_count(np);
if (!count || count > tlc591xx->max_leds)
return -EINVAL;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->regmap = devm_regmap_init_i2c(client, &tlc591xx_regmap);
if (IS_ERR(priv->regmap)) {
err = PTR_ERR(priv->regmap);
dev_err(dev, "Failed to allocate register map: %d\n", err);
return err;
}
priv->reg_ledout_offset = tlc591xx->reg_ledout_offset;
i2c_set_clientdata(client, priv);
for_each_child_of_node(np, child) {
err = of_property_read_u32(child, "reg", &reg);
if (err)
return err;
if (reg < 0 || reg >= tlc591xx->max_leds)
return -EINVAL;
if (priv->leds[reg].active)
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 =
of_get_property(child, "linux,default-trigger", NULL);
}
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;
}
static const struct i2c_device_id tlc591xx_id[] = {
{ "tlc59116" },
{ "tlc59108" },
{},
};
MODULE_DEVICE_TABLE(i2c, tlc591xx_id);
static struct i2c_driver tlc591xx_driver = {
.driver = {
.name = "tlc591xx",
.of_match_table = of_match_ptr(of_tlc591xx_leds_match),
},
.probe = tlc591xx_probe,
.remove = tlc591xx_remove,
.id_table = tlc591xx_id,
};
module_i2c_driver(tlc591xx_driver);
MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TLC591XX LED driver");
......@@ -13,7 +13,6 @@
#ifndef __LEDS_H_INCLUDED
#define __LEDS_H_INCLUDED
#include <linux/device.h>
#include <linux/rwsem.h>
#include <linux/leds.h>
......@@ -50,27 +49,4 @@ void led_stop_software_blink(struct led_classdev *led_cdev);
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
#ifdef CONFIG_LEDS_TRIGGERS
void led_trigger_set_default(struct led_classdev *led_cdev);
void 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_get_trigger_data(struct led_classdev *led_cdev)
{
return led_cdev->trigger_data;
}
#else
#define led_trigger_set_default(x) do {} while (0)
#define led_trigger_set(x, y) do {} while (0)
#define led_trigger_remove(x) do {} while (0)
#define led_get_trigger_data(x) (NULL)
#endif
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);
#endif /* __LEDS_H_INCLUDED */
......@@ -44,6 +44,17 @@ config V4L2_MEM2MEM_DEV
tristate
depends on VIDEOBUF2_CORE
# Used by LED subsystem flash drivers
config V4L2_FLASH_LED_CLASS
tristate "V4L2 flash API for LED flash class devices"
depends on VIDEO_V4L2_SUBDEV_API
depends on LEDS_CLASS_FLASH
---help---
Say Y here to enable V4L2 flash API support for LED flash
class drivers.
When in doubt, say N.
# Used by drivers that need Videobuf modules
config VIDEOBUF_GEN
tristate
......
......@@ -22,6 +22,8 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
......
......@@ -22,10 +22,10 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
static bool match_i2c(struct device *dev, struct v4l2_async_subdev *asd)
static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
{
#if IS_ENABLED(CONFIG_I2C)
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_client *client = i2c_verify_client(sd->dev);
return client &&
asd->match.i2c.adapter_id == client->adapter->nr &&
asd->match.i2c.address == client->addr;
......@@ -34,14 +34,24 @@ static bool match_i2c(struct device *dev, struct v4l2_async_subdev *asd)
#endif
}
static bool match_devname(struct device *dev, struct v4l2_async_subdev *asd)
static bool match_devname(struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
{
return !strcmp(asd->match.device_name.name, dev_name(sd->dev));
}
static bool match_of(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
{
return !strcmp(asd->match.device_name.name, dev_name(dev));
return sd->of_node == asd->match.of.node;
}
static bool match_of(struct device *dev, struct v4l2_async_subdev *asd)
static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
{
return dev->of_node == asd->match.of.node;
if (!asd->match.custom.match)
/* Match always */
return true;
return asd->match.custom.match(sd->dev, asd);
}
static LIST_HEAD(subdev_list);
......@@ -51,17 +61,14 @@ static DEFINE_MUTEX(list_lock);
static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd)
{
bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
struct v4l2_async_subdev *asd;
bool (*match)(struct device *, struct v4l2_async_subdev *);
list_for_each_entry(asd, &notifier->waiting, list) {
/* bus_type has been verified valid before */
switch (asd->match_type) {
case V4L2_ASYNC_MATCH_CUSTOM:
match = asd->match.custom.match;
if (!match)
/* Match always */
return asd;
match = match_custom;
break;
case V4L2_ASYNC_MATCH_DEVNAME:
match = match_devname;
......@@ -79,7 +86,7 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
}
/* match cannot be NULL here */
if (match(sd->dev, asd))
if (match(sd, asd))
return asd;
}
......@@ -266,6 +273,14 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *notifier;
/*
* No reference taken. The reference is held by the device
* (struct v4l2_subdev.dev), and async sub-device does not
* exist independently of the device at any point of time.
*/
if (!sd->of_node && sd->dev)
sd->of_node = sd->dev->of_node;
mutex_lock(&list_lock);
INIT_LIST_HEAD(&sd->async_list);
......
This diff is collapsed.
......@@ -407,6 +407,21 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
return -EINVAL;
}
/* Child properties interface */
struct fwnode_handle;
static inline struct gpio_desc *fwnode_get_named_gpiod(
struct fwnode_handle *fwnode, const char *propname)
{
return ERR_PTR(-ENOSYS);
}
static inline struct gpio_desc *devm_get_gpiod_from_child(
struct device *dev, const char *con_id, struct fwnode_handle *child)
{
return ERR_PTR(-ENOSYS);
}
#endif /* CONFIG_GPIOLIB */
/*
......
......@@ -12,6 +12,7 @@
#ifndef __LINUX_LEDS_H_INCLUDED
#define __LINUX_LEDS_H_INCLUDED
#include <linux/device.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
......@@ -222,6 +223,11 @@ struct led_trigger {
struct list_head next_trig;
};
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);
......@@ -238,6 +244,16 @@ 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 void led_trigger_set(struct led_classdev *led_cdev,
struct led_trigger *trigger);
extern void led_trigger_remove(struct led_classdev *led_cdev);
static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
{
return led_cdev->trigger_data;
}
/**
* led_trigger_rename_static - rename a trigger
* @name: the new trigger name
......@@ -267,6 +283,15 @@ static inline void led_trigger_register_simple(const char *name,
static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {}
static inline void led_trigger_event(struct led_trigger *trigger,
enum led_brightness event) {}
static inline void led_trigger_set_default(struct led_classdev *led_cdev) {}
static inline void led_trigger_set(struct led_classdev *led_cdev,
struct led_trigger *trigger) {}
static inline void led_trigger_remove(struct led_classdev *led_cdev) {}
static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
{
return NULL;
}
#endif /* CONFIG_LEDS_TRIGGERS */
/* Trigger specific functions */
......
/*
* V4L2 flash LED sub-device registration helpers.
*
* 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 _V4L2_FLASH_H
#define _V4L2_FLASH_H
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
struct led_classdev_flash;
struct led_classdev;
struct v4l2_flash;
enum led_brightness;
/*
* struct v4l2_flash_ctrl_data - flash control initialization data, filled
* basing on the features declared by the LED flash
* class driver in the v4l2_flash_config
* @config: initialization data for a control
* @cid: contains v4l2 flash control id if the config
* field was initialized, 0 otherwise
*/
struct v4l2_flash_ctrl_data {
struct v4l2_ctrl_config config;
u32 cid;
};
struct v4l2_flash_ops {
/* setup strobing the flash by hardware pin state assertion */
int (*external_strobe_set)(struct v4l2_flash *v4l2_flash,
bool enable);
/* convert intensity to brightness in a device specific manner */
enum led_brightness (*intensity_to_led_brightness)
(struct v4l2_flash *v4l2_flash, s32 intensity);
/* convert brightness to intensity in a device specific manner */
s32 (*led_brightness_to_intensity)
(struct v4l2_flash *v4l2_flash, enum led_brightness);
};
/**
* struct v4l2_flash_config - V4L2 Flash sub-device initialization data
* @dev_name: the name of the media entity,
unique in the system
* @torch_intensity: constraints for the LED in torch mode
* @indicator_intensity: constraints for the indicator LED
* @flash_faults: bitmask of flash faults that the LED flash class
device can report; corresponding LED_FAULT* bit
definitions are available in the header file
<linux/led-class-flash.h>
* @has_external_strobe: external strobe capability
*/
struct v4l2_flash_config {
char dev_name[32];
struct led_flash_setting torch_intensity;
struct led_flash_setting indicator_intensity;
u32 flash_faults;
unsigned int has_external_strobe:1;
};
/**
* struct v4l2_flash - Flash sub-device context
* @fled_cdev: LED flash class device controlled by this sub-device
* @iled_cdev: LED class device representing indicator LED associated
* with the LED flash class device
* @ops: V4L2 specific flash ops
* @sd: V4L2 sub-device
* @hdl: flash controls handler
* @ctrls: array of pointers to controls, whose values define
* the sub-device state
*/
struct v4l2_flash {
struct led_classdev_flash *fled_cdev;
struct led_classdev_flash *iled_cdev;
const struct v4l2_flash_ops *ops;
struct v4l2_subdev sd;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl **ctrls;
};
static inline struct v4l2_flash *v4l2_subdev_to_v4l2_flash(
struct v4l2_subdev *sd)
{
return container_of(sd, struct v4l2_flash, sd);
}
static inline struct v4l2_flash *v4l2_ctrl_to_v4l2_flash(struct v4l2_ctrl *c)
{
return container_of(c->handler, struct v4l2_flash, hdl);
}
#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
/**
* v4l2_flash_init - initialize V4L2 flash led sub-device
* @dev: flash device, e.g. an I2C device
* @of_node: of_node of the LED, may be NULL if the same as device's
* @fled_cdev: LED flash class device to wrap
* @iled_cdev: LED flash class device representing indicator LED associated
* with fled_cdev, may be NULL
* @flash_ops: V4L2 Flash device ops
* @config: initialization data for V4L2 Flash sub-device
*
* Create V4L2 Flash sub-device wrapping given LED subsystem device.
*
* Returns: A valid pointer, or, when an error occurs, the return
* value is encoded using ERR_PTR(). Use IS_ERR() to check and
* PTR_ERR() to obtain the numeric return value.
*/
struct v4l2_flash *v4l2_flash_init(
struct device *dev, struct device_node *of_node,
struct led_classdev_flash *fled_cdev,
struct led_classdev_flash *iled_cdev,
const struct v4l2_flash_ops *ops,
struct v4l2_flash_config *config);
/**
* v4l2_flash_release - release V4L2 Flash sub-device
* @flash: the V4L2 Flash sub-device to release
*
* Release V4L2 Flash sub-device.
*/
void v4l2_flash_release(struct v4l2_flash *v4l2_flash);
#else
static inline struct v4l2_flash *v4l2_flash_init(
struct device *dev, struct device_node *of_node,
struct led_classdev_flash *fled_cdev,
struct led_classdev_flash *iled_cdev,
const struct v4l2_flash_ops *ops,
struct v4l2_flash_config *config)
{
return NULL;
}
static inline void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
{
}
#endif /* CONFIG_V4L2_FLASH_LED_CLASS */
#endif /* _V4L2_FLASH_H */
......@@ -605,6 +605,8 @@ struct v4l2_subdev {
struct video_device *devnode;
/* pointer to the physical device, if any */
struct device *dev;
/* The device_node of the subdev, usually the same as dev->of_node. */
struct device_node *of_node;
/* Links this subdev to a global subdev_list or @notifier->done list. */
struct list_head async_list;
/* Pointer to respective struct v4l2_async_subdev. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment