2023-03-08 09:52:25

by Svyatoslav Ryhel

[permalink] [raw]
Subject: [PATCH v1 0/2] Add OF support for LM3560

Implement device tree support to lm3560 and make some
minor style adjustmets.

Svyatoslav Ryhel (2):
dt-bindings: media: i2c: add lm3560 binding
media: lm3560: convent to OF

.../bindings/media/i2c/ti,lm3560.yaml | 130 ++++++++++++++++++
drivers/media/i2c/lm3560.c | 128 ++++++++++++-----
2 files changed, 223 insertions(+), 35 deletions(-)
create mode 100644 Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml

--
2.37.2



2023-03-08 09:52:30

by Svyatoslav Ryhel

[permalink] [raw]
Subject: [PATCH v1 1/2] dt-bindings: media: i2c: add lm3560 binding

Signed-off-by: Svyatoslav Ryhel <[email protected]>
---
.../bindings/media/i2c/ti,lm3560.yaml | 130 ++++++++++++++++++
1 file changed, 130 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml

diff --git a/Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml b/Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml
new file mode 100644
index 000000000000..b3c2ccb83a30
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ti,lm3560.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI LM3560 Synchronous Boost Flash Driver
+
+maintainers:
+ - Daniel Jeong <[email protected]>
+ - Ldd-Mlp <[email protected]>
+
+description: |
+ The LM3560 is a 2-MHz fixed frequency synchronous boost
+ converter with two 1000-mA constant current drivers for
+ high-current white LEDs. The dual highside current sources
+ allow for grounded cathode LED operation and can be tied
+ together for providing flash currents at up to 2 A through
+ a single LED. An adaptive regulation method ensures the
+ current for each LED remains in regulation and maximizes
+ efficiency.
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - ti,lm3559
+ - ti,lm3560
+
+ reg:
+ maxItems: 1
+
+ enable-gpios:
+ maxItems: 1
+
+ ti,peak-current:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 0x20, 0x40, 0x60]
+ default: 0x60
+ description: |
+ Peak current can be set to 4 values 1.6A (0x00),
+ 2.3A (0x20), 3.0A (0x40) and 3.6A (0x60).
+
+ ti,max-flash-timeout:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 32
+ maximum: 1024
+ default: 1024
+ description: |
+ Maximum flash timeout in ms with step 32ms.
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - '#address-cells'
+ - '#size-cells'
+
+patternProperties:
+ "^led@[01]$":
+ type: object
+ description: |
+ Properties for a connected LEDs.
+ properties:
+ reg:
+ minimum: 0
+ maximum: 1
+
+ ti,max-flash-current:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 62500
+ maximum: 1000000
+ default: 1000000
+ description: |
+ Maximum current in flash mode in uA with step 62500uA.
+
+ ti,max-torch-current:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 31250
+ maximum: 250000
+ default: 250000
+ description: |
+ Maximum current in tourch mode in uA with step 31250uA.
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ flash-led@53 {
+ compatible = "ti,lm3559";
+ reg = <0x53>;
+
+ enable-gpios = <&gpio 219 GPIO_ACTIVE_HIGH>;
+
+ ti,peak-current = <0>;
+ ti,max-flash-timeout = <1024>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@0 {
+ reg = <0>;
+
+ ti,max-flash-current = <562500>;
+ ti,max-torch-current = <156250>;
+ };
+
+ led@1 {
+ reg = <1>;
+
+ ti,max-flash-current = <562500>;
+ ti,max-torch-current = <156250>;
+ };
+ };
+ };
+...
--
2.37.2


2023-03-08 09:52:36

by Svyatoslav Ryhel

[permalink] [raw]
Subject: [PATCH v1 2/2] media: lm3560: convent to OF

If no pdata is available, try to read from device tree.

Signed-off-by: Svyatoslav Ryhel <[email protected]>
---
drivers/media/i2c/lm3560.c | 128 +++++++++++++++++++++++++++----------
1 file changed, 93 insertions(+), 35 deletions(-)

diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index 5ef613604be7..5541051616b7 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -11,6 +11,7 @@

