blob: e7d514e7770be0cb7d038ea9b6ceed7428b50a44 [file] [log] [blame]
Amy Malochef3d5a062012-08-16 19:14:11 -07001
Amy Malochea5ca5552012-10-23 13:34:46 -07002/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Amy Malochef3d5a062012-08-16 19:14:11 -07003 *
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>
Amy Malocheeea7b592012-10-03 15:59:36 -070024#include <linux/qpnp/pwm.h>
Amy Malochef3d5a062012-08-16 19:14:11 -070025
26#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
27#define WLED_IDAC_DLY_REG(base, n) (WLED_MOD_EN_REG(base, n) + 0x01)
28#define WLED_FULL_SCALE_REG(base, n) (WLED_IDAC_DLY_REG(base, n) + 0x01)
29
30/* wled control registers */
31#define WLED_BRIGHTNESS_CNTL_LSB(base, n) (base + 0x40 + 2*n)
32#define WLED_BRIGHTNESS_CNTL_MSB(base, n) (base + 0x41 + 2*n)
33#define WLED_MOD_CTRL_REG(base) (base + 0x46)
34#define WLED_SYNC_REG(base) (base + 0x47)
35#define WLED_FDBCK_CTRL_REG(base) (base + 0x48)
36#define WLED_SWITCHING_FREQ_REG(base) (base + 0x4C)
37#define WLED_OVP_CFG_REG(base) (base + 0x4D)
38#define WLED_BOOST_LIMIT_REG(base) (base + 0x4E)
39#define WLED_CURR_SINK_REG(base) (base + 0x4F)
40#define WLED_HIGH_POLE_CAP_REG(base) (base + 0x58)
41#define WLED_CURR_SINK_MASK 0xE0
42#define WLED_CURR_SINK_SHFT 0x05
43#define WLED_SWITCH_FREQ_MASK 0x02
44#define WLED_OVP_VAL_MASK 0x03
45#define WLED_OVP_VAL_BIT_SHFT 0x00
46#define WLED_BOOST_LIMIT_MASK 0x07
47#define WLED_BOOST_LIMIT_BIT_SHFT 0x00
48#define WLED_BOOST_ON 0x80
49#define WLED_BOOST_OFF 0x00
50#define WLED_EN_MASK 0x80
51#define WLED_NO_MASK 0x00
52#define WLED_CP_SELECT_MAX 0x03
53#define WLED_CP_SELECT_MASK 0x02
54#define WLED_USE_EXT_GEN_MOD_SRC 0x01
55#define WLED_CTL_DLY_STEP 200
56#define WLED_CTL_DLY_MAX 1400
57#define WLED_MAX_CURR 25
58#define WLED_MSB_MASK 0x0F
59#define WLED_MAX_CURR_MASK 0x19
60#define WLED_OP_FDBCK_MASK 0x07
61#define WLED_OP_FDBCK_BIT_SHFT 0x00
62
63#define WLED_MAX_LEVEL 255
64#define WLED_8_BIT_MASK 0xFF
65#define WLED_4_BIT_MASK 0x0F
66#define WLED_8_BIT_SHFT 0x08
67#define WLED_MAX_DUTY_CYCLE 0xFFF
68
69#define WLED_SYNC_VAL 0x07
70#define WLED_SYNC_RESET_VAL 0x00
71
Amy Malochef3d5a062012-08-16 19:14:11 -070072#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
Amy Maloche864a6d52012-10-03 15:58:12 -070079#define FLASH_SAFETY_TIMER(base) (base + 0x40)
80#define FLASH_MAX_CURR(base) (base + 0x41)
81#define FLASH_LED_0_CURR(base) (base + 0x42)
82#define FLASH_LED_1_CURR(base) (base + 0x43)
83#define FLASH_CLAMP_CURR(base) (base + 0x44)
84#define FLASH_LED_TMR_CTRL(base) (base + 0x48)
85#define FLASH_HEADROOM(base) (base + 0x49)
86#define FLASH_STARTUP_DELAY(base) (base + 0x4B)
87#define FLASH_MASK_ENABLE(base) (base + 0x4C)
88#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
89#define FLASH_ENABLE_CONTROL(base) (base + 0x46)
90#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
91
92#define FLASH_MAX_LEVEL 0x4F
93#define FLASH_NO_MASK 0x00
94
95#define FLASH_MASK_1 0x20
96#define FLASH_MASK_REG_MASK 0xE0
97#define FLASH_HEADROOM_MASK 0x03
98#define FLASH_SAFETY_TIMER_MASK 0x7F
99#define FLASH_CURRENT_MASK 0xFF
100#define FLASH_TMR_MASK 0x03
101#define FLASH_TMR_WATCHDOG 0x03
102#define FLASH_TMR_SAFETY 0x00
103
104#define FLASH_HW_VREG_OK 0x80
105#define FLASH_VREG_MASK 0xC0
106
107#define FLASH_STARTUP_DLY_MASK 0x02
108
109#define FLASH_ENABLE_ALL 0xE0
110#define FLASH_ENABLE_MODULE 0x80
111#define FLASH_ENABLE_MODULE_MASK 0x80
112#define FLASH_DISABLE_ALL 0x00
113#define FLASH_ENABLE_MASK 0x60
114#define FLASH_ENABLE_LED_0 0x40
115#define FLASH_ENABLE_LED_1 0x20
116#define FLASH_INIT_MASK 0xE0
117
118#define FLASH_STROBE_ALL 0xC0
119#define FLASH_STROBE_MASK 0xC0
120#define FLASH_LED_0_OUTPUT 0x80
121#define FLASH_LED_1_OUTPUT 0x40
122
123#define FLASH_CURRENT_PRGM_MIN 1
124#define FLASH_CURRENT_PRGM_SHIFT 1
125
126#define FLASH_DURATION_200ms 0x13
127#define FLASH_CLAMP_200mA 0x0F
128
Amy Malochea5ca5552012-10-23 13:34:46 -0700129#define LED_TRIGGER_DEFAULT "none"
130
Amy Malocheeea7b592012-10-03 15:59:36 -0700131#define RGB_LED_SRC_SEL(base) (base + 0x45)
132#define RGB_LED_EN_CTL(base) (base + 0x46)
133#define RGB_LED_ATC_CTL(base) (base + 0x47)
134
135#define RGB_MAX_LEVEL LED_FULL
136#define RGB_LED_ENABLE_RED 0x80
137#define RGB_LED_ENABLE_GREEN 0x40
138#define RGB_LED_ENABLE_BLUE 0x20
139#define RGB_LED_SOURCE_VPH_PWR 0x01
140#define RGB_LED_ENABLE_MASK 0xE0
141#define RGB_LED_SRC_MASK 0x03
142#define QPNP_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
143#define PWM_LUT_MAX_SIZE 63
144#define RGB_LED_DISABLE 0x00
145
Amy Malochef3d5a062012-08-16 19:14:11 -0700146/**
147 * enum qpnp_leds - QPNP supported led ids
148 * @QPNP_ID_WLED - White led backlight
149 */
150enum qpnp_leds {
Amy Maloche864a6d52012-10-03 15:58:12 -0700151 QPNP_ID_WLED = 0,
152 QPNP_ID_FLASH1_LED0,
153 QPNP_ID_FLASH1_LED1,
Amy Malocheeea7b592012-10-03 15:59:36 -0700154 QPNP_ID_RGB_RED,
155 QPNP_ID_RGB_GREEN,
156 QPNP_ID_RGB_BLUE,
Amy Maloche864a6d52012-10-03 15:58:12 -0700157 QPNP_ID_MAX,
Amy Malochef3d5a062012-08-16 19:14:11 -0700158};
159
160/* current boost limit */
161enum wled_current_boost_limit {
162 WLED_CURR_LIMIT_105mA,
163 WLED_CURR_LIMIT_385mA,
164 WLED_CURR_LIMIT_525mA,
165 WLED_CURR_LIMIT_805mA,
166 WLED_CURR_LIMIT_980mA,
167 WLED_CURR_LIMIT_1260mA,
168 WLED_CURR_LIMIT_1400mA,
169 WLED_CURR_LIMIT_1680mA,
170};
171
172/* over voltage protection threshold */
173enum wled_ovp_threshold {
174 WLED_OVP_35V,
175 WLED_OVP_32V,
176 WLED_OVP_29V,
177 WLED_OVP_37V,
178};
179
180/* switch frquency */
181enum wled_switch_freq {
182 WLED_800kHz = 0,
183 WLED_960kHz,
184 WLED_1600kHz,
185 WLED_3200kHz,
186};
187
Amy Maloche864a6d52012-10-03 15:58:12 -0700188enum flash_headroom {
189 HEADROOM_250mV = 0,
190 HEADROOM_300mV,
191 HEADROOM_400mV,
192 HEADROOM_500mV,
193};
194
195enum flash_startup_dly {
196 DELAY_10us = 0,
197 DELAY_32us,
198 DELAY_64us,
199 DELAY_128us,
200};
201
Amy Malocheeea7b592012-10-03 15:59:36 -0700202enum rgb_mode {
203 RGB_MODE_PWM = 0,
204 RGB_MODE_LPG,
205};
206
Amy Malochef3d5a062012-08-16 19:14:11 -0700207static u8 wled_debug_regs[] = {
208 /* common registers */
209 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
210 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
211 /* LED1 */
212 0x60, 0x61, 0x62, 0x63, 0x66,
Amy Malochea5ca5552012-10-23 13:34:46 -0700213 /* LED2 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700214 0x70, 0x71, 0x72, 0x73, 0x76,
Amy Malochea5ca5552012-10-23 13:34:46 -0700215 /* LED3 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700216 0x80, 0x81, 0x82, 0x83, 0x86,
217};
218
Amy Maloche864a6d52012-10-03 15:58:12 -0700219static u8 flash_debug_regs[] = {
220 0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
221 0x4f, 0x46, 0x47,
222};
223
Amy Malocheeea7b592012-10-03 15:59:36 -0700224static u8 rgb_pwm_debug_regs[] = {
225 0x45, 0x46, 0x47,
226};
Amy Malochef3d5a062012-08-16 19:14:11 -0700227/**
228 * wled_config_data - wled configuration data
229 * @num_strings - number of wled strings supported
230 * @ovp_val - over voltage protection threshold
231 * @boost_curr_lim - boot current limit
232 * @cp_select - high pole capacitance
233 * @ctrl_delay_us - delay in activation of led
234 * @dig_mod_gen_en - digital module generator
235 * @cs_out_en - current sink output enable
236 * @op_fdbck - selection of output as feedback for the boost
237 */
238struct wled_config_data {
239 u8 num_strings;
240 u8 ovp_val;
241 u8 boost_curr_lim;
242 u8 cp_select;
243 u8 ctrl_delay_us;
244 u8 switch_freq;
245 bool dig_mod_gen_en;
246 bool cs_out_en;
247 bool op_fdbck;
248};
249
250/**
Amy Maloche864a6d52012-10-03 15:58:12 -0700251 * flash_config_data - flash configuration data
252 * @current_prgm - current to be programmed, scaled by max level
253 * @clamp_curr - clamp current to use
254 * @headroom - headroom value to use
255 * @duration - duration of the flash
256 * @enable_module - enable address for particular flash
257 * @trigger_flash - trigger flash
258 * @startup_dly - startup delay for flash
259 * @current_addr - address to write for current
260 * @second_addr - address of secondary flash to be written
261 * @safety_timer - enable safety timer or watchdog timer
262 */
263struct flash_config_data {
264 u8 current_prgm;
265 u8 clamp_curr;
266 u8 headroom;
267 u8 duration;
268 u8 enable_module;
269 u8 trigger_flash;
270 u8 startup_dly;
271 u16 current_addr;
272 u16 second_addr;
273 bool safety_timer;
274};
275
276/**
Amy Malocheeea7b592012-10-03 15:59:36 -0700277 * rgb_config_data - rgb configuration data
278 * @lut_params - lut parameters to be used by pwm driver
279 * @pwm_device - pwm device
280 * @pwm_channel - pwm channel to be configured for led
281 * @pwm_period_us - period for pwm, in us
282 * @mode - mode the led operates in
283 */
284struct rgb_config_data {
285 struct lut_params lut_params;
286 struct pwm_device *pwm_dev;
287 int pwm_channel;
288 u32 pwm_period_us;
289 struct pwm_duty_cycles *duty_cycles;
290 u8 mode;
291 u8 enable;
292};
293
294/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700295 * struct qpnp_led_data - internal led data structure
296 * @led_classdev - led class device
297 * @id - led index
298 * @base_reg - base register given in device tree
299 * @lock - to protect the transactions
300 * @reg - cached value of led register
Amy Malochea5ca5552012-10-23 13:34:46 -0700301 * @num_leds - number of leds in the module
Amy Malochef3d5a062012-08-16 19:14:11 -0700302 * @max_current - maximum current supported by LED
303 * @default_on - true: default state max, false, default state 0
304 */
305struct qpnp_led_data {
306 struct led_classdev cdev;
307 struct spmi_device *spmi_dev;
308 int id;
309 u16 base;
310 u8 reg;
Amy Malochea5ca5552012-10-23 13:34:46 -0700311 u8 num_leds;
Amy Malochedc3e5572012-09-25 16:39:06 -0700312 spinlock_t lock;
Amy Malochef3d5a062012-08-16 19:14:11 -0700313 struct wled_config_data *wled_cfg;
Amy Maloche864a6d52012-10-03 15:58:12 -0700314 struct flash_config_data *flash_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700315 struct rgb_config_data *rgb_cfg;
Amy Malochef3d5a062012-08-16 19:14:11 -0700316 int max_current;
317 bool default_on;
318};
319
320static int
321qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
322{
323 int rc;
324 u8 reg;
325
326 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
327 addr, &reg, 1);
328 if (rc) {
329 dev_err(&led->spmi_dev->dev,
330 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
331 }
332
333 reg &= ~mask;
334 reg |= val;
335
336 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
337 addr, &reg, 1);
338 if (rc)
339 dev_err(&led->spmi_dev->dev,
340 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
341 return rc;
342}
343
Amy Malochea5ca5552012-10-23 13:34:46 -0700344static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
345{
346 int i;
347 u8 val;
348
349 pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
350 for (i = 0; i < array_size; i++) {
351 spmi_ext_register_readl(led->spmi_dev->ctrl,
352 led->spmi_dev->sid,
353 led->base + regs[i],
354 &val, sizeof(val));
355 pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
356 }
357 pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
358}
359
Amy Malochef3d5a062012-08-16 19:14:11 -0700360static int qpnp_wled_set(struct qpnp_led_data *led)
361{
362 int rc, duty;
363 u8 level, val, i, num_wled_strings;
364
365 level = led->cdev.brightness;
366
367 if (level > WLED_MAX_LEVEL)
368 level = WLED_MAX_LEVEL;
369 if (level == 0) {
370 val = WLED_BOOST_OFF;
371 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
372 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
373 &val, 1);
374 if (rc) {
375 dev_err(&led->spmi_dev->dev,
376 "WLED write ctrl reg failed(%d)\n", rc);
377 return rc;
378 }
379 } else {
380 val = WLED_BOOST_ON;
381 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
382 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
383 &val, 1);
384 if (rc) {
385 dev_err(&led->spmi_dev->dev,
386 "WLED write ctrl reg failed(%d)\n", rc);
387 return rc;
388 }
389 }
390
391 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
392
393 num_wled_strings = led->wled_cfg->num_strings;
394
395 /* program brightness control registers */
396 for (i = 0; i < num_wled_strings; i++) {
397 rc = qpnp_led_masked_write(led,
398 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
399 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
400 if (rc) {
401 dev_err(&led->spmi_dev->dev,
402 "WLED set brightness MSB failed(%d)\n", rc);
403 return rc;
404 }
405 val = duty & WLED_8_BIT_MASK;
406 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
407 led->spmi_dev->sid,
408 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
409 if (rc) {
410 dev_err(&led->spmi_dev->dev,
411 "WLED set brightness LSB failed(%d)\n", rc);
412 return rc;
413 }
414 }
415
416 /* sync */
417 val = WLED_SYNC_VAL;
418 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
419 WLED_SYNC_REG(led->base), &val, 1);
420 if (rc) {
421 dev_err(&led->spmi_dev->dev,
422 "WLED set sync reg failed(%d)\n", rc);
423 return rc;
424 }
425
426 val = WLED_SYNC_RESET_VAL;
427 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
428 WLED_SYNC_REG(led->base), &val, 1);
429 if (rc) {
430 dev_err(&led->spmi_dev->dev,
431 "WLED reset sync reg failed(%d)\n", rc);
432 return rc;
433 }
434 return 0;
435}
436
Amy Maloche864a6d52012-10-03 15:58:12 -0700437static int qpnp_flash_set(struct qpnp_led_data *led)
438{
439 int rc;
440 int val = led->cdev.brightness;
441
442 led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
443 led->max_current);
444
445 led->flash_cfg->current_prgm =
446 led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
447 if (!led->flash_cfg->current_prgm)
448 led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
449
450 /* Set led current */
451 if (val > 0) {
452 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
453 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
454 if (rc) {
455 dev_err(&led->spmi_dev->dev,
456 "Current reg write failed(%d)\n", rc);
457 return rc;
458 }
459
460 rc = qpnp_led_masked_write(led, led->flash_cfg->second_addr,
461 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
462 if (rc) {
463 dev_err(&led->spmi_dev->dev,
464 "Current reg write failed(%d)\n", rc);
465 return rc;
466 }
467
468 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
469 FLASH_ENABLE_MASK,
470 FLASH_ENABLE_ALL);
471 if (rc) {
472 dev_err(&led->spmi_dev->dev,
473 "Enable reg write failed(%d)\n", rc);
474 return rc;
475 }
476 rc = qpnp_led_masked_write(led,
477 FLASH_LED_STROBE_CTRL(led->base),
478 FLASH_STROBE_MASK, FLASH_STROBE_ALL);
479
480 if (rc) {
481 dev_err(&led->spmi_dev->dev,
482 "LED %d flash write failed(%d)\n", led->id, rc);
483 return rc;
484 }
485 } else {
486 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
487 FLASH_ENABLE_MASK,
488 FLASH_DISABLE_ALL);
489 if (rc) {
490 dev_err(&led->spmi_dev->dev,
491 "Enable reg write failed(%d)\n", rc);
492 return rc;
493 }
494
495 rc = qpnp_led_masked_write(led,
496 FLASH_LED_STROBE_CTRL(led->base),
497 FLASH_STROBE_MASK,
498 FLASH_DISABLE_ALL);
499 if (rc) {
500 dev_err(&led->spmi_dev->dev,
501 "LED %d flash write failed(%d)\n", led->id, rc);
502 return rc;
503 }
504 }
505
Amy Malocheeea7b592012-10-03 15:59:36 -0700506 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
507
508 return 0;
509}
510
511static int qpnp_rgb_set(struct qpnp_led_data *led)
512{
513 int duty_us;
514 int rc;
515
516 if (led->cdev.brightness) {
517 if (led->rgb_cfg->mode == RGB_MODE_PWM) {
518 duty_us = (led->rgb_cfg->pwm_period_us *
519 led->cdev.brightness) / LED_FULL;
520 rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
521 led->rgb_cfg->pwm_period_us);
522 if (rc < 0) {
523 dev_err(&led->spmi_dev->dev, "Failed to " \
524 "configure pwm for new values\n");
525 return rc;
526 }
527 }
528 rc = qpnp_led_masked_write(led,
529 RGB_LED_EN_CTL(led->base),
530 led->rgb_cfg->enable, led->rgb_cfg->enable);
531 if (rc) {
532 dev_err(&led->spmi_dev->dev,
533 "Failed to write led enable reg\n");
534 return rc;
535 }
536 rc = pwm_enable(led->rgb_cfg->pwm_dev);
537 } else {
538 pwm_disable(led->rgb_cfg->pwm_dev);
539 rc = qpnp_led_masked_write(led,
540 RGB_LED_EN_CTL(led->base),
541 led->rgb_cfg->enable, RGB_LED_DISABLE);
542 if (rc) {
543 dev_err(&led->spmi_dev->dev,
544 "Failed to write led enable reg\n");
545 return rc;
546 }
547 }
548
549 qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
550
Amy Maloche864a6d52012-10-03 15:58:12 -0700551 return 0;
552}
553
Amy Malochef3d5a062012-08-16 19:14:11 -0700554static void qpnp_led_set(struct led_classdev *led_cdev,
555 enum led_brightness value)
556{
557 int rc;
558 struct qpnp_led_data *led;
559
560 led = container_of(led_cdev, struct qpnp_led_data, cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -0700561 if (value < LED_OFF || value > led->cdev.max_brightness) {
Amy Malochea5ca5552012-10-23 13:34:46 -0700562 dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
Amy Malochef3d5a062012-08-16 19:14:11 -0700563 return;
564 }
565
Amy Malochedc3e5572012-09-25 16:39:06 -0700566 spin_lock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700567 led->cdev.brightness = value;
568
569 switch (led->id) {
570 case QPNP_ID_WLED:
571 rc = qpnp_wled_set(led);
572 if (rc < 0)
Amy Malochea5ca5552012-10-23 13:34:46 -0700573 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700574 "WLED set brightness failed (%d)\n", rc);
575 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700576 case QPNP_ID_FLASH1_LED0:
577 case QPNP_ID_FLASH1_LED1:
578 rc = qpnp_flash_set(led);
579 if (rc < 0)
580 dev_err(&led->spmi_dev->dev,
581 "FLASH set brightness failed (%d)\n", rc);
582 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700583 case QPNP_ID_RGB_RED:
584 case QPNP_ID_RGB_GREEN:
585 case QPNP_ID_RGB_BLUE:
586 rc = qpnp_rgb_set(led);
587 if (rc < 0)
588 dev_err(&led->spmi_dev->dev,
589 "RGB set brightness failed (%d)\n", rc);
590 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700591 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700592 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700593 break;
594 }
Amy Malochedc3e5572012-09-25 16:39:06 -0700595 spin_unlock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700596}
597
598static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
599{
600 switch (led->id) {
601 case QPNP_ID_WLED:
602 led->cdev.max_brightness = WLED_MAX_LEVEL;
603 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700604 case QPNP_ID_FLASH1_LED0:
605 case QPNP_ID_FLASH1_LED1:
606 led->cdev.max_brightness = led->max_current;
607 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700608 case QPNP_ID_RGB_RED:
609 case QPNP_ID_RGB_GREEN:
610 case QPNP_ID_RGB_BLUE:
611 led->cdev.max_brightness = RGB_MAX_LEVEL;
612 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700613 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700614 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700615 return -EINVAL;
616 }
617
618 return 0;
619}
620
621static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
622{
623 struct qpnp_led_data *led;
624
625 led = container_of(led_cdev, struct qpnp_led_data, cdev);
626
627 return led->cdev.brightness;
628}
629
630static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
631{
632 int rc, i;
633 u8 num_wled_strings;
634
635 num_wled_strings = led->wled_cfg->num_strings;
636
637 /* verify ranges */
638 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
639 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
640 return -EINVAL;
641 }
642
643 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
644 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
645 return -EINVAL;
646 }
647
648 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
649 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
650 return -EINVAL;
651 }
652
653 if ((led->max_current > WLED_MAX_CURR)) {
654 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
655 return -EINVAL;
656 }
657
658 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
659 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
660 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
661 return -EINVAL;
662 }
663
664 /* program over voltage protection threshold */
665 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
666 WLED_OVP_VAL_MASK,
667 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
668 if (rc) {
669 dev_err(&led->spmi_dev->dev,
670 "WLED OVP reg write failed(%d)\n", rc);
671 return rc;
672 }
673
674 /* program current boost limit */
675 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
676 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
677 if (rc) {
678 dev_err(&led->spmi_dev->dev,
679 "WLED boost limit reg write failed(%d)\n", rc);
680 return rc;
681 }
682
683 /* program output feedback */
684 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
685 WLED_OP_FDBCK_MASK,
686 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
687 if (rc) {
688 dev_err(&led->spmi_dev->dev,
689 "WLED fdbck ctrl reg write failed(%d)\n", rc);
690 return rc;
691 }
692
693 /* program switch frequency */
694 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
695 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
696 if (rc) {
697 dev_err(&led->spmi_dev->dev,
698 "WLED switch freq reg write failed(%d)\n", rc);
699 return rc;
700 }
701
702 /* program current sink */
703 if (led->wled_cfg->cs_out_en) {
704 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
705 WLED_CURR_SINK_MASK,
706 (led->wled_cfg->num_strings << WLED_CURR_SINK_SHFT));
707 if (rc) {
708 dev_err(&led->spmi_dev->dev,
709 "WLED curr sink reg write failed(%d)\n", rc);
710 return rc;
711 }
712 }
713
714 /* program high pole capacitance */
715 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
716 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
717 if (rc) {
718 dev_err(&led->spmi_dev->dev,
719 "WLED pole cap reg write failed(%d)\n", rc);
720 return rc;
721 }
722
723 /* program modulator, current mod src and cabc */
724 for (i = 0; i < num_wled_strings; i++) {
725 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
726 WLED_NO_MASK, WLED_EN_MASK);
727 if (rc) {
728 dev_err(&led->spmi_dev->dev,
729 "WLED mod enable reg write failed(%d)\n", rc);
730 return rc;
731 }
732
733 if (led->wled_cfg->dig_mod_gen_en) {
734 rc = qpnp_led_masked_write(led,
735 WLED_MOD_EN_REG(led->base, i),
736 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
737 if (rc) {
738 dev_err(&led->spmi_dev->dev,
739 "WLED dig mod en reg write failed(%d)\n", rc);
740 }
741 }
742
743 rc = qpnp_led_masked_write(led,
744 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
745 led->max_current);
746 if (rc) {
747 dev_err(&led->spmi_dev->dev,
748 "WLED max current reg write failed(%d)\n", rc);
749 return rc;
750 }
751
752 }
753
754 /* dump wled registers */
Amy Malochea5ca5552012-10-23 13:34:46 -0700755 qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
Amy Malochef3d5a062012-08-16 19:14:11 -0700756
757 return 0;
758}
759
Amy Maloche864a6d52012-10-03 15:58:12 -0700760static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
761{
762 int rc;
763
764 rc = qpnp_led_masked_write(led,
765 FLASH_LED_STROBE_CTRL(led->base),
766 FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
767 if (rc) {
768 dev_err(&led->spmi_dev->dev,
769 "LED %d flash write failed(%d)\n", led->id, rc);
770 return rc;
771 }
772 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
773 FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
774 if (rc) {
775 dev_err(&led->spmi_dev->dev,
776 "Enable reg write failed(%d)\n", rc);
777 return rc;
778 }
779
780 /* Set flash safety timer */
781 rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
782 FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
783 if (rc) {
784 dev_err(&led->spmi_dev->dev,
785 "Safety timer reg write failed(%d)\n", rc);
786 return rc;
787 }
788
789 /* Set max current */
790 rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
791 FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
792 if (rc) {
793 dev_err(&led->spmi_dev->dev,
794 "Max current reg write failed(%d)\n", rc);
795 return rc;
796 }
797 /* Set clamp current */
798 rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
799 FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
800 if (rc) {
801 dev_err(&led->spmi_dev->dev,
802 "Clamp current reg write failed(%d)\n", rc);
803 return rc;
804 }
805
806 /* Set timer control - safety or watchdog */
807 if (led->flash_cfg->safety_timer)
808 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
809 FLASH_TMR_MASK, FLASH_TMR_SAFETY);
810 else
811 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
812 FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
813 if (rc) {
814 dev_err(&led->spmi_dev->dev,
815 "LED timer ctrl reg write failed(%d)\n", rc);
816 return rc;
817 }
818 /* Set headroom */
819 rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
820 FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
821 if (rc) {
822 dev_err(&led->spmi_dev->dev,
823 "Headroom reg write failed(%d)\n", rc);
824 return rc;
825 }
826
827 /* Set mask enable */
828 rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
829 FLASH_MASK_REG_MASK, FLASH_MASK_1);
830 if (rc) {
831 dev_err(&led->spmi_dev->dev,
832 "Mask enable reg write failed(%d)\n", rc);
833 return rc;
834 }
835
836 /* Set startup delay */
837 rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
838 FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
839 if (rc) {
840 dev_err(&led->spmi_dev->dev,
841 "Startup delay reg write failed(%d)\n", rc);
842 return rc;
843 }
844
845 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
846 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
847 if (rc) {
848 dev_err(&led->spmi_dev->dev,
849 "Vreg OK reg write failed(%d)\n", rc);
850 return rc;
851 }
852
853 /* Set led current and enable module */
854 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
855 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
856 if (rc) {
857 dev_err(&led->spmi_dev->dev,
858 "Current reg write failed(%d)\n", rc);
859 return rc;
860 }
861
862 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
863 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
864 if (rc) {
865 dev_err(&led->spmi_dev->dev,
866 "Enable reg write failed(%d)\n", rc);
867 return rc;
868 }
869 /* dump flash registers */
870 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
871
872 return 0;
873}
874
Amy Malocheeea7b592012-10-03 15:59:36 -0700875static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
876{
877 int rc, start_idx, idx_len;
878
879 rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
880 RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
881 if (rc) {
882 dev_err(&led->spmi_dev->dev,
883 "Failed to write led source select register\n");
884 return rc;
885 }
886
887 if (led->rgb_cfg->pwm_channel != -1) {
888 led->rgb_cfg->pwm_dev =
889 pwm_request(led->rgb_cfg->pwm_channel,
890 led->cdev.name);
891
892 if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
893 dev_err(&led->spmi_dev->dev,
894 "could not acquire PWM Channel %d, " \
895 "error %ld\n",
896 led->rgb_cfg->pwm_channel,
897 PTR_ERR(led->rgb_cfg->pwm_dev));
898 led->rgb_cfg->pwm_dev = NULL;
899 return -ENODEV;
900 }
901
902 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
903 start_idx =
904 led->rgb_cfg->duty_cycles->start_idx;
905 idx_len =
906 led->rgb_cfg->duty_cycles->num_duty_pcts;
907
908 if (idx_len >= PWM_LUT_MAX_SIZE &&
909 start_idx) {
910 dev_err(&led->spmi_dev->dev,
911 "Wrong LUT size or index\n");
912 return -EINVAL;
913 }
914 if ((start_idx + idx_len) >
915 PWM_LUT_MAX_SIZE) {
916 dev_err(&led->spmi_dev->dev,
917 "Exceed LUT limit\n");
918 return -EINVAL;
919 }
920 rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
921 led->rgb_cfg->pwm_period_us,
922 led->rgb_cfg->duty_cycles->duty_pcts,
923 led->rgb_cfg->lut_params);
924 if (rc < 0) {
925 dev_err(&led->spmi_dev->dev, "Failed to " \
926 "configure pwm LUT\n");
927 return rc;
928 }
929 }
930 } else {
931 dev_err(&led->spmi_dev->dev,
932 "Invalid PWM channel\n");
933 return -EINVAL;
934 }
935
936 /* Initialize led for use in auto trickle charging mode */
937 rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
938 led->rgb_cfg->enable, led->rgb_cfg->enable);
939
940 return 0;
941}
942
Amy Malochef3d5a062012-08-16 19:14:11 -0700943static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
944{
945 int rc;
946
947 switch (led->id) {
948 case QPNP_ID_WLED:
949 rc = qpnp_wled_init(led);
950 if (rc)
Amy Malochea5ca5552012-10-23 13:34:46 -0700951 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700952 "WLED initialize failed(%d)\n", rc);
953 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700954 case QPNP_ID_FLASH1_LED0:
955 case QPNP_ID_FLASH1_LED1:
956 rc = qpnp_flash_init(led);
957 if (rc)
958 dev_err(&led->spmi_dev->dev,
959 "FLASH initialize failed(%d)\n", rc);
960 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700961 case QPNP_ID_RGB_RED:
962 case QPNP_ID_RGB_GREEN:
963 case QPNP_ID_RGB_BLUE:
964 rc = qpnp_rgb_init(led);
965 if (rc)
966 dev_err(&led->spmi_dev->dev,
967 "RGB initialize failed(%d)\n", rc);
968 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700969 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700970 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malocheeea7b592012-10-03 15:59:36 -0700971 return -EINVAL;
Amy Malochef3d5a062012-08-16 19:14:11 -0700972 }
973
Amy Malocheeea7b592012-10-03 15:59:36 -0700974 return 0;
Amy Malochef3d5a062012-08-16 19:14:11 -0700975}
976
Amy Malochea5ca5552012-10-23 13:34:46 -0700977static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
978 struct device_node *node)
979{
980 int rc;
981 const char *temp_string;
982
983 led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
984 rc = of_property_read_string(node, "linux,default-trigger",
985 &temp_string);
986 if (!rc)
987 led->cdev.default_trigger = temp_string;
988 else if (rc != -EINVAL)
989 return rc;
990
991 led->default_on = false;
992 rc = of_property_read_string(node, "qcom,default-state",
993 &temp_string);
994 if (!rc) {
995 if (strncmp(temp_string, "on", sizeof("on")) == 0)
996 led->default_on = true;
997 } else if (rc != -EINVAL)
998 return rc;
999
1000 return 0;
1001}
1002
Amy Malochef3d5a062012-08-16 19:14:11 -07001003/*
1004 * Handlers for alternative sources of platform_data
1005 */
1006static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
1007 struct device_node *node)
1008{
1009 u32 val;
1010 int rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001011
1012 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
1013 sizeof(struct wled_config_data), GFP_KERNEL);
1014 if (!led->wled_cfg) {
1015 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1016 return -ENOMEM;
1017 }
1018
Amy Malochef3d5a062012-08-16 19:14:11 -07001019 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
1020 rc = of_property_read_u32(node, "qcom,num-strings", &val);
1021 if (!rc)
1022 led->wled_cfg->num_strings = (u8) val;
1023 else if (rc != -EINVAL)
1024 return rc;
1025
1026 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
1027 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
1028 if (!rc)
1029 led->wled_cfg->ovp_val = (u8) val;
1030 else if (rc != -EINVAL)
1031 return rc;
1032
1033 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
1034 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
1035 if (!rc)
1036 led->wled_cfg->boost_curr_lim = (u8) val;
1037 else if (rc != -EINVAL)
1038 return rc;
1039
1040 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
1041 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
1042 if (!rc)
1043 led->wled_cfg->cp_select = (u8) val;
1044 else if (rc != -EINVAL)
1045 return rc;
1046
1047 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
1048 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
1049 if (!rc)
1050 led->wled_cfg->ctrl_delay_us = (u8) val;
1051 else if (rc != -EINVAL)
1052 return rc;
1053
1054 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
1055 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
1056 if (!rc)
1057 led->wled_cfg->switch_freq = (u8) val;
1058 else if (rc != -EINVAL)
1059 return rc;
1060
1061 led->wled_cfg->dig_mod_gen_en =
1062 of_property_read_bool(node, "qcom,dig-mod-gen-en");
1063
1064 led->wled_cfg->cs_out_en =
1065 of_property_read_bool(node, "qcom,cs-out-en");
1066
1067 led->wled_cfg->op_fdbck =
1068 of_property_read_bool(node, "qcom,op-fdbck");
1069
1070 return 0;
1071}
1072
Amy Maloche864a6d52012-10-03 15:58:12 -07001073static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
1074 struct device_node *node)
1075{
1076 int rc;
1077 u32 val;
1078
1079 led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
1080 sizeof(struct flash_config_data), GFP_KERNEL);
1081 if (!led->flash_cfg) {
1082 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1083 return -ENOMEM;
1084 }
1085
1086 if (led->id == QPNP_ID_FLASH1_LED0) {
1087 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1088 led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
1089 led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
1090 led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
1091 } else if (led->id == QPNP_ID_FLASH1_LED1) {
1092 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1093 led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
1094 led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
1095 led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
1096 } else {
1097 dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
1098 return -EINVAL;
1099 }
1100
1101 rc = of_property_read_u32(node, "qcom,current", &val);
1102 if (!rc)
1103 led->flash_cfg->current_prgm = (val *
1104 FLASH_MAX_LEVEL / led->max_current);
1105 else
1106 return -EINVAL;
1107
1108 rc = of_property_read_u32(node, "qcom,headroom", &val);
1109 if (!rc)
1110 led->flash_cfg->headroom = (u8) val;
1111 else if (rc == -EINVAL)
1112 led->flash_cfg->headroom = HEADROOM_300mV;
1113 else
1114 return rc;
1115
1116 rc = of_property_read_u32(node, "qcom,duration", &val);
1117 if (!rc)
1118 led->flash_cfg->duration = (((u8) val) - 10) / 10;
1119 else if (rc == -EINVAL)
1120 led->flash_cfg->duration = FLASH_DURATION_200ms;
1121 else
1122 return rc;
1123
1124 rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
1125 if (!rc)
1126 led->flash_cfg->clamp_curr = (val *
1127 FLASH_MAX_LEVEL / led->max_current);
1128 else if (rc == -EINVAL)
1129 led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
1130 else
1131 return rc;
1132
1133 rc = of_property_read_u32(node, "qcom,startup-dly", &val);
1134 if (!rc)
1135 led->flash_cfg->startup_dly = (u8) val;
1136 else if (rc == -EINVAL)
1137 led->flash_cfg->startup_dly = DELAY_32us;
1138 else
1139 return rc;
1140
1141 led->flash_cfg->safety_timer =
1142 of_property_read_bool(node, "qcom,safety-timer");
1143
1144 return 0;
1145}
1146
Amy Malocheeea7b592012-10-03 15:59:36 -07001147static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
1148 struct device_node *node)
1149{
1150 struct property *prop;
1151 int rc, i;
1152 u32 val;
1153 u8 *temp_cfg;
1154
1155 led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
1156 sizeof(struct rgb_config_data), GFP_KERNEL);
1157 if (!led->rgb_cfg) {
1158 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1159 return -ENOMEM;
1160 }
1161
1162 if (led->id == QPNP_ID_RGB_RED)
1163 led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
1164 else if (led->id == QPNP_ID_RGB_GREEN)
1165 led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
1166 else if (led->id == QPNP_ID_RGB_BLUE)
1167 led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
1168 else
1169 return -EINVAL;
1170
1171 rc = of_property_read_u32(node, "qcom,mode", &val);
1172 if (!rc)
1173 led->rgb_cfg->mode = (u8) val;
1174 else
1175 return rc;
1176
1177 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1178 if (!rc)
1179 led->rgb_cfg->pwm_channel = (u8) val;
1180 else
1181 return rc;
1182
1183 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1184 if (!rc)
1185 led->rgb_cfg->pwm_period_us = val;
1186 else
1187 return rc;
1188
1189 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1190 led->rgb_cfg->duty_cycles =
1191 devm_kzalloc(&led->spmi_dev->dev,
1192 sizeof(struct pwm_duty_cycles), GFP_KERNEL);
1193 if (!led->rgb_cfg->duty_cycles) {
1194 dev_err(&led->spmi_dev->dev,
1195 "Unable to allocate memory\n");
1196 return -ENOMEM;
1197 }
1198
1199 rc = of_property_read_u32(node, "qcom,duty-ms", &val);
1200 if (!rc)
1201 led->rgb_cfg->duty_cycles->duty_ms = (u8) val;
1202 else
1203 return rc;
1204
1205 prop = of_find_property(node, "qcom,duty-pcts",
1206 &led->rgb_cfg->duty_cycles->num_duty_pcts);
1207 if (!prop) {
1208 dev_err(&led->spmi_dev->dev, "Looking up property " \
1209 "node qcom,duty-pcts failed\n");
1210 return -ENODEV;
1211 } else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
1212 dev_err(&led->spmi_dev->dev, "Invalid length of " \
1213 "duty pcts\n");
1214 return -EINVAL;
1215 }
1216
1217 led->rgb_cfg->duty_cycles->duty_pcts =
1218 devm_kzalloc(&led->spmi_dev->dev,
1219 sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
1220 GFP_KERNEL);
1221 if (!led->rgb_cfg->duty_cycles->duty_pcts) {
1222 dev_err(&led->spmi_dev->dev,
1223 "Unable to allocate memory\n");
1224 return -ENOMEM;
1225 }
1226
1227 temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1228 led->rgb_cfg->duty_cycles->num_duty_pcts *
1229 sizeof(u8), GFP_KERNEL);
1230 if (!temp_cfg) {
1231 dev_err(&led->spmi_dev->dev, "Failed to allocate " \
1232 "memory for duty pcts\n");
1233 return -ENOMEM;
1234 }
1235
1236 memcpy(temp_cfg, prop->value,
1237 led->rgb_cfg->duty_cycles->num_duty_pcts);
1238
1239 for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
1240 led->rgb_cfg->duty_cycles->duty_pcts[i] =
1241 (int) temp_cfg[i];
1242
1243 rc = of_property_read_u32(node, "qcom,start-idx", &val);
1244 if (!rc) {
1245 led->rgb_cfg->lut_params.start_idx = (u8) val;
1246 led->rgb_cfg->duty_cycles->start_idx = (u8) val;
1247 } else
1248 return rc;
1249
1250 led->rgb_cfg->lut_params.idx_len =
1251 led->rgb_cfg->duty_cycles->num_duty_pcts;
1252 led->rgb_cfg->lut_params.lut_pause_hi = 0;
1253 led->rgb_cfg->lut_params.lut_pause_lo = 0;
1254 led->rgb_cfg->lut_params.ramp_step_ms = 255;
1255 led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
1256 }
1257
1258 return 0;
1259}
1260
Amy Malochef3d5a062012-08-16 19:14:11 -07001261static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
1262{
Amy Malochef9490c62012-11-27 19:26:04 -08001263 struct qpnp_led_data *led, *led_array;
Amy Malochef3d5a062012-08-16 19:14:11 -07001264 struct resource *led_resource;
Amy Malochea5ca5552012-10-23 13:34:46 -07001265 struct device_node *node, *temp;
Amy Malochef9490c62012-11-27 19:26:04 -08001266 int rc, i, num_leds = 0, parsed_leds = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001267 const char *led_label;
1268
Amy Malochea5ca5552012-10-23 13:34:46 -07001269 node = spmi->dev.of_node;
1270 if (node == NULL)
1271 return -ENODEV;
1272
1273 temp = NULL;
1274 while ((temp = of_get_next_child(node, temp)))
1275 num_leds++;
1276
Amy Malochef9490c62012-11-27 19:26:04 -08001277 if (!num_leds)
1278 return -ECHILD;
1279
1280 led_array = devm_kzalloc(&spmi->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001281 (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
Amy Malochef9490c62012-11-27 19:26:04 -08001282 if (!led_array) {
Amy Malochef3d5a062012-08-16 19:14:11 -07001283 dev_err(&spmi->dev, "Unable to allocate memory\n");
1284 return -ENOMEM;
1285 }
1286
Amy Malochea5ca5552012-10-23 13:34:46 -07001287 for_each_child_of_node(node, temp) {
Amy Malochef9490c62012-11-27 19:26:04 -08001288 led = &led_array[parsed_leds];
1289 led->num_leds = num_leds;
Amy Malochea5ca5552012-10-23 13:34:46 -07001290 led->spmi_dev = spmi;
Amy Malochef3d5a062012-08-16 19:14:11 -07001291
Amy Malochea5ca5552012-10-23 13:34:46 -07001292 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
1293 if (!led_resource) {
1294 dev_err(&spmi->dev, "Unable to get LED base address\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001295 rc = -ENXIO;
1296 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001297 }
1298 led->base = led_resource->start;
Amy Malochef3d5a062012-08-16 19:14:11 -07001299
Amy Malochea5ca5552012-10-23 13:34:46 -07001300 rc = of_property_read_string(temp, "label", &led_label);
Amy Malochef3d5a062012-08-16 19:14:11 -07001301 if (rc < 0) {
1302 dev_err(&led->spmi_dev->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001303 "Failure reading label, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001304 goto fail_id_check;
Amy Malochef3d5a062012-08-16 19:14:11 -07001305 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001306
1307 rc = of_property_read_string(temp, "linux,name",
1308 &led->cdev.name);
1309 if (rc < 0) {
1310 dev_err(&led->spmi_dev->dev,
1311 "Failure reading led name, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001312 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001313 }
1314
1315 rc = of_property_read_u32(temp, "qcom,max-current",
1316 &led->max_current);
1317 if (rc < 0) {
1318 dev_err(&led->spmi_dev->dev,
1319 "Failure reading max_current, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001320 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001321 }
1322
1323 rc = of_property_read_u32(temp, "qcom,id", &led->id);
1324 if (rc < 0) {
1325 dev_err(&led->spmi_dev->dev,
1326 "Failure reading led id, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001327 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001328 }
1329
1330 rc = qpnp_get_common_configs(led, temp);
1331 if (rc) {
1332 dev_err(&led->spmi_dev->dev,
1333 "Failure reading common led configuration," \
1334 " rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001335 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001336 }
1337
1338 led->cdev.brightness_set = qpnp_led_set;
1339 led->cdev.brightness_get = qpnp_led_get;
1340
1341 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
1342 rc = qpnp_get_config_wled(led, temp);
1343 if (rc < 0) {
1344 dev_err(&led->spmi_dev->dev,
1345 "Unable to read wled config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001346 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001347 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001348 } else if (strncmp(led_label, "flash", sizeof("flash"))
1349 == 0) {
1350 rc = qpnp_get_config_flash(led, temp);
1351 if (rc < 0) {
1352 dev_err(&led->spmi_dev->dev,
1353 "Unable to read flash config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001354 goto fail_id_check;
Amy Maloche864a6d52012-10-03 15:58:12 -07001355 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001356 } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
1357 rc = qpnp_get_config_rgb(led, temp);
1358 if (rc < 0) {
1359 dev_err(&led->spmi_dev->dev,
1360 "Unable to read rgb config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001361 goto fail_id_check;
Amy Malocheeea7b592012-10-03 15:59:36 -07001362 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001363 } else {
1364 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001365 rc = -EINVAL;
1366 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001367 }
1368
1369 spin_lock_init(&led->lock);
1370
1371 rc = qpnp_led_initialize(led);
1372 if (rc < 0)
1373 goto fail_id_check;
1374
1375 rc = qpnp_led_set_max_brightness(led);
1376 if (rc < 0)
1377 goto fail_id_check;
1378
1379 rc = led_classdev_register(&spmi->dev, &led->cdev);
1380 if (rc) {
1381 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
1382 led->id, rc);
1383 goto fail_id_check;
1384 }
1385 /* configure default state */
1386 if (led->default_on)
1387 led->cdev.brightness = led->cdev.max_brightness;
1388 else
1389 led->cdev.brightness = LED_OFF;
1390
1391 qpnp_led_set(&led->cdev, led->cdev.brightness);
Amy Malochef9490c62012-11-27 19:26:04 -08001392
1393 parsed_leds++;
Amy Malochef3d5a062012-08-16 19:14:11 -07001394 }
Amy Malochef9490c62012-11-27 19:26:04 -08001395 dev_set_drvdata(&spmi->dev, led_array);
Amy Malochef3d5a062012-08-16 19:14:11 -07001396 return 0;
1397
1398fail_id_check:
Amy Malochef9490c62012-11-27 19:26:04 -08001399 for (i = 0; i < parsed_leds; i++)
1400 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001401 return rc;
1402}
1403
1404static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
1405{
Amy Malochef9490c62012-11-27 19:26:04 -08001406 struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
1407 int i, parsed_leds = led_array->num_leds;
Amy Malochef3d5a062012-08-16 19:14:11 -07001408
Amy Malochef9490c62012-11-27 19:26:04 -08001409 for (i = 0; i < parsed_leds; i++)
1410 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001411
1412 return 0;
1413}
1414static struct of_device_id spmi_match_table[] = {
1415 { .compatible = "qcom,leds-qpnp",
1416 }
1417};
1418
1419static struct spmi_driver qpnp_leds_driver = {
1420 .driver = {
1421 .name = "qcom,leds-qpnp",
1422 .of_match_table = spmi_match_table,
1423 },
1424 .probe = qpnp_leds_probe,
1425 .remove = __devexit_p(qpnp_leds_remove),
1426};
1427
1428static int __init qpnp_led_init(void)
1429{
1430 return spmi_driver_register(&qpnp_leds_driver);
1431}
1432module_init(qpnp_led_init);
1433
1434static void __exit qpnp_led_exit(void)
1435{
1436 spmi_driver_unregister(&qpnp_leds_driver);
1437}
1438module_exit(qpnp_led_exit);
1439
1440MODULE_DESCRIPTION("QPNP LEDs driver");
1441MODULE_LICENSE("GPL v2");
1442MODULE_ALIAS("leds:leds-qpnp");
Amy Maloche864a6d52012-10-03 15:58:12 -07001443