LED updates for 5.2-rc1.

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQUwxxKyE5l/npt8ARiEGxRG/Sl2wUCXNHNRQAKCRBiEGxRG/Sl
 26r7AP0QapMWbN0YFvn5/TzIrkMBxz4ZXpWmCWtzpIkJRldAOAEAuhw8HgXPXZOQ
 cn4VO+1zq5VBvJW+QqjqRXr0G6DaYAw=
 =UVPc
 -----END PGP SIGNATURE-----

Merge tag 'leds-for-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds

Pull LED updates from Jacek Anaszewski:
 "LED core fixes and improvements:

      - avoid races with workqueue
      - Kconfig: pedantic cleanup
      - small fixes for Flash class description

  leds-lt3593:

      - remove unneeded assignment in lt3593_led_probe
      - drop pdata handling code

  leds-blinkm:

      - clean up double assignment to data->i2c_addr

  leds-pca955x, leds-pca963x:

      - revert ACPI support, as it turned out that there is no evidence
          of officially registered ACPI IDs for these devices.
      - make use of device property API

  leds-as3645a:

      - switch to fwnode property API

  LED related addition to ACPI documentation:

      - document how to refer to LEDs from remote nodes

  LED related fix to ALSA line6/toneport driver:

      - avoid polluting led_* namespace

  And lm3532 driver relocation from MFD to LED subsystem, accompanied by
  various improvements and optimizations; it entails also a change in
  omap4-droid4-xt894.dts:

      - leds: lm3532: Introduce the lm3532 LED driver
      - mfd: ti-lmu: Remove LM3532 backlight driver references
      - ARM: dts: omap4-droid4: Update backlight dt properties
      - dt: lm3532: Add lm3532 dt doc and update ti_lmu doc"

* tag 'leds-for-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds:
  leds: avoid races with workqueue
  ALSA: line6: Avoid polluting led_* namespace
  leds: lm3532: Introduce the lm3532 LED driver
  mfd: ti-lmu: Remove LM3532 backlight driver references
  ARM: dts: omap4-droid4: Update backlight dt properties
  dt: lm3532: Add lm3532 dt doc and update ti_lmu doc
  leds: Small fixes for Flash class description
  leds: blinkm: clean up double assignment to data->i2c_addr
  leds: pca963x: Make use of device property API
  leds: pca955x: Make use of device property API
  leds: lt3593: Remove unneeded assignment in lt3593_led_probe
  leds: lt3593: drop pdata handling code
  leds: pca955x: Revert "Add ACPI support"
  leds: pca963x: Revert "Add ACPI support"
  drivers: leds: Kconfig: pedantic cleanups
  ACPI: Document how to refer to LEDs from remote nodes
  leds: as3645a: Switch to fwnode property API
This commit is contained in:
Linus Torvalds 2019-05-07 18:02:51 -07:00
commit 8b35ad6232
18 changed files with 1023 additions and 292 deletions

View File

@ -0,0 +1,99 @@
Describing and referring to LEDs in ACPI
Individual LEDs are described by hierarchical data extension [6] nodes under the
device node, the LED driver chip. The "reg" property in the LED specific nodes
tells the numerical ID of each individual LED output to which the LEDs are
connected. [3] The hierarchical data nodes are named "led@X", where X is the
number of the LED output.
Referring to LEDs in Device tree is documented in [4], in "flash-leds" property
documentation. In short, LEDs are directly referred to by using phandles.
While Device tree allows referring to any node in the tree[1], in ACPI
references are limited to device nodes only [2]. For this reason using the same
mechanism on ACPI is not possible. A mechanism to refer to non-device ACPI nodes
is documented in [7].
ACPI allows (as does DT) using integer arguments after the reference. A
combination of the LED driver device reference and an integer argument,
referring to the "reg" property of the relevant LED, is used to identify
individual LEDs. The value of the "reg" property is a contract between the
firmware and software, it uniquely identifies the LED driver outputs.
Under the LED driver device, The first hierarchical data extension package list
entry shall contain the string "led@" followed by the number of the LED,
followed by the referred object name. That object shall be named "LED" followed
by the number of the LED.
An ASL example of a camera sensor device and a LED driver device for two LEDs.
Objects not relevant for LEDs or the references to them have been omitted.
Device (LED)
{
Name (_DSD, Package () {
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "led@0", LED0 },
Package () { "led@1", LED1 },
}
})
Name (LED0, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "reg", 0 },
Package () { "flash-max-microamp", 1000000 },
Package () { "flash-timeout-us", 200000 },
Package () { "led-max-microamp", 100000 },
Package () { "label", "white:flash" },
}
})
Name (LED1, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "reg", 1 },
Package () { "led-max-microamp", 10000 },
Package () { "label", "red:indicator" },
}
})
}
Device (SEN)
{
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {
"flash-leds",
Package () { ^LED, "led@0", ^LED, "led@1" },
}
}
})
}
where
LED LED driver device
LED0 First LED
LED1 Second LED
SEN Camera sensor device (or another device the LED is
related to)
[1] Device tree. <URL:http://www.devicetree.org>, referenced 2019-02-21.
[2] Advanced Configuration and Power Interface Specification.
<URL:https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf>,
referenced 2019-02-21.
[3] Documentation/devicetree/bindings/leds/common.txt
[4] Documentation/devicetree/bindings/media/video-interfaces.txt
[5] Device Properties UUID For _DSD.
<URL:http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf>,
referenced 2019-02-21.
[6] Hierarchical Data Extension UUID For _DSD.
<URL:http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf>,
referenced 2019-02-21.
[7] Documentation/acpi/dsd/data-node-reference.txt

View File

@ -0,0 +1,101 @@
* Texas Instruments - lm3532 White LED driver with ambient light sensing
capability.
The LM3532 provides the 3 high-voltage, low-side current sinks. The device is
programmable over an I2C-compatible interface and has independent
current control for all three channels. The adaptive current regulation
method allows for different LED currents in each current sink thus allowing
for a wide variety of backlight and keypad applications.
The main features of the LM3532 include dual ambient light sensor inputs
each with 32 internal voltage setting resistors, 8-bit logarithmic and linear
brightness control, dual external PWM brightness control inputs, and up to
1000:1 dimming ratio with programmable fade in and fade out settings.
Required properties:
- compatible : "ti,lm3532"
- reg : I2C slave address
- #address-cells : 1
- #size-cells : 0
Optional properties:
- enable-gpios : gpio pin to enable (active high)/disable the device.
- ramp-up-us - The Run time ramp rates/step are from one current
set-point to another after the device has reached its
initial target set point from turn-on
- ramp-down-us - The Run time ramp rates/step are from one current
set-point to another after the device has reached its
initial target set point from turn-on
Range for ramp settings: 8us - 65536us
Optional properties if ALS mode is used:
- ti,als-vmin - Minimum ALS voltage defined in Volts
- ti,als-vmax - Maximum ALS voltage defined in Volts
Per the data sheet the max ALS voltage is 2V and the min is 0V
- ti,als1-imp-sel - ALS1 impedance resistor selection in Ohms
- ti,als2-imp-sel - ALS2 impedance resistor selection in Ohms
Range for impedance select: 37000 Ohms - 1190 Ohms
Values above 37kohms will be set to the "High Impedance" setting
- ti,als-avrg-time-us - Determines the length of time the device needs to
average the two ALS inputs. This is only used if
the input mode is LM3532_ALS_INPUT_AVRG.
Range: 17920us - 2293760us
- ti,als-input-mode - Determines how the device uses the attached ALS
devices.
0x00 - ALS1 and ALS2 input average
0x01 - ALS1 Input
0x02 - ALS2 Input
0x03 - Max of ALS1 and ALS2
Required child properties:
- reg : Indicates control bank the LED string is controlled by
- led-sources : see Documentation/devicetree/bindings/leds/common.txt
- ti,led-mode : Defines if the LED strings are manually controlled or
if the LED strings are controlled by the ALS.
0x00 - LED strings are I2C controlled via full scale
brightness control register
0x01 - LED strings are ALS controlled
Optional LED child properties:
- label : see Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger :
see Documentation/devicetree/bindings/leds/common.txt
Example:
led-controller@38 {
compatible = "ti,lm3532";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x38>;
enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
ramp-up-us = <1024>;
ramp-down-us = <65536>;
ti,als-vmin = <0>;
ti,als-vmax = <2000>;
ti,als1-imp-sel = <4110>;
ti,als2-imp-sel = <2180>;
ti,als-avrg-time-us = <17920>;
ti,als-input-mode = <0x00>;
led@0 {
reg = <0>;
led-sources = <2>;
ti,led-mode = <1>;
label = ":backlight";
linux,default-trigger = "backlight";
};
led@1 {
reg = <1>;
led-sources = <1>;
ti,led-mode = <0>;
label = ":kbd_backlight";
};
};
For more product information please see the links below:
http://www.ti.com/product/LM3532

