diff options
-rw-r--r-- | Documentation/devicetree/bindings/leds/pca9633.txt | 45 | ||||
-rw-r--r-- | drivers/leds/leds-pca9633.c | 71 |
2 files changed, 116 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/leds/pca9633.txt b/Documentation/devicetree/bindings/leds/pca9633.txt new file mode 100644 index 000000000000..8140512c0ac8 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/pca9633.txt @@ -0,0 +1,45 @@ +LEDs connected to pca9633 or pca9632 + +Required properties: +- compatible : should be : "nxp,pca963x" + +Optional properties: +- nxp,totem-pole : use totem pole (push-pull) instead of default open-drain + +Each led is represented as a sub-node of the nxp,pca9633 device. + +LED sub-node properties: +- label : (optional) see Documentation/devicetree/bindings/leds/common.txt +- reg : number of LED line (could be from 0 to 4) +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt + +Examples: + +pca9632: pca9632 { + compatible = "nxp,pca9632", "nxp,pca963x"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x62>; + + red@0 { + label = "red"; + reg = <0>; + linux,default-trigger = "none"; + }; + green@1 { + label = "green"; + reg = <1>; + linux,default-trigger = "none"; + }; + blue@2 { + label = "blue"; + reg = <2>; + linux,default-trigger = "none"; + }; + unused@3 { + label = "unused"; + reg = <3>; + linux,default-trigger = "none"; + }; +}; diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c index 9aae5679ffb2..90935e465c4d 100644 --- a/drivers/leds/leds-pca9633.c +++ b/drivers/leds/leds-pca9633.c @@ -22,6 +22,7 @@ #include <linux/i2c.h> #include <linux/workqueue.h> #include <linux/slab.h> +#include <linux/of.h> #include <linux/platform_data/leds-pca9633.h> /* LED select registers determine the source that drives LED outputs */ @@ -93,6 +94,67 @@ static void pca9633_led_set(struct led_classdev *led_cdev, schedule_work(&pca9633->work); } +#if IS_ENABLED(CONFIG_OF) +static struct pca9633_platform_data * +pca9633_dt_init(struct i2c_client *client) +{ + struct device_node *np = client->dev.of_node, *child; + struct pca9633_platform_data *pdata; + struct led_info *pca9633_leds; + int count; + + count = of_get_child_count(np); + if (!count || count > 4) + return ERR_PTR(-ENODEV); + + pca9633_leds = devm_kzalloc(&client->dev, + sizeof(struct led_info) * count, GFP_KERNEL); + if (!pca9633_leds) + return ERR_PTR(-ENOMEM); + + for_each_child_of_node(np, child) { + struct led_info led; + u32 reg; + int res; + + led.name = + of_get_property(child, "label", NULL) ? : child->name; + led.default_trigger = + of_get_property(child, "linux,default-trigger", NULL); + res = of_property_read_u32(child, "reg", ®); + if (res != 0) + continue; + pca9633_leds[reg] = led; + } + pdata = devm_kzalloc(&client->dev, + sizeof(struct pca9633_platform_data), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->leds.leds = pca9633_leds; + pdata->leds.num_leds = count; + + /* default to open-drain unless totem pole (push-pull) is specified */ + if (of_property_read_bool(np, "nxp,totem-pole")) + pdata->outdrv = PCA9633_TOTEM_POLE; + else + pdata->outdrv = PCA9633_OPEN_DRAIN; + + return pdata; +} + +static const struct of_device_id of_pca9633_match[] = { + { .compatible = "nxp,pca963x", }, + {}, +}; +#else +static struct pca9633_platform_data * +pca9633_dt_init(struct i2c_client *client) +{ + return ERR_PTR(-ENODEV); +} +#endif + static int pca9633_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -102,6 +164,14 @@ static int pca9633_probe(struct i2c_client *client, pdata = client->dev.platform_data; + if (!pdata) { + pdata = pca9633_dt_init(client); + if (IS_ERR(pdata)) { + dev_warn(&client->dev, "could not parse configuration\n"); + pdata = NULL; + } + } + if (pdata) { if (pdata->leds.num_leds <= 0 || pdata->leds.num_leds > 4) { dev_err(&client->dev, "board info must claim at most 4 LEDs"); @@ -181,6 +251,7 @@ static struct i2c_driver pca9633_driver = { .driver = { .name = "leds-pca9633", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_pca9633_match), }, .probe = pca9633_probe, .remove = pca9633_remove, |