[PATCH 0/3] Introduce msm8916 based LG devices

2024-06-23 Thread Nikita Travkin
This series introduces two msm8916-based LG devices:

- LG Leon LTE (c50)
- LG LG K10 (m216)

The devices only have basic support for now.

Signed-off-by: Nikita Travkin 
---
Anton Bambura (1):
  arm64: dts: qcom: msm8916-lg-c50: add initial dts for LG Leon LTE

Cristian Cozzolino (1):
  arm64: dts: qcom: msm8916-lg-m216: Add initial device tree

Nikita Travkin (1):
  dt-bindings: arm: qcom: Add msm8916 based LG devices

 Documentation/devicetree/bindings/arm/qcom.yaml |   2 +
 arch/arm64/boot/dts/qcom/Makefile   |   2 +
 arch/arm64/boot/dts/qcom/msm8916-lg-c50.dts | 140 +
 arch/arm64/boot/dts/qcom/msm8916-lg-m216.dts| 251 
 4 files changed, 395 insertions(+)
---
base-commit: f76698bd9a8ca01d3581236082d786e9a6b72bb7
change-id: 20240621-msm8916-lg-initial-8d4a399ec3c2

Best regards,
-- 
Nikita Travkin 




[PATCH 1/3] dt-bindings: arm: qcom: Add msm8916 based LG devices

2024-06-23 Thread Nikita Travkin
Add compatible values for the msm8916 based LG smartphones.

Signed-off-by: Nikita Travkin 
---
 Documentation/devicetree/bindings/arm/qcom.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml 
b/Documentation/devicetree/bindings/arm/qcom.yaml
index d839691a900c..09edce29ff3a 100644
--- a/Documentation/devicetree/bindings/arm/qcom.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom.yaml
@@ -208,6 +208,8 @@ properties:
   - asus,z00l
   - gplus,fl8005a
   - huawei,g7
+  - lg,c50
+  - lg,m216
   - longcheer,l8910
   - longcheer,l8150
   - motorola,harpia

-- 
2.45.2




[PATCH 2/3] arm64: dts: qcom: msm8916-lg-m216: Add initial device tree

2024-06-23 Thread Nikita Travkin
From: Cristian Cozzolino 

This commit adds initial support for the LG K10 smartphone.

Support for the following features is included:

- Serial
- Keys
- Battery and charger
- Accelerometer, magnetometer
- Touchscreen
- Sound and modem
- Haptic

Signed-off-by: Cristian Cozzolino 
[Nikita: Minor cleanup]
Signed-off-by: Nikita Travkin 
---
 arch/arm64/boot/dts/qcom/Makefile|   1 +
 arch/arm64/boot/dts/qcom/msm8916-lg-m216.dts | 251 +++
 2 files changed, 252 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/Makefile 