View File

@ -4,7 +4,6 @@ TI LMU driver supports lighting devices below.
Name Child nodes
------ ---------------------------------
LM3532 Backlight
LM3631 Backlight and regulator
LM3632 Backlight and regulator
LM3633 Backlight, LED and fault monitor
@ -13,7 +12,6 @@ TI LMU driver supports lighting devices below.
Required properties:
- compatible: Should be one of:
"ti,lm3532"
"ti,lm3631"
"ti,lm3632"
"ti,lm3633"
@ -23,7 +21,6 @@ Required properties:
0x11 for LM3632
0x29 for LM3631
0x36 for LM3633, LM3697
0x38 for LM3532
0x63 for LM3695
Optional property:
@ -47,23 +44,6 @@ Optional nodes:
[2] ../leds/leds-lm3633.txt
[3] ../regulator/lm363x-regulator.txt
lm3532@38 {
compatible = "ti,lm3532";
reg = <0x38>;
enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>;
backlight {
compatible = "ti,lm3532-backlight";
lcd {
led-sources = <0 1 2>;
ramp-up-msec = <30>;
ramp-down-msec = <0>;
};
};
};
lm3631@29 {
compatible = "ti,lm3631";
reg = <0x29>;

View File

@ -214,7 +214,6 @@
width-mm = <50>;
height-mm = <89>;
backlight = <&lcd_backlight>;
panel-timing {
clock-frequency = <0>; /* Calculated by dsi */
@ -383,20 +382,30 @@
};
&i2c1 {
lm3532@38 {
led-controller@38 {
compatible = "ti,lm3532";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x38>;
enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
lcd_backlight: backlight {
compatible = "ti,lm3532-backlight";
ramp-up-us = <1024>;
ramp-down-us = <8193>;
lcd {
led-sources = <0 1 2>;
ramp-up-msec = <1>;
ramp-down-msec = <0>;
};
led@0 {
reg = <0>;
led-sources = <2>;
ti,led-mode = <0>;
label = ":backlight";
linux,default-trigger = "backlight";
};
led@1 {
reg = <1>;
led-sources = <1>;
ti,led-mode = <0>;
label = ":kbd_backlight";
};
};
};

View File

@ -23,8 +23,8 @@ 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
This option enables the flash LED sysfs class in /sys/class/leds.
It wraps 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.
@ -56,7 +56,7 @@ config LEDS_AAT1290
depends on OF
depends on PINCTRL
help
This option enables support for the LEDs on the AAT1290.
This option enables support for the LEDs on the AAT1290.
config LEDS_AN30259A
tristate "LED support for Panasonic AN30259A"
@ -138,6 +138,16 @@ config LEDS_LM3530
controlled manually or using PWM input or using ambient
light automatically.
config LEDS_LM3532
tristate "LCD Backlight driver for LM3532"
depends on LEDS_CLASS
depends on I2C
help
This option enables support for the LCD backlight using
LM3532 ambient light sensor chip. This ALS chip can be
controlled manually or using PWM input or using ambient
light automatically.
config LEDS_LM3533
tristate "LED support for LM3533"
depends on LEDS_CLASS
@ -413,13 +423,13 @@ config LEDS_CLEVO_MAIL
This module can drive the mail LED for the following notebooks:
Clevo D400P
Clevo D410J
Clevo D410V
Clevo D400V/D470V (not tested, but might work)
Clevo M540N
Clevo M5x0N (not tested, but might work)
Positivo Mobile (Clevo M5x0V)
Clevo D400P
Clevo D410J
Clevo D410V
Clevo D400V/D470V (not tested, but might work)
Clevo M540N
Clevo M5x0N (not tested, but might work)
Positivo Mobile (Clevo M5x0V)
If your model is not listed here you can try the "nodetect"
module parameter.
@ -462,7 +472,7 @@ config LEDS_WM831X_STATUS
depends on MFD_WM831X
help
This option enables support for the status LEDs of the WM831x
series of PMICs.
series of PMICs.
config LEDS_WM8350
tristate "LED Support for WM8350 AudioPlus PMIC"
@ -533,6 +543,7 @@ config LEDS_LT3593
tristate "LED driver for LT3593 controllers"
depends on LEDS_CLASS
depends on GPIOLIB || COMPILE_TEST
depends on OF
help
This option enables support for LEDs driven by a Linear Technology
LT3593 controller. This controller uses a special one-wire pulse

View File

@ -18,6 +18,7 @@ obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
obj-$(CONFIG_LEDS_CPCAP) += leds-cpcap.o
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
obj-$(CONFIG_LEDS_LM3532) += leds-lm3532.o
obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o
obj-$(CONFIG_LEDS_LM3642) += leds-lm3642.o
obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o

View File

@ -57,6 +57,7 @@ static ssize_t brightness_store(struct device *dev,
if (state == LED_OFF)
led_trigger_remove(led_cdev);
led_set_brightness(led_cdev, state);
flush_work(&led_cdev->set_brightness_work);
ret = size;
unlock:

View File

@ -164,6 +164,11 @@ static void led_blink_setup(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off)
{
/*
* If "set brightness to 0" is pending in workqueue, we don't
* want that to be reordered after blink_set()
*/
flush_work(&led_cdev->set_brightness_work);
if (!test_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags) &&
led_cdev->blink_set &&
!led_cdev->blink_set(led_cdev, delay_on, delay_off))

View File

@ -25,7 +25,7 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <media/v4l2-flash-led-class.h>
@ -148,8 +148,8 @@ struct as3645a {
struct v4l2_flash *vf;
struct v4l2_flash *vfind;
struct device_node *flash_node;
struct device_node *indicator_node;
struct fwnode_handle *flash_node;
struct fwnode_handle *indicator_node;
struct as3645a_config cfg;
@ -493,30 +493,31 @@ static int as3645a_detect(struct as3645a *flash)
static int as3645a_parse_node(struct as3645a *flash,
struct as3645a_names *names,
struct device_node *node)
struct fwnode_handle *fwnode)
{
struct as3645a_config *cfg = &flash->cfg;
struct device_node *child;
struct fwnode_handle *child;
const char *name;
int rval;
for_each_child_of_node(node, child) {
fwnode_for_each_child_node(fwnode, child) {
u32 id = 0;
of_property_read_u32(child, "reg", &id);
fwnode_property_read_u32(child, "reg", &id);
switch (id) {
case AS_LED_FLASH:
flash->flash_node = of_node_get(child);
flash->flash_node = child;
break;
case AS_LED_INDICATOR:
flash->indicator_node = of_node_get(child);
flash->indicator_node = child;
break;
default:
dev_warn(&flash->client->dev,
"unknown LED %u encountered, ignoring\n", id);
break;
}
fwnode_handle_get(child);
}
if (!flash->flash_node) {
@ -524,42 +525,46 @@ static int as3645a_parse_node(struct as3645a *flash,
return -ENODEV;
}
rval = of_property_read_string(flash->flash_node, "label", &name);
if (!rval)
rval = fwnode_property_read_string(flash->flash_node, "label", &name);
if (!rval) {
strlcpy(names->flash, name, sizeof(names->flash));
else
} else if (is_of_node(fwnode)) {
snprintf(names->flash, sizeof(names->flash),
"%pOFn:flash", node);
"%pOFn:flash", to_of_node(fwnode));
} else {
dev_err(&flash->client->dev, "flash node has no label!\n");
return -EINVAL;
}
rval = of_property_read_u32(flash->flash_node, "flash-timeout-us",
&cfg->flash_timeout_us);
rval = fwnode_property_read_u32(flash->flash_node, "flash-timeout-us",
&cfg->flash_timeout_us);
if (rval < 0) {
dev_err(&flash->client->dev,
"can't read flash-timeout-us property for flash\n");
goto out_err;
}
rval = of_property_read_u32(flash->flash_node, "flash-max-microamp",
&cfg->flash_max_ua);
rval = fwnode_property_read_u32(flash->flash_node, "flash-max-microamp",
&cfg->flash_max_ua);
if (rval < 0) {
dev_err(&flash->client->dev,
"can't read flash-max-microamp property for flash\n");
goto out_err;
}
rval = of_property_read_u32(flash->flash_node, "led-max-microamp",
&cfg->assist_max_ua);
rval = fwnode_property_read_u32(flash->flash_node, "led-max-microamp",
&cfg->assist_max_ua);
if (rval < 0) {
dev_err(&flash->client->dev,
"can't read led-max-microamp property for flash\n");
goto out_err;
}
of_property_read_u32(flash->flash_node, "voltage-reference",
&cfg->voltage_reference);
fwnode_property_read_u32(flash->flash_node, "voltage-reference",
&cfg->voltage_reference);
of_property_read_u32(flash->flash_node, "ams,input-max-microamp",
&cfg->peak);
fwnode_property_read_u32(flash->flash_node, "ams,input-max-microamp",
&cfg->peak);
cfg->peak = AS_PEAK_mA_TO_REG(cfg->peak);
if (!flash->indicator_node) {
@ -568,15 +573,21 @@ static int as3645a_parse_node(struct as3645a *flash,
goto out_err;
}
rval = of_property_read_string(flash->indicator_node, "label", &name);
if (!rval)
rval = fwnode_property_read_string(flash->indicator_node, "label",
&name);
if (!rval) {
strlcpy(names->indicator, name, sizeof(names->indicator));
else
} else if (is_of_node(fwnode)) {
snprintf(names->indicator, sizeof(names->indicator),
"%pOFn:indicator", node);
"%pOFn:indicator", to_of_node(fwnode));
} else {
dev_err(&flash->client->dev, "indicator node has no label!\n");
return -EINVAL;
}
rval = of_property_read_u32(flash->indicator_node, "led-max-microamp",
&cfg->indicator_max_ua);
rval = fwnode_property_read_u32(flash->indicator_node,
"led-max-microamp",
&cfg->indicator_max_ua);
if (rval < 0) {
dev_err(&flash->client->dev,
"can't read led-max-microamp property for indicator\n");
@ -586,8 +597,8 @@ static int as3645a_parse_node(struct as3645a *flash,
return 0;
out_err:
of_node_put(flash->flash_node);
of_node_put(flash->indicator_node);
fwnode_handle_put(flash->flash_node);
fwnode_handle_put(flash->indicator_node);
return rval;
}
@ -668,14 +679,14 @@ static int as3645a_v4l2_setup(struct as3645a *flash)
strlcpy(cfgind.dev_name, flash->iled_cdev.name, sizeof(cfg.dev_name));
flash->vf = v4l2_flash_init(
&flash->client->dev, of_fwnode_handle(flash->flash_node),
&flash->fled, NULL, &cfg);
&flash->client->dev, flash->flash_node, &flash->fled, NULL,
&cfg);
if (IS_ERR(flash->vf))
return PTR_ERR(flash->vf);
flash->vfind = v4l2_flash_indicator_init(
&flash->client->dev, of_fwnode_handle(flash->indicator_node),
&flash->iled_cdev, &cfgind);
&flash->client->dev, flash->indicator_node, &flash->iled_cdev,
&cfgind);
if (IS_ERR(flash->vfind)) {
v4l2_flash_release(flash->vf);
return PTR_ERR(flash->vfind);
@ -690,7 +701,7 @@ static int as3645a_probe(struct i2c_client *client)
struct as3645a *flash;
int rval;
if (client->dev.of_node == NULL)
if (!dev_fwnode(&client->dev))
return -ENODEV;
flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
@ -699,7 +710,7 @@ static int as3645a_probe(struct i2c_client *client)
flash->client = client;
rval = as3645a_parse_node(flash, &names, client->dev.of_node);
rval = as3645a_parse_node(flash, &names, dev_fwnode(&client->dev));
if (rval < 0)
return rval;
@ -731,8 +742,8 @@ out_mutex_destroy:
mutex_destroy(&flash->mutex);
out_put_nodes:
of_node_put(flash->flash_node);
of_node_put(flash->indicator_node);
fwnode_handle_put(flash->flash_node);
fwnode_handle_put(flash->indicator_node);
return rval;
}
@ -751,8 +762,8 @@ static int as3645a_remove(struct i2c_client *client)
mutex_destroy(&flash->mutex);
of_node_put(flash->flash_node);
of_node_put(flash->indicator_node);
fwnode_handle_put(flash->flash_node);
fwnode_handle_put(flash->indicator_node);
return 0;
}

View File

@ -594,7 +594,6 @@ static int blinkm_probe(struct i2c_client *client,
goto exit;
}
data->i2c_addr = 0x09;
data->i2c_addr = 0x08;
/* i2c addr - use fake addr of 0x08 initially (real is 0x09) */
data->fw_ver = 0xfe;

683
drivers/leds/leds-lm3532.c Normal file
View File

@ -0,0 +1,683 @@
// SPDX-License-Identifier: GPL-2.0
// TI LM3532 LED driver
// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <uapi/linux/uleds.h>
#include <linux/gpio/consumer.h>
#define LM3532_NAME "lm3532-led"
#define LM3532_BL_MODE_MANUAL 0x00
#define LM3532_BL_MODE_ALS 0x01
#define LM3532_REG_OUTPUT_CFG 0x10
#define LM3532_REG_STARTSHUT_RAMP 0x11
#define LM3532_REG_RT_RAMP 0x12
#define LM3532_REG_PWM_A_CFG 0x13
#define LM3532_REG_PWM_B_CFG 0x14
#define LM3532_REG_PWM_C_CFG 0x15
#define LM3532_REG_ZONE_CFG_A 0x16
#define LM3532_REG_CTRL_A_BRT 0x17
#define LM3532_REG_ZONE_CFG_B 0x18
#define LM3532_REG_CTRL_B_BRT 0x19
#define LM3532_REG_ZONE_CFG_C 0x1a
#define LM3532_REG_CTRL_C_BRT 0x1b
#define LM3532_REG_ENABLE 0x1d
#define LM3532_ALS_CONFIG 0x23
#define LM3532_REG_ZN_0_HI 0x60
#define LM3532_REG_ZN_0_LO 0x61
#define LM3532_REG_ZN_1_HI 0x62
#define LM3532_REG_ZN_1_LO 0x63
#define LM3532_REG_ZN_2_HI 0x64
#define LM3532_REG_ZN_2_LO 0x65
#define LM3532_REG_ZN_3_HI 0x66
#define LM3532_REG_ZN_3_LO 0x67
#define LM3532_REG_MAX 0x7e
/* Contorl Enable */
#define LM3532_CTRL_A_ENABLE BIT(0)
#define LM3532_CTRL_B_ENABLE BIT(1)
#define LM3532_CTRL_C_ENABLE BIT(2)
/* PWM Zone Control */
#define LM3532_PWM_ZONE_MASK 0x7c
#define LM3532_PWM_ZONE_0_EN BIT(2)
#define LM3532_PWM_ZONE_1_EN BIT(3)
#define LM3532_PWM_ZONE_2_EN BIT(4)
#define LM3532_PWM_ZONE_3_EN BIT(5)
#define LM3532_PWM_ZONE_4_EN BIT(6)
/* Brightness Configuration */
#define LM3532_I2C_CTRL BIT(0)
#define LM3532_ALS_CTRL 0
#define LM3532_LINEAR_MAP BIT(1)
#define LM3532_ZONE_MASK (BIT(2) | BIT(3) | BIT(4))
#define LM3532_ZONE_0 0
#define LM3532_ZONE_1 BIT(2)
#define LM3532_ZONE_2 BIT(3)
#define LM3532_ZONE_3 (BIT(2) | BIT(3))
#define LM3532_ZONE_4 BIT(4)
#define LM3532_ENABLE_ALS BIT(3)
#define LM3532_ALS_SEL_SHIFT 6
/* Zone Boundary Register */
#define LM3532_ALS_WINDOW_mV 2000
#define LM3532_ALS_ZB_MAX 4
#define LM3532_ALS_OFFSET_mV 2
#define LM3532_CONTROL_A 0
#define LM3532_CONTROL_B 1
#define LM3532_CONTROL_C 2
#define LM3532_MAX_CONTROL_BANKS 3
#define LM3532_MAX_LED_STRINGS 3
#define LM3532_OUTPUT_CFG_MASK 0x3
#define LM3532_BRT_VAL_ADJUST 8
#define LM3532_RAMP_DOWN_SHIFT 3
#define LM3532_NUM_RAMP_VALS 8
#define LM3532_NUM_AVG_VALS 8
#define LM3532_NUM_IMP_VALS 32
/*
* struct lm3532_als_data
* @config - value of ALS configuration register
* @als1_imp_sel - value of ALS1 resistor select register
* @als2_imp_sel - value of ALS2 resistor select register
* @als_avrg_time - ALS averaging time
* @als_input_mode - ALS input mode for brightness control
* @als_vmin - Minimum ALS voltage
* @als_vmax - Maximum ALS voltage
* @zone_lo - values of ALS lo ZB(Zone Boundary) registers
* @zone_hi - values of ALS hi ZB(Zone Boundary) registers
*/
struct lm3532_als_data {
u8 config;
u8 als1_imp_sel;
u8 als2_imp_sel;
u8 als_avrg_time;
u8 als_input_mode;
u32 als_vmin;
u32 als_vmax;
u8 zones_lo[LM3532_ALS_ZB_MAX];
u8 zones_hi[LM3532_ALS_ZB_MAX];
};
/**
* struct lm3532_led
* @led_dev: led class device
* @priv - Pointer the device data structure
* @control_bank - Control bank the LED is associated to
* @mode - Mode of the LED string
* @num_leds - Number of LED strings are supported in this array
* @led_strings - The LED strings supported in this array
* @label - LED label
*/
struct lm3532_led {
struct led_classdev led_dev;
struct lm3532_data *priv;
int control_bank;
int mode;
int num_leds;
u32 led_strings[LM3532_MAX_CONTROL_BANKS];
char label[LED_MAX_NAME_SIZE];
};
/**
* struct lm3532_data
* @enable_gpio - Hardware enable gpio
* @regulator: regulator
* @client: i2c client
* @regmap - Devices register map
* @dev - Pointer to the devices device struct
* @lock - Lock for reading/writing the device
* @als_data - Pointer to the als data struct
* @runtime_ramp_up - Runtime ramp up setting
* @runtime_ramp_down - Runtime ramp down setting
* @leds - Array of LED strings
*/
struct lm3532_data {
struct gpio_desc *enable_gpio;
struct regulator *regulator;
struct i2c_client *client;
struct regmap *regmap;
struct device *dev;
struct mutex lock;
struct lm3532_als_data *als_data;
u32 runtime_ramp_up;
u32 runtime_ramp_down;
struct lm3532_led leds[];
};
static const struct reg_default lm3532_reg_defs[] = {
{LM3532_REG_OUTPUT_CFG, 0xe4},
{LM3532_REG_STARTSHUT_RAMP, 0xc0},
{LM3532_REG_RT_RAMP, 0xc0},
{LM3532_REG_PWM_A_CFG, 0x82},
{LM3532_REG_PWM_B_CFG, 0x82},
{LM3532_REG_PWM_C_CFG, 0x82},
{LM3532_REG_ZONE_CFG_A, 0xf1},
{LM3532_REG_CTRL_A_BRT, 0xf3},
{LM3532_REG_ZONE_CFG_B, 0xf1},
{LM3532_REG_CTRL_B_BRT, 0xf3},
{LM3532_REG_ZONE_CFG_C, 0xf1},
{LM3532_REG_CTRL_C_BRT, 0xf3},
{LM3532_REG_ENABLE, 0xf8},
{LM3532_ALS_CONFIG, 0x44},
{LM3532_REG_ZN_0_HI, 0x35},
{LM3532_REG_ZN_0_LO, 0x33},
{LM3532_REG_ZN_1_HI, 0x6a},
{LM3532_REG_ZN_1_LO, 0x66},
{LM3532_REG_ZN_2_HI, 0xa1},
{LM3532_REG_ZN_2_LO, 0x99},
{LM3532_REG_ZN_3_HI, 0xdc},
{LM3532_REG_ZN_3_LO, 0xcc},
};
static const struct regmap_config lm3532_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = LM3532_REG_MAX,
.reg_defaults = lm3532_reg_defs,
.num_reg_defaults = ARRAY_SIZE(lm3532_reg_defs),
.cache_type = REGCACHE_FLAT,
};
const static int als_imp_table[LM3532_NUM_IMP_VALS] = {37000, 18500, 12330,
92500, 7400, 6170, 5290,
4630, 4110, 3700, 3360,
3080, 2850, 2640, 2440,
2310, 2180, 2060, 1950,
1850, 1760, 1680, 1610,
1540, 1480, 1420, 1370,
1320, 1280, 1230, 1190};
static int lm3532_get_als_imp_index(int als_imped)
{
int i;
if (als_imped > als_imp_table[1])
return 0;
if (als_imped < als_imp_table[LM3532_NUM_IMP_VALS - 1])
return LM3532_NUM_IMP_VALS - 1;
for (i = 1; i < LM3532_NUM_IMP_VALS; i++) {
if (als_imped == als_imp_table[i])
return i;
/* Find an approximate index by looking up the table */
if (als_imped < als_imp_table[i - 1] &&
als_imped > als_imp_table[i]) {
if (als_imped - als_imp_table[i - 1] <
als_imp_table[i] - als_imped)
return i + 1;
else
return i;
}
}
return -EINVAL;
}
static int lm3532_get_index(const int table[], int size, int value)
{
int i;
for (i = 1; i < size; i++) {
if (value == table[i])
return i;
/* Find an approximate index by looking up the table */
if (value > table[i - 1] &&
value < table[i]) {
if (value - table[i - 1] < table[i] - value)
return i - 1;
else
return i;
}
}
return -EINVAL;
}
const static int als_avrg_table[LM3532_NUM_AVG_VALS] = {17920, 35840, 71680,
1433360, 286720, 573440,
1146880, 2293760};
static int lm3532_get_als_avg_index(int avg_time)
{
if (avg_time <= als_avrg_table[0])
return 0;
if (avg_time > als_avrg_table[LM3532_NUM_AVG_VALS - 1])
return LM3532_NUM_AVG_VALS - 1;
return lm3532_get_index(&als_avrg_table[0], LM3532_NUM_AVG_VALS,
avg_time);
}
const static int ramp_table[LM3532_NUM_RAMP_VALS] = { 8, 1024, 2048, 4096, 8192,
16384, 32768, 65536};
static int lm3532_get_ramp_index(int ramp_time)
{
if (ramp_time <= ramp_table[0])
return 0;
if (ramp_time > ramp_table[LM3532_NUM_RAMP_VALS - 1])
return LM3532_NUM_RAMP_VALS - 1;
return lm3532_get_index(&ramp_table[0], LM3532_NUM_RAMP_VALS,
ramp_time);
}
static int lm3532_led_enable(struct lm3532_led *led_data)
{
int ctrl_en_val = BIT(led_data->control_bank);
int ret;
ret = regmap_update_bits(led_data->priv->regmap, LM3532_REG_ENABLE,
ctrl_en_val, ctrl_en_val);
if (ret) {
dev_err(led_data->priv->dev, "Failed to set ctrl:%d\n", ret);
return ret;
}
return regulator_enable(led_data->priv->regulator);
}
static int lm3532_led_disable(struct lm3532_led *led_data)
{
int ctrl_en_val = BIT(led_data->control_bank);
int ret;
ret = regmap_update_bits(led_data->priv->regmap, LM3532_REG_ENABLE,
ctrl_en_val, ~ctrl_en_val);
if (ret) {
dev_err(led_data->priv->dev, "Failed to set ctrl:%d\n", ret);
return ret;
}
return regulator_disable(led_data->priv->regulator);
}
static int lm3532_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brt_val)
{
struct lm3532_led *led =
container_of(led_cdev, struct lm3532_led, led_dev);
u8 brightness_reg;
int ret;
mutex_lock(&led->priv->lock);
if (led->mode == LM3532_BL_MODE_ALS) {
if (brt_val > LED_OFF)
ret = lm3532_led_enable(led);
else
ret = lm3532_led_disable(led);
goto unlock;
}
if (brt_val == LED_OFF) {
ret = lm3532_led_disable(led);
goto unlock;
}
ret = lm3532_led_enable(led);
if (ret)
goto unlock;
brightness_reg = LM3532_REG_CTRL_A_BRT + led->control_bank * 2;
brt_val = brt_val / LM3532_BRT_VAL_ADJUST;
ret = regmap_write(led->priv->regmap, brightness_reg, brt_val);
unlock:
mutex_unlock(&led->priv->lock);
return ret;
}
static int lm3532_init_registers(struct lm3532_led *led)
{
struct lm3532_data *drvdata = led->priv;
unsigned int runtime_ramp_val;
unsigned int output_cfg_val = 0;
unsigned int output_cfg_shift = 0;
unsigned int output_cfg_mask = 0;
int ret, i;
for (i = 0; i < led->num_leds; i++) {
output_cfg_shift = led->led_strings[i] * 2;
output_cfg_val |= (led->control_bank << output_cfg_shift);
output_cfg_mask |= LM3532_OUTPUT_CFG_MASK << output_cfg_shift;
}
ret = regmap_update_bits(drvdata->regmap, LM3532_REG_OUTPUT_CFG,
output_cfg_mask, output_cfg_val);
if (ret)
return ret;
runtime_ramp_val = drvdata->runtime_ramp_up |
(drvdata->runtime_ramp_down << LM3532_RAMP_DOWN_SHIFT);
return regmap_write(drvdata->regmap, LM3532_REG_RT_RAMP,
runtime_ramp_val);
}
static int lm3532_als_configure(struct lm3532_data *priv,
struct lm3532_led *led)
{
struct lm3532_als_data *als = priv->als_data;
u32 als_vmin, als_vmax, als_vstep;
int zone_reg = LM3532_REG_ZN_0_HI;
int brightnes_config_reg;
int ret;
int i;
als_vmin = als->als_vmin;
als_vmax = als->als_vmax;
als_vstep = (als_vmax - als_vmin) / ((LM3532_ALS_ZB_MAX + 1) * 2);
for (i = 0; i < LM3532_ALS_ZB_MAX; i++) {
als->zones_lo[i] = ((als_vmin + als_vstep + (i * als_vstep)) *
LED_FULL) / 1000;
als->zones_hi[i] = ((als_vmin + LM3532_ALS_OFFSET_mV +
als_vstep + (i * als_vstep)) * LED_FULL) / 1000;
zone_reg = LM3532_REG_ZN_0_HI + i * 2;
ret = regmap_write(priv->regmap, zone_reg, als->zones_lo[i]);
if (ret)
return ret;
zone_reg += 1;
ret = regmap_write(priv->regmap, zone_reg, als->zones_hi[i]);
if (ret)
return ret;
}
als->config = (als->als_avrg_time | (LM3532_ENABLE_ALS) |
(als->als_input_mode << LM3532_ALS_SEL_SHIFT));
ret = regmap_write(priv->regmap, LM3532_ALS_CONFIG, als->config);
if (ret)
return ret;
brightnes_config_reg = LM3532_REG_ZONE_CFG_A + led->control_bank * 2;
return regmap_update_bits(priv->regmap, brightnes_config_reg,
LM3532_I2C_CTRL, LM3532_ALS_CTRL);
}
static int lm3532_parse_als(struct lm3532_data *priv)
{
struct lm3532_als_data *als;
int als_avg_time;
int als_impedance;
int ret;
als = devm_kzalloc(priv->dev, sizeof(*als), GFP_KERNEL);
if (als == NULL)
return -ENOMEM;
ret = device_property_read_u32(&priv->client->dev, "ti,als-vmin",
&als->als_vmin);
if (ret)
als->als_vmin = 0;
ret = device_property_read_u32(&priv->client->dev, "ti,als-vmax",
&als->als_vmax);
if (ret)
als->als_vmax = LM3532_ALS_WINDOW_mV;
if (als->als_vmax > LM3532_ALS_WINDOW_mV) {
ret = -EINVAL;
return ret;
}
ret = device_property_read_u32(&priv->client->dev, "ti,als1-imp-sel",
&als_impedance);
if (ret)
als->als1_imp_sel = 0;
else
als->als1_imp_sel = lm3532_get_als_imp_index(als_impedance);
ret = device_property_read_u32(&priv->client->dev, "ti,als2-imp-sel",
&als_impedance);
if (ret)
als->als2_imp_sel = 0;
else
als->als2_imp_sel = lm3532_get_als_imp_index(als_impedance);
ret = device_property_read_u32(&priv->client->dev, "ti,als-avrg-time-us",
&als_avg_time);
if (ret)
als->als_avrg_time = 0;
else
als->als_avrg_time = lm3532_get_als_avg_index(als_avg_time);
ret = device_property_read_u8(&priv->client->dev, "ti,als-input-mode",
&als->als_input_mode);
if (ret)
als->als_input_mode = 0;
if (als->als_input_mode > LM3532_BL_MODE_ALS) {
ret = -EINVAL;
return ret;
}
priv->als_data = als;
return ret;
}
static int lm3532_parse_node(struct lm3532_data *priv)
{
struct fwnode_handle *child = NULL;
struct lm3532_led *led;
const char *name;
int control_bank;
u32 ramp_time;
size_t i = 0;
int ret;
priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev,
"enable", GPIOD_OUT_LOW);
if (IS_ERR(priv->enable_gpio))
priv->enable_gpio = NULL;
priv->regulator = devm_regulator_get(&priv->client->dev, "vin");
if (IS_ERR(priv->regulator))
priv->regulator = NULL;
ret = device_property_read_u32(&priv->client->dev, "ramp-up-us",
&ramp_time);
if (ret)
dev_info(&priv->client->dev, "ramp-up-ms property missing\n");
else
priv->runtime_ramp_up = lm3532_get_ramp_index(ramp_time);
ret = device_property_read_u32(&priv->client->dev, "ramp-down-us",
&ramp_time);
if (ret)
dev_info(&priv->client->dev, "ramp-down-ms property missing\n");
else
priv->runtime_ramp_down = lm3532_get_ramp_index(ramp_time);
device_for_each_child_node(priv->dev, child) {
led = &priv->leds[i];
ret = fwnode_property_read_u32(child, "reg", &control_bank);
if (ret) {
dev_err(&priv->client->dev, "reg property missing\n");
fwnode_handle_put(child);
goto child_out;
}
if (control_bank > LM3532_CONTROL_C) {
dev_err(&priv->client->dev, "Control bank invalid\n");
continue;
}
led->control_bank = control_bank;
ret = fwnode_property_read_u32(child, "ti,led-mode",
&led->mode);
if (ret) {
dev_err(&priv->client->dev, "ti,led-mode property missing\n");
fwnode_handle_put(child);
goto child_out;
}
if (led->mode == LM3532_BL_MODE_ALS) {
ret = lm3532_parse_als(priv);
if (ret)
dev_err(&priv->client->dev, "Failed to parse als\n");
else
lm3532_als_configure(priv, led);
}
led->num_leds = fwnode_property_read_u32_array(child,
"led-sources",
NULL, 0);
if (led->num_leds > LM3532_MAX_LED_STRINGS) {
dev_err(&priv->client->dev, "To many LED string defined\n");
continue;
}
ret = fwnode_property_read_u32_array(child, "led-sources",
led->led_strings,
led->num_leds);
if (ret) {
dev_err(&priv->client->dev, "led-sources property missing\n");
fwnode_handle_put(child);
goto child_out;
}
fwnode_property_read_string(child, "linux,default-trigger",
&led->led_dev.default_trigger);
ret = fwnode_property_read_string(child, "label", &name);
if (ret)
snprintf(led->label, sizeof(led->label),
"%s::", priv->client->name);
else
snprintf(led->label, sizeof(led->label),
"%s:%s", priv->client->name, name);
led->priv = priv;
led->led_dev.name = led->label;
led->led_dev.brightness_set_blocking = lm3532_brightness_set;
ret = devm_led_classdev_register(priv->dev, &led->led_dev);
if (ret) {
dev_err(&priv->client->dev, "led register err: %d\n",
ret);
fwnode_handle_put(child);
goto child_out;
}
lm3532_init_registers(led);
i++;
}
child_out:
return ret;
}
static int lm3532_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lm3532_data *drvdata;
int ret = 0;
int count;
count = device_get_child_node_count(&client->dev);
if (!count) {
dev_err(&client->dev, "LEDs are not defined in device tree!");
return -ENODEV;
}
drvdata = devm_kzalloc(&client->dev, struct_size(drvdata, leds, count),
GFP_KERNEL);
if (drvdata == NULL)
return -ENOMEM;
drvdata->client = client;
drvdata->dev = &client->dev;
drvdata->regmap = devm_regmap_init_i2c(client, &lm3532_regmap_config);
if (IS_ERR(drvdata->regmap)) {
ret = PTR_ERR(drvdata->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
mutex_init(&drvdata->lock);
i2c_set_clientdata(client, drvdata);
ret = lm3532_parse_node(drvdata);
if (ret) {
dev_err(&client->dev, "Failed to parse node\n");
return ret;
}
if (drvdata->enable_gpio)
gpiod_direction_output(drvdata->enable_gpio, 1);
return ret;
}
static int lm3532_remove(struct i2c_client *client)
{
struct lm3532_data *drvdata = i2c_get_clientdata(client);
mutex_destroy(&drvdata->lock);
if (drvdata->enable_gpio)
gpiod_direction_output(drvdata->enable_gpio, 0);
return 0;
}
static const struct of_device_id of_lm3532_leds_match[] = {
{ .compatible = "ti,lm3532", },
{},
};
MODULE_DEVICE_TABLE(of, of_lm3532_leds_match);
static const struct i2c_device_id lm3532_id[] = {
{LM3532_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, lm3532_id);
static struct i2c_driver lm3532_i2c_driver = {
.probe = lm3532_probe,
.remove = lm3532_remove,
.id_table = lm3532_id,
.driver = {
.name = LM3532_NAME,
.of_match_table = of_lm3532_leds_match,
},
};
module_i2c_driver(lm3532_i2c_driver);
MODULE_DESCRIPTION("Back Light driver for LM3532");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");

View File

@ -60,67 +60,14 @@ static int lt3593_led_set(struct led_classdev *led_cdev,
return 0;
}
static struct lt3593_led_data *lt3593_led_probe_pdata(struct device *dev)
{
struct gpio_led_platform_data *pdata = dev_get_platdata(dev);
const struct gpio_led *template = &pdata->leds[0];
struct lt3593_led_data *led_data;
int ret, state;
if (pdata->num_leds != 1)
return ERR_PTR(-EINVAL);
led_data = devm_kzalloc(dev, sizeof(*led_data), GFP_KERNEL);
if (!led_data)
return ERR_PTR(-ENOMEM);
led_data->cdev.name = template->name;
led_data->cdev.default_trigger = template->default_trigger;
led_data->cdev.brightness_set_blocking = lt3593_led_set;
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_data->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_data->cdev.flags |= LED_CORE_SUSPENDRESUME;
ret = devm_gpio_request_one(dev, template->gpio, state ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
template->name);
if (ret < 0)
return ERR_PTR(ret);
led_data->gpiod = gpio_to_desc(template->gpio);
if (!led_data->gpiod)
return ERR_PTR(-EPROBE_DEFER);
ret = devm_led_classdev_register(dev, &led_data->cdev);
if (ret < 0)
return ERR_PTR(ret);
dev_info(dev, "registered LT3593 LED '%s' at GPIO %d\n",
template->name, template->gpio);
return led_data;
}
static int lt3593_led_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct lt3593_led_data *led_data;
struct fwnode_handle *child;
int ret, state = LEDS_GPIO_DEFSTATE_OFF;
enum gpiod_flags flags = GPIOD_OUT_LOW;
const char *tmp;
if (dev_get_platdata(dev)) {
led_data = lt3593_led_probe_pdata(dev);
if (IS_ERR(led_data))
return PTR_ERR(led_data);
goto out;
}
if (!dev->of_node)
return -ENODEV;
@ -151,13 +98,8 @@ static int lt3593_led_probe(struct platform_device *pdev)
&led_data->cdev.default_trigger);
if (!fwnode_property_read_string(child, "default-state", &tmp)) {
if (!strcmp(tmp, "keep")) {
state = LEDS_GPIO_DEFSTATE_KEEP;
flags = GPIOD_ASIS;
} else if (!strcmp(tmp, "on")) {
if (!strcmp(tmp, "on"))
state = LEDS_GPIO_DEFSTATE_ON;
flags = GPIOD_OUT_HIGH;
}
}
led_data->cdev.name = led_data->name;
@ -171,20 +113,16 @@ static int lt3593_led_probe(struct platform_device *pdev)
}
led_data->cdev.dev->of_node = dev->of_node;
out:
platform_set_drvdata(pdev, led_data);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id of_lt3593_leds_match[] = {
{ .compatible = "lltc,lt3593", },
{},
};
MODULE_DEVICE_TABLE(of, of_lt3593_leds_match);
#endif
static struct platform_driver lt3593_led_driver = {
.probe = lt3593_led_probe,

View File

@ -40,7 +40,6 @@
* bits the chip supports.
*/
#include <linux/acpi.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/err.h>
@ -48,8 +47,8 @@
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/string.h>
@ -110,15 +109,6 @@ static const struct i2c_device_id pca955x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pca955x_id);
static const struct acpi_device_id pca955x_acpi_ids[] = {
{ "PCA9550", pca9550 },
{ "PCA9551", pca9551 },
{ "PCA9552", pca9552 },
{ "PCA9553", pca9553 },
{ }
};
MODULE_DEVICE_TABLE(acpi, pca955x_acpi_ids);
struct pca955x {
struct mutex lock;
struct pca955x_led *leds;
@ -373,16 +363,14 @@ static int pca955x_gpio_direction_output(struct gpio_chip *gc,
}
#endif /* CONFIG_LEDS_PCA955X_GPIO */
#if IS_ENABLED(CONFIG_OF)
static struct pca955x_platform_data *
pca955x_pdata_of_init(struct i2c_client *client, struct pca955x_chipdef *chip)
pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
{
struct device_node *np = client->dev.of_node;
struct device_node *child;
struct pca955x_platform_data *pdata;
struct fwnode_handle *child;
int count;
count = of_get_child_count(np);
count = device_get_child_node_count(&client->dev);
if (!count || count > chip->bits)
return ERR_PTR(-ENODEV);
@ -396,24 +384,25 @@ pca955x_pdata_of_init(struct i2c_client *client, struct pca955x_chipdef *chip)
if (!pdata->leds)
return ERR_PTR(-ENOMEM);
for_each_child_of_node(np, child) {
device_for_each_child_node(&client->dev, child) {
const char *name;
u32 reg;
int res;
res = of_property_read_u32(child, "reg", &reg);
res = fwnode_property_read_u32(child, "reg", &reg);
if ((res != 0) || (reg >= chip->bits))
continue;
if (of_property_read_string(child, "label", &name))
name = child->name;
res = fwnode_property_read_string(child, "label", &name);
if ((res != 0) && is_of_node(child))
name = to_of_node(child)->name;
snprintf(pdata->leds[reg].name, sizeof(pdata->leds[reg].name),
"%s", name);
pdata->leds[reg].type = PCA955X_TYPE_LED;
of_property_read_u32(child, "type", &pdata->leds[reg].type);
of_property_read_string(child, "linux,default-trigger",
fwnode_property_read_u32(child, "type", &pdata->leds[reg].type);
fwnode_property_read_string(child, "linux,default-trigger",
&pdata->leds[reg].default_trigger);
}
@ -429,15 +418,7 @@ static const struct of_device_id of_pca955x_match[] = {
{ .compatible = "nxp,pca9553", .data = (void *)pca9553 },
{},
};
MODULE_DEVICE_TABLE(of, of_pca955x_match);
#else
static struct pca955x_platform_data *
pca955x_pdata_of_init(struct i2c_client *client, struct pca955x_chipdef *chip)
{
return ERR_PTR(-ENODEV);
}
#endif
static int pca955x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@ -450,20 +431,11 @@ static int pca955x_probe(struct i2c_client *client,
struct pca955x_platform_data *pdata;
int ngpios = 0;
if (id) {
chip = &pca955x_chipdefs[id->driver_data];
} else {
const struct acpi_device_id *acpi_id;
acpi_id = acpi_match_device(pca955x_acpi_ids, &client->dev);
if (!acpi_id)
return -ENODEV;
chip = &pca955x_chipdefs[acpi_id->driver_data];
}
chip = &pca955x_chipdefs[id->driver_data];
adapter = to_i2c_adapter(client->dev.parent);
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
pdata = pca955x_pdata_of_init(client, chip);
pdata = pca955x_get_pdata(client, chip);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
@ -602,8 +574,7 @@ static int pca955x_probe(struct i2c_client *client,
static struct i2c_driver pca955x_driver = {
.driver = {
.name = "leds-pca955x",
.acpi_match_table = ACPI_PTR(pca955x_acpi_ids),
.of_match_table = of_match_ptr(of_pca955x_match),
.of_match_table = of_pca955x_match,
},
.probe = pca955x_probe,
.id_table = pca955x_id,

View File

@ -25,7 +25,6 @@
* or by adding the 'nxp,hw-blink' property to the DTS.
*/
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/string.h>
@ -33,6 +32,7 @@
#include <linux/leds.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/platform_data/leds-pca963x.h>
@ -97,15 +97,6 @@ static const struct i2c_device_id pca963x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pca963x_id);
static const struct acpi_device_id pca963x_acpi_ids[] = {
{ "PCA9632", pca9633 },
{ "PCA9633", pca9633 },
{ "PCA9634", pca9634 },
{ "PCA9635", pca9635 },
{ }
};
MODULE_DEVICE_TABLE(acpi, pca963x_acpi_ids);
struct pca963x_led;
struct pca963x {
@ -287,16 +278,15 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
return 0;
}
#if IS_ENABLED(CONFIG_OF)
static struct pca963x_platform_data *
pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip)
pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip)
{
struct device_node *np = client->dev.of_node, *child;
struct pca963x_platform_data *pdata;
struct led_info *pca963x_leds;
struct fwnode_handle *child;
int count;
count = of_get_child_count(np);
count = device_get_child_node_count(&client->dev);
if (!count || count > chip->n_leds)
return ERR_PTR(-ENODEV);
@ -305,18 +295,22 @@ pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip)
if (!pca963x_leds)
return ERR_PTR(-ENOMEM);
for_each_child_of_node(np, child) {
device_for_each_child_node(&client->dev, child) {
struct led_info led = {};
u32 reg;
int res;
res = of_property_read_u32(child, "reg", &reg);
res = fwnode_property_read_u32(child, "reg", &reg);
if ((res != 0) || (reg >= chip->n_leds))
continue;
led.name =
of_get_property(child, "label", NULL) ? : child->name;
led.default_trigger =
of_get_property(child, "linux,default-trigger", NULL);
res = fwnode_property_read_string(child, "label", &led.name);
if ((res != 0) && is_of_node(child))
led.name = to_of_node(child)->name;
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
pca963x_leds[reg] = led;
}
pdata = devm_kzalloc(&client->dev,
@ -328,22 +322,23 @@ pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip)
pdata->leds.num_leds = chip->n_leds;
/* default to open-drain unless totem pole (push-pull) is specified */
if (of_property_read_bool(np, "nxp,totem-pole"))
if (device_property_read_bool(&client->dev, "nxp,totem-pole"))
pdata->outdrv = PCA963X_TOTEM_POLE;
else
pdata->outdrv = PCA963X_OPEN_DRAIN;
/* default to software blinking unless hardware blinking is specified */
if (of_property_read_bool(np, "nxp,hw-blink"))
if (device_property_read_bool(&client->dev, "nxp,hw-blink"))
pdata->blink_type = PCA963X_HW_BLINK;
else
pdata->blink_type = PCA963X_SW_BLINK;
if (of_property_read_u32(np, "nxp,period-scale", &chip->scaling))
if (device_property_read_u32(&client->dev, "nxp,period-scale",
&chip->scaling))
chip->scaling = 1000;
/* default to non-inverted output, unless inverted is specified */
if (of_property_read_bool(np, "nxp,inverted-out"))
if (device_property_read_bool(&client->dev, "nxp,inverted-out"))
pdata->dir = PCA963X_INVERTED;
else
pdata->dir = PCA963X_NORMAL;
@ -359,13 +354,6 @@ static const struct of_device_id of_pca963x_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, of_pca963x_match);
#else
static struct pca963x_platform_data *
pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip)
{
return ERR_PTR(-ENODEV);
}
#endif
static int pca963x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@ -376,20 +364,11 @@ static int pca963x_probe(struct i2c_client *client,
struct pca963x_chipdef *chip;
int i, err;
if (id) {
chip = &pca963x_chipdefs[id->driver_data];
} else {
const struct acpi_device_id *acpi_id;
acpi_id = acpi_match_device(pca963x_acpi_ids, &client->dev);
if (!acpi_id)
return -ENODEV;
chip = &pca963x_chipdefs[acpi_id->driver_data];
}
chip = &pca963x_chipdefs[id->driver_data];
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
pdata = pca963x_dt_init(client, chip);
pdata = pca963x_get_pdata(client, chip);
if (IS_ERR(pdata)) {
dev_warn(&client->dev, "could not parse configuration\n");
pdata = NULL;
@ -495,8 +474,7 @@ static int pca963x_remove(struct i2c_client *client)
static struct i2c_driver pca963x_driver = {
.driver = {
.name = "leds-pca963x",
.of_match_table = of_match_ptr(of_pca963x_match),
.acpi_match_table = ACPI_PTR(pca963x_acpi_ids),
.of_match_table = of_pca963x_match,
},
.probe = pca963x_probe,
.remove = pca963x_remove,

View File

@ -54,14 +54,6 @@ static void ti_lmu_disable_hw(void *data)
gpiod_set_value(lmu->en_gpio, 0);
}
static const struct mfd_cell lm3532_devices[] = {
{
.name = "ti-lmu-backlight",
.id = LM3532,
.of_compatible = "ti,lm3532-backlight",
},
};
#define LM363X_REGULATOR(_id) \
{ \
.name = "lm363x-regulator", \
@ -141,7 +133,6 @@ static const struct ti_lmu_data chip##_data = \
.max_register = max_reg, \
} \
TI_LMU_DATA(lm3532, LM3532_MAX_REG);
TI_LMU_DATA(lm3631, LM3631_MAX_REG);
TI_LMU_DATA(lm3632, LM3632_MAX_REG);
TI_LMU_DATA(lm3633, LM3633_MAX_REG);
@ -211,7 +202,6 @@ static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
}
static const struct of_device_id ti_lmu_of_match[] = {
{ .compatible = "ti,lm3532", .data = &lm3532_data },
{ .compatible = "ti,lm3631", .data = &lm3631_data },
{ .compatible = "ti,lm3632", .data = &lm3632_data },
{ .compatible = "ti,lm3633", .data = &lm3633_data },
@ -222,7 +212,6 @@ static const struct of_device_id ti_lmu_of_match[] = {
MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
static const struct i2c_device_id ti_lmu_ids[] = {
{ "lm3532", LM3532 },
{ "lm3631", LM3631 },
{ "lm3632", LM3632 },
{ "lm3633", LM3633 },

View File

@ -15,50 +15,6 @@
#include <linux/bitops.h>
/* LM3532 */
#define LM3532_REG_OUTPUT_CFG 0x10
#define LM3532_ILED1_CFG_MASK 0x03
#define LM3532_ILED2_CFG_MASK 0x0C
#define LM3532_ILED3_CFG_MASK 0x30
#define LM3532_ILED1_CFG_SHIFT 0
#define LM3532_ILED2_CFG_SHIFT 2
#define LM3532_ILED3_CFG_SHIFT 4
#define LM3532_REG_RAMPUP 0x12
#define LM3532_REG_RAMPDN LM3532_REG_RAMPUP
#define LM3532_RAMPUP_MASK 0x07
#define LM3532_RAMPUP_SHIFT 0
#define LM3532_RAMPDN_MASK 0x38
#define LM3532_RAMPDN_SHIFT 3
#define LM3532_REG_ENABLE 0x1D
#define LM3532_REG_PWM_A_CFG 0x13
#define LM3532_PWM_A_MASK 0x05 /* zone 0 */
#define LM3532_PWM_ZONE_0 BIT(2)
#define LM3532_REG_PWM_B_CFG 0x14
#define LM3532_PWM_B_MASK 0x09 /* zone 1 */
#define LM3532_PWM_ZONE_1 BIT(3)
#define LM3532_REG_PWM_C_CFG 0x15
#define LM3532_PWM_C_MASK 0x11 /* zone 2 */
#define LM3532_PWM_ZONE_2 BIT(4)
#define LM3532_REG_ZONE_CFG_A 0x16
#define LM3532_REG_ZONE_CFG_B 0x18
#define LM3532_REG_ZONE_CFG_C 0x1A
#define LM3532_ZONE_MASK (BIT(2) | BIT(3) | BIT(4))
#define LM3532_ZONE_0 0
#define LM3532_ZONE_1 BIT(2)
#define LM3532_ZONE_2 BIT(3)
#define LM3532_REG_BRT_A 0x70 /* zone 0 */
#define LM3532_REG_BRT_B 0x76 /* zone 1 */
#define LM3532_REG_BRT_C 0x7C /* zone 2 */
#define LM3532_MAX_REG 0x7E
/* LM3631 */
#define LM3631_REG_DEVCTRL 0x00
#define LM3631_LCD_EN_MASK BIT(1)

View File

@ -22,7 +22,6 @@
#define LMU_EVENT_MONITOR_DONE 0x01
enum ti_lmu_id {
LM3532,
LM3631,
LM3632,
LM3633,

View File

@ -291,8 +291,8 @@ static bool toneport_has_led(struct usb_line6_toneport *toneport)
}
}
static const char * const led_colors[2] = { "red", "green" };
static const int led_init_vals[2] = { 0x00, 0x26 };
static const char * const toneport_led_colors[2] = { "red", "green" };
static const int toneport_led_init_vals[2] = { 0x00, 0x26 };
static void toneport_update_led(struct usb_line6_toneport *toneport)
{
@ -320,9 +320,9 @@ static int toneport_init_leds(struct usb_line6_toneport *toneport)
led->toneport = toneport;
snprintf(led->name, sizeof(led->name), "%s::%s",
dev_name(dev), led_colors[i]);
dev_name(dev), toneport_led_colors[i]);
leddev->name = led->name;
leddev->brightness = led_init_vals[i];
leddev->brightness = toneport_led_init_vals[i];
leddev->max_brightness = 0x26;
leddev->brightness_set = toneport_led_brightness_set;
err = led_classdev_register(dev, leddev);