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