Merge tag 'leds-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 14 Oct 2020 22:22:07 +0000 (15:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 14 Oct 2020 22:22:07 +0000 (15:22 -0700)
Pull LED updates from Pavel Machek:
 "Quite a lot of stuff is going on here. Great cleanups/fixes from Marek
  and others are biggest part.

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

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

61 files changed:
Documentation/devicetree/bindings/leds/leds-is31fl319x.txt
Documentation/devicetree/bindings/leds/leds-lp50xx.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/leds/leds-lp55xx.yaml
Documentation/devicetree/bindings/leds/leds-pca955x.txt
Documentation/devicetree/bindings/leds/tca6507.txt [deleted file]
Documentation/devicetree/bindings/leds/ti,tca6507.yaml [new file with mode: 0644]
Documentation/leds/ledtrig-transient.rst
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/TODO [new file with mode: 0644]
drivers/leds/led-class.c
drivers/leds/leds-88pm860x.c
drivers/leds/leds-aat1290.c
drivers/leds/leds-acer-a500.c [new file with mode: 0644]
drivers/leds/leds-an30259a.c
drivers/leds/leds-aw2013.c
drivers/leds/leds-bcm6328.c
drivers/leds/leds-bcm6358.c
drivers/leds/leds-cpcap.c
drivers/leds/leds-cr0014114.c
drivers/leds/leds-el15203000.c
drivers/leds/leds-gpio.c
drivers/leds/leds-ip30.c
drivers/leds/leds-is31fl319x.c
drivers/leds/leds-is31fl32xx.c
drivers/leds/leds-ktd2692.c
drivers/leds/leds-lm3532.c
drivers/leds/leds-lm36274.c
drivers/leds/leds-lm3692x.c
drivers/leds/leds-lm3697.c
drivers/leds/leds-lp50xx.c [new file with mode: 0644]
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-lp5562.c
drivers/leds/leds-lp55xx-common.c
drivers/leds/leds-lp8501.c
drivers/leds/leds-lp8860.c
drivers/leds/leds-lt3593.c
drivers/leds/leds-max77650.c
drivers/leds/leds-max77693.c
drivers/leds/leds-mc13783.c
drivers/leds/leds-mt6323.c
drivers/leds/leds-netxbig.c
drivers/leds/leds-ns2.c
drivers/leds/leds-pca9532.c
drivers/leds/leds-pca955x.c
drivers/leds/leds-pca963x.c
drivers/leds/leds-pm8058.c
drivers/leds/leds-powernv.c
drivers/leds/leds-pwm.c
drivers/leds/leds-s3c24xx.c
drivers/leds/leds-sc27xx-bltc.c
drivers/leds/leds-sgm3140.c
drivers/leds/leds-spi-byte.c
drivers/leds/leds-syscon.c
drivers/leds/leds-tca6507.c
drivers/leds/leds-tlc591xx.c
drivers/leds/leds-turris-omnia.c
drivers/leds/trigger/ledtrig-cpu.c
include/linux/leds-tca6507.h [deleted file]
include/linux/platform_data/leds-pca963x.h [deleted file]

index fc26034..676d43e 100644 (file)
@@ -16,6 +16,7 @@ Optional properties:
 - audio-gain-db : audio gain selection for external analog modulation input.
        Valid values: 0 - 21, step by 3 (rounded down)
        Default: 0
+- shutdown-gpios : Specifier of the GPIO connected to SDB pin of the chip.
 
 Each led is represented as a sub-node of the issi,is31fl319x device.
 There can be less leds subnodes than the chip can support but not more.
@@ -44,6 +45,7 @@ fancy_leds: leds@65 {
        #address-cells = <1>;
        #size-cells = <0>;
        reg = <0x65>;
+       shutdown-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>;
 
        red_aux: led@1 {
                label = "red:aux";
diff --git a/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml b/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml
new file mode 100644 (file)
index 0000000..947542a
--- /dev/null
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/leds-lp50xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LED driver for LP50XX RGB LED from Texas Instruments.
+
+maintainers:
+  - Dan Murphy <dmurphy@ti.com>
+
+description: |
+  The LP50XX is multi-channel, I2C RGB LED Drivers that can group RGB LEDs into
+  a LED group or control them individually.
+
+  The difference in these RGB LED drivers is the number of supported RGB
+  modules.
+
+  For more product information please see the link below:
+  https://www.ti.com/lit/ds/symlink/lp5012.pdf
+  https://www.ti.com/lit/ds/symlink/lp5024.pdf
+  https://www.ti.com/lit/ds/symlink/lp5036.pdf
+
+properties:
+  compatible:
+    enum:
+      - ti,lp5009
+      - ti,lp5012
+      - ti,lp5018
+      - ti,lp5024
+      - ti,lp5030
+      - ti,lp5036
+
+  reg:
+    maxItems: 1
+    description:
+      I2C slave address
+      lp5009/12 - 0x14, 0x15, 0x16, 0x17
+      lp5018/24 - 0x28, 0x29, 0x2a, 0x2b
+      lp5030/36 - 0x30, 0x31, 0x32, 0x33
+
+  enable-gpios:
+    maxItems: 1
+    description: GPIO pin to enable/disable the device.
+
+  vled-supply:
+    description: LED supply.
+
+patternProperties:
+  '^multi-led@[0-9a-f]$':
+    type: object
+    allOf:
+      - $ref: leds-class-multicolor.yaml#
+    properties:
+      reg:
+        minItems: 1
+        maxItems: 12
+        description:
+          This property denotes the LED module number(s) that is used on the
+          for the child node.  The LED modules can either be used stand alone
+          or grouped into a module bank.
+
+    patternProperties:
+      "(^led-[0-9a-f]$|led)":
+        type: object
+        $ref: common.yaml#
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+   #include <dt-bindings/gpio/gpio.h>
+   #include <dt-bindings/leds/common.h>
+
+   i2c {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       led-controller@14 {
+           compatible = "ti,lp5009";
+           reg = <0x14>;
+           #address-cells = <1>;
+           #size-cells = <0>;
+           enable-gpios = <&gpio1 16>;
+
+           multi-led@1 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x1>;
+               color = <LED_COLOR_ID_RGB>;
+               function = LED_FUNCTION_CHARGING;
+
+               led-0 {
+                   color = <LED_COLOR_ID_RED>;
+               };
+
+               led-1 {
+                   color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led-2 {
+                   color = <LED_COLOR_ID_BLUE>;
+               };
+          };
+
+          multi-led@2 {
+            #address-cells = <1>;
+            #size-cells = <2>;
+            reg = <0x2 0x3 0x5>;
+            color = <LED_COLOR_ID_RGB>;
+            function = LED_FUNCTION_STANDBY;
+
+            led-6 {
+              color = <LED_COLOR_ID_RED>;
+            };
+
+            led-7 {
+              color = <LED_COLOR_ID_GREEN>;
+            };
+
+            led-8 {
+              color = <LED_COLOR_ID_BLUE>;
+            };
+         };
+       };
+    };
+
+...
index b1bb3fe..89f69d6 100644 (file)
@@ -189,7 +189,7 @@ examples:
                #address-cells = <1>;
                #size-cells = <0>;
                reg = <0x2>;
-               color = <LED_COLOR_ID_MULTI>;
+               color = <LED_COLOR_ID_RGB>;
                function = LED_FUNCTION_STANDBY;
                linux,default-trigger = "heartbeat";
 
index 7a5830f..817f460 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
        "nxp,pca9550"
        "nxp,pca9551"
        "nxp,pca9552"
+       "ibm,pca9552"
        "nxp,pca9553"
 - #address-cells: must be 1
 - #size-cells: must be 0
diff --git a/Documentation/devicetree/bindings/leds/tca6507.txt b/Documentation/devicetree/bindings/leds/tca6507.txt
deleted file mode 100644 (file)
index bad9102..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-LEDs connected to tca6507
-
-Required properties:
-- compatible : should be : "ti,tca6507".
-- #address-cells: must be 1
-- #size-cells: must be 0
-- reg: typically 0x45.
-
-Optional properties:
-- gpio-controller: allows lines to be used as output-only GPIOs.
-- #gpio-cells: if present, must not be 0.
-
-Each led is represented as a sub-node of the ti,tca6507 device.
-
-LED sub-node properties:
-- label : (optional) see Documentation/devicetree/bindings/leds/common.txt
-- reg : number of LED line (could be from 0 to 6)
-- linux,default-trigger : (optional)
-   see Documentation/devicetree/bindings/leds/common.txt
-- compatible: either "led" (the default) or "gpio".
-
-Examples:
-
-tca6507@45 {
-       compatible = "ti,tca6507";
-       #address-cells = <1>;
-       #size-cells = <0>;
-       reg = <0x45>;
-
-       gpio-controller;
-       #gpio-cells = <2>;
-
-       led0: red-aux@0 {
-               label = "red:aux";
-               reg = <0x0>;
-       };
-
-       led1: green-aux@1 {
-               label = "green:aux";
-               reg = <0x5>;
-               linux,default-trigger = "default-on";
-       };
-
-       wifi-reset@6 {
-               reg = <0x6>;
-               compatible = "gpio";
-       };
-};
-
diff --git a/Documentation/devicetree/bindings/leds/ti,tca6507.yaml b/Documentation/devicetree/bindings/leds/ti,tca6507.yaml
new file mode 100644 (file)
index 0000000..94c307c
--- /dev/null
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/ti,tca6507.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TCA6507 LED and GPIO controller
+
+maintainers:
+  - NeilBrown <neilb@suse.de>
+
+description:
+  The TCA6507 is a programmable LED controller connected via I2C that can drive
+  7 separate lines either by holding them low, or by pulsing them with modulated
+  width.
+
+properties:
+  compatible:
+    const: ti,tca6507
+
+  reg:
+    description: I2C slave address of the controller.
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  gpio-controller: true
+
+  "#gpio-cells":
+    const: 2
+
+  gpio-line-names: true
+
+patternProperties:
+  "^led@[0-6]$":
+    type: object
+
+    $ref: common.yaml#
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 6
+
+    required:
+      - reg
+
+  "^gpio@[0-6]$":
+    type: object
+
+    properties:
+      compatible:
+        const: gpio
+
+      reg:
+        minimum: 0
+        maximum: 6
+
+    additionalProperties: false
+
+    required:
+      - reg
+      - compatible
+
+if:
+  patternProperties:
+    "^gpio@[0-6]$":
+      properties:
+        compatible:
+          contains:
+            const: gpio
+then:
+  required:
+    - gpio-controller
+    - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/leds/common.h>
+
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        led-controller@45 {
+            compatible = "ti,tca6507";
+            #address-cells = <1>;
+            #size-cells = <0>;
+            reg = <0x45>;
+
+            gpio-controller;
+            #gpio-cells = <2>;
+
+            gpio-line-names = "wifi_reset@6";
+
+            led@0 {
+                label = "gta04:red:aux";
+                reg = <0x0>;
+            };
+
+            led@1 {
+                label = "gta04:green:aux";
+                reg = <0x1>;
+            };
+
+            led@3 {
+                reg = <0x3>;
+                color = <LED_COLOR_ID_RED>;
+                function = LED_FUNCTION_POWER;
+                linux,default-trigger = "default-on";
+            };
+
+            led@4 {
+                color = <LED_COLOR_ID_GREEN>;
+                function = LED_FUNCTION_POWER;
+                reg = <0x4>;
+            };
+
+            gpio@6 {
+                compatible = "gpio";
+                reg = <0x6>;
+            };
+        };
+    };
+
+...
index eedfa16..63072f3 100644 (file)
@@ -17,12 +17,6 @@ set a timer to hold a state, however when user space application crashes or
 goes away without deactivating the timer, the hardware will be left in that
 state permanently.
 
-As a specific example of this use-case, let's look at vibrate feature on
-phones. Vibrate function on phones is implemented using PWM pins on SoC or
-PMIC. There is a need to activate one shot timer to control the vibrate
-feature, to prevent user space crashes leaving the phone in vibrate mode
-permanently causing the battery to drain.
-
 Transient trigger addresses the need for one shot timer activation. The
 transient trigger can be enabled and disabled just like the other leds
 triggers.
@@ -159,7 +153,6 @@ repeat the following step as needed::
 
 This trigger is intended to be used for the following example use cases:
 
- - Control of vibrate (phones, tablets etc.) hardware by user space app.
  - Use of LED by user space app as activity indicator.
  - Use of LED by user space app as a kind of watchdog indicator -- as
    long as the app is alive, it can keep the LED illuminated, if it dies
index 1c181df..849d3c5 100644 (file)
@@ -274,7 +274,7 @@ config LEDS_MT6323
 config LEDS_S3C24XX
        tristate "LED Support for Samsung S3C24XX GPIO LEDs"
        depends on LEDS_CLASS
-       depends on ARCH_S3C24XX
+       depends on ARCH_S3C24XX || COMPILE_TEST
        help
          This option enables support for LEDs connected to GPIO lines
          on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440.
@@ -304,13 +304,13 @@ config LEDS_WRAP
 config LEDS_COBALT_QUBE
        tristate "LED Support for the Cobalt Qube series front LED"
        depends on LEDS_CLASS
-       depends on MIPS_COBALT
+       depends on MIPS_COBALT || COMPILE_TEST
        help
          This option enables support for the front LED on Cobalt Qube series
 
 config LEDS_COBALT_RAQ
        bool "LED Support for the Cobalt Raq series"
-       depends on LEDS_CLASS=y && MIPS_COBALT
+       depends on LEDS_CLASS=y && (MIPS_COBALT || COMPILE_TEST)
        select LEDS_TRIGGERS
        help
          This option enables support for the Cobalt Raq series LEDs.
@@ -395,8 +395,20 @@ config LEDS_LP3952
          To compile this driver as a module, choose M here: the
          module will be called leds-lp3952.
 
+config LEDS_LP50XX
+       tristate "LED Support for TI LP5036/30/24/18/12/9 LED driver chip"
+       depends on LEDS_CLASS && REGMAP_I2C
+       depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
+       help
+         If you say yes here you get support for the Texas Instruments
+         LP5036, LP5030, LP5024, LP5018, LP5012 and LP5009 LED driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called leds-lp50xx.
+
 config LEDS_LP55XX_COMMON
        tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
+       depends on LEDS_CLASS
        depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
        depends on OF
        depends on I2C
@@ -632,7 +644,7 @@ config LEDS_MC13783
 config LEDS_NS2
        tristate "LED support for Network Space v2 GPIO LEDs"
        depends on LEDS_CLASS
-       depends on MACH_KIRKWOOD || MACH_ARMADA_370
+       depends on MACH_KIRKWOOD || MACH_ARMADA_370 || COMPILE_TEST
        default y
        help
          This option enables support for the dual-GPIO LEDs found on the
@@ -646,7 +658,7 @@ config LEDS_NS2
 config LEDS_NETXBIG
        tristate "LED support for Big Network series LEDs"
        depends on LEDS_CLASS
-       depends on MACH_KIRKWOOD
+       depends on MACH_KIRKWOOD || COMPILE_TEST
        depends on OF_GPIO
        default y
        help
@@ -893,7 +905,7 @@ config LEDS_TPS6105X
 config LEDS_IP30
        tristate "LED support for SGI Octane machines"
        depends on LEDS_CLASS
-       depends on SGI_MFD_IOC3
+       depends on SGI_MFD_IOC3 || COMPILE_TEST
        help
          This option enables support for the Red and White LEDs of
          SGI Octane machines.
@@ -909,6 +921,13 @@ config LEDS_SGM3140
          This option enables support for the SGM3140 500mA Buck/Boost Charge
          Pump LED Driver.
 
+config LEDS_ACER_A500
+       tristate "Power button LED support for Acer Iconia Tab A500"
+       depends on LEDS_CLASS && MFD_ACER_A500_EC
+       help
+         This option enables support for the Power Button LED of
+         Acer Iconia Tab A500.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
index c2c7d7a..73e603e 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_LEDS_TRIGGERS)           += led-triggers.o
 # LED Platform Drivers (keep this sorted, M-| sort)
 obj-$(CONFIG_LEDS_88PM860X)            += leds-88pm860x.o
 obj-$(CONFIG_LEDS_AAT1290)             += leds-aat1290.o
+obj-$(CONFIG_LEDS_ACER_A500)           += leds-acer-a500.o
 obj-$(CONFIG_LEDS_ADP5520)             += leds-adp5520.o
 obj-$(CONFIG_LEDS_AN30259A)            += leds-an30259a.o
 obj-$(CONFIG_LEDS_APU)                 += leds-apu.o
@@ -49,6 +50,7 @@ obj-$(CONFIG_LEDS_LM3697)             += leds-lm3697.o
 obj-$(CONFIG_LEDS_LOCOMO)              += leds-locomo.o
 obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
 obj-$(CONFIG_LEDS_LP3952)              += leds-lp3952.o
+obj-$(CONFIG_LEDS_LP50XX)              += leds-lp50xx.o
 obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
 obj-$(CONFIG_LEDS_LP5523)              += leds-lp5523.o
 obj-$(CONFIG_LEDS_LP5562)              += leds-lp5562.o
diff --git a/drivers/leds/TODO b/drivers/leds/TODO
new file mode 100644 (file)
index 0000000..bfa60fa
--- /dev/null
@@ -0,0 +1,75 @@
+-*- org -*-
+
+* On/off LEDs should have max_brightness of 1
+* Get rid of enum led_brightness
+
+It is really an integer, as maximum is configurable. Get rid of it, or
+make it into typedef or something.
+
+* Review atomicity requirements in LED subsystem
+
+Calls that may and that may not block are mixed in same structure, and
+semantics is sometimes non-intuitive. (For example blink callback may
+not sleep.) Review the requirements for any bugs and document them
+clearly.
+
+* LED names are still a mess
+
+No two LEDs have same name, so the names are probably unusable for the
+userland. Nudge authors into creating common LED names for common
+functionality.
+
+? Perhaps check for known LED names during boot, and warn if there are
+LEDs not on the list?
+
+* Split drivers into subdirectories
+
+The number of drivers is getting big, and driver for on/off LED on a
+i/o port is really quite different from camera flash LED, which is
+really different from driver for RGB color LED that can run its own
+microcode. Split the drivers somehow.
+
+* Figure out what to do with RGB leds
+
+Multicolor is a bit too abstract. Yes, we can have
+Green-Magenta-Ultraviolet LED, but so far all the LEDs we support are
+RGB, and not even RGB-White or RGB-Yellow variants emerged.
+
+Multicolor is not a good fit for RGB LED. It does not really know
+about LED color.  In particular, there's no way to make LED "white".
+
+Userspace is interested in knowing "this LED can produce arbitrary
+color", which not all multicolor LEDs can.
+
+       Proposal: let's add "rgb" to led_colors in drivers/leds/led-core.c,
+       add corresponding device tree defines, and use that, instead of
+       multicolor for RGB LEDs.
+
+       We really need to do that now; "white" stuff can wait.
+
+RGB LEDs are quite common, and it would be good to be able to turn LED
+white and to turn it into any arbitrary color. It is essential that
+userspace is able to set arbitrary colors, and it might be good to
+have that ability from kernel, too... to allow full-color triggers.
+
+* Command line utility to manipulate the LEDs?
+
+/sys interface is not really suitable to use by hand, should we have
+an utility to perform LED control?
+
+In particular, LED names are still a mess (see above) and utility
+could help there by presenting both old and new names while we clean
+them up.
+
+In future, I'd like utility to accept both old and new names while we
+clean them up.
+
+It would be also nice to have useful listing mode -- name, type,
+current brightness/trigger...
+
+In future, it would be good to be able to set rgb led to particular
+color.
+
+And probably user-friendly interface to access LEDs for particular
+ethernet interface would be nice.
+
index cc3929f..131ca83 100644 (file)
@@ -354,6 +354,11 @@ int led_classdev_register_ext(struct device *parent,
                ret = led_compose_name(parent, init_data, composed_name);
                if (ret < 0)
                        return ret;
+
+               if (init_data->fwnode)
+                       fwnode_property_read_string(init_data->fwnode,
+                               "linux,default-trigger",
+                               &led_cdev->default_trigger);
        } else {
                proposed_name = led_cdev->name;
        }