#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/mutex.h>
@@ -22,16 +23,16 @@

/* registers definitions */
#define REG_ENABLE 0x10
-#define REG_TORCH_BR 0xa0
-#define REG_FLASH_BR 0xb0
-#define REG_FLASH_TOUT 0xc0
+#define REG_TORCH_BR 0xa0
+#define REG_FLASH_BR 0xb0
+#define REG_FLASH_TOUT 0xc0
#define REG_FLAG 0xd0
#define REG_CONFIG1 0xe0

/* fault mask */
-#define FAULT_TIMEOUT (1<<0)
-#define FAULT_OVERTEMP (1<<1)
-#define FAULT_SHORT_CIRCUIT (1<<2)
+#define FAULT_TIMEOUT BIT(0)
+#define FAULT_OVERTEMP BIT(1)
+#define FAULT_SHORT_CIRCUIT BIT(2)

enum led_enable {
MODE_SHDN = 0x0,
@@ -54,6 +55,7 @@ struct lm3560_flash {
struct device *dev;
struct lm3560_platform_data *pdata;
struct regmap *regmap;
+ struct gpio_desc *hwen_gpio;
struct mutex lock;

enum v4l2_flash_led_mode led_mode;
@@ -356,12 +358,19 @@ static int lm3560_subdev_init(struct lm3560_flash *flash,
flash->subdev_led[led_no].flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
strscpy(flash->subdev_led[led_no].name, led_name,
sizeof(flash->subdev_led[led_no].name));
+
rval = lm3560_init_controls(flash, led_no);
- if (rval)
+ if (rval) {
+ dev_err(flash->dev, "failed to init controls: %d\n", rval);
goto err_out;
+ }
+
rval = media_entity_pads_init(&flash->subdev_led[led_no].entity, 0, NULL);
- if (rval < 0)
+ if (rval < 0) {
+ dev_err(flash->dev, "failed to init media entity pads: %d\n", rval);
goto err_out;
+ }
+
flash->subdev_led[led_no].entity.function = MEDIA_ENT_F_FLASH;

return rval;
@@ -391,6 +400,49 @@ static int lm3560_init_device(struct lm3560_flash *flash)
return rval;
}

+static int lm3560_of_probe(struct lm3560_flash *flash)
+{
+ struct lm3560_platform_data *pdata;
+ struct fwnode_handle *node;
+ int ret, reg;
+
+ pdata = devm_kzalloc(flash->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENODEV;
+
+ ret = device_property_read_u32(flash->dev,
+ "ti,peak-current", &pdata->peak);
+ if (ret)
+ pdata->peak = LM3560_PEAK_3600mA;
+
+ ret = device_property_read_u32(flash->dev,
+ "ti,max-flash-timeout",
+ &pdata->max_flash_timeout);
+ if (ret)
+ pdata->max_flash_timeout = LM3560_FLASH_TOUT_MAX;
+
+ device_for_each_child_node(flash->dev, node) {
+ fwnode_property_read_u32(node, "reg", &reg);
+
+ if (reg == LM3560_LED0 || reg == LM3560_LED1) {
+ ret = device_property_read_u32(flash->dev,
+ "ti,max-flash-current",
+ &pdata->max_flash_brt[reg]);
+ if (ret)
+ pdata->max_flash_brt[reg] = LM3560_FLASH_TOUT_MAX;
+
+ ret = device_property_read_u32(flash->dev,
+ "ti,max-torch-current",
+ &pdata->max_torch_brt[reg]);
+ if (ret)
+ pdata->max_torch_brt[reg] = LM3560_TORCH_BRT_MAX;
+ }
+ }
+ flash->pdata = pdata;
+
+ return 0;
+}
+
static int lm3560_probe(struct i2c_client *client)
{
struct lm3560_flash *flash;
@@ -398,44 +450,41 @@ static int lm3560_probe(struct i2c_client *client)
int rval;

flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
- if (flash == NULL)
+ if (!flash)
return -ENOMEM;

flash->regmap = devm_regmap_init_i2c(client, &lm3560_regmap);
- if (IS_ERR(flash->regmap)) {
- rval = PTR_ERR(flash->regmap);
- return rval;
- }
+ if (IS_ERR(flash->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(flash->regmap),
+ "failed to init regmap\n");

- /* if there is no platform data, use chip default value */
- if (pdata == NULL) {
- pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
- if (pdata == NULL)
- return -ENODEV;
- pdata->peak = LM3560_PEAK_3600mA;
- pdata->max_flash_timeout = LM3560_FLASH_TOUT_MAX;
- /* led 1 */
- pdata->max_flash_brt[LM3560_LED0] = LM3560_FLASH_BRT_MAX;
- pdata->max_torch_brt[LM3560_LED0] = LM3560_TORCH_BRT_MAX;
- /* led 2 */
- pdata->max_flash_brt[LM3560_LED1] = LM3560_FLASH_BRT_MAX;
- pdata->max_torch_brt[LM3560_LED1] = LM3560_TORCH_BRT_MAX;
- }
- flash->pdata = pdata;
flash->dev = &client->dev;
mutex_init(&flash->lock);

+ /* if there is no platform data, try to read from device tree */
+ if (!pdata)
+ lm3560_of_probe(flash);
+
+ flash->hwen_gpio = devm_gpiod_get_optional(flash->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(flash->hwen_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(flash->hwen_gpio),
+ "failed to get hwen gpio\n");
+
rval = lm3560_subdev_init(flash, LM3560_LED0, "lm3560-led0");
if (rval < 0)
- return rval;
+ return dev_err_probe(&client->dev, rval,
+ "failed to init led0 subdev\n");

rval = lm3560_subdev_init(flash, LM3560_LED1, "lm3560-led1");
if (rval < 0)
- return rval;
+ return dev_err_probe(&client->dev, rval,
+ "failed to init led1 subdev\n");

rval = lm3560_init_device(flash);
if (rval < 0)
- return rval;
+ return dev_err_probe(&client->dev, rval,
+ "failed to init device\n");

i2c_set_clientdata(client, flash);

@@ -452,21 +501,30 @@ static void lm3560_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(&flash->ctrls_led[i]);
media_entity_cleanup(&flash->subdev_led[i].entity);
}
+
+ gpiod_set_value_cansleep(flash->hwen_gpio, 0);
}

+static const struct of_device_id lm3560_match[] = {
+ { .compatible = "ti,lm3559" },
+ { .compatible = "ti,lm3560" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3560_match);
+
static const struct i2c_device_id lm3560_id_table[] = {
{LM3559_NAME, 0},
{LM3560_NAME, 0},
{}
};
-
MODULE_DEVICE_TABLE(i2c, lm3560_id_table);

static struct i2c_driver lm3560_i2c_driver = {
.driver = {
- .name = LM3560_NAME,
- .pm = NULL,
- },
+ .name = LM3560_NAME,
+ .pm = NULL,
+ .of_match_table = lm3560_match,
+ },
.probe_new = lm3560_probe,
.remove = lm3560_remove,
.id_table = lm3560_id_table,
--
2.37.2


2023-03-08 14:08:25

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] dt-bindings: media: i2c: add lm3560 binding


On Wed, 08 Mar 2023 11:52:08 +0200, Svyatoslav Ryhel wrote:
> Signed-off-by: Svyatoslav Ryhel <[email protected]>
> ---
> .../bindings/media/i2c/ti,lm3560.yaml | 130 ++++++++++++++++++
> 1 file changed, 130 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml
>

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Error: Documentation/devicetree/bindings/media/i2c/ti,lm3560.example.dts:26.43-44 syntax error
FATAL ERROR: Unable to parse input tree
make[1]: *** [scripts/Makefile.lib:419: Documentation/devicetree/bindings/media/i2c/ti,lm3560.example.dtb] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:1512: dt_binding_check] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


2023-03-08 18:21:27

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] dt-bindings: media: i2c: add lm3560 binding

On Wed, Mar 08, 2023 at 11:52:08AM +0200, Svyatoslav Ryhel wrote:
> Signed-off-by: Svyatoslav Ryhel <[email protected]>
> ---
> .../bindings/media/i2c/ti,lm3560.yaml | 130 ++++++++++++++++++
> 1 file changed, 130 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml
>
> diff --git a/Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml b/Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml
> new file mode 100644
> index 000000000000..b3c2ccb83a30
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/ti,lm3560.yaml
> @@ -0,0 +1,130 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/i2c/ti,lm3560.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: TI LM3560 Synchronous Boost Flash Driver
> +
> +maintainers:
> + - Daniel Jeong <[email protected]>
> + - Ldd-Mlp <[email protected]>
> +
> +description: |
> + The LM3560 is a 2-MHz fixed frequency synchronous boost
> + converter with two 1000-mA constant current drivers for
> + high-current white LEDs. The dual highside current sources
> + allow for grounded cathode LED operation and can be tied
> + together for providing flash currents at up to 2 A through
> + a single LED. An adaptive regulation method ensures the
> + current for each LED remains in regulation and maximizes
> + efficiency.
> +
> +properties:
> + compatible:
> + items:
> + - enum:
> + - ti,lm3559
> + - ti,lm3560
> +
> + reg:
> + maxItems: 1
> +
> + enable-gpios:
> + maxItems: 1
> +
> + ti,peak-current:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 0x20, 0x40, 0x60]
> + default: 0x60
> + description: |
> + Peak current can be set to 4 values 1.6A (0x00),
> + 2.3A (0x20), 3.0A (0x40) and 3.6A (0x60).

Pretty sure we have common properties for this.

> +
> + ti,max-flash-timeout:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 32
> + maximum: 1024
> + default: 1024
> + description: |
> + Maximum flash timeout in ms with step 32ms.

And this too.

> +
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> +required:
> + - compatible
> + - reg
> + - '#address-cells'
> + - '#size-cells'
> +
> +patternProperties:
> + "^led@[01]$":
> + type: object
> + description: |
> + Properties for a connected LEDs.
> + properties:
> + reg:
> + minimum: 0
> + maximum: 1
> +
> + ti,max-flash-current:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 62500
> + maximum: 1000000
> + default: 1000000
> + description: |
> + Maximum current in flash mode in uA with step 62500uA.

Or maybe it's these per LED settings that are common.

BTW, anything with units, should have a standard unit suffix.

> +
> + ti,max-torch-current:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 31250
> + maximum: 250000
> + default: 250000
> + description: |
> + Maximum current in tourch mode in uA with step 31250uA.
> +
> + required:
> + - reg
> +
> + additionalProperties: false
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + flash-led@53 {

led-controller@53

> + compatible = "ti,lm3559";
> + reg = <0x53>;
> +
> + enable-gpios = <&gpio 219 GPIO_ACTIVE_HIGH>;
> +
> + ti,peak-current = <0>;
> + ti,max-flash-timeout = <1024>;
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + led@0 {
> + reg = <0>;
> +
> + ti,max-flash-current = <562500>;
> + ti,max-torch-current = <156250>;
> + };
> +
> + led@1 {
> + reg = <1>;
> +
> + ti,max-flash-current = <562500>;
> + ti,max-torch-current = <156250>;
> + };
> + };
> + };
> +...
> --
> 2.37.2
>

