diff options
author | Alexander Shiyan <shc_work@mail.ru> | 2014-02-01 01:37:23 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@gmail.com> | 2014-02-27 12:56:56 -0500 |
commit | 25c6579f872d0542809067d56fad22984b8ff565 (patch) | |
tree | bfcdc2a70f81c0c435bd5f3172d3b4024f92c171 /drivers/leds | |
parent | 2f18f8d638cc66a5339d901dea2c9d8af72e69c2 (diff) |
leds: leds-mc13783: Add devicetree support
This patch adds devicetree support for the MC13XXX LED driver.
(cooloney@gmail.com: remove unneeded semicolon)
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Signed-off-by: Bryan Wu <cooloney@gmail.com>
Diffstat (limited to 'drivers/leds')
-rw-r--r-- | drivers/leds/leds-mc13783.c | 112 |
1 files changed, 93 insertions, 19 deletions
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index 15fa5e86abcf..021adc11162e 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/leds.h> | 22 | #include <linux/leds.h> |
23 | #include <linux/of.h> | ||
23 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
24 | #include <linux/mfd/mc13xxx.h> | 25 | #include <linux/mfd/mc13xxx.h> |
25 | 26 | ||
@@ -42,7 +43,7 @@ struct mc13xxx_leds { | |||
42 | struct mc13xxx *master; | 43 | struct mc13xxx *master; |
43 | struct mc13xxx_led_devtype *devtype; | 44 | struct mc13xxx_led_devtype *devtype; |
44 | int num_leds; | 45 | int num_leds; |
45 | struct mc13xxx_led led[0]; | 46 | struct mc13xxx_led *led; |
46 | }; | 47 | }; |
47 | 48 | ||
48 | static unsigned int mc13xxx_max_brightness(int id) | 49 | static unsigned int mc13xxx_max_brightness(int id) |
@@ -120,6 +121,74 @@ static void mc13xxx_led_set(struct led_classdev *led_cdev, | |||
120 | schedule_work(&led->work); | 121 | schedule_work(&led->work); |
121 | } | 122 | } |
122 | 123 | ||
124 | #ifdef CONFIG_OF | ||
125 | static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt( | ||
126 | struct platform_device *pdev) | ||
127 | { | ||
128 | struct mc13xxx_leds *leds = platform_get_drvdata(pdev); | ||
129 | struct mc13xxx_leds_platform_data *pdata; | ||
130 | struct device_node *parent, *child; | ||
131 | struct device *dev = &pdev->dev; | ||
132 | int i = 0, ret = -ENODATA; | ||
133 | |||
134 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||
135 | if (!pdata) | ||
136 | return ERR_PTR(-ENOMEM); | ||
137 | |||
138 | of_node_get(dev->parent->of_node); | ||
139 | |||
140 | parent = of_find_node_by_name(dev->parent->of_node, "leds"); | ||
141 | if (!parent) | ||
142 | goto out_node_put; | ||
143 | |||
144 | ret = of_property_read_u32_array(parent, "led-control", | ||
145 | pdata->led_control, | ||
146 | leds->devtype->num_regs); | ||
147 | if (ret) | ||
148 | goto out_node_put; | ||
149 | |||
150 | pdata->num_leds = of_get_child_count(parent); | ||
151 | |||
152 | pdata->led = devm_kzalloc(dev, pdata->num_leds * sizeof(*pdata->led), | ||
153 | GFP_KERNEL); | ||
154 | if (!pdata->led) { | ||
155 | ret = -ENOMEM; | ||
156 | goto out_node_put; | ||
157 | } | ||
158 | |||
159 | for_each_child_of_node(parent, child) { | ||
160 | const char *str; | ||
161 | u32 tmp; | ||
162 | |||
163 | if (of_property_read_u32(child, "reg", &tmp)) | ||
164 | continue; | ||
165 | pdata->led[i].id = leds->devtype->led_min + tmp; | ||
166 | |||
167 | if (!of_property_read_string(child, "label", &str)) | ||
168 | pdata->led[i].name = str; | ||
169 | if (!of_property_read_string(child, "linux,default-trigger", | ||
170 | &str)) | ||
171 | pdata->led[i].default_trigger = str; | ||
172 | |||
173 | i++; | ||
174 | } | ||
175 | |||
176 | pdata->num_leds = i; | ||
177 | ret = i > 0 ? 0 : -ENODATA; | ||
178 | |||
179 | out_node_put: | ||
180 | of_node_put(parent); | ||
181 | |||
182 | return ret ? ERR_PTR(ret) : pdata; | ||
183 | } | ||
184 | #else | ||
185 | static inline struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt( | ||
186 | struct platform_device *pdev) | ||
187 | { | ||
188 | return ERR_PTR(-ENOSYS); | ||
189 | } | ||
190 | #endif | ||
191 | |||
123 | static int __init mc13xxx_led_probe(struct platform_device *pdev) | 192 | static int __init mc13xxx_led_probe(struct platform_device *pdev) |
124 | { | 193 | { |
125 | struct device *dev = &pdev->dev; | 194 | struct device *dev = &pdev->dev; |
@@ -128,32 +197,37 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) | |||
128 | struct mc13xxx_led_devtype *devtype = | 197 | struct mc13xxx_led_devtype *devtype = |
129 | (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; | 198 | (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; |
130 | struct mc13xxx_leds *leds; | 199 | struct mc13xxx_leds *leds; |
131 | int i, id, num_leds, ret = -ENODATA; | 200 | int i, id, ret = -ENODATA; |
132 | u32 init_led = 0; | 201 | u32 init_led = 0; |
133 | 202 | ||
134 | if (!pdata) { | 203 | leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); |
135 | dev_err(dev, "Missing platform data\n"); | ||
136 | return -ENODEV; | ||
137 | } | ||
138 | |||
139 | num_leds = pdata->num_leds; | ||
140 | |||
141 | if ((num_leds < 1) || | ||
142 | (num_leds > (devtype->led_max - devtype->led_min + 1))) { | ||
143 | dev_err(dev, "Invalid LED count %d\n", num_leds); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | |||
147 | leds = devm_kzalloc(dev, num_leds * sizeof(struct mc13xxx_led) + | ||
148 | sizeof(struct mc13xxx_leds), GFP_KERNEL); | ||
149 | if (!leds) | 204 | if (!leds) |
150 | return -ENOMEM; | 205 | return -ENOMEM; |
151 | 206 | ||
152 | leds->devtype = devtype; | 207 | leds->devtype = devtype; |
153 | leds->num_leds = num_leds; | ||
154 | leds->master = mcdev; | 208 | leds->master = mcdev; |
155 | platform_set_drvdata(pdev, leds); | 209 | platform_set_drvdata(pdev, leds); |
156 | 210 | ||
211 | if (dev->parent->of_node) { | ||
212 | pdata = mc13xxx_led_probe_dt(pdev); | ||
213 | if (IS_ERR(pdata)) | ||
214 | return PTR_ERR(pdata); | ||
215 | } else if (!pdata) | ||
216 | return -ENODATA; | ||
217 | |||
218 | leds->num_leds = pdata->num_leds; | ||
219 | |||
220 | if ((leds->num_leds < 1) || | ||
221 | (leds->num_leds > (devtype->led_max - devtype->led_min + 1))) { | ||
222 | dev_err(dev, "Invalid LED count %d\n", leds->num_leds); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | |||
226 | leds->led = devm_kzalloc(dev, leds->num_leds * sizeof(*leds->led), | ||
227 | GFP_KERNEL); | ||
228 | if (!leds->led) | ||
229 | return -ENOMEM; | ||
230 | |||
157 | for (i = 0; i < devtype->num_regs; i++) { | 231 | for (i = 0; i < devtype->num_regs; i++) { |
158 | ret = mc13xxx_reg_write(mcdev, leds->devtype->ledctrl_base + i, | 232 | ret = mc13xxx_reg_write(mcdev, leds->devtype->ledctrl_base + i, |
159 | pdata->led_control[i]); | 233 | pdata->led_control[i]); |
@@ -161,7 +235,7 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) | |||
161 | return ret; | 235 | return ret; |
162 | } | 236 | } |
163 | 237 | ||
164 | for (i = 0; i < num_leds; i++) { | 238 | for (i = 0; i < leds->num_leds; i++) { |
165 | const char *name, *trig; | 239 | const char *name, *trig; |
166 | 240 | ||
167 | ret = -EINVAL; | 241 | ret = -EINVAL; |