b/arch/arm64/boot/dts/qcom/Makefile
index 5576c7d6ea06..b35e46d75a1d 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -31,6 +31,7 @@ dtb-$(CONFIG_ARCH_QCOM)   += msm8916-alcatel-idol347.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-asus-z00l.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-gplus-fl8005a.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-huawei-g7.dtb
+dtb-$(CONFIG_ARCH_QCOM)+= msm8916-lg-m216.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-longcheer-l8150.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-longcheer-l8910.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-motorola-harpia.dtb
diff --git a/arch/arm64/boot/dts/qcom/msm8916-lg-m216.dts 
b/arch/arm64/boot/dts/qcom/msm8916-lg-m216.dts
new file mode 100644
index ..07345e694f6f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8916-lg-m216.dts
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/dts-v1/;
+
+#include "msm8916-pm8916.dtsi"
+#include "msm8916-modem-qdsp6.dtsi"
+
+#include 
+
+/ {
+   model = "LG K10 (K420n)";
+   compatible = "lg,m216", "qcom,msm8916";
+   chassis-type = "handset";
+
+   aliases {
+   mmc0 = _1; /* eMMC */
+   mmc1 = _2; /* SD card */
+   serial0 = _uart2;
+   };
+
+   chosen {
+   stdout-path = "serial0";
+   };
+
+   battery: battery {
+   compatible = "simple-battery";
+   voltage-min-design-microvolt = <330>;
+   voltage-max-design-microvolt = <435>;
+   energy-full-design-microwatt-hours = <880>;
+   charge-full-design-microamp-hours = <230>;
+
+   ocv-capacity-celsius = <25>;
+   ocv-capacity-table-0 = <4342000 100>, <4266000 95>, <4206000 
90>,
+   <4148000 85>, <4094000 80>, <4046000 75>, <3994000 70>,
+   <3956000 65>, <3916000 60>, <3866000 55>, <3831000 50>,
+   <3808000 45>, <3789000 40>, <3776000 35>, <3769000 30>,
+   <376 25>, <374 20>, <3712000 16>, <3684000 13>,
+   <3676000 11>, <3674000 10>, <3672000 9>, <3669000 8>,
+   <3665000 7>, <366 6>, <3643000 5>, <3602000 4>,
+   <3542000 3>, <3458000 2>, <3326000 1>, <300 0>;
+   };
+
+   gpio-keys {
+   compatible = "gpio-keys";
+
+   pinctrl-0 = <_keys_default>;
+   pinctrl-names = "default";
+
+   label = "GPIO Buttons";
+
+   volume-up-button {
+   label = "Volume Up";
+   gpios = < 107 GPIO_ACTIVE_LOW>;
+   linux,code = ;
+   };
+
+   volume-down-button {
+   label = "Volume Down";
+   gpios = < 108 GPIO_ACTIVE_LOW>;
+   linux,code = ;
+   };
+   };
+};
+
+_i2c2 {
+   status = "okay";
+
+   accelerometer@11 {
+   compatible = "bosch,bmc150_accel";
+   reg = <0x11>;
+
+   interrupts-extended = < 115 IRQ_TYPE_EDGE_RISING>;
+
+   mount-matrix =   "0", "1", "0",
+   "-1", "0", "0",
+"0", "0", "1";
+
+   vdd-supply = <_l17>;
+   vddio-supply = <_l6>;
+
+   pinctrl-0 = <_int_default>;
+   pinctrl-names = "default";
+   };
+
+   magnetometer@13 {
+   compatible = "bosch,bmc150_magn";
+   reg = <0x13>;
+
+   interrupts-extended = < 69 IRQ_TYPE_EDGE_RISING>;
+
+   vdd-supply = <_l17>;
+   vddio-supply = <_l6>;
+
+   pinctrl-0 = <_int_default>;
+   pinctrl-names = "def

[PATCH 3/3] arm64: dts: qcom: msm8916-lg-c50: add initial dts for LG Leon LTE

2024-06-23 Thread Nikita Travkin
From: Anton Bambura 

Add initial device-tree for LG Leon LTE (lg-c50), currently supported
features:
- eMMC;
- MicroSD;
- usb in peripheral mode;
- WiFi/BT;
- vibration;
- keys.

Signed-off-by: Anton Bambura 
Signed-off-by: Nikita Travkin 
---
 arch/arm64/boot/dts/qcom/Makefile   |   1 +
 arch/arm64/boot/dts/qcom/msm8916-lg-c50.dts | 140 
 2 files changed, 141 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/Makefile 
b/arch/arm64/boot/dts/qcom/Makefile
index b35e46d75a1d..919dfcb26d15 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -31,6 +31,7 @@ dtb-$(CONFIG_ARCH_QCOM)   += msm8916-alcatel-idol347.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-asus-z00l.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-gplus-fl8005a.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-huawei-g7.dtb
+dtb-$(CONFIG_ARCH_QCOM)+= msm8916-lg-c50.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-lg-m216.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-longcheer-l8150.dtb
 dtb-$(CONFIG_ARCH_QCOM)+= msm8916-longcheer-l8910.dtb
diff --git a/arch/arm64/boot/dts/qcom/msm8916-lg-c50.dts 
b/arch/arm64/boot/dts/qcom/msm8916-lg-c50.dts
new file mode 100644
index ..a823a1c40208
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8916-lg-c50.dts
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/dts-v1/;
+
+#include "msm8916-pm8916.dtsi"
+
+#include 
+
+/ {
+   model = "LG Leon LTE";
+   compatible = "lg,c50", "qcom,msm8916";
+   chassis-type = "handset";
+
+   aliases {
+   mmc0 = _1; /* eMMC */
+   mmc1 = _2; /* SD card */
+   serial0 = _uart2;
+   };
+
+   chosen {
+   stdout-path = "serial0";
+   };
+
+   gpio-keys {
+   compatible = "gpio-keys";
+
+   pinctrl-0 = <_keys_default>;
+   pinctrl-names = "default";
+
+   label = "GPIO Buttons";
+
+   volume-up-button {
+   label = "Volume Up";
+   gpios = < 108 GPIO_ACTIVE_LOW>;
+   linux,code = ;
+   };
+
+   volume-down-button {
+   label = "Volume Down";
+   gpios = < 107 GPIO_ACTIVE_LOW>;
+   linux,code = ;
+   };
+   };
+
+   reg_sd_vmmc: regulator-sdcard-vmmc {
+   compatible = "regulator-fixed";
+   regulator-name = "sdcard-vmmc";
+   regulator-min-microvolt = <295>;
+   regulator-max-microvolt = <295>;
+
+   gpio = < 60 GPIO_ACTIVE_HIGH>;
+   enable-active-high;
+
+   startup-delay-us = <5000>;
+
+   pinctrl-0 = <_vmmc_en_default>;
+   pinctrl-names = "default";
+   };
+};
+
+_uart2 {
+   status = "okay";
+};
+
+_usbin {
+   status = "okay";
+};
+
+_vib {
+   status = "okay";
+};
+
+_1 {
+   status = "okay";
+};
+
+_2 {
+   vmmc-supply = <_sd_vmmc>;
+
+   pinctrl-0 = <_default _cd_default>;
+   pinctrl-1 = <_sleep _cd_default>;
+   pinctrl-names = "default", "sleep";
+
+   cd-gpios = < 38 GPIO_ACTIVE_HIGH>;
+
+   status = "okay";
+};
+
+ {
+   dr_mode = "peripheral";
+   extcon = <_usbin>;
+   status = "okay";
+};
+
+_hs_phy {
+   extcon = <_usbin>;
+};
+
+ {
+   status = "okay";
+};
+
+_mem {
+   status = "okay";
+};
+
+ {
+   status = "okay";
+};
+
+_iris {
+   compatible = "qcom,wcn3620";
+};
+
+_mem {
+   status = "okay";
+};
+
+ {
+   gpio_keys_default: gpio-keys-default-state {
+   pins = "gpio107", "gpio108";
+   function = "gpio";
+   drive-strength = <2>;
+   bias-pull-up;
+   };
+
+   sd_vmmc_en_default: sd-vmmc-en-default-state {
+   pins = "gpio60";
+   function = "gpio";
+   drive-strength = <2>;
+   bias-disable;
+   };
+
+   sdc2_cd_default: sdc2-cd-default-state {
+   pins = "gpio38";
+   function = "gpio";
+   drive-strength = <2>;
+   bias-pull-down;
+   };
+};

-- 
2.45.2




Re: [PATCH 1/2] dt-bindings: soc: qcom: Add bindings for Qualcomm Memshare service

2021-04-15 Thread Nikita Travkin



14.04.2021 08:15, Bjorn Andersson пишет:
> On Sat 10 Apr 03:05 CDT 2021, Nikita Travkin wrote:
>
>> Hi, sorry for a late reply but I couldn't answer earlier.
>>
>> 30.03.2021 19:40, Rob Herring ??:
>>> On Fri, Mar 19, 2021 at 10:23:20PM +0500, nikitos...@gmail.com wrote:
>>>> From: Nikita Travkin 
>>>>
>>>> Add DT bindings for memshare: QMI service that allocates
>>>> memory per remote processor request.
>>>>
>>>> Signed-off-by: Nikita Travkin 
>>>> ---
>>>>  .../bindings/soc/qcom/qcom,memshare.yaml  | 109 ++
>>>>  include/dt-bindings/soc/qcom,memshare.h   |  10 ++
>>>>  2 files changed, 119 insertions(+)
>>>>  create mode 100644 
>>>> Documentation/devicetree/bindings/soc/qcom/qcom,memshare.yaml
>>>>  create mode 100644 include/dt-bindings/soc/qcom,memshare.h
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,memshare.yaml 
>>>> b/Documentation/devicetree/bindings/soc/qcom/qcom,memshare.yaml
>>>> new file mode 100644
>>>> index ..ebdf128b066c
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,memshare.yaml
>>>> @@ -0,0 +1,109 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: "http://devicetree.org/schemas/soc/qcom/qcom,memshare.yaml#;
>>>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#;
>>>> +
>>>> +title: Qualcomm QMI Shared Memory Service
>>> How many shared memory interfaces does Qcom have...
>>>
>>>> +
>>>> +description: |
>>>> +  This driver provides a QMI service that allows remote processors (like 
>>>> modem)
>>>> +  to request additional memory. It is used for applications like GPS in 
>>>> modem.
>>> If the memory region is defined in reserved-memory, how are you 
>>> allocating additional memory? 
>> Initially remoteproc is loaded into it's own reserved-memory region
>> but qcom decided that they sometimes need more memory than that.
>> Memshare driver in msm8916 downstream tree seem to blindly allocate
>> DMA region for every request that it gets. Additionally for those
>> clients described in the DT, they do the DMA allocation on boot
>> time and never free the region. They call it "guaranteed" allocation.
>>
>> On msm8916 only one "guaranteed" client seem to be used so I decided
>> to implement it with reserved-memory node. On newer platforms they
>> seem to have more clients but I think that the driver can be easily
>> extended to support dynamic allocation if someone really needs it.
>>
> Is the "guaranteed" memory required to come from the reserved-memory
> part of memory, or could it simply be allocated on demand as well (or
> preallocated, but at a dynamic address)?

This is rather complicated.

For most (msm8916) devices it works with a region from dma_alloc but
there are at least three devices where it causes problems.

If the region was allocated by dma_alloc (somewhere near 0xfe10
if I remember correctly) then
- Wileyfox Swift (Longcheer L8150): Location service "crashes"
  (repeats request every 10-ish seconds while location session is
  open and gives no location data)
- Samsung A3, A5: The entire modem crashes after it gets the response
  with such address.

Downstream kernel allocates the region at slightly different address
which works fine.

It's probably possible to change the allocation address with dma mask
but I have no idea why the crash happens on those devices, if it's
even possible to debug this or find all the "bad" regions.
Because of that I prefer using a known-good address at least for the
location client that keeps it forever.

> If these allocations always came from a reserved-memory region, then
> adding a "qcom,memshare" compatible to the reserved-memory node itself
> seems like a reasonable approach. But if dma_alloc is sufficient, and
> there's cases where there's no "guaranteed" region, perhaps we should
> just describe this as part of the remoteproc node (i.e. essentially
> flipping the node/subnode in your current binding).
>
>
> E.g. can we get away with simply adding an optional qcom,memshare-node
> to the remoteproc binding and when that's present we make the Qualcomm
> remoteproc drivers spawn the memshare handler and listen for requests
> from that node?

I'm having a hard time imagining how this would be implemented...

Assuming tha

Re: [PATCH 1/2] dt-bindings: soc: qcom: Add bindings for Qualcomm Memshare service

2021-04-10 Thread Nikita Travkin
Hi, sorry for a late reply but I couldn't answer earlier.

30.03.2021 19:40, Rob Herring пишет:
> On Fri, Mar 19, 2021 at 10:23:20PM +0500, nikitos...@gmail.com wrote:
>> From: Nikita Travkin 
>>
>> Add DT bindings for memshare: QMI service that allocates
>> memory per remote processor request.
>>
>> Signed-off-by: Nikita Travkin 
>> ---
>>  .../bindings/soc/qcom/qcom,memshare.yaml  | 109 ++
>>  include/dt-bindings/soc/qcom,memshare.h   |  10 ++
>>  2 files changed, 119 insertions(+)
>>  create mode 100644 
>> Documentation/devicetree/bindings/soc/qcom/qcom,memshare.yaml
>>  create mode 100644 include/dt-bindings/soc/qcom,memshare.h
>>
>> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,memshare.yaml 
>> b/Documentation/devicetree/bindings/soc/qcom/qcom,memshare.yaml
>> new file mode 100644
>> index ..ebdf128b066c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,memshare.yaml
>> @@ -0,0 +1,109 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: "http://devicetree.org/schemas/soc/qcom/qcom,memshare.yaml#;
>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#;
>> +
>> +title: Qualcomm QMI Shared Memory Service
> How many shared memory interfaces does Qcom have...
>
>> +
>> +description: |
>> +  This driver provides a QMI service that allows remote processors (like 
>> modem)
>> +  to request additional memory. It is used for applications like GPS in 
>> modem.
> If the memory region is defined in reserved-memory, how are you 
> allocating additional memory? 

Initially remoteproc is loaded into it's own reserved-memory region
but qcom decided that they sometimes need more memory than that.
Memshare driver in msm8916 downstream tree seem to blindly allocate
DMA region for every request that it gets. Additionally for those
clients described in the DT, they do the DMA allocation on boot
time and never free the region. They call it "guaranteed" allocation.

On msm8916 only one "guaranteed" client seem to be used so I decided
to implement it with reserved-memory node. On newer platforms they
seem to have more clients but I think that the driver can be easily
extended to support dynamic allocation if someone really needs it.

I tried to explain that in the cover letter but I think I made some
mistake as I don't see it in the Patchwork.

>> +
>> +maintainers:
>> +  - Nikita Travkin 
>> +
>> +properties:
>> +  compatible:
>> +const: qcom,memshare
>> +
>> +  qcom,legacy-client:
>> +$ref: /schemas/types.yaml#/definitions/phandle
>> +description: Phandle to a memshare client node used for legacy requests.
>> +
>> +  "#address-cells":
>> +const: 1
>> +
>> +  "#size-cells":
>> +const: 0
>> +
>> +patternProperties:
>> +  "^.*@[0-9]+$":
>> +type: object
>> +
>> +properties:
>> +  reg:
>> +description: Proc-ID for clients in this node.
> What's Proc-ID?

The requests from the remote nodes contain client-id and proc-id
that are supposed to differentiate the clients. It's possible to
find the values in downstream DT or by observing what messages
are received by the memshare service (I left dev_dbg logging in
the driver for that reason)

I think I should reword it to make this more apparent, maybe
"Proc-ID that clients in this node send."?

>
>> +
>> +  qcom,qrtr-node:
>> +$ref: /schemas/types.yaml#/definitions/uint32
>> +description: Node from which the requests are expected.
>> +
>> +  "#address-cells":
>> +const: 1
>> +
>> +  "#size-cells":
>> +const: 0
>> +
>> +patternProperties:
>> +  "^.*@[0-9]+$":
>> +type: object
>> +
>> +properties:
>> +  reg:
>> +description: ID of this client.
> How does one determine the ID?

As with proc-id, maybe reword to "ID that this client sends."?

I will change those in v2, I still expect comments on the driver
itself, so I'll wait for that before submitting it with just a
couple lines changed.

>
>> +
>> +  memory-region:
>> +$ref: /schemas/types.yaml#/definitions/phandle
>> +description: |
>> +  Reserved memory region that should be used for allocation.
>> +
>> +required:
>> +  - reg
>> +
>> +required:
>> +  - reg
>>

Re: [PATCH 1/3] leds: add aw2013 driver

2020-05-05 Thread Nikita Travkin
> Hi!
>
>> +#define AW2013_NAME "aw2013"
> That's not really useful define. Make it NAME? Drop it?
Will drop it as well as (unnecessary) lines it is used in.
>> +#define AW2013_TIME_STEP 130
> I'd add comment with /* units */.
Will add.
>> +#define STATE_OFF 0
>> +#define STATE_KEEP 1
>> +#define STATE_ON 2
> We should add enum into core for this...
>
>> +static int aw2013_chip_init(struct aw2013 *chip)
>> +{
>> +int i, ret;
>> +
>> +ret = regmap_write(chip->regmap, AW2013_GCR, AW2013_GCR_ENABLE);
>> +if (ret) {
>> +dev_err(>client->dev, "Failed to enable the chip: %d\n",
>> +ret);
>> +goto error;
>> +}
>> +
>> +for (i = 0; i < chip->num_leds; i++) {
>> +ret = regmap_update_bits(chip->regmap,
>> + AW2013_LCFG(chip->leds[i].num),
>> + AW2013_LCFG_IMAX_MASK,
>> + chip->leds[i].imax);
>> +if (ret) {
>> +dev_err(>client->dev,
>> +"Failed to set maximum current for led %d: 
>> %d\n",
>> +chip->leds[i].num, ret);
>> +goto error;
>> +}
>> +}
>> +
>> +error:
>> +return ret;
>> +}
> No need for goto if you are just returning.
Will change it.
>> +static bool aw2013_chip_in_use(struct aw2013 *chip)
>> +{
>> +int i;
>> +
>> +for (i = 0; i < chip->num_leds; i++)
>> +if (chip->leds[i].cdev.brightness)
>> +return true;
>> +
>> +return false;
>> +}
> How is this going to interact with ledstate == KEEP?
>
>> +static int aw2013_brightness_set(struct led_classdev *cdev,
>> + enum led_brightness brightness)
>> +{
>> +struct aw2013_led *led = container_of(cdev, struct aw2013_led, cdev);
>> +int ret, num;
>> +
>> +mutex_lock(>chip->mutex);
>> +
>> +if (aw2013_chip_in_use(led->chip)) {
>> +ret = aw2013_chip_enable(led->chip);
>> +if (ret)
>> +return ret;
>> +}
> You are returning with mutex held.
Will fix.
>> +/* Never on - just set to off */
>> +if (!*delay_on)
>> +return aw2013_brightness_set(>cdev, LED_OFF);
>> +
>> +/* Never off - just set to brightness */
>> +if (!*delay_off)
>> +return aw2013_brightness_set(>cdev, led->cdev.brightness);
> Is this dance neccessary? Should we do it in the core somewhere?
Right now blink_set() can be called with either delay_on or delay_off
being zero.

Passing zero into calculations I do later will result in garbage so
I'm trying to avoid it.

Core could probably handle situation where both are zero (This way
default values will be shared across all drivers) and if only
delay_on is zero it could disable led and the blink mode. (As if
brightness was set to 0)
In case where only delay_off is zero it's a bit more complicated
since driver should disable blinking but leave led on if it was
blinking already.

That also means that my current solution is a bit broken since changing
delay_off to zero while led is already blinking will call brightness_set
without clearing the mode bit so the led will still blink.

For now I will fix that and leave all those checks in place.
>> +} else {
>> +led->imax = 1; // 5mA
>> +dev_info(>dev,
>> + "DT property led-max-microamp is missing!\n");
>> +}
> Lets remove the exclamation mark.
Will do.
>> +led->num = source;
>> +led->chip = chip;
>> +led->fwnode = of_fwnode_handle(child);
>> +
>> +if (!of_property_read_string(child, "default-state", )) {
>> +if (!strcmp(str, "on"))
>> +led->default_state = STATE_ON;
>> +else if (!strcmp(str, "keep"))
>> +led->default_state = STATE_KEEP;
>> +else
>> +led->default_state = STATE_OFF;
>> +}
> We should really have something in core for this. Should we support
> arbitrary brightness there?
Not sure if there is good dt property for that.
>> +static void aw2013_read_current_state(struct aw2013 *chip)
>> +{
>> +int i, led_on;
>> +
>> +regmap_read(chip->regmap, AW2013_LCTR, _on);
>> +
>> +for (i = 0; i < chip->num_leds; i++) {
>> +if (!(led_on & AW2013_LCTR_LE(chip->leds[i].num))) {
>> +chip->leds[i].cdev.brightness = LED_OFF;
>> +continue;
>> +}
>> +regmap_read(chip->regmap, AW2013_REG_PWM(chip->leds[i].num),
>> +>leds[i].cdev.brightness);
>> +}
>> +}
>> +
>> +static void aw2013_init_default_state(struct aw2013_led *led)
>> +{
>> +switch (led->default_state) {
>> +case STATE_ON:
>> +led->cdev.brightness = LED_FULL;
>> +