2023-03-14 11:02:00

by Sakari Ailus

[permalink] [raw]
Subject: Re: [PATCH v1 2/2] media: lm3560: convent to OF

Hi Svyatoslav,

Thanks for the patch.

On Wed, Mar 08, 2023 at 11:52:09AM +0200, Svyatoslav Ryhel wrote:
> If no pdata is available, try to read from device tree.

I think platform data support could be even dropped these days. But it
should probably be a separate patch. I think either before or after this
one would be fine.

>
> Signed-off-by: Svyatoslav Ryhel <[email protected]>
> ---
> drivers/media/i2c/lm3560.c | 128 +++++++++++++++++++++++++++----------
> 1 file changed, 93 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
> index 5ef613604be7..5541051616b7 100644
> --- a/drivers/media/i2c/lm3560.c
> +++ b/drivers/media/i2c/lm3560.c
> @@ -11,6 +11,7 @@
>
> #include <linux/delay.h>
> #include <linux/module.h>
> +#include <linux/gpio.h>
> #include <linux/i2c.h>
> #include <linux/slab.h>
> #include <linux/mutex.h>
> @@ -22,16 +23,16 @@
>
> /* registers definitions */
> #define REG_ENABLE 0x10
> -#define REG_TORCH_BR 0xa0
> -#define REG_FLASH_BR 0xb0
> -#define REG_FLASH_TOUT 0xc0
> +#define REG_TORCH_BR 0xa0
> +#define REG_FLASH_BR 0xb0
> +#define REG_FLASH_TOUT 0xc0
> #define REG_FLAG 0xd0
> #define REG_CONFIG1 0xe0
>
> /* fault mask */
> -#define FAULT_TIMEOUT (1<<0)
> -#define FAULT_OVERTEMP (1<<1)
> -#define FAULT_SHORT_CIRCUIT (1<<2)
> +#define FAULT_TIMEOUT BIT(0)
> +#define FAULT_OVERTEMP BIT(1)
> +#define FAULT_SHORT_CIRCUIT BIT(2)
>
> enum led_enable {
> MODE_SHDN = 0x0,
> @@ -54,6 +55,7 @@ struct lm3560_flash {
> struct device *dev;
> struct lm3560_platform_data *pdata;
> struct regmap *regmap;
> + struct gpio_desc *hwen_gpio;
> struct mutex lock;
>
> enum v4l2_flash_led_mode led_mode;
> @@ -356,12 +358,19 @@ static int lm3560_subdev_init(struct lm3560_flash *flash,
> flash->subdev_led[led_no].flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> strscpy(flash->subdev_led[led_no].name, led_name,
> sizeof(flash->subdev_led[led_no].name));
> +
> rval = lm3560_init_controls(flash, led_no);
> - if (rval)
> + if (rval) {
> + dev_err(flash->dev, "failed to init controls: %d\n", rval);
> goto err_out;
> + }
> +
> rval = media_entity_pads_init(&flash->subdev_led[led_no].entity, 0, NULL);
> - if (rval < 0)
> + if (rval < 0) {
> + dev_err(flash->dev, "failed to init media entity pads: %d\n", rval);
> goto err_out;
> + }
> +
> flash->subdev_led[led_no].entity.function = MEDIA_ENT_F_FLASH;
>
> return rval;
> @@ -391,6 +400,49 @@ static int lm3560_init_device(struct lm3560_flash *flash)
> return rval;
> }
>
> +static int lm3560_of_probe(struct lm3560_flash *flash)
> +{
> + struct lm3560_platform_data *pdata;
> + struct fwnode_handle *node;
> + int ret, reg;
> +
> + pdata = devm_kzalloc(flash->dev, sizeof(*pdata), GFP_KERNEL);
> + if (!pdata)
> + return -ENODEV;
> +
> + ret = device_property_read_u32(flash->dev,
> + "ti,peak-current", &pdata->peak);
> + if (ret)
> + pdata->peak = LM3560_PEAK_3600mA;
> +
> + ret = device_property_read_u32(flash->dev,
> + "ti,max-flash-timeout",
> + &pdata->max_flash_timeout);
> + if (ret)
> + pdata->max_flash_timeout = LM3560_FLASH_TOUT_MAX;
> +
> + device_for_each_child_node(flash->dev, node) {
> + fwnode_property_read_u32(node, "reg", &reg);
> +
> + if (reg == LM3560_LED0 || reg == LM3560_LED1) {
> + ret = device_property_read_u32(flash->dev,
> + "ti,max-flash-current",
> + &pdata->max_flash_brt[reg]);
> + if (ret)
> + pdata->max_flash_brt[reg] = LM3560_FLASH_TOUT_MAX;
> +
> + ret = device_property_read_u32(flash->dev,
> + "ti,max-torch-current",
> + &pdata->max_torch_brt[reg]);
> + if (ret)
> + pdata->max_torch_brt[reg] = LM3560_TORCH_BRT_MAX;
> + }
> + }
> + flash->pdata = pdata;
> +
> + return 0;
> +}
> +
> static int lm3560_probe(struct i2c_client *client)
> {
> struct lm3560_flash *flash;
> @@ -398,44 +450,41 @@ static int lm3560_probe(struct i2c_client *client)
> int rval;
>
> flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
> - if (flash == NULL)
> + if (!flash)
> return -ENOMEM;
>
> flash->regmap = devm_regmap_init_i2c(client, &lm3560_regmap);
> - if (IS_ERR(flash->regmap)) {
> - rval = PTR_ERR(flash->regmap);
> - return rval;
> - }
> + if (IS_ERR(flash->regmap))
> + return dev_err_probe(&client->dev, PTR_ERR(flash->regmap),
> + "failed to init regmap\n");
>
> - /* if there is no platform data, use chip default value */
> - if (pdata == NULL) {
> - pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
> - if (pdata == NULL)
> - return -ENODEV;
> - pdata->peak = LM3560_PEAK_3600mA;
> - pdata->max_flash_timeout = LM3560_FLASH_TOUT_MAX;
> - /* led 1 */
> - pdata->max_flash_brt[LM3560_LED0] = LM3560_FLASH_BRT_MAX;
> - pdata->max_torch_brt[LM3560_LED0] = LM3560_TORCH_BRT_MAX;
> - /* led 2 */
> - pdata->max_flash_brt[LM3560_LED1] = LM3560_FLASH_BRT_MAX;
> - pdata->max_torch_brt[LM3560_LED1] = LM3560_TORCH_BRT_MAX;
> - }
> - flash->pdata = pdata;
> flash->dev = &client->dev;
> mutex_init(&flash->lock);
>
> + /* if there is no platform data, try to read from device tree */
> + if (!pdata)
> + lm3560_of_probe(flash);
> +
> + flash->hwen_gpio = devm_gpiod_get_optional(flash->dev, "enable",
> + GPIOD_OUT_HIGH);
> + if (IS_ERR(flash->hwen_gpio))
> + return dev_err_probe(&client->dev, PTR_ERR(flash->hwen_gpio),
> + "failed to get hwen gpio\n");
> +
> rval = lm3560_subdev_init(flash, LM3560_LED0, "lm3560-led0");
> if (rval < 0)
> - return rval;
> + return dev_err_probe(&client->dev, rval,
> + "failed to init led0 subdev\n");
>
> rval = lm3560_subdev_init(flash, LM3560_LED1, "lm3560-led1");
> if (rval < 0)
> - return rval;
> + return dev_err_probe(&client->dev, rval,
> + "failed to init led1 subdev\n");
>
> rval = lm3560_init_device(flash);
> if (rval < 0)
> - return rval;
> + return dev_err_probe(&client->dev, rval,
> + "failed to init device\n");
>
> i2c_set_clientdata(client, flash);
>
> @@ -452,21 +501,30 @@ static void lm3560_remove(struct i2c_client *client)
> v4l2_ctrl_handler_free(&flash->ctrls_led[i]);
> media_entity_cleanup(&flash->subdev_led[i].entity);
> }
> +
> + gpiod_set_value_cansleep(flash->hwen_gpio, 0);
> }
>
> +static const struct of_device_id lm3560_match[] = {
> + { .compatible = "ti,lm3559" },
> + { .compatible = "ti,lm3560" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, lm3560_match);
> +
> static const struct i2c_device_id lm3560_id_table[] = {
> {LM3559_NAME, 0},
> {LM3560_NAME, 0},
> {}
> };
> -
> MODULE_DEVICE_TABLE(i2c, lm3560_id_table);
>
> static struct i2c_driver lm3560_i2c_driver = {
> .driver = {
> - .name = LM3560_NAME,
> - .pm = NULL,
> - },
> + .name = LM3560_NAME,
> + .pm = NULL,
> + .of_match_table = lm3560_match,
> + },
> .probe_new = lm3560_probe,
> .remove = lm3560_remove,
> .id_table = lm3560_id_table,

--
Kind regards,

Sakari Ailus