index 465c375..508d0d8 100644 (file)
@@ -118,14 +118,14 @@ static int pm860x_led_dt_init(struct platform_device *pdev,
        struct device_node *nproot, *np;
        int iset = 0;
 
-       if (!pdev->dev.parent->of_node)
+       if (!dev_of_node(pdev->dev.parent))
                return -ENODEV;
-       nproot = of_get_child_by_name(pdev->dev.parent->of_node, "leds");
+       nproot = of_get_child_by_name(dev_of_node(pdev->dev.parent), "leds");
        if (!nproot) {
                dev_err(&pdev->dev, "failed to find leds node\n");
                return -ENODEV;
        }
-       for_each_child_of_node(nproot, np) {
+       for_each_available_child_of_node(nproot, np) {
                if (of_node_name_eq(np, data->name)) {
                        of_property_read_u32(np, "marvell,88pm860x-iset",
                                             &iset);
index 5a0fe7b..589484b 100644 (file)
@@ -248,7 +248,7 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
        }
 #endif
 
-       child_node = of_get_next_available_child(dev->of_node, NULL);
+       child_node = of_get_next_available_child(dev_of_node(dev), NULL);
        if (!child_node) {
                dev_err(dev, "No DT child node found for connected LED.\n");
                return -EINVAL;
diff --git a/drivers/leds/leds-acer-a500.c b/drivers/leds/leds-acer-a500.c
new file mode 100644 (file)
index 0000000..8cf0b11
--- /dev/null
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define A500_EC_LED_DELAY_USEC (100 * 1000)
+
+enum {
+       REG_RESET_LEDS = 0x40,
+       REG_POWER_LED_ON = 0x42,
+       REG_CHARGE_LED_ON = 0x43,
+       REG_ANDROID_LEDS_OFF = 0x5a,
+};
+
+struct a500_led {
+       struct led_classdev cdev;
+       const struct reg_sequence *enable_seq;
+       struct a500_led *other;
+       struct regmap *rmap;
+};
+
+static const struct reg_sequence a500_ec_leds_reset_seq[] = {
+       REG_SEQ(REG_RESET_LEDS, 0x0, A500_EC_LED_DELAY_USEC),
+       REG_SEQ(REG_ANDROID_LEDS_OFF, 0x0, A500_EC_LED_DELAY_USEC),
+};
+
+static const struct reg_sequence a500_ec_white_led_enable_seq[] = {
+       REG_SEQ(REG_POWER_LED_ON, 0x0, A500_EC_LED_DELAY_USEC),
+};
+
+static const struct reg_sequence a500_ec_orange_led_enable_seq[] = {
+       REG_SEQ(REG_CHARGE_LED_ON, 0x0, A500_EC_LED_DELAY_USEC),
+};
+
+static int a500_ec_led_brightness_set(struct led_classdev *led_cdev,
+                                     enum led_brightness value)
+{
+       struct a500_led *led = container_of(led_cdev, struct a500_led, cdev);
+       struct reg_sequence control_seq[2];
+       unsigned int num_regs = 1;
+
+       if (value) {
+               control_seq[0] = led->enable_seq[0];
+       } else {
+               /*
+                * There is no separate controls which can disable LEDs
+                * individually, there is only RESET_LEDS command that turns
+                * off both LEDs.
+                *
+                * RESET_LEDS turns off both LEDs, thus restore other LED if
+                * it's turned ON.
+                */
+               if (led->other->cdev.brightness)
+                       num_regs = 2;
+
+               control_seq[0] = a500_ec_leds_reset_seq[0];
+               control_seq[1] = led->other->enable_seq[0];
+       }
+
+       return regmap_multi_reg_write(led->rmap, control_seq, num_regs);
+}
+
+static int a500_ec_leds_probe(struct platform_device *pdev)
+{
+       struct a500_led *white_led, *orange_led;
+       struct regmap *rmap;
+       int err;
+
+       rmap = dev_get_regmap(pdev->dev.parent, "KB930");
+       if (!rmap)
+               return -EINVAL;
+
+       /* reset and turn off LEDs */
+       regmap_multi_reg_write(rmap, a500_ec_leds_reset_seq, 2);
+
+       white_led = devm_kzalloc(&pdev->dev, sizeof(*white_led), GFP_KERNEL);
+       if (!white_led)
+               return -ENOMEM;
+
+       white_led->cdev.name = "power:white";
+       white_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
+       white_led->cdev.flags = LED_CORE_SUSPENDRESUME;
+       white_led->cdev.max_brightness = 1;
+       white_led->enable_seq = a500_ec_white_led_enable_seq;
+       white_led->rmap = rmap;
+
+       orange_led = devm_kzalloc(&pdev->dev, sizeof(*orange_led), GFP_KERNEL);
+       if (!orange_led)
+               return -ENOMEM;
+
+       orange_led->cdev.name = "power:orange";
+       orange_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
+       orange_led->cdev.flags = LED_CORE_SUSPENDRESUME;
+       orange_led->cdev.max_brightness = 1;
+       orange_led->enable_seq = a500_ec_orange_led_enable_seq;
+       orange_led->rmap = rmap;
+
+       white_led->other = orange_led;
+       orange_led->other = white_led;
+
+       err = devm_led_classdev_register(&pdev->dev, &white_led->cdev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register white LED\n");
+               return err;
+       }
+
+       err = devm_led_classdev_register(&pdev->dev, &orange_led->cdev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register orange LED\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static struct platform_driver a500_ec_leds_driver = {
+       .driver = {
+               .name = "acer-a500-iconia-leds",
+       },
+       .probe = a500_ec_leds_probe,
+};
+module_platform_driver(a500_ec_leds_driver);
+
+MODULE_DESCRIPTION("LED driver for Acer Iconia Tab A500 Power Button");
+MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
+MODULE_ALIAS("platform:acer-a500-iconia-leds");
+MODULE_LICENSE("GPL");
index 82350a2..a0df1fb 100644 (file)
@@ -202,13 +202,13 @@ error:
 static int an30259a_dt_init(struct i2c_client *client,
                            struct an30259a *chip)
 {
-       struct device_node *np = client->dev.of_node, *child;
+       struct device_node *np = dev_of_node(&client->dev), *child;
        int count, ret;
        int i = 0;
        const char *str;
        struct an30259a_led *led;
 
-       count = of_get_child_count(np);
+       count = of_get_available_child_count(np);
        if (!count || count > AN30259A_MAX_LEDS)
                return -EINVAL;
 
@@ -238,9 +238,6 @@ static int an30259a_dt_init(struct i2c_client *client,
                                led->default_state = STATE_OFF;
                }
 
-               of_property_read_string(child, "linux,default-trigger",
-                                       &led->cdev.default_trigger);
-
                i++;
        }
 
index d709cc1..80d9374 100644 (file)
@@ -261,11 +261,11 @@ out:
 
 static int aw2013_probe_dt(struct aw2013 *chip)
 {
-       struct device_node *np = chip->client->dev.of_node, *child;
+       struct device_node *np = dev_of_node(&chip->client->dev), *child;
        int count, ret = 0, i = 0;
        struct aw2013_led *led;
 
-       count = of_get_child_count(np);
+       count = of_get_available_child_count(np);
        if (!count || count > AW2013_MAX_LEDS)
                return -EINVAL;
 
@@ -297,16 +297,15 @@ static int aw2013_probe_dt(struct aw2013 *chip)
                                 "DT property led-max-microamp is missing\n");
                }
 
-               of_property_read_string(child, "linux,default-trigger",
-                                       &led->cdev.default_trigger);
-
                led->cdev.brightness_set_blocking = aw2013_brightness_set;
                led->cdev.blink_set = aw2013_blink_set;
 
                ret = devm_led_classdev_register_ext(&chip->client->dev,
                                                     &led->cdev, &init_data);
-               if (ret < 0)
+               if (ret < 0) {
+                       of_node_put(child);
                        return ret;
+               }
 
                i++;
        }
index bad7efb..226d17d 100644 (file)
@@ -328,6 +328,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
                       void __iomem *mem, spinlock_t *lock,
                       unsigned long *blink_leds, unsigned long *blink_delay)
 {
+       struct led_init_data init_data = {};
        struct bcm6328_led *led;
        const char *state;
        int rc;
@@ -345,11 +346,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
        if (of_property_read_bool(nc, "active-low"))
                led->active_low = true;
 
-       led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name;
-       led->cdev.default_trigger = of_get_property(nc,
-                                                   "linux,default-trigger",
-                                                   NULL);
-
        if (!of_property_read_string(nc, "default-state", &state)) {
                if (!strcmp(state, "on")) {
                        led->cdev.brightness = LED_FULL;
@@ -382,8 +378,9 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
 
        led->cdev.brightness_set = bcm6328_led_set;
        led->cdev.blink_set = bcm6328_blink_set;
+       init_data.fwnode = of_fwnode_handle(nc);
 
-       rc = led_classdev_register(dev, &led->cdev);
+       rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
        if (rc < 0)
                return rc;
 
@@ -395,7 +392,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
 static int bcm6328_leds_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *np = dev_of_node(&pdev->dev);
        struct device_node *child;
        void __iomem *mem;
        spinlock_t *lock; /* memory lock */
index 94fefd4..9d2e487 100644 (file)
@@ -94,6 +94,7 @@ static void bcm6358_led_set(struct led_classdev *led_cdev,
 static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
                       void __iomem *mem, spinlock_t *lock)
 {
+       struct led_init_data init_data = {};
        struct bcm6358_led *led;
        const char *state;
        int rc;
@@ -109,11 +110,6 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
        if (of_property_read_bool(nc, "active-low"))
                led->active_low = true;
 
-       led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name;
-       led->cdev.default_trigger = of_get_property(nc,
-                                                   "linux,default-trigger",
-                                                   NULL);
-
        if (!of_property_read_string(nc, "default-state", &state)) {
                if (!strcmp(state, "on")) {
                        led->cdev.brightness = LED_FULL;
@@ -136,8 +132,9 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
        bcm6358_led_set(&led->cdev, led->cdev.brightness);
 
        led->cdev.brightness_set = bcm6358_led_set;
+       init_data.fwnode = of_fwnode_handle(nc);
 
-       rc = led_classdev_register(dev, &led->cdev);
+       rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
        if (rc < 0)
                return rc;
 
@@ -149,7 +146,7 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
 static int bcm6358_leds_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *np = dev_of_node(&pdev->dev);
        struct device_node *child;
        void __iomem *mem;
        spinlock_t *lock; /* memory lock */
index 9f3fa47..7d41ce8 100644 (file)
@@ -158,19 +158,14 @@ MODULE_DEVICE_TABLE(of, cpcap_led_of_match);
 
 static int cpcap_led_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *match;
        struct cpcap_led *led;
        int err;
 
-       match = of_match_device(of_match_ptr(cpcap_led_of_match), &pdev->dev);
-       if (!match || !match->data)
-               return -EINVAL;
-
        led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
        if (!led)
                return -ENOMEM;
        platform_set_drvdata(pdev, led);
-       led->info = match->data;
+       led->info = device_get_match_data(&pdev->dev);
        led->dev = &pdev->dev;
 
        if (led->info->reg == 0x0000) {
index 2da448a..d03cfd3 100644 (file)
@@ -188,9 +188,6 @@ static int cr0014114_probe_dt(struct cr0014114 *priv)
        device_for_each_child_node(priv->dev, child) {
                led = &priv->leds[i];
 
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                           &led->ldev.default_trigger);
-
                led->priv                         = priv;
                led->ldev.max_brightness          = CR_MAX_BRIGHTNESS;
                led->ldev.brightness_set_blocking = cr0014114_set_sync;
index 298b13e..6ca47f2 100644 (file)
@@ -263,9 +263,6 @@ static int el15203000_probe_dt(struct el15203000 *priv)
                        return -EINVAL;
                }
 
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                           &led->ldev.default_trigger);
-
                led->priv                         = priv;
                led->ldev.max_brightness          = LED_ON;
                led->ldev.brightness_set_blocking = el15203000_set_blocking;
index cf84096..93f5b1b 100644 (file)
@@ -160,9 +160,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
 
                led_dat->gpiod = led.gpiod;
 
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                           &led.default_trigger);
-
                if (!fwnode_property_read_string(child, "default-state",
                                                 &state)) {
                        if (!strcmp(state, "keep"))
index d4ec736..1f952ba 100644 (file)
@@ -3,6 +3,7 @@
  * LED Driver for SGI Octane machines
  */
 
+#include <asm/io.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
index ca6634b..4161b9d 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 
 /* register numbers */
 #define IS31FL319X_SHUTDOWN            0x00
@@ -61,6 +63,7 @@
 struct is31fl319x_chip {
        const struct is31fl319x_chipdef *cdef;
        struct i2c_client               *client;
+       struct gpio_desc                *shutdown_gpio;
        struct regmap                   *regmap;
        struct mutex                    lock;
        u32                             audio_gain_db;
@@ -199,26 +202,27 @@ static int is31fl319x_parse_child_dt(const struct device *dev,
 static int is31fl319x_parse_dt(struct device *dev,
                               struct is31fl319x_chip *is31)
 {
-       struct device_node *np = dev->of_node, *child;
-       const struct of_device_id *of_dev_id;
+       struct device_node *np = dev_of_node(dev), *child;
        int count;
        int ret;
 
        if (!np)
                return -ENODEV;
 
-       of_dev_id = of_match_device(of_is31fl319x_match, dev);
-       if (!of_dev_id) {
-               dev_err(dev, "Failed to match device with supported chips\n");
-               return -EINVAL;
+       is31->shutdown_gpio = devm_gpiod_get_optional(dev,
+                                               "shutdown",
+                                               GPIOD_OUT_HIGH);
+       if (IS_ERR(is31->shutdown_gpio)) {
+               ret = PTR_ERR(is31->shutdown_gpio);
+               dev_err(dev, "Failed to get shutdown gpio: %d\n", ret);
+               return ret;
        }
 
-       is31->cdef = of_dev_id->data;
+       is31->cdef = device_get_match_data(dev);
 
-       count = of_get_child_count(np);
+       count = of_get_available_child_count(np);
 
-       dev_dbg(dev, "probe %s with %d leds defined in DT\n",
-               of_dev_id->compatible, count);
+       dev_dbg(dev, "probing with %d leds defined in DT\n", count);
 
        if (!count || count > is31->cdef->num_leds) {
                dev_err(dev, "Number of leds defined must be between 1 and %u\n",
@@ -226,7 +230,7 @@ static int is31fl319x_parse_dt(struct device *dev,
                return -ENODEV;
        }
 
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                struct is31fl319x_led *led;
                u32 reg;
 
@@ -350,6 +354,12 @@ static int is31fl319x_probe(struct i2c_client *client,
        if (err)
                goto free_mutex;
 
+       if (is31->shutdown_gpio) {
+               gpiod_direction_output(is31->shutdown_gpio, 0);
+               mdelay(5);
+               gpiod_direction_output(is31->shutdown_gpio, 1);
+       }
+
        is31->client = client;
        is31->regmap = devm_regmap_init_i2c(client, &regmap_config);
        if (IS_ERR(is31->regmap)) {
index cd768f9..2180255 100644 (file)
@@ -332,9 +332,6 @@ static int is31fl32xx_parse_child_dt(const struct device *dev,
        int ret = 0;
        u32 reg;
 
-       if (of_property_read_string(child, "label", &cdev->name))
-               cdev->name = child->name;
-
        ret = of_property_read_u32(child, "reg", &reg);
        if (ret || reg < 1 || reg > led_data->priv->cdef->channels) {
                dev_err(dev,
@@ -344,9 +341,6 @@ static int is31fl32xx_parse_child_dt(const struct device *dev,
        }
        led_data->channel = reg;
 
-       of_property_read_string(child, "linux,default-trigger",
-                               &cdev->default_trigger);
-
        cdev->brightness_set_blocking = is31fl32xx_brightness_set;
 
        return 0;
@@ -372,7 +366,8 @@ static int is31fl32xx_parse_dt(struct device *dev,
        struct device_node *child;
        int ret = 0;
 
-       for_each_child_of_node(dev->of_node, child) {
+       for_each_available_child_of_node(dev_of_node(dev), child) {
+               struct led_init_data init_data = {};
                struct is31fl32xx_led_data *led_data =
                        &priv->leds[priv->num_leds];
                const struct is31fl32xx_led_data *other_led_data;
@@ -388,17 +383,18 @@ static int is31fl32xx_parse_dt(struct device *dev,
                                                          led_data->channel);
                if (other_led_data) {
                        dev_err(dev,
-                               "%s and %s both attempting to use channel %d\n",
-                               led_data->cdev.name,
-                               other_led_data->cdev.name,
-                               led_data->channel);
+                               "Node %pOF 'reg' conflicts with another LED\n",
+                               child);
                        goto err;
                }
 
-               ret = devm_led_classdev_register(dev, &led_data->cdev);
+               init_data.fwnode = of_fwnode_handle(child);
+
+               ret = devm_led_classdev_register_ext(dev, &led_data->cdev,
+                                                    &init_data);
                if (ret) {
-                       dev_err(dev, "failed to register PWM led for %s: %d\n",
-                               led_data->cdev.name, ret);
+                       dev_err(dev, "Failed to register LED for %pOF: %d\n",
+                               child, ret);
                        goto err;
                }
 
@@ -428,19 +424,14 @@ static int is31fl32xx_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
        const struct is31fl32xx_chipdef *cdef;
-       const struct of_device_id *of_dev_id;
        struct device *dev = &client->dev;
        struct is31fl32xx_priv *priv;
        int count;
        int ret = 0;
 
-       of_dev_id = of_match_device(of_is31fl32xx_match, dev);
-       if (!of_dev_id)
-               return -EINVAL;
-
-       cdef = of_dev_id->data;
+       cdef = device_get_match_data(dev);
 
-       count = of_get_child_count(dev->of_node);
+       count = of_get_available_child_count(dev_of_node(dev));
        if (!count)
                return -EINVAL;
 
index 670efee..632f10d 100644 (file)
@@ -259,11 +259,11 @@ static void ktd2692_setup(struct ktd2692_context *led)
 static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
                            struct ktd2692_led_config_data *cfg)
 {
-       struct device_node *np = dev->of_node;
+       struct device_node *np = dev_of_node(dev);
        struct device_node *child_node;
        int ret;
 
-       if (!dev->of_node)
+       if (!dev_of_node(dev))
                return -ENXIO;
 
        led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
index 946ad67..0bf25bd 100644 (file)
 
 /*
  * struct lm3532_als_data
- * @config - value of ALS configuration register
- * @als1_imp_sel - value of ALS1 resistor select register
- * @als2_imp_sel - value of ALS2 resistor select register
- * @als_avrg_time - ALS averaging time
- * @als_input_mode - ALS input mode for brightness control
- * @als_vmin - Minimum ALS voltage
- * @als_vmax - Maximum ALS voltage
- * @zone_lo - values of ALS lo ZB(Zone Boundary) registers
- * @zone_hi - values of ALS hi ZB(Zone Boundary) registers
+ * @config: value of ALS configuration register
+ * @als1_imp_sel: value of ALS1 resistor select register
+ * @als2_imp_sel: value of ALS2 resistor select register
+ * @als_avrg_time: ALS averaging time
+ * @als_input_mode: ALS input mode for brightness control
+ * @als_vmin: Minimum ALS voltage
+ * @als_vmax: Maximum ALS voltage
+ * @zone_lo: values of ALS lo ZB(Zone Boundary) registers
+ * @zone_hi: values of ALS hi ZB(Zone Boundary) registers
  */
 struct lm3532_als_data {
        u8 config;
@@ -121,15 +121,14 @@ struct lm3532_als_data {
 /**
  * struct lm3532_led
  * @led_dev: led class device
- * @priv - Pointer the device data structure
- * @control_bank - Control bank the LED is associated to
- * @mode - Mode of the LED string
- * @ctrl_brt_pointer - Zone target register that controls the sink
- * @num_leds - Number of LED strings are supported in this array
- * @full_scale_current - The full-scale current setting for the current sink.
- * @led_strings - The LED strings supported in this array
- * @enabled - Enabled status
- * @label - LED label
+ * @priv: Pointer the device data structure
+ * @control_bank: Control bank the LED is associated to
+ * @mode: Mode of the LED string
+ * @ctrl_brt_pointer: Zone target register that controls the sink
+ * @num_leds: Number of LED strings are supported in this array
+ * @full_scale_current: The full-scale current setting for the current sink.
+ * @led_strings: The LED strings supported in this array
+ * @enabled: Enabled status
  */
 struct lm3532_led {
        struct led_classdev led_dev;
@@ -142,21 +141,20 @@ struct lm3532_led {
        int full_scale_current;
        unsigned int enabled:1;
        u32 led_strings[LM3532_MAX_CONTROL_BANKS];
-       char label[LED_MAX_NAME_SIZE];
 };
 
 /**
  * struct lm3532_data
- * @enable_gpio - Hardware enable gpio
+ * @enable_gpio: Hardware enable gpio
  * @regulator: regulator
  * @client: i2c client
- * @regmap - Devices register map
- * @dev - Pointer to the devices device struct
- * @lock - Lock for reading/writing the device
- * @als_data - Pointer to the als data struct
- * @runtime_ramp_up - Runtime ramp up setting
- * @runtime_ramp_down - Runtime ramp down setting
- * @leds - Array of LED strings
+ * @regmap: Devices register map
+ * @dev: Pointer to the devices device struct
+ * @lock: Lock for reading/writing the device
+ * @als_data: Pointer to the als data struct
+ * @runtime_ramp_up: Runtime ramp up setting
+ * @runtime_ramp_down: Runtime ramp down setting
+ * @leds: Array of LED strings
  */
 struct lm3532_data {
        struct gpio_desc *enable_gpio;
@@ -548,7 +546,6 @@ static int lm3532_parse_node(struct lm3532_data *priv)
 {
        struct fwnode_handle *child = NULL;
        struct lm3532_led *led;
-       const char *name;
        int control_bank;
        u32 ramp_time;
        size_t i = 0;
@@ -643,19 +640,7 @@ static int lm3532_parse_node(struct lm3532_data *priv)
                        goto child_out;
                }
 
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                           &led->led_dev.default_trigger);
-
-               ret = fwnode_property_read_string(child, "label", &name);
-               if (ret)
-                       snprintf(led->label, sizeof(led->label),
-                               "%s::", priv->client->name);
-               else
-                       snprintf(led->label, sizeof(led->label),
-                                "%s:%s", priv->client->name, name);
-
                led->priv = priv;
-               led->led_dev.name = led->label;
                led->led_dev.brightness_set_blocking = lm3532_brightness_set;
 
                ret = devm_led_classdev_register_ext(priv->dev, &led->led_dev, &idata);
index bfeee03..aadb034 100644 (file)
@@ -26,8 +26,8 @@
  * @lmu_data: Register and setting values for common code
  * @regmap: Devices register map
  * @dev: Pointer to the devices device struct
- * @led_sources - The LED strings supported in this array
- * @num_leds - Number of LED strings are supported in this array
+ * @led_sources: The LED strings supported in this array
+ * @num_leds: Number of LED strings are supported in this array
  */
 struct lm36274 {
        struct platform_device *pdev;
@@ -41,122 +41,113 @@ struct lm36274 {
 };
 
 static int lm36274_brightness_set(struct led_classdev *led_cdev,
-                               enum led_brightness brt_val)
+                                 enum led_brightness brt_val)
 {
-       struct lm36274 *led = container_of(led_cdev, struct lm36274, led_dev);
+       struct lm36274 *chip = container_of(led_cdev, struct lm36274, led_dev);
 
-       return ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
+       return ti_lmu_common_set_brightness(&chip->lmu_data, brt_val);
 }
 
-static int lm36274_init(struct lm36274 *lm36274_data)
+static int lm36274_init(struct lm36274 *chip)
 {
        int enable_val = 0;
        int i;
 
-       for (i = 0; i < lm36274_data->num_leds; i++)
-               enable_val |= (1 << lm36274_data->led_sources[i]);
+       for (i = 0; i < chip->num_leds; i++)
+               enable_val |= (1 << chip->led_sources[i]);
 
        if (!enable_val) {
-               dev_err(lm36274_data->dev, "No LEDs were enabled\n");
+               dev_err(chip->dev, "No LEDs were enabled\n");
                return -EINVAL;
        }
 
        enable_val |= LM36274_BL_EN;
 
-       return regmap_write(lm36274_data->regmap, LM36274_REG_BL_EN,
-                           enable_val);
+       return regmap_write(chip->regmap, LM36274_REG_BL_EN, enable_val);
 }
 
-static int lm36274_parse_dt(struct lm36274 *lm36274_data)
+static int lm36274_parse_dt(struct lm36274 *chip,
+                           struct led_init_data *init_data)
 {
-       struct fwnode_handle *child = NULL;
-       char label[LED_MAX_NAME_SIZE];
-       struct device *dev = &lm36274_data->pdev->dev;
-       const char *name;
-       int child_cnt;
-       int ret = -EINVAL;
+       struct device *dev = chip->dev;
+       struct fwnode_handle *child;
+       int ret;
 
        /* There should only be 1 node */
-       child_cnt = device_get_child_node_count(dev);
-       if (child_cnt != 1)
+       if (device_get_child_node_count(dev) != 1)
                return -EINVAL;
 
-       device_for_each_child_node(dev, child) {
-               ret = fwnode_property_read_string(child, "label", &name);
-               if (ret)
-                       snprintf(label, sizeof(label),
-                               "%s::", lm36274_data->pdev->name);
-               else
-                       snprintf(label, sizeof(label),
-                                "%s:%s", lm36274_data->pdev->name, name);
-
-               lm36274_data->num_leds = fwnode_property_count_u32(child, "led-sources");
-               if (lm36274_data->num_leds <= 0)
-                       return -ENODEV;
-
-               ret = fwnode_property_read_u32_array(child, "led-sources",
-                                                    lm36274_data->led_sources,
-                                                    lm36274_data->num_leds);
-               if (ret) {
-                       dev_err(dev, "led-sources property missing\n");
-                       return ret;
-               }
-
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                       &lm36274_data->led_dev.default_trigger);
+       child = device_get_next_child_node(dev, NULL);
 
-       }
+       init_data->fwnode = child;
+       init_data->devicename = chip->pdev->name;
+       /* for backwards compatibility when `label` property is not present */
+       init_data->default_label = ":";
 
-       lm36274_data->lmu_data.regmap = lm36274_data->regmap;
-       lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
-       lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
-       lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
+       chip->num_leds = fwnode_property_count_u32(child, "led-sources");
+       if (chip->num_leds <= 0) {
+               ret = -ENODEV;
+               goto err;
+       }
 
-       lm36274_data->led_dev.name = label;
-       lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
-       lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set;
+       ret = fwnode_property_read_u32_array(child, "led-sources",
+                                            chip->led_sources, chip->num_leds);
+       if (ret) {
+               dev_err(dev, "led-sources property missing\n");
+               goto err;
+       }
 
        return 0;
+err:
+       fwnode_handle_put(child);
+       return ret;
 }
 
 static int lm36274_probe(struct platform_device *pdev)
 {
        struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
-       struct lm36274 *lm36274_data;
+       struct led_init_data init_data = {};
+       struct lm36274 *chip;
        int ret;
 
-       lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data),
-                                   GFP_KERNEL);
-       if (!lm36274_data)
+       chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
                return -ENOMEM;
 
-       lm36274_data->pdev = pdev;
-       lm36274_data->dev = lmu->dev;
-       lm36274_data->regmap = lmu->regmap;
-       platform_set_drvdata(pdev, lm36274_data);
+       chip->pdev = pdev;
+       chip->dev = &pdev->dev;
+       chip->regmap = lmu->regmap;
+       platform_set_drvdata(pdev, chip);
 
-       ret = lm36274_parse_dt(lm36274_data);
+       ret = lm36274_parse_dt(chip, &init_data);
        if (ret) {
-               dev_err(lm36274_data->dev, "Failed to parse DT node\n");
+               dev_err(chip->dev, "Failed to parse DT node\n");
                return ret;
        }
 
-       ret = lm36274_init(lm36274_data);
+       ret = lm36274_init(chip);
        if (ret) {
-               dev_err(lm36274_data->dev, "Failed to init the device\n");
+               dev_err(chip->dev, "Failed to init the device\n");
                return ret;
        }
 
-       return led_classdev_register(lm36274_data->dev, &lm36274_data->led_dev);
-}
+       chip->lmu_data.regmap = chip->regmap;
+       chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
+       chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
+       chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
 
-static int lm36274_remove(struct platform_device *pdev)
-{
-       struct lm36274 *lm36274_data = platform_get_drvdata(pdev);
+       chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
+       chip->led_dev.brightness_set_blocking = lm36274_brightness_set;
 
-       led_classdev_unregister(&lm36274_data->led_dev);
+       ret = devm_led_classdev_register_ext(chip->dev, &chip->led_dev,
+                                            &init_data);
+       if (ret)
+               dev_err(chip->dev, "Failed to register LED for node %pfw\n",
+                       init_data.fwnode);
 
-       return 0;
+       fwnode_handle_put(init_data.fwnode);
+
+       return ret;
 }
 
 static const struct of_device_id of_lm36274_leds_match[] = {
@@ -167,9 +158,9 @@ MODULE_DEVICE_TABLE(of, of_lm36274_leds_match);
 
 static struct platform_driver lm36274_driver = {
        .probe  = lm36274_probe,
-       .remove = lm36274_remove,
        .driver = {
                .name = "lm36274-leds",
+               .of_match_table = of_lm36274_leds_match,
        },
 };
 module_platform_driver(lm36274_driver)
index e1e2d2b..e945de4 100644 (file)
@@ -394,13 +394,10 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
        led->regulator = devm_regulator_get_optional(&led->client->dev, "vled");
        if (IS_ERR(led->regulator)) {
                ret = PTR_ERR(led->regulator);
-               if (ret != -ENODEV) {
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(&led->client->dev,
-                                       "Failed to get vled regulator: %d\n",
-                                       ret);
-                       return ret;
-               }
+               if (ret != -ENODEV)
+                       return dev_err_probe(&led->client->dev, ret,
+                                            "Failed to get vled regulator\n");
+
                led->regulator = NULL;
        }
 
@@ -436,9 +433,6 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
                return -ENODEV;
        }
 
-       fwnode_property_read_string(child, "linux,default-trigger",
-                                   &led->led_dev.default_trigger);
-
        ret = fwnode_property_read_u32(child, "reg", &led->led_enable);
        if (ret) {
                dev_err(&led->client->dev, "reg DT property missing\n");
index 0249830..7d216cd 100644 (file)
@@ -78,6 +78,7 @@ struct lm3697 {
        struct mutex lock;
 
        int bank_cfg;
+       int num_banks;
 
        struct lm3697_led leds[];
 };
@@ -115,6 +116,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
        struct lm3697_led *led = container_of(led_cdev, struct lm3697_led,
                                              led_dev);
        int ctrl_en_val = (1 << led->control_bank);
+       struct device *dev = led->priv->dev;
        int ret;
 
        mutex_lock(&led->priv->lock);
@@ -123,7 +125,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
                ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE,
                                         ctrl_en_val, ~ctrl_en_val);
                if (ret) {
-                       dev_err(&led->priv->client->dev, "Cannot write ctrl register\n");
+                       dev_err(dev, "Cannot write ctrl register\n");
                        goto brightness_out;
                }
 
@@ -131,8 +133,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
        } else {
                ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
                if (ret) {
-                       dev_err(&led->priv->client->dev,
-                               "Cannot write brightness\n");
+                       dev_err(dev, "Cannot write brightness\n");
                        goto brightness_out;
                }
 
@@ -141,8 +142,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev,
                                                 LM3697_CTRL_ENABLE,
                                                 ctrl_en_val, ctrl_en_val);
                        if (ret) {
-                               dev_err(&led->priv->client->dev,
-                                       "Cannot enable the device\n");
+                               dev_err(dev, "Cannot enable the device\n");
                                goto brightness_out;
                        }
 
@@ -157,6 +157,7 @@ brightness_out:
 
 static int lm3697_init(struct lm3697 *priv)
 {
+       struct device *dev = priv->dev;
        struct lm3697_led *led;
        int i, ret;
 
@@ -165,26 +166,26 @@ static int lm3697_init(struct lm3697 *priv)
        } else {
                ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET);
                if (ret) {
-                       dev_err(&priv->client->dev, "Cannot reset the device\n");
+                       dev_err(dev, "Cannot reset the device\n");
                        goto out;
                }
        }
 
        ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0);
        if (ret) {
-               dev_err(&priv->client->dev, "Cannot write ctrl enable\n");
+               dev_err(dev, "Cannot write ctrl enable\n");
                goto out;
        }
 
        ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg);
        if (ret)
-               dev_err(&priv->client->dev, "Cannot write OUTPUT config\n");
+               dev_err(dev, "Cannot write OUTPUT config\n");
 
-       for (i = 0; i < LM3697_MAX_CONTROL_BANKS; i++) {
+       for (i = 0; i < priv->num_banks; i++) {
                led = &priv->leds[i];
                ret = ti_lmu_common_set_ramp(&led->lmu_data);
                if (ret)
-                       dev_err(&priv->client->dev, "Setting the ramp rate failed\n");
+                       dev_err(dev, "Setting the ramp rate failed\n");
        }
 out:
        return ret;
@@ -193,36 +194,37 @@ out:
 static int lm3697_probe_dt(struct lm3697 *priv)
 {
        struct fwnode_handle *child = NULL;
+       struct device *dev = priv->dev;
        struct lm3697_led *led;
-       const char *name;
+       int ret = -EINVAL;
        int control_bank;
        size_t i = 0;
-       int ret = -EINVAL;
        int j;
 
-       priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev,
-                                                  "enable", GPIOD_OUT_LOW);
+       priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+                                                   GPIOD_OUT_LOW);
        if (IS_ERR(priv->enable_gpio)) {
                ret = PTR_ERR(priv->enable_gpio);
-               dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n",
-                       ret);
+               dev_err(dev, "Failed to get enable gpio: %d\n", ret);
                return ret;
        }
 
-       priv->regulator = devm_regulator_get(&priv->client->dev, "vled");
+       priv->regulator = devm_regulator_get(dev, "vled");
        if (IS_ERR(priv->regulator))
                priv->regulator = NULL;
 
-       device_for_each_child_node(priv->dev, child) {
+       device_for_each_child_node(dev, child) {
+               struct led_init_data init_data = {};
+
                ret = fwnode_property_read_u32(child, "reg", &control_bank);
                if (ret) {
-                       dev_err(&priv->client->dev, "reg property missing\n");
+                       dev_err(dev, "reg property missing\n");
                        fwnode_handle_put(child);
                        goto child_out;
                }
 
                if (control_bank > LM3697_CONTROL_B) {
-                       dev_err(&priv->client->dev, "reg property is invalid\n");
+                       dev_err(dev, "reg property is invalid\n");
                        ret = -EINVAL;
                        fwnode_handle_put(child);
                        goto child_out;
@@ -230,10 +232,10 @@ static int lm3697_probe_dt(struct lm3697 *priv)
 
                led = &priv->leds[i];
 
-               ret = ti_lmu_common_get_brt_res(&priv->client->dev,
-                                               child, &led->lmu_data);
+               ret = ti_lmu_common_get_brt_res(dev, child, &led->lmu_data);
                if (ret)
-                       dev_warn(&priv->client->dev, "brightness resolution property missing\n");
+                       dev_warn(dev,
+                                "brightness resolution property missing\n");
 
                led->control_bank = control_bank;
                led->lmu_data.regmap = priv->regmap;
@@ -246,7 +248,7 @@ static int lm3697_probe_dt(struct lm3697 *priv)
 
                led->num_leds = fwnode_property_count_u32(child, "led-sources");
                if (led->num_leds > LM3697_MAX_LED_STRINGS) {
-                       dev_err(&priv->client->dev, "Too many LED strings defined\n");
+                       dev_err(dev, "Too many LED strings defined\n");
                        continue;
                }
 
@@ -254,7 +256,7 @@ static int lm3697_probe_dt(struct lm3697 *priv)
                                                    led->hvled_strings,
                                                    led->num_leds);
                if (ret) {
-                       dev_err(&priv->client->dev, "led-sources property missing\n");
+                       dev_err(dev, "led-sources property missing\n");
                        fwnode_handle_put(child);
                        goto child_out;
                }
@@ -263,31 +265,23 @@ static int lm3697_probe_dt(struct lm3697 *priv)
                        priv->bank_cfg |=
                                (led->control_bank << led->hvled_strings[j]);
 
-               ret = ti_lmu_common_get_ramp_params(&priv->client->dev,
-                                                   child, &led->lmu_data);
+               ret = ti_lmu_common_get_ramp_params(dev, child, &led->lmu_data);
                if (ret)
-                       dev_warn(&priv->client->dev, "runtime-ramp properties missing\n");
+                       dev_warn(dev, "runtime-ramp properties missing\n");
 
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                           &led->led_dev.default_trigger);
-
-               ret = fwnode_property_read_string(child, "label", &name);
-               if (ret)
-                       snprintf(led->label, sizeof(led->label),
-                               "%s::", priv->client->name);
-               else
-                       snprintf(led->label, sizeof(led->label),
-                                "%s:%s", priv->client->name, name);
+               init_data.fwnode = child;
+               init_data.devicename = priv->client->name;
+               /* for backwards compatibility if `label` is not present */
+               init_data.default_label = ":";
 
                led->priv = priv;
-               led->led_dev.name = led->label;
                led->led_dev.max_brightness = led->lmu_data.max_brightness;
                led->led_dev.brightness_set_blocking = lm3697_brightness_set;
 
-               ret = devm_led_classdev_register(priv->dev, &led->led_dev);
+               ret = devm_led_classdev_register_ext(dev, &led->led_dev,
+                                                    &init_data);
                if (ret) {
-                       dev_err(&priv->client->dev, "led register err: %d\n",
-                               ret);
+                       dev_err(dev, "led register err: %d\n", ret);
                        fwnode_handle_put(child);
                        goto child_out;
                }
@@ -302,18 +296,18 @@ child_out:
 static int lm3697_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
        struct lm3697 *led;
        int count;
        int ret;
 
-       count = device_get_child_node_count(&client->dev);
-       if (!count) {
-               dev_err(&client->dev, "LEDs are not defined in device tree!");
+       count = device_get_child_node_count(dev);
+       if (!count || count > LM3697_MAX_CONTROL_BANKS) {
+               dev_err(dev, "Strange device tree!");
                return -ENODEV;
        }
 
-       led = devm_kzalloc(&client->dev, struct_size(led, leds, count),
-                          GFP_KERNEL);
+       led = devm_kzalloc(dev, struct_size(led, leds, count), GFP_KERNEL);
        if (!led)
                return -ENOMEM;
 
@@ -321,12 +315,12 @@ static int lm3697_probe(struct i2c_client *client,
        i2c_set_clientdata(client, led);
 
        led->client = client;
-       led->dev = &client->dev;
+       led->dev = dev;
+       led->num_banks = count;
        led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config);
        if (IS_ERR(led->regmap)) {
                ret = PTR_ERR(led->regmap);
-               dev_err(&client->dev, "Failed to allocate register map: %d\n",
-                       ret);
+               dev_err(dev, "Failed to allocate register map: %d\n", ret);
                return ret;
        }
 
@@ -340,12 +334,13 @@ static int lm3697_probe(struct i2c_client *client,
 static int lm3697_remove(struct i2c_client *client)
 {
        struct lm3697 *led = i2c_get_clientdata(client);
+       struct device *dev = &led->client->dev;
        int ret;
 
        ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE,
                                 LM3697_CTRL_A_B_EN, 0);
        if (ret) {
-               dev_err(&led->client->dev, "Failed to disable the device\n");
+               dev_err(dev, "Failed to disable the device\n");
                return ret;
        }
 
@@ -355,8 +350,7 @@ static int lm3697_remove(struct i2c_client *client)
        if (led->regulator) {
                ret = regulator_disable(led->regulator);
                if (ret)
-                       dev_err(&led->client->dev,
-                               "Failed to disable regulator\n");
+                       dev_err(dev, "Failed to disable regulator\n");
        }
 
        mutex_destroy(&led->lock);
diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c
new file mode 100644 (file)
index 0000000..5fb4f24
--- /dev/null
@@ -0,0 +1,631 @@
+// SPDX-License-Identifier: GPL-2.0
+// TI LP50XX LED chip family driver
+// Copyright (C) 2018-20 Texas Instruments Incorporated - https://www.ti.com/
+
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <uapi/linux/uleds.h>
+
+#include <linux/led-class-multicolor.h>
+
+#include "leds.h"
+
+#define LP50XX_DEV_CFG0                0x00
+#define LP50XX_DEV_CFG1                0x01
+#define LP50XX_LED_CFG0                0x02
+
+/* LP5009 and LP5012 registers */
+#define LP5012_BNK_BRT         0x03
+#define LP5012_BNKA_CLR                0x04
+#define LP5012_BNKB_CLR                0x05
+#define LP5012_BNKC_CLR                0x06
+#define LP5012_LED0_BRT                0x07
+#define LP5012_OUT0_CLR                0x0b
+#define LP5012_RESET           0x17
+
+/* LP5018 and LP5024 registers */
+#define LP5024_BNK_BRT         0x03
+#define LP5024_BNKA_CLR                0x04
+#define LP5024_BNKB_CLR                0x05
+#define LP5024_BNKC_CLR                0x06
+#define LP5024_LED0_BRT                0x07
+#define LP5024_OUT0_CLR                0x0f
+#define LP5024_RESET           0x27
+
+/* LP5030 and LP5036 registers */
+#define LP5036_LED_CFG1                0x03
+#define LP5036_BNK_BRT         0x04
+#define LP5036_BNKA_CLR                0x05
+#define LP5036_BNKB_CLR                0x06
+#define LP5036_BNKC_CLR                0x07
+#define LP5036_LED0_BRT                0x08
+#define LP5036_OUT0_CLR                0x14
+#define LP5036_RESET           0x38
+
+#define LP50XX_SW_RESET                0xff
+#define LP50XX_CHIP_EN         BIT(6)
+
+/* There are 3 LED outputs per bank */
+#define LP50XX_LEDS_PER_MODULE 3
+
+#define LP5009_MAX_LED_MODULES 2
+#define LP5012_MAX_LED_MODULES 4
+#define LP5018_MAX_LED_MODULES 6
+#define LP5024_MAX_LED_MODULES 8
+#define LP5030_MAX_LED_MODULES 10
+#define LP5036_MAX_LED_MODULES 12
+
+static const struct reg_default lp5012_reg_defs[] = {
+       {LP50XX_DEV_CFG0, 0x0},
+       {LP50XX_DEV_CFG1, 0x3c},
+       {LP50XX_LED_CFG0, 0x0},
+       {LP5012_BNK_BRT, 0xff},
+       {LP5012_BNKA_CLR, 0x0f},
+       {LP5012_BNKB_CLR, 0x0f},
+       {LP5012_BNKC_CLR, 0x0f},
+       {LP5012_LED0_BRT, 0x0f},
+       /* LEDX_BRT registers are all 0xff for defaults */
+       {0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff},
+       {LP5012_OUT0_CLR, 0x0f},
+       /* OUTX_CLR registers are all 0x0 for defaults */
+       {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00}, {0x10, 0x00},
+       {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, {0x14, 0x00}, {0x15, 0x00},
+       {0x16, 0x00},
+       {LP5012_RESET, 0x00}
+};
+
+static const struct reg_default lp5024_reg_defs[] = {
+       {LP50XX_DEV_CFG0, 0x0},
+       {LP50XX_DEV_CFG1, 0x3c},
+       {LP50XX_LED_CFG0, 0x0},
+       {LP5024_BNK_BRT, 0xff},
+       {LP5024_BNKA_CLR, 0x0f},
+       {LP5024_BNKB_CLR, 0x0f},
+       {LP5024_BNKC_CLR, 0x0f},
+       {LP5024_LED0_BRT, 0x0f},
+       /* LEDX_BRT registers are all 0xff for defaults */
+       {0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff}, {0x0b, 0xff}, {0x0c, 0xff},
+       {0x0d, 0xff}, {0x0e, 0xff},
+       {LP5024_OUT0_CLR, 0x0f},
+       /* OUTX_CLR registers are all 0x0 for defaults */
+       {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, {0x14, 0x00},
+       {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, {0x18, 0x00}, {0x19, 0x00},
+       {0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00},
+       {0x1f, 0x00}, {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+       {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00},
+       {LP5024_RESET, 0x00}
+};
+
+static const struct reg_default lp5036_reg_defs[] = {
+       {LP50XX_DEV_CFG0, 0x0},
+       {LP50XX_DEV_CFG1, 0x3c},
+       {LP50XX_LED_CFG0, 0x0},
+       {LP5036_LED_CFG1, 0x0},
+       {LP5036_BNK_BRT, 0xff},
+       {LP5036_BNKA_CLR, 0x0f},
+       {LP5036_BNKB_CLR, 0x0f},
+       {LP5036_BNKC_CLR, 0x0f},
+       {LP5036_LED0_BRT, 0x0f},
+       /* LEDX_BRT registers are all 0xff for defaults */
+       {0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff}, {0x0b, 0xff}, {0x0c, 0xff},
+       {0x0d, 0xff}, {0x0e, 0xff}, {0x0f, 0xff}, {0x10, 0xff}, {0x11, 0xff},
+       {0x12, 0xff}, {0x13, 0xff},
+       {LP5036_OUT0_CLR, 0x0f},
+       /* OUTX_CLR registers are all 0x0 for defaults */
+       {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, {0x18, 0x00}, {0x19, 0x00},
+       {0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00},
+       {0x1f, 0x00}, {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+       {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
+       {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, {0x2c, 0x00}, {0x2d, 0x00},
+       {0x2e, 0x00}, {0x2f, 0x00}, {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00},
+       {0x33, 0x00}, {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+       {LP5036_RESET, 0x00}
+};
+
+static const struct regmap_config lp5012_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = LP5012_RESET,
+       .reg_defaults = lp5012_reg_defs,
+       .num_reg_defaults = ARRAY_SIZE(lp5012_reg_defs),
+       .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config lp5024_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = LP5024_RESET,
+       .reg_defaults = lp5024_reg_defs,
+       .num_reg_defaults = ARRAY_SIZE(lp5024_reg_defs),
+       .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config lp5036_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = LP5036_RESET,
+       .reg_defaults = lp5036_reg_defs,
+       .num_reg_defaults = ARRAY_SIZE(lp5036_reg_defs),
+       .cache_type = REGCACHE_FLAT,
+};
+
+enum lp50xx_model {
+       LP5009,
+       LP5012,
+       LP5018,
+       LP5024,
+       LP5030,
+       LP5036,
+};
+
+/**
+ * struct lp50xx_chip_info -
+ * @lp50xx_regmap_config: regmap register configuration
+ * @model_id: LED device model
+ * @max_modules: total number of supported LED modules
+ * @num_leds: number of LED outputs available on the device
+ * @led_brightness0_reg: first brightness register of the device
+ * @mix_out0_reg: first color mix register of the device
+ * @bank_brt_reg: bank brightness register
+ * @bank_mix_reg: color mix register
+ * @reset_reg: device reset register
+ */
+struct lp50xx_chip_info {
+       const struct regmap_config *lp50xx_regmap_config;
+       int model_id;
+       u8 max_modules;
+       u8 num_leds;
+       u8 led_brightness0_reg;
+       u8 mix_out0_reg;
+       u8 bank_brt_reg;
+       u8 bank_mix_reg;
+       u8 reset_reg;
+};
+
+static const struct lp50xx_chip_info lp50xx_chip_info_tbl[] = {
+       [LP5009] = {
+               .model_id = LP5009,
+               .max_modules = LP5009_MAX_LED_MODULES,
+               .num_leds = LP5009_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
+               .led_brightness0_reg = LP5012_LED0_BRT,
+               .mix_out0_reg = LP5012_OUT0_CLR,
+               .bank_brt_reg = LP5012_BNK_BRT,
+               .bank_mix_reg = LP5012_BNKA_CLR,
+               .reset_reg = LP5012_RESET,
+               .lp50xx_regmap_config = &lp5012_regmap_config,
+       },
+       [LP5012] = {
+               .model_id = LP5012,
+               .max_modules = LP5012_MAX_LED_MODULES,
+               .num_leds = LP5012_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
+               .led_brightness0_reg = LP5012_LED0_BRT,
+               .mix_out0_reg = LP5012_OUT0_CLR,
+               .bank_brt_reg = LP5012_BNK_BRT,
+               .bank_mix_reg = LP5012_BNKA_CLR,
+               .reset_reg = LP5012_RESET,
+               .lp50xx_regmap_config = &lp5012_regmap_config,
+       },
+       [LP5018] = {
+               .model_id = LP5018,
+               .max_modules = LP5018_MAX_LED_MODULES,
+               .num_leds = LP5018_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
+               .led_brightness0_reg = LP5024_LED0_BRT,
+               .mix_out0_reg = LP5024_OUT0_CLR,
+               .bank_brt_reg = LP5024_BNK_BRT,
+               .bank_mix_reg = LP5024_BNKA_CLR,
+               .reset_reg = LP5024_RESET,
+               .lp50xx_regmap_config = &lp5024_regmap_config,
+       },
+       [LP5024] = {
+               .model_id = LP5024,
+               .max_modules = LP5024_MAX_LED_MODULES,
+               .num_leds = LP5024_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
+               .led_brightness0_reg = LP5024_LED0_BRT,
+               .mix_out0_reg = LP5024_OUT0_CLR,
+               .bank_brt_reg = LP5024_BNK_BRT,
+               .bank_mix_reg = LP5024_BNKA_CLR,
+               .reset_reg = LP5024_RESET,
+               .lp50xx_regmap_config = &lp5024_regmap_config,
+       },
+       [LP5030] = {
+               .model_id = LP5030,
+               .max_modules = LP5030_MAX_LED_MODULES,
+               .num_leds = LP5030_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
+               .led_brightness0_reg = LP5036_LED0_BRT,
+               .mix_out0_reg = LP5036_OUT0_CLR,
+               .bank_brt_reg = LP5036_BNK_BRT,
+               .bank_mix_reg = LP5036_BNKA_CLR,
+               .reset_reg = LP5036_RESET,
+               .lp50xx_regmap_config = &lp5036_regmap_config,
+       },
+       [LP5036] = {
+               .model_id = LP5036,
+               .max_modules = LP5036_MAX_LED_MODULES,
+               .num_leds = LP5036_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE,
+               .led_brightness0_reg = LP5036_LED0_BRT,
+               .mix_out0_reg = LP5036_OUT0_CLR,
+               .bank_brt_reg = LP5036_BNK_BRT,
+               .bank_mix_reg = LP5036_BNKA_CLR,
+               .reset_reg = LP5036_RESET,
+               .lp50xx_regmap_config = &lp5036_regmap_config,
+       },
+};
+
+struct lp50xx_led {
+       struct led_classdev_mc mc_cdev;
+       struct lp50xx *priv;
+       unsigned long bank_modules;
+       int led_intensity[LP50XX_LEDS_PER_MODULE];
+       u8 ctrl_bank_enabled;
+       int led_number;
+};
+
+/**
+ * struct lp50xx -
+ * @enable_gpio: hardware enable gpio
+ * @regulator: LED supply regulator pointer
+ * @client: pointer to the I2C client
+ * @regmap: device register map
+ * @dev: pointer to the devices device struct
+ * @lock: lock for reading/writing the device
+ * @chip_info: chip specific information (ie num_leds)
+ * @num_of_banked_leds: holds the number of banked LEDs
+ * @leds: array of LED strings
+ */
+struct lp50xx {
+       struct gpio_desc *enable_gpio;
+       struct regulator *regulator;
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct device *dev;
+       struct mutex lock;
+       const struct lp50xx_chip_info *chip_info;
+       int num_of_banked_leds;
+
+       /* This needs to be at the end of the struct */
+       struct lp50xx_led leds[];
+};
+
+static struct lp50xx_led *mcled_cdev_to_led(struct led_classdev_mc *mc_cdev)
+{
+       return container_of(mc_cdev, struct lp50xx_led, mc_cdev);
+}
+
+static int lp50xx_brightness_set(struct led_classdev *cdev,
+                            enum led_brightness brightness)
+{
+       struct led_classdev_mc *mc_dev = lcdev_to_mccdev(cdev);
+       struct lp50xx_led *led = mcled_cdev_to_led(mc_dev);
+       const struct lp50xx_chip_info *led_chip = led->priv->chip_info;
+       u8 led_offset, reg_val;
+       int ret = 0;
+       int i;
+
+       mutex_lock(&led->priv->lock);
+       if (led->ctrl_bank_enabled)
+               reg_val = led_chip->bank_brt_reg;
+       else
+               reg_val = led_chip->led_brightness0_reg +
+                         led->led_number;
+
+       ret = regmap_write(led->priv->regmap, reg_val, brightness);
+       if (ret) {
+               dev_err(&led->priv->client->dev,
+                       "Cannot write brightness value %d\n", ret);
+               goto out;
+       }
+
+       for (i = 0; i < led->mc_cdev.num_colors; i++) {
+               if (led->ctrl_bank_enabled) {
+                       reg_val = led_chip->bank_mix_reg + i;
+               } else {
+                       led_offset = (led->led_number * 3) + i;
+                       reg_val = led_chip->mix_out0_reg + led_offset;
+               }
+
+               ret = regmap_write(led->priv->regmap, reg_val,
+                                  mc_dev->subled_info[i].intensity);
+               if (ret) {
+                       dev_err(&led->priv->client->dev,
+                               "Cannot write intensity value %d\n", ret);
+                       goto out;
+               }
+       }
+out:
+       mutex_unlock(&led->priv->lock);
+       return ret;
+}
+
+static int lp50xx_set_banks(struct lp50xx *priv, u32 led_banks[])
+{
+       u8 led_config_lo, led_config_hi;
+       u32 bank_enable_mask = 0;
+       int ret;
+       int i;
+
+       for (i = 0; i < priv->chip_info->max_modules; i++) {
+               if (led_banks[i])
+                       bank_enable_mask |= (1 << led_banks[i]);
+       }
+
+       led_config_lo = (u8)(bank_enable_mask & 0xff);
+       led_config_hi = (u8)(bank_enable_mask >> 8) & 0xff;
+
+       ret = regmap_write(priv->regmap, LP50XX_LED_CFG0, led_config_lo);
+       if (ret)
+               return ret;
+
+       if (priv->chip_info->model_id >= LP5030)
+               ret = regmap_write(priv->regmap, LP5036_LED_CFG1, led_config_hi);
+
+       return ret;
+}
+
+static int lp50xx_reset(struct lp50xx *priv)
+{
+       return regmap_write(priv->regmap, priv->chip_info->reset_reg, LP50XX_SW_RESET);
+}
+
+static int lp50xx_enable_disable(struct lp50xx *priv, int enable_disable)
+{
+       int ret;
+
+       if (priv->enable_gpio) {
+               ret = gpiod_direction_output(priv->enable_gpio, enable_disable);
+               if (ret)
+                       return ret;
+       }
+
+       if (enable_disable)
+               return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN);
+       else
+               return regmap_write(priv->regmap, LP50XX_DEV_CFG0, 0);
+
+}
+
+static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv,
+                            struct lp50xx_led *led, int num_leds)
+{
+       u32 led_banks[LP5036_MAX_LED_MODULES] = {0};
+       int led_number;
+       int ret;
+
+       if (num_leds > 1) {
+               if (num_leds > priv->chip_info->max_modules) {
+                       dev_err(&priv->client->dev, "reg property is invalid\n");
+                       return -EINVAL;
+               }
+
+               priv->num_of_banked_leds = num_leds;
+
+               ret = fwnode_property_read_u32_array(child, "reg", led_banks, num_leds);
+               if (ret) {
+                       dev_err(&priv->client->dev, "reg property is missing\n");
+                       return ret;
+               }
+
+               ret = lp50xx_set_banks(priv, led_banks);
+               if (ret) {
+                       dev_err(&priv->client->dev, "Cannot setup banked LEDs\n");
+                       return ret;
+               }
+
+               led->ctrl_bank_enabled = 1;
+       } else {
+               ret = fwnode_property_read_u32(child, "reg", &led_number);
+               if (ret) {
+                       dev_err(&priv->client->dev, "led reg property missing\n");
+                       return ret;
+               }
+
+               if (led_number > priv->chip_info->num_leds) {
+                       dev_err(&priv->client->dev, "led-sources property is invalid\n");
+                       return -EINVAL;
+               }
+
+               led->led_number = led_number;
+       }
+
+       return 0;
+}
+
+static int lp50xx_probe_dt(struct lp50xx *priv)
+{
+       struct fwnode_handle *child = NULL;
+       struct fwnode_handle *led_node = NULL;
+       struct led_init_data init_data = {};
+       struct led_classdev *led_cdev;
+       struct mc_subled *mc_led_info;
+       struct lp50xx_led *led;
+       int ret = -EINVAL;
+       int num_colors;
+       u32 color_id;
+       int i = 0;
+
+       priv->enable_gpio = devm_gpiod_get_optional(priv->dev, "enable", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->enable_gpio)) {
+               ret = PTR_ERR(priv->enable_gpio);
+               dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n",
+                       ret);
+               return ret;
+       }
+
+       priv->regulator = devm_regulator_get(priv->dev, "vled");
+       if (IS_ERR(priv->regulator))
+               priv->regulator = NULL;
+
+       device_for_each_child_node(priv->dev, child) {
+               led = &priv->leds[i];
+               ret = fwnode_property_count_u32(child, "reg");
+               if (ret < 0) {
+                       dev_err(&priv->client->dev, "reg property is invalid\n");
+                       goto child_out;
+               }
+
+               ret = lp50xx_probe_leds(child, priv, led, ret);
+               if (ret)
+                       goto child_out;
+
+               init_data.fwnode = child;
+               num_colors = 0;
+
+               /*
+                * There are only 3 LEDs per module otherwise they should be
+                * banked which also is presented as 3 LEDs.
+                */
+               mc_led_info = devm_kcalloc(priv->dev, LP50XX_LEDS_PER_MODULE,
+                                          sizeof(*mc_led_info), GFP_KERNEL);
+               if (!mc_led_info)
+                       return -ENOMEM;
+
+               fwnode_for_each_child_node(child, led_node) {
+                       ret = fwnode_property_read_u32(led_node, "color",
+                                                      &color_id);
+                       if (ret) {
+                               dev_err(priv->dev, "Cannot read color\n");
+                               goto child_out;
+                       }
+
+                       mc_led_info[num_colors].color_index = color_id;
+                       num_colors++;
+               }
+
+               led->priv = priv;
+               led->mc_cdev.num_colors = num_colors;
+               led->mc_cdev.subled_info = mc_led_info;
+               led_cdev = &led->mc_cdev.led_cdev;
+               led_cdev->brightness_set_blocking = lp50xx_brightness_set;
+
+               ret = devm_led_classdev_multicolor_register_ext(&priv->client->dev,
+                                                      &led->mc_cdev,
+                                                      &init_data);
+               if (ret) {
+                       dev_err(&priv->client->dev, "led register err: %d\n",
+                               ret);
+                       goto child_out;
+               }
+               i++;
+               fwnode_handle_put(child);
+       }
+
+       return 0;
+
+child_out:
+       fwnode_handle_put(child);
+       return ret;
+}
+
+static int lp50xx_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct lp50xx *led;
+       int count;
+       int ret;
+
+       count = device_get_child_node_count(&client->dev);
+       if (!count) {
+               dev_err(&client->dev, "LEDs are not defined in device tree!");
+               return -ENODEV;
+       }
+
+       led = devm_kzalloc(&client->dev, struct_size(led, leds, count),
+                          GFP_KERNEL);
+       if (!led)
+               return -ENOMEM;
+
+       mutex_init(&led->lock);
+       led->client = client;
+       led->dev = &client->dev;
+       led->chip_info = &lp50xx_chip_info_tbl[id->driver_data];
+       i2c_set_clientdata(client, led);
+       led->regmap = devm_regmap_init_i2c(client,
+                                       led->chip_info->lp50xx_regmap_config);
+       if (IS_ERR(led->regmap)) {
+               ret = PTR_ERR(led->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = lp50xx_reset(led);
+       if (ret)
+               return ret;
+
+       ret = lp50xx_enable_disable(led, 1);
+       if (ret)
+               return ret;
+
+       return lp50xx_probe_dt(led);
+}
+
+static int lp50xx_remove(struct i2c_client *client)
+{
+       struct lp50xx *led = i2c_get_clientdata(client);
+       int ret;
+
+       ret = lp50xx_enable_disable(led, 0);
+       if (ret) {
+               dev_err(&led->client->dev, "Failed to disable chip\n");
+               return ret;
+       }
+
+       if (led->regulator) {
+               ret = regulator_disable(led->regulator);
+               if (ret)
+                       dev_err(&led->client->dev,
+                               "Failed to disable regulator\n");
+       }
+
+       mutex_destroy(&led->lock);
+
+       return 0;
+}
+
+static const struct i2c_device_id lp50xx_id[] = {
+       { "lp5009", LP5009 },
+       { "lp5012", LP5012 },
+       { "lp5018", LP5018 },
+       { "lp5024", LP5024 },
+       { "lp5030", LP5030 },
+       { "lp5036", LP5036 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lp50xx_id);
+
+static const struct of_device_id of_lp50xx_leds_match[] = {
+       { .compatible = "ti,lp5009", .data = (void *)LP5009 },
+       { .compatible = "ti,lp5012", .data = (void *)LP5012 },
+       { .compatible = "ti,lp5018", .data = (void *)LP5018 },
+       { .compatible = "ti,lp5024", .data = (void *)LP5024 },
+       { .compatible = "ti,lp5030", .data = (void *)LP5030 },
+       { .compatible = "ti,lp5036", .data = (void *)LP5036 },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_lp50xx_leds_match);
+
+static struct i2c_driver lp50xx_driver = {
+       .driver = {
+               .name   = "lp50xx",
+               .of_match_table = of_lp50xx_leds_match,
+       },
+       .probe          = lp50xx_probe,
+       .remove         = lp50xx_remove,
+       .id_table       = lp50xx_id,
+};
+module_i2c_driver(lp50xx_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP50XX LED driver");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_LICENSE("GPL v2");
index ef8c3bf..a9e7507 100644 (file)
@@ -523,7 +523,7 @@ static int lp5521_probe(struct i2c_client *client,
        struct lp55xx_chip *chip;
        struct lp55xx_led *led;
        struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
-       struct device_node *np = client->dev.of_node;
+       struct device_node *np = dev_of_node(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index f55d972..fc433e6 100644 (file)
@@ -891,7 +891,7 @@ static int lp5523_probe(struct i2c_client *client,
        struct lp55xx_chip *chip;
        struct lp55xx_led *led;
        struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
-       struct device_node *np = client->dev.of_node;
+       struct device_node *np = dev_of_node(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index 7ecdd19..31c1401 100644 (file)
@@ -518,7 +518,7 @@ static int lp5562_probe(struct i2c_client *client,
        struct lp55xx_chip *chip;
        struct lp55xx_led *led;
        struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
-       struct device_node *np = client->dev.of_node;
+       struct device_node *np = dev_of_node(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index 56210f4..81de134 100644 (file)
@@ -611,11 +611,13 @@ static int lp55xx_parse_multi_led(struct device_node *np,
        struct device_node *child;
        int num_colors = 0, ret;
 
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                ret = lp55xx_parse_multi_led_child(child, cfg, child_number,
                                                   num_colors);
-               if (ret)
+               if (ret) {
+                       of_node_put(child);
                        return ret;
+               }
                num_colors++;
        }
 
@@ -665,7 +667,7 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev,
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       num_channels = of_get_child_count(np);
+       num_channels = of_get_available_child_count(np);
        if (num_channels == 0) {
                dev_err(dev, "no LED channels\n");
                return ERR_PTR(-EINVAL);
@@ -679,10 +681,12 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev,
        pdata->num_channels = num_channels;
        cfg->max_channel = chip->cfg->max_channel;
 
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                ret = lp55xx_parse_logical_led(child, cfg, i);
-               if (ret)
+               if (ret) {
+                       of_node_put(child);
                        return ERR_PTR(-EINVAL);
+               }
                i++;
        }
 
index ac2c31d..2d2fda2 100644 (file)
@@ -306,7 +306,7 @@ static int lp8501_probe(struct i2c_client *client,
        struct lp55xx_chip *chip;
        struct lp55xx_led *led;
        struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
-       struct device_node *np = client->dev.of_node;
+       struct device_node *np = dev_of_node(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index ac2f5d6..f0533a3 100644 (file)
@@ -380,7 +380,7 @@ static int lp8860_probe(struct i2c_client *client,
 {
        int ret;
        struct lp8860_led *led;
-       struct device_node *np = client->dev.of_node;
+       struct device_node *np = dev_of_node(&client->dev);
        struct device_node *child_node;
        struct led_init_data init_data = {};
 
@@ -392,10 +392,6 @@ static int lp8860_probe(struct i2c_client *client,
        if (!child_node)
                return -EINVAL;
 
-       led->led_dev.default_trigger = of_get_property(child_node,
-                                           "linux,default-trigger",
-                                           NULL);
-
        led->enable_gpio = devm_gpiod_get_optional(&client->dev,
                                                   "enable", GPIOD_OUT_LOW);
        if (IS_ERR(led->enable_gpio)) {
index 9079850..68e0643 100644 (file)
@@ -68,7 +68,7 @@ static int lt3593_led_probe(struct platform_device *pdev)
        struct led_init_data init_data = {};
        const char *tmp;
 
-       if (!dev->of_node)
+       if (!dev_of_node(dev))
                return -ENODEV;
 
        led_data = devm_kzalloc(dev, sizeof(*led_data), GFP_KERNEL);
@@ -86,9 +86,6 @@ static int lt3593_led_probe(struct platform_device *pdev)
 
        child = device_get_next_child_node(dev, NULL);
 
-       fwnode_property_read_string(child, "linux,default-trigger",
-                                   &led_data->cdev.default_trigger);
-
        if (!fwnode_property_read_string(child, "default-state", &tmp)) {
                if (!strcmp(tmp, "on"))
                        state = LEDS_GPIO_DEFSTATE_ON;
@@ -107,7 +104,6 @@ static int lt3593_led_probe(struct platform_device *pdev)
                return ret;
        }
 
-       led_data->cdev.dev->of_node = dev->of_node;
        platform_set_drvdata(pdev, led_data);
 
        return 0;
index a0d4b72..1eeac56 100644 (file)
@@ -66,7 +66,6 @@ static int max77650_led_probe(struct platform_device *pdev)
        struct max77650_led *leds, *led;
        struct device *dev;
        struct regmap *map;
-       const char *label;
        int rv, num_leds;
        u32 reg;
 
@@ -86,6 +85,8 @@ static int max77650_led_probe(struct platform_device *pdev)
                return -ENODEV;
 
        device_for_each_child_node(dev, child) {
+               struct led_init_data init_data = {};
+
                rv = fwnode_property_read_u32(child, "reg", &reg);
                if (rv || reg >= MAX77650_LED_NUM_LEDS) {
                        rv = -EINVAL;
@@ -99,22 +100,13 @@ static int max77650_led_probe(struct platform_device *pdev)
                led->cdev.brightness_set_blocking = max77650_led_brightness_set;
                led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS;
 
-               rv = fwnode_property_read_string(child, "label", &label);
-               if (rv) {
-                       led->cdev.name = "max77650::";
-               } else {
-                       led->cdev.name = devm_kasprintf(dev, GFP_KERNEL,
-                                                       "max77650:%s", label);
-                       if (!led->cdev.name) {
-                               rv = -ENOMEM;
-                               goto err_node_put;
-                       }
-               }
-
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                           &led->cdev.default_trigger);
+               init_data.fwnode = child;
+               init_data.devicename = "max77650";
+               /* for backwards compatibility if `label` is not present */
+               init_data.default_label = ":";
 
-               rv = devm_led_classdev_register(dev, &led->cdev);
+               rv = devm_led_classdev_register_ext(dev, &led->cdev,
+                                                   &init_data);
                if (rv)
                        goto err_node_put;
 
index fec5609..5c1faeb 100644 (file)
@@ -599,7 +599,7 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
 {
        struct device *dev = &led->pdev->dev;
        struct max77693_sub_led *sub_leds = led->sub_leds;
-       struct device_node *node = dev->of_node, *child_node;
+       struct device_node *node = dev_of_node(dev), *child_node;
        struct property *prop;
        u32 led_sources[2];
        int i, ret, fled_id;
index 5cd810c..675502c 100644 (file)
@@ -121,7 +121,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       parent = of_get_child_by_name(dev->parent->of_node, "leds");
+       parent = of_get_child_by_name(dev_of_node(dev->parent), "leds");
        if (!parent)
                goto out_node_put;
 
@@ -131,7 +131,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
        if (ret)
                goto out_node_put;
 
-       pdata->num_leds = of_get_child_count(parent);
+       pdata->num_leds = of_get_available_child_count(parent);
 
        pdata->led = devm_kcalloc(dev, pdata->num_leds, sizeof(*pdata->led),
                                  GFP_KERNEL);
@@ -140,7 +140,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
                goto out_node_put;
        }
 
-       for_each_child_of_node(parent, child) {
+       for_each_available_child_of_node(parent, child) {
                const char *str;
                u32 tmp;
 
@@ -192,7 +192,7 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
        leds->master = mcdev;
        platform_set_drvdata(pdev, leds);
 
-       if (dev->parent->of_node) {
+       if (dev_of_node(dev->parent)) {
                pdata = mc13xxx_led_probe_dt(pdev);
                if (IS_ERR(pdata))
                        return PTR_ERR(pdata);
index 2a13e31..f59e0e8 100644 (file)
@@ -249,15 +249,6 @@ static int mt6323_led_set_blink(struct led_classdev *cdev,
        int ret;
 
        /*
-        * Units are in ms, if over the hardware able
-        * to support, fallback into software blink
-        */
-       period = *delay_on + *delay_off;
-
-       if (period > MT6323_MAX_PERIOD)
-               return -EINVAL;
-
-       /*
         * LED subsystem requires a default user
         * friendly blink pattern for the LED so using
         * 1Hz duty cycle 50% here if without specific
@@ -269,6 +260,15 @@ static int mt6323_led_set_blink(struct led_classdev *cdev,
        }
 
        /*
+        * Units are in ms, if over the hardware able
+        * to support, fallback into software blink
+        */
+       period = *delay_on + *delay_off;
+
+       if (period > MT6323_MAX_PERIOD)
+               return -EINVAL;
+
+       /*
         * Calculate duty_hw based on the percentage of period during
         * which the led is ON.
         */
@@ -342,11 +342,6 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev,
        const char *state;
        int ret = 0;
 
-       led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
-       led->cdev.default_trigger = of_get_property(np,
-                                                   "linux,default-trigger",
-                                                   NULL);
-
        state = of_get_property(np, "default-state", NULL);
        if (state) {
                if (!strcmp(state, "keep")) {
@@ -369,9 +364,9 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev,
 static int mt6323_led_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *np = dev_of_node(dev);
        struct device_node *child;
-       struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent);
+       struct mt6397_chip *hw = dev_get_drvdata(dev->parent);
        struct mt6323_leds *leds;
        struct mt6323_led *led;
        int ret;
@@ -402,6 +397,8 @@ static int mt6323_led_probe(struct platform_device *pdev)
        }
 
        for_each_available_child_of_node(np, child) {
+               struct led_init_data init_data = {};
+
                ret = of_property_read_u32(child, "reg", &reg);
                if (ret) {
                        dev_err(dev, "Failed to read led 'reg' property\n");
@@ -437,13 +434,14 @@ static int mt6323_led_probe(struct platform_device *pdev)
                        goto put_child_node;
                }
 
-               ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev);
+               init_data.fwnode = of_fwnode_handle(child);
+
+               ret = devm_led_classdev_register_ext(dev, &leds->led[reg]->cdev,
+                                                    &init_data);
                if (ret) {
-                       dev_err(&pdev->dev, "Failed to register LED: %d\n",
-                               ret);
+                       dev_err(dev, "Failed to register LED: %d\n", ret);
                        goto put_child_node;
                }
-               leds->led[reg]->cdev.dev->of_node = child;
        }
 
        return 0;
index ceceeb6..e6fd473 100644 (file)
@@ -419,7 +419,7 @@ static int netxbig_gpio_ext_get(struct device *dev,
 static int netxbig_leds_get_of_pdata(struct device *dev,
                                     struct netxbig_led_platform_data *pdata)
 {
-       struct device_node *np = dev->of_node;
+       struct device_node *np = dev_of_node(dev);
        struct device_node *gpio_ext_np;
        struct platform_device *gpio_ext_pdev;
        struct device *gpio_ext_dev;
@@ -485,7 +485,7 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
        }
 
        /* LEDs */
-       num_leds = of_get_child_count(np);
+       num_leds = of_get_available_child_count(np);
        if (!num_leds) {
                dev_err(dev, "No LED subnodes found in DT\n");
                return -ENODEV;
@@ -496,7 +496,7 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
                return -ENOMEM;
 
        led = leds;
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                const char *string;
                int *mode_val;
                int num_modes;
index bd806e7..1677d66 100644 (file)
@@ -24,25 +24,16 @@ enum ns2_led_modes {
        NS_V2_LED_SATA,
 };
 
+/*
+ * If the size of this structure or types of its members is changed,
+ * the filling of array modval in function ns2_led_register must be changed
+ * accordingly.
+ */
 struct ns2_led_modval {
-       enum ns2_led_modes      mode;
-       int                     cmd_level;
-       int                     slow_level;
-};
-
-struct ns2_led {
-       const char      *name;
-       const char      *default_trigger;
-       struct gpio_desc *cmd;
-       struct gpio_desc *slow;
-       int             num_modes;
-       struct ns2_led_modval *modval;
-};
-
-struct ns2_led_platform_data {
-       int             num_leds;
-       struct ns2_led  *leds;
-};
+       u32                     mode;
+       u32                     cmd_level;
+       u32                     slow_level;
+} __packed;
 
 /*
  * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED
@@ -51,7 +42,7 @@ struct ns2_led_platform_data {
  * for the command/slow GPIOs corresponds to a LED mode.
  */
 
-struct ns2_led_data {
+struct ns2_led {
        struct led_classdev     cdev;
        struct gpio_desc        *cmd;
        struct gpio_desc        *slow;
@@ -62,77 +53,67 @@ struct ns2_led_data {
        struct ns2_led_modval   *modval;
 };
 
-static int ns2_led_get_mode(struct ns2_led_data *led_dat,
-                           enum ns2_led_modes *mode)
+static int ns2_led_get_mode(struct ns2_led *led, enum ns2_led_modes *mode)
 {
        int i;
-       int ret = -EINVAL;
        int cmd_level;
        int slow_level;
 
-       cmd_level = gpiod_get_value_cansleep(led_dat->cmd);
-       slow_level = gpiod_get_value_cansleep(led_dat->slow);
+       cmd_level = gpiod_get_value_cansleep(led->cmd);
+       slow_level = gpiod_get_value_cansleep(led->slow);
 
-       for (i = 0; i < led_dat->num_modes; i++) {
-               if (cmd_level == led_dat->modval[i].cmd_level &&
-                   slow_level == led_dat->modval[i].slow_level) {
-                       *mode = led_dat->modval[i].mode;
-                       ret = 0;
-                       break;
+       for (i = 0; i < led->num_modes; i++) {
+               if (cmd_level == led->modval[i].cmd_level &&
+                   slow_level == led->modval[i].slow_level) {
+                       *mode = led->modval[i].mode;
+                       return 0;
                }
        }
 
-       return ret;
+       return -EINVAL;
 }
 
-static void ns2_led_set_mode(struct ns2_led_data *led_dat,
-                            enum ns2_led_modes mode)
+static void ns2_led_set_mode(struct ns2_led *led, enum ns2_led_modes mode)
 {
        int i;
-       bool found = false;
        unsigned long flags;
 
-       for (i = 0; i < led_dat->num_modes; i++)
-               if (mode == led_dat->modval[i].mode) {
-                       found = true;
+       for (i = 0; i < led->num_modes; i++)
+               if (mode == led->modval[i].mode)
                        break;
-               }
 
-       if (!found)
+       if (i == led->num_modes)
                return;
 
-       write_lock_irqsave(&led_dat->rw_lock, flags);
+       write_lock_irqsave(&led->rw_lock, flags);
 
-       if (!led_dat->can_sleep) {
-               gpiod_set_value(led_dat->cmd,
-                               led_dat->modval[i].cmd_level);
-               gpiod_set_value(led_dat->slow,
-                               led_dat->modval[i].slow_level);
+       if (!led->can_sleep) {
+               gpiod_set_value(led->cmd, led->modval[i].cmd_level);
+               gpiod_set_value(led->slow, led->modval[i].slow_level);
                goto exit_unlock;
        }
 
-       gpiod_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
-       gpiod_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
+       gpiod_set_value_cansleep(led->cmd, led->modval[i].cmd_level);
+       gpiod_set_value_cansleep(led->slow, led->modval[i].slow_level);
 
 exit_unlock:
-       write_unlock_irqrestore(&led_dat->rw_lock, flags);
+       write_unlock_irqrestore(&led->rw_lock, flags);
 }
 
 static void ns2_led_set(struct led_classdev *led_cdev,
                        enum led_brightness value)
 {
-       struct ns2_led_data *led_dat =
-               container_of(led_cdev, struct ns2_led_data, cdev);
+       struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
        enum ns2_led_modes mode;
 
        if (value == LED_OFF)
                mode = NS_V2_LED_OFF;
-       else if (led_dat->sata)
+       else if (led->sata)
                mode = NS_V2_LED_SATA;
        else
                mode = NS_V2_LED_ON;
 
-       ns2_led_set_mode(led_dat, mode);
+       ns2_led_set_mode(led, mode);
 }
 
 static int ns2_led_set_blocking(struct led_classdev *led_cdev,
@@ -147,8 +128,7 @@ static ssize_t ns2_led_sata_store(struct device *dev,
                                  const char *buff, size_t count)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct ns2_led_data *led_dat =
-               container_of(led_cdev, struct ns2_led_data, cdev);
+       struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
        int ret;
        unsigned long enable;
 
@@ -158,18 +138,18 @@ static ssize_t ns2_led_sata_store(struct device *dev,
 
        enable = !!enable;
 
-       if (led_dat->sata == enable)
+       if (led->sata == enable)
                goto exit;
 
-       led_dat->sata = enable;
+       led->sata = enable;
 
        if (!led_get_brightness(led_cdev))
                goto exit;
 
        if (enable)
-               ns2_led_set_mode(led_dat, NS_V2_LED_SATA);
+               ns2_led_set_mode(led, NS_V2_LED_SATA);
        else
-               ns2_led_set_mode(led_dat, NS_V2_LED_ON);
+               ns2_led_set_mode(led, NS_V2_LED_ON);
 
 exit:
        return count;
@@ -179,10 +159,9 @@ static ssize_t ns2_led_sata_show(struct device *dev,
                                 struct device_attribute *attr, char *buf)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct ns2_led_data *led_dat =
-               container_of(led_cdev, struct ns2_led_data, cdev);
+       struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
 
-       return sprintf(buf, "%d\n", led_dat->sata);
+       return sprintf(buf, "%d\n", led->sata);
 }
 
 static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store);
@@ -193,147 +172,94 @@ static struct attribute *ns2_led_attrs[] = {
 };
 ATTRIBUTE_GROUPS(ns2_led);
 
-static int
-create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
-              const struct ns2_led *template)
+static int ns2_led_register(struct device *dev, struct fwnode_handle *node,
+                           struct ns2_led *led)
 {
-       int ret;
+       struct led_init_data init_data = {};
+       struct ns2_led_modval *modval;
        enum ns2_led_modes mode;
+       int nmodes, ret;
+
+       led->cmd = devm_fwnode_gpiod_get_index(dev, node, "cmd", 0, GPIOD_ASIS,
+                                              fwnode_get_name(node));
+       if (IS_ERR(led->cmd))
+               return PTR_ERR(led->cmd);
+
+       led->slow = devm_fwnode_gpiod_get_index(dev, node, "slow", 0,
+                                               GPIOD_ASIS,
+                                               fwnode_get_name(node));
+       if (IS_ERR(led->slow))
+               return PTR_ERR(led->slow);
+
+       ret = fwnode_property_count_u32(node, "modes-map");
+       if (ret < 0 || ret % 3) {
+               dev_err(dev, "Missing or malformed modes-map for %pfw\n", node);
+               return -EINVAL;
+       }
+
+       nmodes = ret / 3;
+       modval = devm_kcalloc(dev, nmodes, sizeof(*modval), GFP_KERNEL);
+       if (!modval)
+               return -ENOMEM;
+
+       fwnode_property_read_u32_array(node, "modes-map", (void *)modval,
+                                      nmodes * 3);
+
+       rwlock_init(&led->rw_lock);
 
-       rwlock_init(&led_dat->rw_lock);
-
-       led_dat->cdev.name = template->name;
-       led_dat->cdev.default_trigger = template->default_trigger;
-       led_dat->cdev.blink_set = NULL;
-       led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
-       led_dat->cdev.groups = ns2_led_groups;
-       led_dat->cmd = template->cmd;
-       led_dat->slow = template->slow;
-       led_dat->can_sleep = gpiod_cansleep(led_dat->cmd) |
-                               gpiod_cansleep(led_dat->slow);
-       if (led_dat->can_sleep)
-               led_dat->cdev.brightness_set_blocking = ns2_led_set_blocking;
+       led->cdev.blink_set = NULL;
+       led->cdev.flags |= LED_CORE_SUSPENDRESUME;
+       led->cdev.groups = ns2_led_groups;
+       led->can_sleep = gpiod_cansleep(led->cmd) || gpiod_cansleep(led->slow);
+       if (led->can_sleep)
+               led->cdev.brightness_set_blocking = ns2_led_set_blocking;
        else
-               led_dat->cdev.brightness_set = ns2_led_set;
-       led_dat->modval = template->modval;
-       led_dat->num_modes = template->num_modes;
+               led->cdev.brightness_set = ns2_led_set;
+       led->num_modes = nmodes;
+       led->modval = modval;
 
-       ret = ns2_led_get_mode(led_dat, &mode);
+       ret = ns2_led_get_mode(led, &mode);
        if (ret < 0)
                return ret;
 
        /* Set LED initial state. */
-       led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
-       led_dat->cdev.brightness =
-               (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
+       led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
+       led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
 
-       ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
-       if (ret < 0)
-               return ret;
+       init_data.fwnode = node;
 
-       return 0;
-}
+       ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
+       if (ret)
+               dev_err(dev, "Failed to register LED for node %pfw\n", node);
 
-static void delete_ns2_led(struct ns2_led_data *led_dat)
-{
-       led_classdev_unregister(&led_dat->cdev);
+       return ret;
 }
 
-#ifdef CONFIG_OF_GPIO
-/*
- * Translate OpenFirmware node properties into platform_data.
- */
-static int
-ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
+static int ns2_led_probe(struct platform_device *pdev)
 {
-       struct device_node *np = dev->of_node;
-       struct device_node *child;
-       struct ns2_led *led, *leds;
-       int ret, num_leds = 0;
+       struct device *dev = &pdev->dev;
+       struct fwnode_handle *child;
+       struct ns2_led *leds;
+       int count;
+       int ret;
 
-       num_leds = of_get_child_count(np);
-       if (!num_leds)
+       count = device_get_child_node_count(dev);
+       if (!count)
                return -ENODEV;
 
-       leds = devm_kcalloc(dev, num_leds, sizeof(struct ns2_led),
-                           GFP_KERNEL);
+       leds = devm_kzalloc(dev, array_size(sizeof(*leds), count), GFP_KERNEL);
        if (!leds)
                return -ENOMEM;
 
-       led = leds;
-       for_each_child_of_node(np, child) {
-               const char *string;
-               int i, num_modes;
-               struct ns2_led_modval *modval;
-               struct gpio_desc *gd;
-
-               ret = of_property_read_string(child, "label", &string);
-               led->name = (ret == 0) ? string : child->name;
-
-               gd = gpiod_get_from_of_node(child, "cmd-gpio", 0,
-                                           GPIOD_ASIS, led->name);
-               if (IS_ERR(gd)) {
-                       ret = PTR_ERR(gd);
-                       goto err_node_put;
-               }
-               led->cmd = gd;
-               gd = gpiod_get_from_of_node(child, "slow-gpio", 0,
-                                           GPIOD_ASIS, led->name);
-               if (IS_ERR(gd)) {
-                       ret = PTR_ERR(gd);
-                       goto err_node_put;
-               }
-               led->slow = gd;
-
-               ret = of_property_read_string(child, "linux,default-trigger",
-                                             &string);
-               if (ret == 0)
-                       led->default_trigger = string;
-
-               ret = of_property_count_u32_elems(child, "modes-map");
-               if (ret < 0 || ret % 3) {
-                       dev_err(dev,
-                               "Missing or malformed modes-map property\n");
-                       ret = -EINVAL;
-                       goto err_node_put;
-               }
-
-               num_modes = ret / 3;
-               modval = devm_kcalloc(dev,
-                                     num_modes,
-                                     sizeof(struct ns2_led_modval),
-                                     GFP_KERNEL);
-               if (!modval) {
-                       ret = -ENOMEM;
-                       goto err_node_put;
-               }
-
-               for (i = 0; i < num_modes; i++) {
-                       of_property_read_u32_index(child,
-                                               "modes-map", 3 * i,
-                                               (u32 *) &modval[i].mode);
-                       of_property_read_u32_index(child,
-                                               "modes-map", 3 * i + 1,
-                                               (u32 *) &modval[i].cmd_level);
-                       of_property_read_u32_index(child,
-                                               "modes-map", 3 * i + 2,
-                                               (u32 *) &modval[i].slow_level);
+       device_for_each_child_node(dev, child) {
+               ret = ns2_led_register(dev, child, leds++);
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return ret;
                }
-
-               led->num_modes = num_modes;
-               led->modval = modval;
-
-               led++;
        }
 
-       pdata->leds = leds;
-       pdata->num_leds = num_leds;
-
        return 0;
-
-err_node_put:
-       of_node_put(child);
-       return ret;
 }
 
 static const struct of_device_id of_ns2_leds_match[] = {
@@ -341,76 +267,12 @@ static const struct of_device_id of_ns2_leds_match[] = {
        {},
 };
 MODULE_DEVICE_TABLE(of, of_ns2_leds_match);
-#endif /* CONFIG_OF_GPIO */
-
-struct ns2_led_priv {
-       int num_leds;
-       struct ns2_led_data leds_data[];
-};
-
-static int ns2_led_probe(struct platform_device *pdev)
-{
-       struct ns2_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct ns2_led_priv *priv;
-       int i;
-       int ret;
-
-#ifdef CONFIG_OF_GPIO
-       if (!pdata) {
-               pdata = devm_kzalloc(&pdev->dev,
-                                    sizeof(struct ns2_led_platform_data),
-                                    GFP_KERNEL);
-               if (!pdata)
-                       return -ENOMEM;
-
-               ret = ns2_leds_get_of_pdata(&pdev->dev, pdata);
-               if (ret)
-                       return ret;
-       }
-#else
-       if (!pdata)
-               return -EINVAL;
-#endif /* CONFIG_OF_GPIO */
-
-       priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds_data, pdata->num_leds), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-       priv->num_leds = pdata->num_leds;
-
-       for (i = 0; i < priv->num_leds; i++) {
-               ret = create_ns2_led(pdev, &priv->leds_data[i],
-                                    &pdata->leds[i]);
-               if (ret < 0) {
-                       for (i = i - 1; i >= 0; i--)
-                               delete_ns2_led(&priv->leds_data[i]);
-                       return ret;
-               }
-       }
-
-       platform_set_drvdata(pdev, priv);
-
-       return 0;
-}
-
-static int ns2_led_remove(struct platform_device *pdev)
-{
-       int i;
-       struct ns2_led_priv *priv;
-
-       priv = platform_get_drvdata(pdev);
-
-       for (i = 0; i < priv->num_leds; i++)
-               delete_ns2_led(&priv->leds_data[i]);
-
-       return 0;
-}
 
 static struct platform_driver ns2_led_driver = {
        .probe          = ns2_led_probe,
-       .remove         = ns2_led_remove,
        .driver         = {
                .name           = "leds-ns2",
-               .of_match_table = of_match_ptr(of_ns2_leds_match),
+               .of_match_table = of_ns2_leds_match,
        },
 };
 
index 7d515d5..27d0271 100644 (file)
@@ -27,6 +27,8 @@
 #define PCA9532_REG_PWM(m, i)  (PCA9532_REG_OFFSET(m) + 0x2 + (i) * 2)
 #define LED_REG(m, led)                (PCA9532_REG_OFFSET(m) + 0x5 + (led >> 2))
 #define LED_NUM(led)           (led & 0x3)
+#define LED_SHIFT(led)         (LED_NUM(led) * 2)
+#define LED_MASK(led)          (0x3 << LED_SHIFT(led))
 
 #define ldev_to_led(c)       container_of(c, struct pca9532_led, ldev)
 
@@ -162,9 +164,9 @@ static void pca9532_setled(struct pca9532_led *led)
        mutex_lock(&data->update_lock);
        reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
        /* zero led bits */
-       reg = reg & ~(0x3<<LED_NUM(led->id)*2);
+       reg = reg & ~LED_MASK(led->id);
        /* set the new value */
-       reg = reg | (led->state << LED_NUM(led->id)*2);
+       reg = reg | (led->state << LED_SHIFT(led->id));
        i2c_smbus_write_byte_data(client, LED_REG(maxleds, led->id), reg);
        mutex_unlock(&data->update_lock);
 }
@@ -260,7 +262,7 @@ static enum pca9532_state pca9532_getled(struct pca9532_led *led)
 
        mutex_lock(&data->update_lock);
        reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
-       ret = reg >> LED_NUM(led->id)/2;
+       ret = (reg & LED_MASK(led->id)) >> LED_SHIFT(led->id);
        mutex_unlock(&data->update_lock);
        return ret;
 }
@@ -478,7 +480,12 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np)
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       for_each_child_of_node(np, child) {
+       of_property_read_u8_array(np, "nxp,pwm", &pdata->pwm[0],
+                                 ARRAY_SIZE(pdata->pwm));
+       of_property_read_u8_array(np, "nxp,psc", &pdata->psc[0],
+                                 ARRAY_SIZE(pdata->psc));
+
+       for_each_available_child_of_node(np, child) {
                if (of_property_read_string(child, "label",
                                            &pdata->leds[i].name))
                        pdata->leds[i].name = child->name;
@@ -507,7 +514,7 @@ static int pca9532_probe(struct i2c_client *client,
        struct pca9532_data *data = i2c_get_clientdata(client);
        struct pca9532_platform_data *pca9532_pdata =
                        dev_get_platdata(&client->dev);
-       struct device_node *np = client->dev.of_node;
+       struct device_node *np = dev_of_node(&client->dev);
 
        if (!pca9532_pdata) {
                if (np) {
@@ -545,13 +552,8 @@ static int pca9532_probe(struct i2c_client *client,
 static int pca9532_remove(struct i2c_client *client)
 {
        struct pca9532_data *data = i2c_get_clientdata(client);
-       int err;
 
-       err = pca9532_destroy_devices(data, data->chip_info->num_leds);
-       if (err)
-               return err;
-
-       return 0;
+       return pca9532_destroy_devices(data, data->chip_info->num_leds);
 }
 
 module_i2c_driver(pca9532_driver);
index 131f8e9..7087ca4 100644 (file)
@@ -65,6 +65,7 @@ enum pca955x_type {
        pca9550,
        pca9551,
        pca9552,
+       ibm_pca9552,
        pca9553,
 };
 
@@ -90,6 +91,11 @@ static struct pca955x_chipdef pca955x_chipdefs[] = {
                .slv_addr       = /* 1100xxx */ 0x60,
                .slv_addr_shift = 3,
        },
+       [ibm_pca9552] = {
+               .bits           = 16,
+               .slv_addr       = /* 0110xxx */ 0x30,
+               .slv_addr_shift = 3,
+       },
        [pca9553] = {
                .bits           = 4,
                .slv_addr       = /* 110001x */ 0x62,
@@ -101,6 +107,7 @@ static const struct i2c_device_id pca955x_id[] = {
        { "pca9550", pca9550 },
        { "pca9551", pca9551 },
        { "pca9552", pca9552 },
+       { "ibm-pca9552", ibm_pca9552 },
        { "pca9553", pca9553 },
        { }
 };
@@ -412,6 +419,7 @@ static const struct of_device_id of_pca955x_match[] = {
        { .compatible = "nxp,pca9550", .data = (void *)pca9550 },
        { .compatible = "nxp,pca9551", .data = (void *)pca9551 },
        { .compatible = "nxp,pca9552", .data = (void *)pca9552 },
+       { .compatible = "ibm,pca9552", .data = (void *)ibm_pca9552 },
        { .compatible = "nxp,pca9553", .data = (void *)pca9553 },
        {},
 };
index d288acb..00aecd6 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/of.h>
-#include <linux/platform_data/leds-pca963x.h>
 
 /* LED select registers determine the source that drives LED outputs */
 #define PCA963X_LED_OFF                0x0     /* LED driver off */
@@ -96,142 +95,148 @@ static const struct i2c_device_id pca963x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pca963x_id);
 
-struct pca963x_led;
-
-struct pca963x {
-       struct pca963x_chipdef *chipdef;
-       struct mutex mutex;
-       struct i2c_client *client;
-       struct pca963x_led *leds;
-       unsigned long leds_on;
-};
+struct pca963x;
 
 struct pca963x_led {
        struct pca963x *chip;
        struct led_classdev led_cdev;
        int led_num; /* 0 .. 15 potentially */
-       char name[32];
        u8 gdc;
        u8 gfrq;
 };
 
-static int pca963x_brightness(struct pca963x_led *pca963x,
-                              enum led_brightness brightness)
+struct pca963x {
+       struct pca963x_chipdef *chipdef;
+       struct mutex mutex;
+       struct i2c_client *client;
+       unsigned long leds_on;
+       struct pca963x_led leds[];
+};
+
+static int pca963x_brightness(struct pca963x_led *led,
+                             enum led_brightness brightness)
 {
-       u8 ledout_addr = pca963x->chip->chipdef->ledout_base
-               + (pca963x->led_num / 4);
-       u8 ledout;
-       int shift = 2 * (pca963x->led_num % 4);
-       u8 mask = 0x3 << shift;
+       struct i2c_client *client = led->chip->client;
+       struct pca963x_chipdef *chipdef = led->chip->chipdef;
+       u8 ledout_addr, ledout, mask, val;
+       int shift;
        int ret;
 
-       ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
+       ledout_addr = chipdef->ledout_base + (led->led_num / 4);
+       shift = 2 * (led->led_num % 4);
+       mask = 0x3 << shift;
+       ledout = i2c_smbus_read_byte_data(client, ledout_addr);
+
        switch (brightness) {
        case LED_FULL:
-               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
-                       ledout_addr,
-                       (ledout & ~mask) | (PCA963X_LED_ON << shift));
+               val = (ledout & ~mask) | (PCA963X_LED_ON << shift);
+               ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
                break;
        case LED_OFF:
-               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
-                       ledout_addr, ledout & ~mask);
+               val = ledout & ~mask;
+               ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
                break;
        default:
-               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
-                       PCA963X_PWM_BASE + pca963x->led_num,
-                       brightness);
+               ret = i2c_smbus_write_byte_data(client,
+                                               PCA963X_PWM_BASE +
+                                               led->led_num,
+                                               brightness);
                if (ret < 0)
                        return ret;
-               ret = i2c_smbus_write_byte_data(pca963x->chip->client,
-                       ledout_addr,
-                       (ledout & ~mask) | (PCA963X_LED_PWM << shift));
+
+               val = (ledout & ~mask) | (PCA963X_LED_PWM << shift);
+               ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
                break;
        }
 
        return ret;
 }
 
-static void pca963x_blink(struct pca963x_led *pca963x)
+static void pca963x_blink(struct pca963x_led *led)
 {
-       u8 ledout_addr = pca963x->chip->chipdef->ledout_base +
-               (pca963x->led_num / 4);
-       u8 ledout;
-       u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client,
-                                                       PCA963X_MODE2);
-       int shift = 2 * (pca963x->led_num % 4);
-       u8 mask = 0x3 << shift;
+       struct i2c_client *client = led->chip->client;
+       struct pca963x_chipdef *chipdef = led->chip->chipdef;
+       u8 ledout_addr, ledout, mask, val, mode2;
+       int shift;
+
+       ledout_addr = chipdef->ledout_base + (led->led_num / 4);
+       shift = 2 * (led->led_num % 4);
+       mask = 0x3 << shift;
+       mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2);
 
-       i2c_smbus_write_byte_data(pca963x->chip->client,
-                       pca963x->chip->chipdef->grppwm, pca963x->gdc);
+       i2c_smbus_write_byte_data(client, chipdef->grppwm, led->gdc);
 
-       i2c_smbus_write_byte_data(pca963x->chip->client,
-                       pca963x->chip->chipdef->grpfreq, pca963x->gfrq);
+       i2c_smbus_write_byte_data(client, chipdef->grpfreq, led->gfrq);
 
        if (!(mode2 & PCA963X_MODE2_DMBLNK))
-               i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
-                       mode2 | PCA963X_MODE2_DMBLNK);
-
-       mutex_lock(&pca963x->chip->mutex);
-       ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
-       if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift))
-               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
-                       (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift));
-       mutex_unlock(&pca963x->chip->mutex);
+               i2c_smbus_write_byte_data(client, PCA963X_MODE2,
+                                         mode2 | PCA963X_MODE2_DMBLNK);
+
+       mutex_lock(&led->chip->mutex);
+
+       ledout = i2c_smbus_read_byte_data(client, ledout_addr);
+       if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) {
+               val = (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift);
+               i2c_smbus_write_byte_data(client, ledout_addr, val);
+       }
+
+       mutex_unlock(&led->chip->mutex);
 }
 
-static int pca963x_power_state(struct pca963x_led *pca963x)
+static int pca963x_power_state(struct pca963x_led *led)
 {
-       unsigned long *leds_on = &pca963x->chip->leds_on;
-       unsigned long cached_leds = pca963x->chip->leds_on;
+       struct i2c_client *client = led->chip->client;
+       unsigned long *leds_on = &led->chip->leds_on;
+       unsigned long cached_leds = *leds_on;
 
-       if (pca963x->led_cdev.brightness)
-               set_bit(pca963x->led_num, leds_on);
+       if (led->led_cdev.brightness)
+               set_bit(led->led_num, leds_on);
        else
-               clear_bit(pca963x->led_num, leds_on);
+               clear_bit(led->led_num, leds_on);
 
        if (!(*leds_on) != !cached_leds)
-               return i2c_smbus_write_byte_data(pca963x->chip->client,
-                       PCA963X_MODE1, *leds_on ? 0 : BIT(4));
+               return i2c_smbus_write_byte_data(client, PCA963X_MODE1,
+                                                *leds_on ? 0 : BIT(4));
 
        return 0;
 }
 
 static int pca963x_led_set(struct led_classdev *led_cdev,
-       enum led_brightness value)
+                          enum led_brightness value)
 {
-       struct pca963x_led *pca963x;
+       struct pca963x_led *led;
        int ret;
 
-       pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
+       led = container_of(led_cdev, struct pca963x_led, led_cdev);
 
-       mutex_lock(&pca963x->chip->mutex);
+       mutex_lock(&led->chip->mutex);
 
-       ret = pca963x_brightness(pca963x, value);
+       ret = pca963x_brightness(led, value);
        if (ret < 0)
                goto unlock;
-       ret = pca963x_power_state(pca963x);
+       ret = pca963x_power_state(led);
 
 unlock:
-       mutex_unlock(&pca963x->chip->mutex);
+       mutex_unlock(&led->chip->mutex);
        return ret;
 }
 
-static unsigned int pca963x_period_scale(struct pca963x_led *pca963x,
-       unsigned int val)
+static unsigned int pca963x_period_scale(struct pca963x_led *led,
+                                        unsigned int val)
 {
-       unsigned int scaling = pca963x->chip->chipdef->scaling;
+       unsigned int scaling = led->chip->chipdef->scaling;
 
        return scaling ? DIV_ROUND_CLOSEST(val * scaling, 1000) : val;
 }
 
 static int pca963x_blink_set(struct led_classdev *led_cdev,
-               unsigned long *delay_on, unsigned long *delay_off)
+                            unsigned long *delay_on, unsigned long *delay_off)
 {
-       struct pca963x_led *pca963x;
        unsigned long time_on, time_off, period;
+       struct pca963x_led *led;
        u8 gdc, gfrq;
 
-       pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
+       led = container_of(led_cdev, struct pca963x_led, led_cdev);
 
        time_on = *delay_on;
        time_off = *delay_off;
@@ -242,14 +247,14 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
                time_off = 500;
        }
 
-       period = pca963x_period_scale(pca963x, time_on + time_off);
+       period = pca963x_period_scale(led, time_on + time_off);
 
        /* If period not supported by hardware, default to someting sane. */
        if ((period < PCA963X_BLINK_PERIOD_MIN) ||
            (period > PCA963X_BLINK_PERIOD_MAX)) {
                time_on = 500;
                time_off = 500;
-               period = pca963x_period_scale(pca963x, 1000);
+               period = pca963x_period_scale(led, 1000);
        }
 
        /*
@@ -257,7 +262,7 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
         *      (time_on / period) = (GDC / 256) ->
         *              GDC = ((time_on * 256) / period)
         */
-       gdc = (pca963x_period_scale(pca963x, time_on) * 256) / period;
+       gdc = (pca963x_period_scale(led, time_on) * 256) / period;
 
        /*
         * From manual: period = ((GFRQ + 1) / 24) in seconds.
@@ -266,10 +271,10 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
         */
        gfrq = (period * 24 / 1000) - 1;
 
-       pca963x->gdc = gdc;
-       pca963x->gfrq = gfrq;
+       led->gdc = gdc;
+       led->gfrq = gfrq;
 
-       pca963x_blink(pca963x);
+       pca963x_blink(led);
 
        *delay_on = time_on;
        *delay_off = time_off;
@@ -277,72 +282,84 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
        return 0;
 }
 
-static struct pca963x_platform_data *
-pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip)
+static int pca963x_register_leds(struct i2c_client *client,
+                                struct pca963x *chip)
 {
-       struct pca963x_platform_data *pdata;
-       struct led_info *pca963x_leds;
+       struct pca963x_chipdef *chipdef = chip->chipdef;
+       struct pca963x_led *led = chip->leds;
+       struct device *dev = &client->dev;
        struct fwnode_handle *child;
-       int count;
-
-       count = device_get_child_node_count(&client->dev);
-       if (!count || count > chip->n_leds)
-               return ERR_PTR(-ENODEV);
-
-       pca963x_leds = devm_kcalloc(&client->dev,
-                       chip->n_leds, sizeof(struct led_info), GFP_KERNEL);
-       if (!pca963x_leds)
-               return ERR_PTR(-ENOMEM);
-
-       device_for_each_child_node(&client->dev, child) {
-               struct led_info led = {};
-               u32 reg;
-               int res;
-
-               res = fwnode_property_read_u32(child, "reg", &reg);
-               if ((res != 0) || (reg >= chip->n_leds))
-                       continue;
+       bool hw_blink;
+       s32 mode2;
+       u32 reg;
+       int ret;
 
-               res = fwnode_property_read_string(child, "label", &led.name);
-               if ((res != 0) && is_of_node(child))
-                       led.name = to_of_node(child)->name;
+       if (device_property_read_u32(dev, "nxp,period-scale",
+                                    &chipdef->scaling))
+               chipdef->scaling = 1000;
 
-               fwnode_property_read_string(child, "linux,default-trigger",
-                                           &led.default_trigger);
+       hw_blink = device_property_read_bool(dev, "nxp,hw-blink");
 
-               pca963x_leds[reg] = led;
-       }
-       pdata = devm_kzalloc(&client->dev,
-                            sizeof(struct pca963x_platform_data), GFP_KERNEL);
-       if (!pdata)
-               return ERR_PTR(-ENOMEM);
-
-       pdata->leds.leds = pca963x_leds;
-       pdata->leds.num_leds = chip->n_leds;
+       mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2);
+       if (mode2 < 0)
+               return mode2;
 
        /* default to open-drain unless totem pole (push-pull) is specified */
-       if (device_property_read_bool(&client->dev, "nxp,totem-pole"))
-               pdata->outdrv = PCA963X_TOTEM_POLE;
+       if (device_property_read_bool(dev, "nxp,totem-pole"))
+               mode2 |= PCA963X_MODE2_OUTDRV;
        else
-               pdata->outdrv = PCA963X_OPEN_DRAIN;
+               mode2 &= ~PCA963X_MODE2_OUTDRV;
 
-       /* default to software blinking unless hardware blinking is specified */
-       if (device_property_read_bool(&client->dev, "nxp,hw-blink"))
-               pdata->blink_type = PCA963X_HW_BLINK;
+       /* default to non-inverted output, unless inverted is specified */
+       if (device_property_read_bool(dev, "nxp,inverted-out"))
+               mode2 |= PCA963X_MODE2_INVRT;
        else
-               pdata->blink_type = PCA963X_SW_BLINK;
+               mode2 &= ~PCA963X_MODE2_INVRT;
+
+       ret = i2c_smbus_write_byte_data(client, PCA963X_MODE2, mode2);
+       if (ret < 0)
+               return ret;
+
+       device_for_each_child_node(dev, child) {
+               struct led_init_data init_data = {};
+               char default_label[32];
+
+               ret = fwnode_property_read_u32(child, "reg", &reg);
+               if (ret || reg >= chipdef->n_leds) {
+                       dev_err(dev, "Invalid 'reg' property for node %pfw\n",
+                               child);
+                       ret = -EINVAL;
+                       goto err;
+               }
 
-       if (device_property_read_u32(&client->dev, "nxp,period-scale",
-                                    &chip->scaling))
-               chip->scaling = 1000;
+               led->led_num = reg;
+               led->chip = chip;
+               led->led_cdev.brightness_set_blocking = pca963x_led_set;
+               if (hw_blink)
+                       led->led_cdev.blink_set = pca963x_blink_set;
+
+               init_data.fwnode = child;
+               /* for backwards compatibility */
+               init_data.devicename = "pca963x";
+               snprintf(default_label, sizeof(default_label), "%d:%.2x:%u",
+                        client->adapter->nr, client->addr, reg);
+               init_data.default_label = default_label;
+
+               ret = devm_led_classdev_register_ext(dev, &led->led_cdev,
+                                                    &init_data);
+               if (ret) {
+                       dev_err(dev, "Failed to register LED for node %pfw\n",
+                               child);
+                       goto err;
+               }
 
-       /* default to non-inverted output, unless inverted is specified */
-       if (device_property_read_bool(&client->dev, "nxp,inverted-out"))
-               pdata->dir = PCA963X_INVERTED;
-       else
-               pdata->dir = PCA963X_NORMAL;
+               ++led;
+       }
 
-       return pdata;
+       return 0;
+err:
+       fwnode_handle_put(child);
+       return ret;
 }
 
 static const struct of_device_id of_pca963x_match[] = {
@@ -355,119 +372,40 @@ static const struct of_device_id of_pca963x_match[] = {
 MODULE_DEVICE_TABLE(of, of_pca963x_match);
 
 static int pca963x_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+                        const struct i2c_device_id *id)
 {
-       struct pca963x *pca963x_chip;
-       struct pca963x_led *pca963x;
-       struct pca963x_platform_data *pdata;
-       struct pca963x_chipdef *chip;
-       int i, err;
-
-       chip = &pca963x_chipdefs[id->driver_data];
-       pdata = dev_get_platdata(&client->dev);
-
-       if (!pdata) {
-               pdata = pca963x_get_pdata(client, chip);
-               if (IS_ERR(pdata)) {
-                       dev_warn(&client->dev, "could not parse configuration\n");
-                       pdata = NULL;
-               }
-       }
+       struct device *dev = &client->dev;
+       struct pca963x_chipdef *chipdef;
+       struct pca963x *chip;
+       int i, count;
 
-       if (pdata && (pdata->leds.num_leds < 1 ||
-                                pdata->leds.num_leds > chip->n_leds)) {
-               dev_err(&client->dev, "board info must claim 1-%d LEDs",
-                                                               chip->n_leds);
+       chipdef = &pca963x_chipdefs[id->driver_data];
+
+       count = device_get_child_node_count(dev);
+       if (!count || count > chipdef->n_leds) {
+               dev_err(dev, "Node %pfw must define between 1 and %d LEDs\n",
+                       dev_fwnode(dev), chipdef->n_leds);
                return -EINVAL;
        }
 
-       pca963x_chip = devm_kzalloc(&client->dev, sizeof(*pca963x_chip),
-                                                               GFP_KERNEL);
-       if (!pca963x_chip)
-               return -ENOMEM;
-       pca963x = devm_kcalloc(&client->dev, chip->n_leds, sizeof(*pca963x),
-                                                               GFP_KERNEL);
-       if (!pca963x)
+       chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL);
+       if (!chip)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, pca963x_chip);
+       i2c_set_clientdata(client, chip);
 
-       mutex_init(&pca963x_chip->mutex);
-       pca963x_chip->chipdef = chip;
-       pca963x_chip->client = client;
-       pca963x_chip->leds = pca963x;
+       mutex_init(&chip->mutex);
+       chip->chipdef = chipdef;
+       chip->client = client;
 
        /* Turn off LEDs by default*/
-       for (i = 0; i < chip->n_leds / 4; i++)
-               i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00);
-
-       for (i = 0; i < chip->n_leds; i++) {
-               pca963x[i].led_num = i;
-               pca963x[i].chip = pca963x_chip;
-
-               /* Platform data can specify LED names and default triggers */
-               if (pdata && i < pdata->leds.num_leds) {
-                       if (pdata->leds.leds[i].name)
-                               snprintf(pca963x[i].name,
-                                        sizeof(pca963x[i].name), "pca963x:%s",
-                                        pdata->leds.leds[i].name);
-                       if (pdata->leds.leds[i].default_trigger)
-                               pca963x[i].led_cdev.default_trigger =
-                                       pdata->leds.leds[i].default_trigger;
-               }
-               if (!pdata || i >= pdata->leds.num_leds ||
-                                               !pdata->leds.leds[i].name)
-                       snprintf(pca963x[i].name, sizeof(pca963x[i].name),
-                                "pca963x:%d:%.2x:%d", client->adapter->nr,
-                                client->addr, i);
-
-               pca963x[i].led_cdev.name = pca963x[i].name;
-               pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set;
-
-               if (pdata && pdata->blink_type == PCA963X_HW_BLINK)
-                       pca963x[i].led_cdev.blink_set = pca963x_blink_set;
-
-               err = led_classdev_register(&client->dev, &pca963x[i].led_cdev);
-               if (err < 0)
-                       goto exit;
-       }
+       for (i = 0; i < chipdef->n_leds / 4; i++)
+               i2c_smbus_write_byte_data(client, chipdef->ledout_base + i, 0x00);
 
        /* Disable LED all-call address, and power down initially */
        i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4));
 
-       if (pdata) {
-               u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client,
-                                                   PCA963X_MODE2);
-               /* Configure output: open-drain or totem pole (push-pull) */
-               if (pdata->outdrv == PCA963X_OPEN_DRAIN)
-                       mode2 &= ~PCA963X_MODE2_OUTDRV;
-               else
-                       mode2 |= PCA963X_MODE2_OUTDRV;
-               /* Configure direction: normal or inverted */
-               if (pdata->dir == PCA963X_INVERTED)
-                       mode2 |= PCA963X_MODE2_INVRT;
-               i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
-                                         mode2);
-       }
-
-       return 0;
-
-exit:
-       while (i--)
-               led_classdev_unregister(&pca963x[i].led_cdev);
-
-       return err;
-}
-
-static int pca963x_remove(struct i2c_client *client)
-{
-       struct pca963x *pca963x = i2c_get_clientdata(client);
-       int i;
-
-       for (i = 0; i < pca963x->chipdef->n_leds; i++)
-               led_classdev_unregister(&pca963x->leds[i].led_cdev);
-
-       return 0;
+       return pca963x_register_leds(client, chip);
 }
 
 static struct i2c_driver pca963x_driver = {
@@ -476,7 +414,6 @@ static struct i2c_driver pca963x_driver = {
                .of_match_table = of_pca963x_match,
        },
        .probe  = pca963x_probe,
-       .remove = pca963x_remove,
        .id_table = pca963x_id,
 };
 
index 7869ccd..fb2ab72 100644 (file)
@@ -87,36 +87,36 @@ static enum led_brightness pm8058_led_get(struct led_classdev *cled)
 
 static int pm8058_led_probe(struct platform_device *pdev)
 {
+       struct led_init_data init_data = {};
+       struct device *dev = &pdev->dev;
        struct pm8058_led *led;
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *np;
        int ret;
        struct regmap *map;
        const char *state;
        enum led_brightness maxbright;
 
-       led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
+       led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
        if (!led)
                return -ENOMEM;
 
-       led->ledtype = (u32)(unsigned long)of_device_get_match_data(&pdev->dev);
+       led->ledtype = (u32)(unsigned long)of_device_get_match_data(dev);
 
-       map = dev_get_regmap(pdev->dev.parent, NULL);
+       map = dev_get_regmap(dev->parent, NULL);
        if (!map) {
-               dev_err(&pdev->dev, "Parent regmap unavailable.\n");
+               dev_err(dev, "Parent regmap unavailable.\n");
                return -ENXIO;
        }
        led->map = map;
 
+       np = dev_of_node(dev);
+
        ret = of_property_read_u32(np, "reg", &led->reg);
        if (ret) {
-               dev_err(&pdev->dev, "no register offset specified\n");
+               dev_err(dev, "no register offset specified\n");
                return -EINVAL;
        }
 
-       /* Use label else node name */
-       led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
-       led->cdev.default_trigger =
-               of_get_property(np, "linux,default-trigger", NULL);
        led->cdev.brightness_set = pm8058_led_set;
        led->cdev.brightness_get = pm8058_led_get;
        if (led->ledtype == PM8058_LED_TYPE_COMMON)
@@ -142,14 +142,13 @@ static int pm8058_led_probe(struct platform_device *pdev)
            led->ledtype == PM8058_LED_TYPE_FLASH)
                led->cdev.flags = LED_CORE_SUSPENDRESUME;
 
-       ret = devm_led_classdev_register(&pdev->dev, &led->cdev);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to register led \"%s\"\n",
-                       led->cdev.name);
-               return ret;
-       }
+       init_data.fwnode = of_fwnode_handle(np);
+
+       ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
+       if (ret)
+               dev_err(dev, "Failed to register LED for %pOF\n", np);
 
-       return 0;
+       return ret;
 }
 
 static const struct of_device_id pm8058_leds_id_table[] = {
index cd43d5d..743e2cd 100644 (file)
@@ -250,7 +250,7 @@ static int powernv_led_classdev(struct platform_device *pdev,
        struct powernv_led_data *powernv_led;
        struct device *dev = &pdev->dev;
 
-       for_each_child_of_node(led_node, np) {
+       for_each_available_child_of_node(led_node, np) {
                p = of_find_property(np, "led-types", NULL);
 
                while ((cur = of_prop_next_string(p, cur)) != NULL) {
index ef7b91b..f53f930 100644 (file)
 
 struct led_pwm {
        const char      *name;
-       const char      *default_trigger;
        u8              active_low;
        unsigned int    max_brightness;
 };
 
-struct led_pwm_platform_data {
-       int             num_leds;
-       struct led_pwm  *leds;
-};
-
 struct led_pwm_data {
        struct led_classdev     cdev;
        struct pwm_device       *pwm;
@@ -61,36 +55,31 @@ static int led_pwm_set(struct led_classdev *led_cdev,
        return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate);
 }
 
+__attribute__((nonnull))
 static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
                       struct led_pwm *led, struct fwnode_handle *fwnode)
 {
        struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
+       struct led_init_data init_data = { .fwnode = fwnode };
        int ret;
 
        led_data->active_low = led->active_low;
        led_data->cdev.name = led->name;
-       led_data->cdev.default_trigger = led->default_trigger;
        led_data->cdev.brightness = LED_OFF;
        led_data->cdev.max_brightness = led->max_brightness;
        led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
 
-       if (fwnode)
-               led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
-       else
-               led_data->pwm = devm_pwm_get(dev, led->name);
-       if (IS_ERR(led_data->pwm)) {
-               ret = PTR_ERR(led_data->pwm);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "unable to request PWM for %s: %d\n",
-                               led->name, ret);
-               return ret;
-       }
+       led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
+       if (IS_ERR(led_data->pwm))
+               return dev_err_probe(dev, PTR_ERR(led_data->pwm),
+                                    "unable to request PWM for %s\n",
+                                    led->name);
 
        led_data->cdev.brightness_set_blocking = led_pwm_set;
 
        pwm_init_state(led_data->pwm, &led_data->pwmstate);
 
-       ret = devm_led_classdev_register(dev, &led_data->cdev);
+       ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
        if (ret) {
                dev_err(dev, "failed to register PWM led for %s: %d\n",
                        led->name, ret);
@@ -126,9 +115,6 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
                        return -EINVAL;
                }
 
-               fwnode_property_read_string(fwnode, "linux,default-trigger",
-                                           &led.default_trigger);
-
                led.active_low = fwnode_property_read_bool(fwnode,
                                                           "active-low");
                fwnode_property_read_u32(fwnode, "max-brightness",
@@ -146,15 +132,11 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
 
 static int led_pwm_probe(struct platform_device *pdev)
 {
-       struct led_pwm_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct led_pwm_priv *priv;
-       int count, i;
        int ret = 0;
+       int count;
 
-       if (pdata)
-               count = pdata->num_leds;
-       else
-               count = device_get_child_node_count(&pdev->dev);
+       count = device_get_child_node_count(&pdev->dev);
 
        if (!count)
                return -EINVAL;
@@ -164,16 +146,7 @@ static int led_pwm_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       if (pdata) {
-               for (i = 0; i < count; i++) {
-                       ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i],
-                                         NULL);
-                       if (ret)
-                               break;
-               }
-       } else {
-               ret = led_pwm_create_fwnode(&pdev->dev, priv);
-       }
+       ret = led_pwm_create_fwnode(&pdev->dev, priv);
 
        if (ret)
                return ret;
index 9b5e676..3c0c7aa 100644 (file)
@@ -16,8 +16,6 @@
 #include <linux/module.h>
 #include <linux/platform_data/leds-s3c24xx.h>
 
-#include <mach/regs-gpio.h>
-
 /* our context */
 
 struct s3c24xx_gpio_led {
index 0ede874..e199ea1 100644 (file)
@@ -276,12 +276,12 @@ static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)
 static int sc27xx_led_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node, *child;
+       struct device_node *np = dev_of_node(dev), *child;
        struct sc27xx_led_priv *priv;
        u32 base, count, reg;
        int err;
 
-       count = of_get_child_count(np);
+       count = of_get_available_child_count(np);
        if (!count || count > SC27XX_LEDS_MAX)
                return -EINVAL;
 
@@ -305,7 +305,7 @@ static int sc27xx_led_probe(struct platform_device *pdev)
                return err;
        }
 
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                err = of_property_read_u32(child, "reg", &reg);
                if (err) {
                        of_node_put(child);
index c494b93..f4f8315 100644 (file)
@@ -195,30 +195,21 @@ static int sgm3140_probe(struct platform_device *pdev)
 
        priv->flash_gpio = devm_gpiod_get(&pdev->dev, "flash", GPIOD_OUT_LOW);
        ret = PTR_ERR_OR_ZERO(priv->flash_gpio);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev,
-                               "Failed to request flash gpio: %d\n", ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "Failed to request flash gpio\n");
 
        priv->enable_gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW);
        ret = PTR_ERR_OR_ZERO(priv->enable_gpio);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev,
-                               "Failed to request enable gpio: %d\n", ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "Failed to request enable gpio\n");
 
        priv->vin_regulator = devm_regulator_get(&pdev->dev, "vin");
        ret = PTR_ERR_OR_ZERO(priv->vin_regulator);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev,
-                               "Failed to request regulator: %d\n", ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "Failed to request regulator\n");
 
        child_node = fwnode_get_next_available_child_node(pdev->dev.fwnode,
                                                          NULL);
@@ -316,5 +307,5 @@ static struct platform_driver sgm3140_driver = {
 module_platform_driver(sgm3140_driver);
 
 MODULE_AUTHOR("Luca Weiss <luca@z3ntu.xyz>");
-MODULE_DESCRIPTION("SG Micro SGM3140 charge pump led driver");
+MODULE_DESCRIPTION("SG Micro SGM3140 charge pump LED driver");
 MODULE_LICENSE("GPL v2");
index b231b56..f1964c9 100644 (file)
@@ -80,7 +80,6 @@ static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
 
 static int spi_byte_probe(struct spi_device *spi)
 {
-       const struct of_device_id *of_dev_id;
        struct device_node *child;
        struct device *dev = &spi->dev;
        struct spi_byte_led *led;
@@ -88,15 +87,11 @@ static int spi_byte_probe(struct spi_device *spi)
        const char *state;
        int ret;
 
-       of_dev_id = of_match_device(spi_byte_dt_ids, dev);
-       if (!of_dev_id)
-               return -EINVAL;
-
-       if (of_get_child_count(dev->of_node) != 1) {
+       if (of_get_available_child_count(dev_of_node(dev)) != 1) {
                dev_err(dev, "Device must have exactly one LED sub-node.");
                return -EINVAL;
        }
-       child = of_get_next_child(dev->of_node, NULL);
+       child = of_get_next_available_child(dev_of_node(dev), NULL);
 
        led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
        if (!led)
@@ -106,7 +101,7 @@ static int spi_byte_probe(struct spi_device *spi)
        strlcpy(led->name, name, sizeof(led->name));
        led->spi = spi;
        mutex_init(&led->mutex);
-       led->cdef = of_dev_id->data;
+       led->cdef = device_get_match_data(dev);
        led->ldev.name = led->name;
        led->ldev.brightness = LED_OFF;
        led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value;
index b58f3ca..7eddb8e 100644 (file)
@@ -55,8 +55,9 @@ static void syscon_led_set(struct led_classdev *led_cdev,
 
 static int syscon_led_probe(struct platform_device *pdev)
 {
+       struct led_init_data init_data = {};
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
+       struct device_node *np = dev_of_node(dev);
        struct device *parent;
        struct regmap *map;
        struct syscon_led *sled;
@@ -68,7 +69,7 @@ static int syscon_led_probe(struct platform_device *pdev)
                dev_err(dev, "no parent for syscon LED\n");
                return -ENODEV;
        }
-       map = syscon_node_to_regmap(parent->of_node);
+       map = syscon_node_to_regmap(dev_of_node(parent));
        if (IS_ERR(map)) {
                dev_err(dev, "no regmap for syscon LED parent\n");
                return PTR_ERR(map);
@@ -84,10 +85,6 @@ static int syscon_led_probe(struct platform_device *pdev)
                return -EINVAL;
        if (of_property_read_u32(np, "mask", &sled->mask))
                return -EINVAL;
-       sled->cdev.name =
-               of_get_property(np, "label", NULL) ? : np->name;
-       sled->cdev.default_trigger =
-               of_get_property(np, "linux,default-trigger", NULL);
 
        state = of_get_property(np, "default-state", NULL);
        if (state) {
@@ -115,7 +112,9 @@ static int syscon_led_probe(struct platform_device *pdev)
        }
        sled->cdev.brightness_set = syscon_led_set;
 
-       ret = devm_led_classdev_register(dev, &sled->cdev);
+       init_data.fwnode = of_fwnode_handle(np);
+
+       ret = devm_led_classdev_register_ext(dev, &sled->cdev, &init_data);
        if (ret < 0)
                return ret;
 
index 1128ac7..225b765 100644 (file)
  * defaulted.  Similarly the banks know if each time was explicit or a
  * default.  Defaults are permitted to be changed freely - they are
  * not recognised when matching.
- *
- *
- * An led-tca6507 device must be provided with platform data or
- * configured via devicetree.
- *
- * The platform-data lists for each output: the name, default trigger,
- * and whether the signal is being used as a GPIO rather than an LED.
- * 'struct led_plaform_data' is used for this.  If 'name' is NULL, the
- * output isn't used.  If 'flags' is TCA6507_MAKE_GPIO, the output is
- * a GPO.  The "struct led_platform_data" can be embedded in a "struct
- * tca6507_platform_data" which adds a 'gpio_base' for the GPIOs, and
- * a 'setup' callback which is called once the GPIOs are available.
- *
- * When configured via devicetree there is one child for each output.
- * The "reg" determines the output number and "compatible" determines
- * whether it is an LED or a GPIO.  "linux,default-trigger" can set a
- * default trigger.
  */
 
 #include <linux/module.h>
@@ -94,9 +77,8 @@
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/gpio/driver.h>
+#include <linux/property.h>
 #include <linux/workqueue.h>
-#include <linux/leds-tca6507.h>
-#include <linux/of.h>
 
 /* LED select registers determine the source that drives LED outputs */
 #define TCA6507_LS_LED_OFF     0x0     /* Output HI-Z (off) */
 #define TCA6507_LS_BLINK0      0x6     /* Blink at Bank0 rate */
 #define TCA6507_LS_BLINK1      0x7     /* Blink at Bank1 rate */
 
+struct tca6507_platform_data {
+       struct led_platform_data leds;
+#ifdef CONFIG_GPIOLIB
+       int gpio_base;
+#endif
+};
+
+#define        TCA6507_MAKE_GPIO 1
+
 enum {
        BANK0,
        BANK1,
@@ -189,7 +180,6 @@ struct tca6507_chip {
        } leds[NUM_LEDS];
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip                gpio;
-       const char                      *gpio_name[NUM_LEDS];
        int                             gpio_map[NUM_LEDS];
 #endif
 };
@@ -628,7 +618,7 @@ static int tca6507_gpio_direction_output(struct gpio_chip *gc,
        return 0;
 }
 
-static int tca6507_probe_gpios(struct i2c_client *client,
+static int tca6507_probe_gpios(struct device *dev,
                               struct tca6507_chip *tca,
                               struct tca6507_platform_data *pdata)
 {
@@ -639,7 +629,6 @@ static int tca6507_probe_gpios(struct i2c_client *client,
        for (i = 0; i < NUM_LEDS; i++)
                if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) {
                        /* Configure as a gpio */
-                       tca->gpio_name[gpios] = pdata->leds.leds[i].name;
                        tca->gpio_map[gpios] = i;
                        gpios++;
                }
@@ -648,23 +637,20 @@ static int tca6507_probe_gpios(struct i2c_client *client,
                return 0;
 
        tca->gpio.label = "gpio-tca6507";
-       tca->gpio.names = tca->gpio_name;
        tca->gpio.ngpio = gpios;
        tca->gpio.base = pdata->gpio_base;
        tca->gpio.owner = THIS_MODULE;
        tca->gpio.direction_output = tca6507_gpio_direction_output;
        tca->gpio.set = tca6507_gpio_set_value;
-       tca->gpio.parent = &client->dev;
+       tca->gpio.parent = dev;
 #ifdef CONFIG_OF_GPIO
-       tca->gpio.of_node = of_node_get(client->dev.of_node);
+       tca->gpio.of_node = of_node_get(dev_of_node(dev));
 #endif
        err = gpiochip_add_data(&tca->gpio, tca);
        if (err) {
                tca->gpio.ngpio = 0;
                return err;
        }
-       if (pdata->setup)
-               pdata->setup(tca->gpio.base, tca->gpio.ngpio);
        return 0;
 }
 
@@ -674,7 +660,7 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca)
                gpiochip_remove(&tca->gpio);
 }
 #else /* CONFIG_GPIOLIB */
-static int tca6507_probe_gpios(struct i2c_client *client,
+static int tca6507_probe_gpios(struct device *dev,
                               struct tca6507_chip *tca,
                               struct tca6507_platform_data *pdata)
 {
@@ -685,44 +671,50 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca)
 }
 #endif /* CONFIG_GPIOLIB */
 
-#ifdef CONFIG_OF
 static struct tca6507_platform_data *
-tca6507_led_dt_init(struct i2c_client *client)
+tca6507_led_dt_init(struct device *dev)
 {
-       struct device_node *np = client->dev.of_node, *child;
        struct tca6507_platform_data *pdata;
+       struct fwnode_handle *child;
        struct led_info *tca_leds;
        int count;
 
-       count = of_get_child_count(np);
+       count = device_get_child_node_count(dev);
        if (!count || count > NUM_LEDS)
                return ERR_PTR(-ENODEV);
 
-       tca_leds = devm_kcalloc(&client->dev,
-                       NUM_LEDS, sizeof(struct led_info), GFP_KERNEL);
+       tca_leds = devm_kcalloc(dev, NUM_LEDS, sizeof(struct led_info),
+                               GFP_KERNEL);
        if (!tca_leds)
                return ERR_PTR(-ENOMEM);
 
-       for_each_child_of_node(np, child) {
+       device_for_each_child_node(dev, child) {
                struct led_info led;
                u32 reg;
                int ret;
 
-               led.name =
-                       of_get_property(child, "label", NULL) ? : child->name;
-               led.default_trigger =
-                       of_get_property(child, "linux,default-trigger", NULL);
+               if (fwnode_property_read_string(child, "label", &led.name))
+                       led.name = fwnode_get_name(child);
+
+               fwnode_property_read_string(child, "linux,default-trigger",
+                                           &led.default_trigger);
+
                led.flags = 0;
-               if (of_property_match_string(child, "compatible", "gpio") >= 0)
+               if (fwnode_property_match_string(child, "compatible",
+                                                "gpio") >= 0)
                        led.flags |= TCA6507_MAKE_GPIO;
-               ret = of_property_read_u32(child, "reg", &reg);
-               if (ret != 0 || reg >= NUM_LEDS)
-                       continue;
+
+               ret = fwnode_property_read_u32(child, "reg", &reg);
+               if (ret || reg >= NUM_LEDS) {
+                       fwnode_handle_put(child);
+                       return ERR_PTR(ret ? : -EINVAL);
+               }
 
                tca_leds[reg] = led;
        }
-       pdata = devm_kzalloc(&client->dev,
-                       sizeof(struct tca6507_platform_data), GFP_KERNEL);
+
+       pdata = devm_kzalloc(dev, sizeof(struct tca6507_platform_data),
+                            GFP_KERNEL);
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
@@ -731,48 +723,37 @@ tca6507_led_dt_init(struct i2c_client *client)
 #ifdef CONFIG_GPIOLIB
        pdata->gpio_base = -1;
 #endif
+
        return pdata;
 }
 
-static const struct of_device_id of_tca6507_leds_match[] = {
+static const struct of_device_id __maybe_unused of_tca6507_leds_match[] = {
        { .compatible = "ti,tca6507", },
        {},
 };
 MODULE_DEVICE_TABLE(of, of_tca6507_leds_match);
 
-#else
-static struct tca6507_platform_data *
-tca6507_led_dt_init(struct i2c_client *client)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-#endif
-
 static int tca6507_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
-       struct tca6507_chip *tca;
+       struct device *dev = &client->dev;
        struct i2c_adapter *adapter;
+       struct tca6507_chip *tca;
        struct tca6507_platform_data *pdata;
        int err;
        int i = 0;
 
        adapter = client->adapter;
-       pdata = dev_get_platdata(&client->dev);
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
                return -EIO;
 
-       if (!pdata || pdata->leds.num_leds != NUM_LEDS) {
-               pdata = tca6507_led_dt_init(client);
-               if (IS_ERR(pdata)) {
-                       dev_err(&client->dev, "Need %d entries in platform-data list\n",
-                               NUM_LEDS);
-                       return PTR_ERR(pdata);
-               }
+       pdata = tca6507_led_dt_init(dev);
+       if (IS_ERR(pdata)) {
+               dev_err(dev, "Need %d entries in platform-data list\n", NUM_LEDS);
+               return PTR_ERR(pdata);
        }
-       tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL);
+       tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL);
        if (!tca)
                return -ENOMEM;
 
@@ -793,13 +774,12 @@ static int tca6507_probe(struct i2c_client *client,
                        l->led_cdev.brightness_set = tca6507_brightness_set;
                        l->led_cdev.blink_set = tca6507_blink_set;
                        l->bank = -1;
-                       err = led_classdev_register(&client->dev,
-                                                   &l->led_cdev);
+                       err = led_classdev_register(dev, &l->led_cdev);
                        if (err < 0)
                                goto exit;
                }
        }
-       err = tca6507_probe_gpios(client, tca, pdata);
+       err = tca6507_probe_gpios(dev, tca, pdata);
        if (err)
                goto exit;
        /* set all registers to known state - zero */
index 0929f12..5b9dfdf 100644 (file)
@@ -148,22 +148,17 @@ static int
 tlc591xx_probe(struct i2c_client *client,
               const struct i2c_device_id *id)
 {
-       struct device_node *np = client->dev.of_node, *child;
+       struct device_node *np = dev_of_node(&client->dev), *child;
        struct device *dev = &client->dev;
-       const struct of_device_id *match;
        const struct tlc591xx *tlc591xx;
        struct tlc591xx_priv *priv;
        int err, count, reg;
 
-       match = of_match_device(of_tlc591xx_leds_match, dev);
-       if (!match)
-               return -ENODEV;
-
-       tlc591xx = match->data;
+       tlc591xx = device_get_match_data(dev);
        if (!np)
                return -ENODEV;
 
-       count = of_get_child_count(np);
+       count = of_get_available_child_count(np);
        if (!count || count > tlc591xx->max_leds)
                return -EINVAL;
 
@@ -185,7 +180,7 @@ tlc591xx_probe(struct i2c_client *client,
        if (err < 0)
                return err;
 
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                struct tlc591xx_led *led;
                struct led_init_data init_data = {};
 
@@ -204,9 +199,6 @@ tlc591xx_probe(struct i2c_client *client,
                led = &priv->leds[reg];
 
                led->active = true;
-               led->ldev.default_trigger =
-                       of_get_property(child, "linux,default-trigger", NULL);
-
                led->priv = priv;
                led->led_no = reg;
                led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
@@ -214,10 +206,10 @@ tlc591xx_probe(struct i2c_client *client,
                err = devm_led_classdev_register_ext(dev, &led->ldev,
                                                     &init_data);
                if (err < 0) {
-                       if (err != -EPROBE_DEFER)
-                               dev_err(dev, "couldn't register LED %s\n",
-                                       led->ldev.name);
-                       return err;
+                       of_node_put(child);
+                       return dev_err_probe(dev, err,
+                                            "couldn't register LED %s\n",
+                                            led->ldev.name);
                }
        }
        return 0;
index bb23d8e..8c5bdc3 100644 (file)
@@ -121,8 +121,6 @@ static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,
        cdev->max_brightness = 255;
        cdev->brightness_set_blocking = omnia_led_brightness_set_blocking;
 
-       of_property_read_string(np, "linux,default-trigger", &cdev->default_trigger);
-
        /* put the LED into software mode */
        ret = i2c_smbus_write_byte_data(client, CMD_LED_MODE,
                                        CMD_LED_MODE_LED(led->reg) |
@@ -210,7 +208,7 @@ static int omnia_leds_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
-       struct device_node *np = dev->of_node, *child;
+       struct device_node *np = dev_of_node(dev), *child;
        struct omnia_leds *leds;
        struct omnia_led *led;
        int ret, count;
@@ -236,8 +234,10 @@ static int omnia_leds_probe(struct i2c_client *client,
        led = &leds->leds[0];
        for_each_available_child_of_node(np, child) {
                ret = omnia_led_register(client, led, child);
-               if (ret < 0)
+               if (ret < 0) {
+                       of_node_put(child);
                        return ret;
+               }
 
                led += ret;
        }
index 869976d..fca62d5 100644 (file)
@@ -2,14 +2,18 @@
 /*
  * ledtrig-cpu.c - LED trigger based on CPU activity
  *
- * This LED trigger will be registered for each possible CPU and named as
- * cpu0, cpu1, cpu2, cpu3, etc.
+ * This LED trigger will be registered for first 8 CPUs and named
+ * as cpu0..cpu7. There's additional trigger called cpu that
+ * is on when any CPU is active.
+ *
+ * If you want support for arbitrary number of CPUs, make it one trigger,
+ * with additional sysfs file selecting which CPU to watch.
  *
  * It can be bound to any LED just like other triggers using either a
  * board file or via sysfs interface.
  *
  * An API named ledtrig_cpu is exported for any user, who want to add CPU
- * activity indication in their code
+ * activity indication in their code.
  *
  * Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
  * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com>
@@ -145,6 +149,9 @@ static int __init ledtrig_cpu_init(void)
        for_each_possible_cpu(cpu) {
                struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
 
+               if (cpu >= 8)
+                       continue;
+
                snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
 
                led_trigger_register_simple(trig->name, &trig->_trig);
diff --git a/include/linux/leds-tca6507.h b/include/linux/leds-tca6507.h
deleted file mode 100644 (file)
index 50d330e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * TCA6507 LED chip driver.
- *
- * Copyright (C) 2011 Neil Brown <neil@brown.name>
- */
-
-#ifndef __LINUX_TCA6507_H
-#define __LINUX_TCA6507_H
-#include <linux/leds.h>
-
-struct tca6507_platform_data {
-       struct led_platform_data leds;
-#ifdef CONFIG_GPIOLIB
-       int gpio_base;
-       void (*setup)(unsigned gpio_base, unsigned ngpio);
-#endif
-};
-
-#define        TCA6507_MAKE_GPIO 1
-#endif /* __LINUX_TCA6507_H*/
diff --git a/include/linux/platform_data/leds-pca963x.h b/include/linux/platform_data/leds-pca963x.h
deleted file mode 100644 (file)
index 6091337..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * PCA963X LED chip driver.
- *
- * Copyright 2012 bct electronic GmbH
- * Copyright 2013 Qtechnology A/S
- */
-
-#ifndef __LINUX_PCA963X_H
-#define __LINUX_PCA963X_H
-#include <linux/leds.h>
-
-enum pca963x_outdrv {
-       PCA963X_OPEN_DRAIN,
-       PCA963X_TOTEM_POLE, /* aka push-pull */
-};
-
-enum pca963x_blink_type {
-       PCA963X_SW_BLINK,
-       PCA963X_HW_BLINK,
-};
-
-enum pca963x_direction {
-       PCA963X_NORMAL,
-       PCA963X_INVERTED,
-};
-
-struct pca963x_platform_data {
-       struct led_platform_data leds;
-       enum pca963x_outdrv outdrv;
-       enum pca963x_blink_type blink_type;
-       enum pca963x_direction dir;
-};
-
-#endif /* __LINUX_PCA963X_H*/