blob: f42fb5ecdf185a844e21c1ec17822c456843899c [file] [log] [blame]
Amy Malochef3d5a062012-08-16 19:14:11 -07001
2/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/leds.h>
19#include <linux/err.h>
20#include <linux/of_platform.h>
21#include <linux/of_device.h>
22#include <linux/spmi.h>
23
24#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
25#define WLED_IDAC_DLY_REG(base, n) (WLED_MOD_EN_REG(base, n) + 0x01)
26#define WLED_FULL_SCALE_REG(base, n) (WLED_IDAC_DLY_REG(base, n) + 0x01)
27
28/* wled control registers */
29#define WLED_BRIGHTNESS_CNTL_LSB(base, n) (base + 0x40 + 2*n)
30#define WLED_BRIGHTNESS_CNTL_MSB(base, n) (base + 0x41 + 2*n)
31#define WLED_MOD_CTRL_REG(base) (base + 0x46)
32#define WLED_SYNC_REG(base) (base + 0x47)
33#define WLED_FDBCK_CTRL_REG(base) (base + 0x48)
34#define WLED_SWITCHING_FREQ_REG(base) (base + 0x4C)
35#define WLED_OVP_CFG_REG(base) (base + 0x4D)
36#define WLED_BOOST_LIMIT_REG(base) (base + 0x4E)
37#define WLED_CURR_SINK_REG(base) (base + 0x4F)
38#define WLED_HIGH_POLE_CAP_REG(base) (base + 0x58)
39#define WLED_CURR_SINK_MASK 0xE0
40#define WLED_CURR_SINK_SHFT 0x05
41#define WLED_SWITCH_FREQ_MASK 0x02
42#define WLED_OVP_VAL_MASK 0x03
43#define WLED_OVP_VAL_BIT_SHFT 0x00
44#define WLED_BOOST_LIMIT_MASK 0x07
45#define WLED_BOOST_LIMIT_BIT_SHFT 0x00
46#define WLED_BOOST_ON 0x80
47#define WLED_BOOST_OFF 0x00
48#define WLED_EN_MASK 0x80
49#define WLED_NO_MASK 0x00
50#define WLED_CP_SELECT_MAX 0x03
51#define WLED_CP_SELECT_MASK 0x02
52#define WLED_USE_EXT_GEN_MOD_SRC 0x01
53#define WLED_CTL_DLY_STEP 200
54#define WLED_CTL_DLY_MAX 1400
55#define WLED_MAX_CURR 25
56#define WLED_MSB_MASK 0x0F
57#define WLED_MAX_CURR_MASK 0x19
58#define WLED_OP_FDBCK_MASK 0x07
59#define WLED_OP_FDBCK_BIT_SHFT 0x00
60
61#define WLED_MAX_LEVEL 255
62#define WLED_8_BIT_MASK 0xFF
63#define WLED_4_BIT_MASK 0x0F
64#define WLED_8_BIT_SHFT 0x08
65#define WLED_MAX_DUTY_CYCLE 0xFFF
66
67#define WLED_SYNC_VAL 0x07
68#define WLED_SYNC_RESET_VAL 0x00
69
70#define WLED_TRIGGER_DEFAULT "none"
71#define WLED_FLAGS_DEFAULT 0x00
72#define WLED_DEFAULT_STRINGS 0x01
73#define WLED_DEFAULT_OVP_VAL 0x02
74#define WLED_BOOST_LIM_DEFAULT 0x03
75#define WLED_CP_SEL_DEFAULT 0x00
76#define WLED_CTRL_DLY_DEFAULT 0x00
77#define WLED_SWITCH_FREQ_DEFAULT 0x02
78
79/**
80 * enum qpnp_leds - QPNP supported led ids
81 * @QPNP_ID_WLED - White led backlight
82 */
83enum qpnp_leds {
84 QPNP_ID_WLED,
85};
86
87/* current boost limit */
88enum wled_current_boost_limit {
89 WLED_CURR_LIMIT_105mA,
90 WLED_CURR_LIMIT_385mA,
91 WLED_CURR_LIMIT_525mA,
92 WLED_CURR_LIMIT_805mA,
93 WLED_CURR_LIMIT_980mA,
94 WLED_CURR_LIMIT_1260mA,
95 WLED_CURR_LIMIT_1400mA,
96 WLED_CURR_LIMIT_1680mA,
97};
98
99/* over voltage protection threshold */
100enum wled_ovp_threshold {
101 WLED_OVP_35V,
102 WLED_OVP_32V,
103 WLED_OVP_29V,
104 WLED_OVP_37V,
105};
106
107/* switch frquency */
108enum wled_switch_freq {
109 WLED_800kHz = 0,
110 WLED_960kHz,
111 WLED_1600kHz,
112 WLED_3200kHz,
113};
114
115static u8 wled_debug_regs[] = {
116 /* common registers */
117 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
118 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
119 /* LED1 */
120 0x60, 0x61, 0x62, 0x63, 0x66,
121 /* LED1 */
122 0x70, 0x71, 0x72, 0x73, 0x76,
123 /* LED1 */
124 0x80, 0x81, 0x82, 0x83, 0x86,
125};
126
127/**
128 * wled_config_data - wled configuration data
129 * @num_strings - number of wled strings supported
130 * @ovp_val - over voltage protection threshold
131 * @boost_curr_lim - boot current limit
132 * @cp_select - high pole capacitance
133 * @ctrl_delay_us - delay in activation of led
134 * @dig_mod_gen_en - digital module generator
135 * @cs_out_en - current sink output enable
136 * @op_fdbck - selection of output as feedback for the boost
137 */
138struct wled_config_data {
139 u8 num_strings;
140 u8 ovp_val;
141 u8 boost_curr_lim;
142 u8 cp_select;
143 u8 ctrl_delay_us;
144 u8 switch_freq;
145 bool dig_mod_gen_en;
146 bool cs_out_en;
147 bool op_fdbck;
148};
149
150/**
151 * struct qpnp_led_data - internal led data structure
152 * @led_classdev - led class device
153 * @id - led index
154 * @base_reg - base register given in device tree
155 * @lock - to protect the transactions
156 * @reg - cached value of led register
157 * @max_current - maximum current supported by LED
158 * @default_on - true: default state max, false, default state 0
159 */
160struct qpnp_led_data {
161 struct led_classdev cdev;
162 struct spmi_device *spmi_dev;
163 int id;
164 u16 base;
165 u8 reg;
166 struct mutex lock;
167 struct wled_config_data *wled_cfg;
168 int max_current;
169 bool default_on;
170};
171
172static int
173qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
174{
175 int rc;
176 u8 reg;
177
178 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
179 addr, &reg, 1);
180 if (rc) {
181 dev_err(&led->spmi_dev->dev,
182 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
183 }
184
185 reg &= ~mask;
186 reg |= val;
187
188 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
189 addr, &reg, 1);
190 if (rc)
191 dev_err(&led->spmi_dev->dev,
192 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
193 return rc;
194}
195
196static int qpnp_wled_set(struct qpnp_led_data *led)
197{
198 int rc, duty;
199 u8 level, val, i, num_wled_strings;
200
201 level = led->cdev.brightness;
202
203 if (level > WLED_MAX_LEVEL)
204 level = WLED_MAX_LEVEL;
205 if (level == 0) {
206 val = WLED_BOOST_OFF;
207 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
208 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
209 &val, 1);
210 if (rc) {
211 dev_err(&led->spmi_dev->dev,
212 "WLED write ctrl reg failed(%d)\n", rc);
213 return rc;
214 }
215 } else {
216 val = WLED_BOOST_ON;
217 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
218 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
219 &val, 1);
220 if (rc) {
221 dev_err(&led->spmi_dev->dev,
222 "WLED write ctrl reg failed(%d)\n", rc);
223 return rc;
224 }
225 }
226
227 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
228
229 num_wled_strings = led->wled_cfg->num_strings;
230
231 /* program brightness control registers */
232 for (i = 0; i < num_wled_strings; i++) {
233 rc = qpnp_led_masked_write(led,
234 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
235 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
236 if (rc) {
237 dev_err(&led->spmi_dev->dev,
238 "WLED set brightness MSB failed(%d)\n", rc);
239 return rc;
240 }
241 val = duty & WLED_8_BIT_MASK;
242 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
243 led->spmi_dev->sid,
244 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
245 if (rc) {
246 dev_err(&led->spmi_dev->dev,
247 "WLED set brightness LSB failed(%d)\n", rc);
248 return rc;
249 }
250 }
251
252 /* sync */
253 val = WLED_SYNC_VAL;
254 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
255 WLED_SYNC_REG(led->base), &val, 1);
256 if (rc) {
257 dev_err(&led->spmi_dev->dev,
258 "WLED set sync reg failed(%d)\n", rc);
259 return rc;
260 }
261
262 val = WLED_SYNC_RESET_VAL;
263 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
264 WLED_SYNC_REG(led->base), &val, 1);
265 if (rc) {
266 dev_err(&led->spmi_dev->dev,
267 "WLED reset sync reg failed(%d)\n", rc);
268 return rc;
269 }
270 return 0;
271}
272
273static void qpnp_wled_dump_regs(struct qpnp_led_data *led)
274{
275 int i;
276 u8 val;
277
278 pr_debug("===== WLED register dump start =====\n");
279 for (i = 0; i < ARRAY_SIZE(wled_debug_regs); i++) {
280 spmi_ext_register_readl(led->spmi_dev->ctrl,
281 led->spmi_dev->sid,
282 led->base + wled_debug_regs[i],
283 &val, sizeof(val));
284 pr_debug("0x%x = 0x%x\n", led->base + wled_debug_regs[i], val);
285 }
286 pr_debug("===== WLED register dump end =====\n");
287}
288
289static void qpnp_led_set(struct led_classdev *led_cdev,
290 enum led_brightness value)
291{
292 int rc;
293 struct qpnp_led_data *led;
294
295 led = container_of(led_cdev, struct qpnp_led_data, cdev);
296
297 if (value < LED_OFF || value > led->cdev.max_brightness) {
298 dev_err(led->cdev.dev, "Invalid brightness value\n");
299 return;
300 }
301
302 mutex_lock(&led->lock);
303 led->cdev.brightness = value;
304
305 switch (led->id) {
306 case QPNP_ID_WLED:
307 rc = qpnp_wled_set(led);
308 if (rc < 0)
309 dev_err(led->cdev.dev,
310 "WLED set brightness failed (%d)\n", rc);
311 break;
312 default:
313 dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
314 break;
315 }
316 mutex_unlock(&led->lock);
317}
318
319static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
320{
321 switch (led->id) {
322 case QPNP_ID_WLED:
323 led->cdev.max_brightness = WLED_MAX_LEVEL;
324 break;
325 default:
326 dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
327 return -EINVAL;
328 }
329
330 return 0;
331}
332
333static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
334{
335 struct qpnp_led_data *led;
336
337 led = container_of(led_cdev, struct qpnp_led_data, cdev);
338
339 return led->cdev.brightness;
340}
341
342static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
343{
344 int rc, i;
345 u8 num_wled_strings;
346
347 num_wled_strings = led->wled_cfg->num_strings;
348
349 /* verify ranges */
350 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
351 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
352 return -EINVAL;
353 }
354
355 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
356 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
357 return -EINVAL;
358 }
359
360 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
361 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
362 return -EINVAL;
363 }
364
365 if ((led->max_current > WLED_MAX_CURR)) {
366 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
367 return -EINVAL;
368 }
369
370 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
371 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
372 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
373 return -EINVAL;
374 }
375
376 /* program over voltage protection threshold */
377 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
378 WLED_OVP_VAL_MASK,
379 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
380 if (rc) {
381 dev_err(&led->spmi_dev->dev,
382 "WLED OVP reg write failed(%d)\n", rc);
383 return rc;
384 }
385
386 /* program current boost limit */
387 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
388 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
389 if (rc) {
390 dev_err(&led->spmi_dev->dev,
391 "WLED boost limit reg write failed(%d)\n", rc);
392 return rc;
393 }
394
395 /* program output feedback */
396 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
397 WLED_OP_FDBCK_MASK,
398 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
399 if (rc) {
400 dev_err(&led->spmi_dev->dev,
401 "WLED fdbck ctrl reg write failed(%d)\n", rc);
402 return rc;
403 }
404
405 /* program switch frequency */
406 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
407 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
408 if (rc) {
409 dev_err(&led->spmi_dev->dev,
410 "WLED switch freq reg write failed(%d)\n", rc);
411 return rc;
412 }
413
414 /* program current sink */
415 if (led->wled_cfg->cs_out_en) {
416 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
417 WLED_CURR_SINK_MASK,
418 (led->wled_cfg->num_strings << WLED_CURR_SINK_SHFT));
419 if (rc) {
420 dev_err(&led->spmi_dev->dev,
421 "WLED curr sink reg write failed(%d)\n", rc);
422 return rc;
423 }
424 }
425
426 /* program high pole capacitance */
427 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
428 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
429 if (rc) {
430 dev_err(&led->spmi_dev->dev,
431 "WLED pole cap reg write failed(%d)\n", rc);
432 return rc;
433 }
434
435 /* program modulator, current mod src and cabc */
436 for (i = 0; i < num_wled_strings; i++) {
437 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
438 WLED_NO_MASK, WLED_EN_MASK);
439 if (rc) {
440 dev_err(&led->spmi_dev->dev,
441 "WLED mod enable reg write failed(%d)\n", rc);
442 return rc;
443 }
444
445 if (led->wled_cfg->dig_mod_gen_en) {
446 rc = qpnp_led_masked_write(led,
447 WLED_MOD_EN_REG(led->base, i),
448 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
449 if (rc) {
450 dev_err(&led->spmi_dev->dev,
451 "WLED dig mod en reg write failed(%d)\n", rc);
452 }
453 }
454
455 rc = qpnp_led_masked_write(led,
456 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
457 led->max_current);
458 if (rc) {
459 dev_err(&led->spmi_dev->dev,
460 "WLED max current reg write failed(%d)\n", rc);
461 return rc;
462 }
463
464 }
465
466 /* dump wled registers */
467 qpnp_wled_dump_regs(led);
468
469 return 0;
470}
471
472static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
473{
474 int rc;
475
476 switch (led->id) {
477 case QPNP_ID_WLED:
478 rc = qpnp_wled_init(led);
479 if (rc)
480 dev_err(led->cdev.dev,
481 "WLED initialize failed(%d)\n", rc);
482 break;
483 default:
484 dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
485 rc = -EINVAL;
486 }
487
488 return rc;
489}
490
491/*
492 * Handlers for alternative sources of platform_data
493 */
494static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
495 struct device_node *node)
496{
497 u32 val;
498 int rc;
499 const char *temp_string;
500
501 led->id = QPNP_ID_WLED;
502
503 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
504 sizeof(struct wled_config_data), GFP_KERNEL);
505 if (!led->wled_cfg) {
506 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
507 return -ENOMEM;
508 }
509
510 led->cdev.default_trigger = WLED_TRIGGER_DEFAULT;
511 rc = of_property_read_string(node, "linux,default-trigger",
512 &temp_string);
513 if (!rc)
514 led->cdev.default_trigger = temp_string;
515 else if (rc != -EINVAL)
516 return rc;
517
518
519 led->cdev.flags = WLED_FLAGS_DEFAULT;
520 rc = of_property_read_u32(node, "qcom,flags", &val);
521 if (!rc)
522 led->cdev.flags = (int) val;
523 else if (rc != -EINVAL)
524 return rc;
525
526 led->default_on = true;
527 rc = of_property_read_string(node, "qcom,default-state",
528 &temp_string);
529 if (!rc) {
530 if (!strncmp(temp_string, "off", sizeof("off")))
531 led->default_on = false;
532 } else if (rc != -EINVAL)
533 return rc;
534
535 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
536 rc = of_property_read_u32(node, "qcom,num-strings", &val);
537 if (!rc)
538 led->wled_cfg->num_strings = (u8) val;
539 else if (rc != -EINVAL)
540 return rc;
541
542 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
543 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
544 if (!rc)
545 led->wled_cfg->ovp_val = (u8) val;
546 else if (rc != -EINVAL)
547 return rc;
548
549 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
550 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
551 if (!rc)
552 led->wled_cfg->boost_curr_lim = (u8) val;
553 else if (rc != -EINVAL)
554 return rc;
555
556 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
557 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
558 if (!rc)
559 led->wled_cfg->cp_select = (u8) val;
560 else if (rc != -EINVAL)
561 return rc;
562
563 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
564 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
565 if (!rc)
566 led->wled_cfg->ctrl_delay_us = (u8) val;
567 else if (rc != -EINVAL)
568 return rc;
569
570 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
571 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
572 if (!rc)
573 led->wled_cfg->switch_freq = (u8) val;
574 else if (rc != -EINVAL)
575 return rc;
576
577 led->wled_cfg->dig_mod_gen_en =
578 of_property_read_bool(node, "qcom,dig-mod-gen-en");
579
580 led->wled_cfg->cs_out_en =
581 of_property_read_bool(node, "qcom,cs-out-en");
582
583 led->wled_cfg->op_fdbck =
584 of_property_read_bool(node, "qcom,op-fdbck");
585
586 return 0;
587}
588
589static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
590{
591 struct qpnp_led_data *led;
592 struct resource *led_resource;
593 struct device_node *node;
594 int rc;
595 const char *led_label;
596
597 led = devm_kzalloc(&spmi->dev, (sizeof(struct qpnp_led_data)),
598 GFP_KERNEL);
599 if (!led) {
600 dev_err(&spmi->dev, "Unable to allocate memory\n");
601 return -ENOMEM;
602 }
603
604 led->spmi_dev = spmi;
605
606 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
607 if (!led_resource) {
608 dev_err(&spmi->dev, "Unable to get LED base address\n");
609 return -ENXIO;
610 }
611 led->base = led_resource->start;
612
613 dev_set_drvdata(&spmi->dev, led);
614
615 node = led->spmi_dev->dev.of_node;
616 if (node == NULL)
617 return -ENODEV;
618
619 rc = of_property_read_string(node, "qcom,label", &led_label);
620 if (rc < 0) {
621 dev_err(&led->spmi_dev->dev,
622 "Failure reading label, rc = %d\n", rc);
623 return rc;
624 }
625
626 rc = of_property_read_string(node, "qcom,name", &led->cdev.name);
627 if (rc < 0) {
628 dev_err(&led->spmi_dev->dev,
629 "Failure reading led name, rc = %d\n", rc);
630 return rc;
631 }
632
633 rc = of_property_read_u32(node, "qcom,max-current", &led->max_current);
634 if (rc < 0) {
635 dev_err(&led->spmi_dev->dev,
636 "Failure reading max_current, rc = %d\n", rc);
637 return rc;
638 }
639
640 led->cdev.brightness_set = qpnp_led_set;
641 led->cdev.brightness_get = qpnp_led_get;
642 led->cdev.brightness = LED_OFF;
643
644 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
645 rc = qpnp_get_config_wled(led, node);
646 if (rc < 0) {
647 dev_err(&led->spmi_dev->dev,
648 "Unable to read wled config data\n");
649 return rc;
650 }
651 } else {
652 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
653 return -EINVAL;
654 }
655
656 mutex_init(&led->lock);
657
658 rc = qpnp_led_initialize(led);
659 if (rc < 0)
660 goto fail_id_check;
661
662 rc = qpnp_led_set_max_brightness(led);
663 if (rc < 0)
664 goto fail_id_check;
665
666
667 rc = led_classdev_register(&spmi->dev, &led->cdev);
668 if (rc) {
669 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
670 led->id, rc);
671 goto fail_id_check;
672 }
673
674 /* configure default state */
675 if (led->default_on)
676 led->cdev.brightness = led->cdev.max_brightness;
677
678 qpnp_led_set(&led->cdev, led->cdev.brightness);
679
680 return 0;
681
682fail_id_check:
683 mutex_destroy(&led->lock);
684 led_classdev_unregister(&led->cdev);
685 return rc;
686}
687
688static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
689{
690 struct qpnp_led_data *led = dev_get_drvdata(&spmi->dev);
691
692 mutex_destroy(&led->lock);
693 led_classdev_unregister(&led->cdev);
694
695 return 0;
696}
697static struct of_device_id spmi_match_table[] = {
698 { .compatible = "qcom,leds-qpnp",
699 }
700};
701
702static struct spmi_driver qpnp_leds_driver = {
703 .driver = {
704 .name = "qcom,leds-qpnp",
705 .of_match_table = spmi_match_table,
706 },
707 .probe = qpnp_leds_probe,
708 .remove = __devexit_p(qpnp_leds_remove),
709};
710
711static int __init qpnp_led_init(void)
712{
713 return spmi_driver_register(&qpnp_leds_driver);
714}
715module_init(qpnp_led_init);
716
717static void __exit qpnp_led_exit(void)
718{
719 spmi_driver_unregister(&qpnp_leds_driver);
720}
721module_exit(qpnp_led_exit);
722
723MODULE_DESCRIPTION("QPNP LEDs driver");
724MODULE_LICENSE("GPL v2");
725MODULE_ALIAS("leds:leds-qpnp");