blob: 6cb4ead73ec5d58a33760140aaa3653ca2d45e03 [file] [log] [blame]
Amy Malochef3d5a062012-08-16 19:14:11 -07001
Amy Maloche832d90a2013-01-07 10:15:29 -08002/* Copyright (c) 2012-2013, 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>
Asaf Penso55ac8472013-01-21 21:17:37 +020025#include <linux/workqueue.h>
Amy Malochef3d5a062012-08-16 19:14:11 -070026
27#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
28#define WLED_IDAC_DLY_REG(base, n) (WLED_MOD_EN_REG(base, n) + 0x01)
29#define WLED_FULL_SCALE_REG(base, n) (WLED_IDAC_DLY_REG(base, n) + 0x01)
30
31/* wled control registers */
32#define WLED_BRIGHTNESS_CNTL_LSB(base, n) (base + 0x40 + 2*n)
33#define WLED_BRIGHTNESS_CNTL_MSB(base, n) (base + 0x41 + 2*n)
34#define WLED_MOD_CTRL_REG(base) (base + 0x46)
35#define WLED_SYNC_REG(base) (base + 0x47)
36#define WLED_FDBCK_CTRL_REG(base) (base + 0x48)
37#define WLED_SWITCHING_FREQ_REG(base) (base + 0x4C)
38#define WLED_OVP_CFG_REG(base) (base + 0x4D)
39#define WLED_BOOST_LIMIT_REG(base) (base + 0x4E)
40#define WLED_CURR_SINK_REG(base) (base + 0x4F)
41#define WLED_HIGH_POLE_CAP_REG(base) (base + 0x58)
42#define WLED_CURR_SINK_MASK 0xE0
43#define WLED_CURR_SINK_SHFT 0x05
44#define WLED_SWITCH_FREQ_MASK 0x02
45#define WLED_OVP_VAL_MASK 0x03
46#define WLED_OVP_VAL_BIT_SHFT 0x00
47#define WLED_BOOST_LIMIT_MASK 0x07
48#define WLED_BOOST_LIMIT_BIT_SHFT 0x00
49#define WLED_BOOST_ON 0x80
50#define WLED_BOOST_OFF 0x00
51#define WLED_EN_MASK 0x80
52#define WLED_NO_MASK 0x00
53#define WLED_CP_SELECT_MAX 0x03
54#define WLED_CP_SELECT_MASK 0x02
55#define WLED_USE_EXT_GEN_MOD_SRC 0x01
56#define WLED_CTL_DLY_STEP 200
57#define WLED_CTL_DLY_MAX 1400
58#define WLED_MAX_CURR 25
59#define WLED_MSB_MASK 0x0F
60#define WLED_MAX_CURR_MASK 0x19
61#define WLED_OP_FDBCK_MASK 0x07
62#define WLED_OP_FDBCK_BIT_SHFT 0x00
63
64#define WLED_MAX_LEVEL 255
65#define WLED_8_BIT_MASK 0xFF
66#define WLED_4_BIT_MASK 0x0F
67#define WLED_8_BIT_SHFT 0x08
68#define WLED_MAX_DUTY_CYCLE 0xFFF
69
70#define WLED_SYNC_VAL 0x07
71#define WLED_SYNC_RESET_VAL 0x00
72
Amy Malochef3d5a062012-08-16 19:14:11 -070073#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
Amy Maloche864a6d52012-10-03 15:58:12 -070080#define FLASH_SAFETY_TIMER(base) (base + 0x40)
81#define FLASH_MAX_CURR(base) (base + 0x41)
82#define FLASH_LED_0_CURR(base) (base + 0x42)
83#define FLASH_LED_1_CURR(base) (base + 0x43)
84#define FLASH_CLAMP_CURR(base) (base + 0x44)
85#define FLASH_LED_TMR_CTRL(base) (base + 0x48)
86#define FLASH_HEADROOM(base) (base + 0x49)
87#define FLASH_STARTUP_DELAY(base) (base + 0x4B)
88#define FLASH_MASK_ENABLE(base) (base + 0x4C)
89#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
90#define FLASH_ENABLE_CONTROL(base) (base + 0x46)
91#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
92
93#define FLASH_MAX_LEVEL 0x4F
94#define FLASH_NO_MASK 0x00
95
96#define FLASH_MASK_1 0x20
97#define FLASH_MASK_REG_MASK 0xE0
98#define FLASH_HEADROOM_MASK 0x03
99#define FLASH_SAFETY_TIMER_MASK 0x7F
100#define FLASH_CURRENT_MASK 0xFF
101#define FLASH_TMR_MASK 0x03
102#define FLASH_TMR_WATCHDOG 0x03
103#define FLASH_TMR_SAFETY 0x00
104
105#define FLASH_HW_VREG_OK 0x80
106#define FLASH_VREG_MASK 0xC0
107
108#define FLASH_STARTUP_DLY_MASK 0x02
109
110#define FLASH_ENABLE_ALL 0xE0
111#define FLASH_ENABLE_MODULE 0x80
112#define FLASH_ENABLE_MODULE_MASK 0x80
113#define FLASH_DISABLE_ALL 0x00
Amy Maloche38b9aae2013-02-07 12:15:34 -0800114#define FLASH_ENABLE_MASK 0xE0
Amy Maloche864a6d52012-10-03 15:58:12 -0700115#define FLASH_ENABLE_LED_0 0x40
116#define FLASH_ENABLE_LED_1 0x20
117#define FLASH_INIT_MASK 0xE0
118
119#define FLASH_STROBE_ALL 0xC0
120#define FLASH_STROBE_MASK 0xC0
121#define FLASH_LED_0_OUTPUT 0x80
122#define FLASH_LED_1_OUTPUT 0x40
123
124#define FLASH_CURRENT_PRGM_MIN 1
125#define FLASH_CURRENT_PRGM_SHIFT 1
126
127#define FLASH_DURATION_200ms 0x13
128#define FLASH_CLAMP_200mA 0x0F
129
Amy Malochea5ca5552012-10-23 13:34:46 -0700130#define LED_TRIGGER_DEFAULT "none"
131
Amy Malocheeea7b592012-10-03 15:59:36 -0700132#define RGB_LED_SRC_SEL(base) (base + 0x45)
133#define RGB_LED_EN_CTL(base) (base + 0x46)
134#define RGB_LED_ATC_CTL(base) (base + 0x47)
135
136#define RGB_MAX_LEVEL LED_FULL
137#define RGB_LED_ENABLE_RED 0x80
138#define RGB_LED_ENABLE_GREEN 0x40
139#define RGB_LED_ENABLE_BLUE 0x20
140#define RGB_LED_SOURCE_VPH_PWR 0x01
141#define RGB_LED_ENABLE_MASK 0xE0
142#define RGB_LED_SRC_MASK 0x03
143#define QPNP_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
144#define PWM_LUT_MAX_SIZE 63
145#define RGB_LED_DISABLE 0x00
146
Amy Malochef3d5a062012-08-16 19:14:11 -0700147/**
148 * enum qpnp_leds - QPNP supported led ids
149 * @QPNP_ID_WLED - White led backlight
150 */
151enum qpnp_leds {
Amy Maloche864a6d52012-10-03 15:58:12 -0700152 QPNP_ID_WLED = 0,
153 QPNP_ID_FLASH1_LED0,
154 QPNP_ID_FLASH1_LED1,
Amy Malocheeea7b592012-10-03 15:59:36 -0700155 QPNP_ID_RGB_RED,
156 QPNP_ID_RGB_GREEN,
157 QPNP_ID_RGB_BLUE,
Amy Maloche864a6d52012-10-03 15:58:12 -0700158 QPNP_ID_MAX,
Amy Malochef3d5a062012-08-16 19:14:11 -0700159};
160
161/* current boost limit */
162enum wled_current_boost_limit {
163 WLED_CURR_LIMIT_105mA,
164 WLED_CURR_LIMIT_385mA,
165 WLED_CURR_LIMIT_525mA,
166 WLED_CURR_LIMIT_805mA,
167 WLED_CURR_LIMIT_980mA,
168 WLED_CURR_LIMIT_1260mA,
169 WLED_CURR_LIMIT_1400mA,
170 WLED_CURR_LIMIT_1680mA,
171};
172
173/* over voltage protection threshold */
174enum wled_ovp_threshold {
175 WLED_OVP_35V,
176 WLED_OVP_32V,
177 WLED_OVP_29V,
178 WLED_OVP_37V,
179};
180
181/* switch frquency */
182enum wled_switch_freq {
183 WLED_800kHz = 0,
184 WLED_960kHz,
185 WLED_1600kHz,
186 WLED_3200kHz,
187};
188
Amy Maloche864a6d52012-10-03 15:58:12 -0700189enum flash_headroom {
190 HEADROOM_250mV = 0,
191 HEADROOM_300mV,
192 HEADROOM_400mV,
193 HEADROOM_500mV,
194};
195
196enum flash_startup_dly {
197 DELAY_10us = 0,
198 DELAY_32us,
199 DELAY_64us,
200 DELAY_128us,
201};
202
Amy Malocheeea7b592012-10-03 15:59:36 -0700203enum rgb_mode {
204 RGB_MODE_PWM = 0,
205 RGB_MODE_LPG,
206};
207
Amy Malochef3d5a062012-08-16 19:14:11 -0700208static u8 wled_debug_regs[] = {
209 /* common registers */
210 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
211 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
212 /* LED1 */
213 0x60, 0x61, 0x62, 0x63, 0x66,
Amy Malochea5ca5552012-10-23 13:34:46 -0700214 /* LED2 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700215 0x70, 0x71, 0x72, 0x73, 0x76,
Amy Malochea5ca5552012-10-23 13:34:46 -0700216 /* LED3 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700217 0x80, 0x81, 0x82, 0x83, 0x86,
218};
219
Amy Maloche864a6d52012-10-03 15:58:12 -0700220static u8 flash_debug_regs[] = {
221 0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
222 0x4f, 0x46, 0x47,
223};
224
Amy Malocheeea7b592012-10-03 15:59:36 -0700225static u8 rgb_pwm_debug_regs[] = {
226 0x45, 0x46, 0x47,
227};
Amy Malochef3d5a062012-08-16 19:14:11 -0700228/**
229 * wled_config_data - wled configuration data
230 * @num_strings - number of wled strings supported
231 * @ovp_val - over voltage protection threshold
232 * @boost_curr_lim - boot current limit
233 * @cp_select - high pole capacitance
234 * @ctrl_delay_us - delay in activation of led
235 * @dig_mod_gen_en - digital module generator
236 * @cs_out_en - current sink output enable
237 * @op_fdbck - selection of output as feedback for the boost
238 */
239struct wled_config_data {
240 u8 num_strings;
241 u8 ovp_val;
242 u8 boost_curr_lim;
243 u8 cp_select;
244 u8 ctrl_delay_us;
245 u8 switch_freq;
246 bool dig_mod_gen_en;
247 bool cs_out_en;
248 bool op_fdbck;
249};
250
251/**
Amy Maloche864a6d52012-10-03 15:58:12 -0700252 * flash_config_data - flash configuration data
253 * @current_prgm - current to be programmed, scaled by max level
254 * @clamp_curr - clamp current to use
255 * @headroom - headroom value to use
256 * @duration - duration of the flash
257 * @enable_module - enable address for particular flash
258 * @trigger_flash - trigger flash
259 * @startup_dly - startup delay for flash
260 * @current_addr - address to write for current
261 * @second_addr - address of secondary flash to be written
262 * @safety_timer - enable safety timer or watchdog timer
263 */
264struct flash_config_data {
265 u8 current_prgm;
266 u8 clamp_curr;
267 u8 headroom;
268 u8 duration;
269 u8 enable_module;
270 u8 trigger_flash;
271 u8 startup_dly;
272 u16 current_addr;
273 u16 second_addr;
274 bool safety_timer;
275};
276
277/**
Amy Malocheeea7b592012-10-03 15:59:36 -0700278 * rgb_config_data - rgb configuration data
279 * @lut_params - lut parameters to be used by pwm driver
280 * @pwm_device - pwm device
281 * @pwm_channel - pwm channel to be configured for led
282 * @pwm_period_us - period for pwm, in us
283 * @mode - mode the led operates in
284 */
285struct rgb_config_data {
286 struct lut_params lut_params;
287 struct pwm_device *pwm_dev;
288 int pwm_channel;
289 u32 pwm_period_us;
290 struct pwm_duty_cycles *duty_cycles;
291 u8 mode;
292 u8 enable;
293};
294
295/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700296 * struct qpnp_led_data - internal led data structure
297 * @led_classdev - led class device
Asaf Penso55ac8472013-01-21 21:17:37 +0200298 * @delayed_work - delayed work for turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700299 * @id - led index
300 * @base_reg - base register given in device tree
301 * @lock - to protect the transactions
302 * @reg - cached value of led register
Amy Malochea5ca5552012-10-23 13:34:46 -0700303 * @num_leds - number of leds in the module
Amy Malochef3d5a062012-08-16 19:14:11 -0700304 * @max_current - maximum current supported by LED
305 * @default_on - true: default state max, false, default state 0
Asaf Penso55ac8472013-01-21 21:17:37 +0200306 * @turn_off_delay_ms - number of msec before turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700307 */
308struct qpnp_led_data {
309 struct led_classdev cdev;
310 struct spmi_device *spmi_dev;
Asaf Penso55ac8472013-01-21 21:17:37 +0200311 struct delayed_work dwork;
Amy Malochef3d5a062012-08-16 19:14:11 -0700312 int id;
313 u16 base;
314 u8 reg;
Amy Malochea5ca5552012-10-23 13:34:46 -0700315 u8 num_leds;
Amy Malochedc3e5572012-09-25 16:39:06 -0700316 spinlock_t lock;
Amy Malochef3d5a062012-08-16 19:14:11 -0700317 struct wled_config_data *wled_cfg;
Amy Maloche864a6d52012-10-03 15:58:12 -0700318 struct flash_config_data *flash_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700319 struct rgb_config_data *rgb_cfg;
Amy Malochef3d5a062012-08-16 19:14:11 -0700320 int max_current;
321 bool default_on;
Asaf Penso55ac8472013-01-21 21:17:37 +0200322 int turn_off_delay_ms;
Amy Malochef3d5a062012-08-16 19:14:11 -0700323};
324
325static int
326qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
327{
328 int rc;
329 u8 reg;
330
331 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
332 addr, &reg, 1);
333 if (rc) {
334 dev_err(&led->spmi_dev->dev,
335 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
336 }
337
338 reg &= ~mask;
339 reg |= val;
340
341 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
342 addr, &reg, 1);
343 if (rc)
344 dev_err(&led->spmi_dev->dev,
345 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
346 return rc;
347}
348
Amy Malochea5ca5552012-10-23 13:34:46 -0700349static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
350{
351 int i;
352 u8 val;
353
354 pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
355 for (i = 0; i < array_size; i++) {
356 spmi_ext_register_readl(led->spmi_dev->ctrl,
357 led->spmi_dev->sid,
358 led->base + regs[i],
359 &val, sizeof(val));
360 pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
361 }
362 pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
363}
364
Amy Malochef3d5a062012-08-16 19:14:11 -0700365static int qpnp_wled_set(struct qpnp_led_data *led)
366{
367 int rc, duty;
368 u8 level, val, i, num_wled_strings;
369
370 level = led->cdev.brightness;
371
372 if (level > WLED_MAX_LEVEL)
373 level = WLED_MAX_LEVEL;
374 if (level == 0) {
375 val = WLED_BOOST_OFF;
376 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
377 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
378 &val, 1);
379 if (rc) {
380 dev_err(&led->spmi_dev->dev,
381 "WLED write ctrl reg failed(%d)\n", rc);
382 return rc;
383 }
384 } else {
385 val = WLED_BOOST_ON;
386 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
387 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
388 &val, 1);
389 if (rc) {
390 dev_err(&led->spmi_dev->dev,
391 "WLED write ctrl reg failed(%d)\n", rc);
392 return rc;
393 }
394 }
395
396 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
397
398 num_wled_strings = led->wled_cfg->num_strings;
399
400 /* program brightness control registers */
401 for (i = 0; i < num_wled_strings; i++) {
402 rc = qpnp_led_masked_write(led,
403 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
404 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
405 if (rc) {
406 dev_err(&led->spmi_dev->dev,
407 "WLED set brightness MSB failed(%d)\n", rc);
408 return rc;
409 }
410 val = duty & WLED_8_BIT_MASK;
411 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
412 led->spmi_dev->sid,
413 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
414 if (rc) {
415 dev_err(&led->spmi_dev->dev,
416 "WLED set brightness LSB failed(%d)\n", rc);
417 return rc;
418 }
419 }
420
421 /* sync */
422 val = WLED_SYNC_VAL;
423 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
424 WLED_SYNC_REG(led->base), &val, 1);
425 if (rc) {
426 dev_err(&led->spmi_dev->dev,
427 "WLED set sync reg failed(%d)\n", rc);
428 return rc;
429 }
430
431 val = WLED_SYNC_RESET_VAL;
432 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
433 WLED_SYNC_REG(led->base), &val, 1);
434 if (rc) {
435 dev_err(&led->spmi_dev->dev,
436 "WLED reset sync reg failed(%d)\n", rc);
437 return rc;
438 }
439 return 0;
440}
441
Amy Maloche864a6d52012-10-03 15:58:12 -0700442static int qpnp_flash_set(struct qpnp_led_data *led)
443{
444 int rc;
445 int val = led->cdev.brightness;
446
447 led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
448 led->max_current);
449
450 led->flash_cfg->current_prgm =
451 led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
452 if (!led->flash_cfg->current_prgm)
453 led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
454
455 /* Set led current */
456 if (val > 0) {
Amy Maloche38b9aae2013-02-07 12:15:34 -0800457 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
458 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
459 if (rc) {
460 dev_err(&led->spmi_dev->dev,
461 "Enable reg write failed(%d)\n", rc);
462 return rc;
463 }
464
Amy Maloche864a6d52012-10-03 15:58:12 -0700465 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
466 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
467 if (rc) {
468 dev_err(&led->spmi_dev->dev,
469 "Current reg write failed(%d)\n", rc);
470 return rc;
471 }
472
473 rc = qpnp_led_masked_write(led, led->flash_cfg->second_addr,
474 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
475 if (rc) {
476 dev_err(&led->spmi_dev->dev,
477 "Current reg write failed(%d)\n", rc);
478 return rc;
479 }
480
481 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
482 FLASH_ENABLE_MASK,
483 FLASH_ENABLE_ALL);
484 if (rc) {
485 dev_err(&led->spmi_dev->dev,
486 "Enable reg write failed(%d)\n", rc);
487 return rc;
488 }
489 rc = qpnp_led_masked_write(led,
490 FLASH_LED_STROBE_CTRL(led->base),
491 FLASH_STROBE_MASK, FLASH_STROBE_ALL);
492
493 if (rc) {
494 dev_err(&led->spmi_dev->dev,
495 "LED %d flash write failed(%d)\n", led->id, rc);
496 return rc;
497 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800498 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
499 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
500 if (rc) {
501 dev_err(&led->spmi_dev->dev,
502 "Vreg OK reg write failed(%d)\n", rc);
503 return rc;
504 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700505 } else {
506 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
507 FLASH_ENABLE_MASK,
508 FLASH_DISABLE_ALL);
509 if (rc) {
510 dev_err(&led->spmi_dev->dev,
511 "Enable reg write failed(%d)\n", rc);
512 return rc;
513 }
514
515 rc = qpnp_led_masked_write(led,
516 FLASH_LED_STROBE_CTRL(led->base),
517 FLASH_STROBE_MASK,
518 FLASH_DISABLE_ALL);
519 if (rc) {
520 dev_err(&led->spmi_dev->dev,
521 "LED %d flash write failed(%d)\n", led->id, rc);
522 return rc;
523 }
524 }
525
Amy Malocheeea7b592012-10-03 15:59:36 -0700526 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
527
528 return 0;
529}
530
531static int qpnp_rgb_set(struct qpnp_led_data *led)
532{
533 int duty_us;
534 int rc;
535
536 if (led->cdev.brightness) {
537 if (led->rgb_cfg->mode == RGB_MODE_PWM) {
538 duty_us = (led->rgb_cfg->pwm_period_us *
539 led->cdev.brightness) / LED_FULL;
540 rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
541 led->rgb_cfg->pwm_period_us);
542 if (rc < 0) {
543 dev_err(&led->spmi_dev->dev, "Failed to " \
544 "configure pwm for new values\n");
545 return rc;
546 }
547 }
548 rc = qpnp_led_masked_write(led,
549 RGB_LED_EN_CTL(led->base),
550 led->rgb_cfg->enable, led->rgb_cfg->enable);
551 if (rc) {
552 dev_err(&led->spmi_dev->dev,
553 "Failed to write led enable reg\n");
554 return rc;
555 }
556 rc = pwm_enable(led->rgb_cfg->pwm_dev);
557 } else {
558 pwm_disable(led->rgb_cfg->pwm_dev);
559 rc = qpnp_led_masked_write(led,
560 RGB_LED_EN_CTL(led->base),
561 led->rgb_cfg->enable, RGB_LED_DISABLE);
562 if (rc) {
563 dev_err(&led->spmi_dev->dev,
564 "Failed to write led enable reg\n");
565 return rc;
566 }
567 }
568
569 qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
570
Amy Maloche864a6d52012-10-03 15:58:12 -0700571 return 0;
572}
573
Amy Malochef3d5a062012-08-16 19:14:11 -0700574static void qpnp_led_set(struct led_classdev *led_cdev,
575 enum led_brightness value)
576{
577 int rc;
578 struct qpnp_led_data *led;
579
580 led = container_of(led_cdev, struct qpnp_led_data, cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -0700581 if (value < LED_OFF || value > led->cdev.max_brightness) {
Amy Malochea5ca5552012-10-23 13:34:46 -0700582 dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
Amy Malochef3d5a062012-08-16 19:14:11 -0700583 return;
584 }
585
Amy Malochedc3e5572012-09-25 16:39:06 -0700586 spin_lock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700587 led->cdev.brightness = value;
588
589 switch (led->id) {
590 case QPNP_ID_WLED:
591 rc = qpnp_wled_set(led);
592 if (rc < 0)
Amy Malochea5ca5552012-10-23 13:34:46 -0700593 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700594 "WLED set brightness failed (%d)\n", rc);
595 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700596 case QPNP_ID_FLASH1_LED0:
597 case QPNP_ID_FLASH1_LED1:
598 rc = qpnp_flash_set(led);
599 if (rc < 0)
600 dev_err(&led->spmi_dev->dev,
601 "FLASH set brightness failed (%d)\n", rc);
602 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700603 case QPNP_ID_RGB_RED:
604 case QPNP_ID_RGB_GREEN:
605 case QPNP_ID_RGB_BLUE:
606 rc = qpnp_rgb_set(led);
607 if (rc < 0)
608 dev_err(&led->spmi_dev->dev,
609 "RGB set brightness failed (%d)\n", rc);
610 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700611 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700612 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700613 break;
614 }
Amy Malochedc3e5572012-09-25 16:39:06 -0700615 spin_unlock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700616}
617
618static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
619{
620 switch (led->id) {
621 case QPNP_ID_WLED:
622 led->cdev.max_brightness = WLED_MAX_LEVEL;
623 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700624 case QPNP_ID_FLASH1_LED0:
625 case QPNP_ID_FLASH1_LED1:
626 led->cdev.max_brightness = led->max_current;
627 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700628 case QPNP_ID_RGB_RED:
629 case QPNP_ID_RGB_GREEN:
630 case QPNP_ID_RGB_BLUE:
631 led->cdev.max_brightness = RGB_MAX_LEVEL;
632 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700633 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700634 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700635 return -EINVAL;
636 }
637
638 return 0;
639}
640
641static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
642{
643 struct qpnp_led_data *led;
644
645 led = container_of(led_cdev, struct qpnp_led_data, cdev);
646
647 return led->cdev.brightness;
648}
649
Asaf Penso55ac8472013-01-21 21:17:37 +0200650static void qpnp_led_turn_off_delayed(struct work_struct *work)
651{
652 struct delayed_work *dwork = to_delayed_work(work);
653 struct qpnp_led_data *led
654 = container_of(dwork, struct qpnp_led_data, dwork);
655
656 led->cdev.brightness = LED_OFF;
657 qpnp_led_set(&led->cdev, led->cdev.brightness);
658}
659
660static void qpnp_led_turn_off(struct qpnp_led_data *led)
661{
662 INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed);
663 schedule_delayed_work(&led->dwork,
664 msecs_to_jiffies(led->turn_off_delay_ms));
665}
666
Amy Malochef3d5a062012-08-16 19:14:11 -0700667static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
668{
669 int rc, i;
670 u8 num_wled_strings;
671
672 num_wled_strings = led->wled_cfg->num_strings;
673
674 /* verify ranges */
675 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
676 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
677 return -EINVAL;
678 }
679
680 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
681 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
682 return -EINVAL;
683 }
684
685 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
686 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
687 return -EINVAL;
688 }
689
690 if ((led->max_current > WLED_MAX_CURR)) {
691 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
692 return -EINVAL;
693 }
694
695 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
696 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
697 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
698 return -EINVAL;
699 }
700
701 /* program over voltage protection threshold */
702 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
703 WLED_OVP_VAL_MASK,
704 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
705 if (rc) {
706 dev_err(&led->spmi_dev->dev,
707 "WLED OVP reg write failed(%d)\n", rc);
708 return rc;
709 }
710
711 /* program current boost limit */
712 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
713 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
714 if (rc) {
715 dev_err(&led->spmi_dev->dev,
716 "WLED boost limit reg write failed(%d)\n", rc);
717 return rc;
718 }
719
720 /* program output feedback */
721 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
722 WLED_OP_FDBCK_MASK,
723 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
724 if (rc) {
725 dev_err(&led->spmi_dev->dev,
726 "WLED fdbck ctrl reg write failed(%d)\n", rc);
727 return rc;
728 }
729
730 /* program switch frequency */
731 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
732 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
733 if (rc) {
734 dev_err(&led->spmi_dev->dev,
735 "WLED switch freq reg write failed(%d)\n", rc);
736 return rc;
737 }
738
739 /* program current sink */
740 if (led->wled_cfg->cs_out_en) {
741 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
742 WLED_CURR_SINK_MASK,
Amy Maloche832d90a2013-01-07 10:15:29 -0800743 (((1 << led->wled_cfg->num_strings) - 1)
744 << WLED_CURR_SINK_SHFT));
Amy Malochef3d5a062012-08-16 19:14:11 -0700745 if (rc) {
746 dev_err(&led->spmi_dev->dev,
747 "WLED curr sink reg write failed(%d)\n", rc);
748 return rc;
749 }
750 }
751
752 /* program high pole capacitance */
753 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
754 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
755 if (rc) {
756 dev_err(&led->spmi_dev->dev,
757 "WLED pole cap reg write failed(%d)\n", rc);
758 return rc;
759 }
760
761 /* program modulator, current mod src and cabc */
762 for (i = 0; i < num_wled_strings; i++) {
763 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
764 WLED_NO_MASK, WLED_EN_MASK);
765 if (rc) {
766 dev_err(&led->spmi_dev->dev,
767 "WLED mod enable reg write failed(%d)\n", rc);
768 return rc;
769 }
770
771 if (led->wled_cfg->dig_mod_gen_en) {
772 rc = qpnp_led_masked_write(led,
773 WLED_MOD_EN_REG(led->base, i),
774 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
775 if (rc) {
776 dev_err(&led->spmi_dev->dev,
777 "WLED dig mod en reg write failed(%d)\n", rc);
778 }
779 }
780
781 rc = qpnp_led_masked_write(led,
782 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
783 led->max_current);
784 if (rc) {
785 dev_err(&led->spmi_dev->dev,
786 "WLED max current reg write failed(%d)\n", rc);
787 return rc;
788 }
789
790 }
791
792 /* dump wled registers */
Amy Malochea5ca5552012-10-23 13:34:46 -0700793 qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
Amy Malochef3d5a062012-08-16 19:14:11 -0700794
795 return 0;
796}
797
Amy Maloche864a6d52012-10-03 15:58:12 -0700798static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
799{
800 int rc;
801
802 rc = qpnp_led_masked_write(led,
803 FLASH_LED_STROBE_CTRL(led->base),
804 FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
805 if (rc) {
806 dev_err(&led->spmi_dev->dev,
807 "LED %d flash write failed(%d)\n", led->id, rc);
808 return rc;
809 }
810 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
811 FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
812 if (rc) {
813 dev_err(&led->spmi_dev->dev,
814 "Enable reg write failed(%d)\n", rc);
815 return rc;
816 }
817
818 /* Set flash safety timer */
819 rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
820 FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
821 if (rc) {
822 dev_err(&led->spmi_dev->dev,
823 "Safety timer reg write failed(%d)\n", rc);
824 return rc;
825 }
826
827 /* Set max current */
828 rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
829 FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
830 if (rc) {
831 dev_err(&led->spmi_dev->dev,
832 "Max current reg write failed(%d)\n", rc);
833 return rc;
834 }
835 /* Set clamp current */
836 rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
837 FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
838 if (rc) {
839 dev_err(&led->spmi_dev->dev,
840 "Clamp current reg write failed(%d)\n", rc);
841 return rc;
842 }
843
844 /* Set timer control - safety or watchdog */
845 if (led->flash_cfg->safety_timer)
846 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
847 FLASH_TMR_MASK, FLASH_TMR_SAFETY);
848 else
849 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
850 FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
851 if (rc) {
852 dev_err(&led->spmi_dev->dev,
853 "LED timer ctrl reg write failed(%d)\n", rc);
854 return rc;
855 }
856 /* Set headroom */
857 rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
858 FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
859 if (rc) {
860 dev_err(&led->spmi_dev->dev,
861 "Headroom reg write failed(%d)\n", rc);
862 return rc;
863 }
864
865 /* Set mask enable */
866 rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
867 FLASH_MASK_REG_MASK, FLASH_MASK_1);
868 if (rc) {
869 dev_err(&led->spmi_dev->dev,
870 "Mask enable reg write failed(%d)\n", rc);
871 return rc;
872 }
873
874 /* Set startup delay */
875 rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
876 FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
877 if (rc) {
878 dev_err(&led->spmi_dev->dev,
879 "Startup delay reg write failed(%d)\n", rc);
880 return rc;
881 }
882
883 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
884 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
885 if (rc) {
886 dev_err(&led->spmi_dev->dev,
887 "Vreg OK reg write failed(%d)\n", rc);
888 return rc;
889 }
890
891 /* Set led current and enable module */
892 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
893 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
894 if (rc) {
895 dev_err(&led->spmi_dev->dev,
896 "Current reg write failed(%d)\n", rc);
897 return rc;
898 }
899
900 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
Amy Maloche38b9aae2013-02-07 12:15:34 -0800901 FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
Amy Maloche864a6d52012-10-03 15:58:12 -0700902 if (rc) {
903 dev_err(&led->spmi_dev->dev,
904 "Enable reg write failed(%d)\n", rc);
905 return rc;
906 }
907 /* dump flash registers */
908 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
909
910 return 0;
911}
912
Amy Malocheeea7b592012-10-03 15:59:36 -0700913static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
914{
915 int rc, start_idx, idx_len;
916
917 rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
918 RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
919 if (rc) {
920 dev_err(&led->spmi_dev->dev,
921 "Failed to write led source select register\n");
922 return rc;
923 }
924
925 if (led->rgb_cfg->pwm_channel != -1) {
926 led->rgb_cfg->pwm_dev =
927 pwm_request(led->rgb_cfg->pwm_channel,
928 led->cdev.name);
929
930 if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
931 dev_err(&led->spmi_dev->dev,
932 "could not acquire PWM Channel %d, " \
933 "error %ld\n",
934 led->rgb_cfg->pwm_channel,
935 PTR_ERR(led->rgb_cfg->pwm_dev));
936 led->rgb_cfg->pwm_dev = NULL;
937 return -ENODEV;
938 }
939
940 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
941 start_idx =
942 led->rgb_cfg->duty_cycles->start_idx;
943 idx_len =
944 led->rgb_cfg->duty_cycles->num_duty_pcts;
945
946 if (idx_len >= PWM_LUT_MAX_SIZE &&
947 start_idx) {
948 dev_err(&led->spmi_dev->dev,
949 "Wrong LUT size or index\n");
950 return -EINVAL;
951 }
952 if ((start_idx + idx_len) >
953 PWM_LUT_MAX_SIZE) {
954 dev_err(&led->spmi_dev->dev,
955 "Exceed LUT limit\n");
956 return -EINVAL;
957 }
958 rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
959 led->rgb_cfg->pwm_period_us,
960 led->rgb_cfg->duty_cycles->duty_pcts,
961 led->rgb_cfg->lut_params);
962 if (rc < 0) {
963 dev_err(&led->spmi_dev->dev, "Failed to " \
964 "configure pwm LUT\n");
965 return rc;
966 }
967 }
968 } else {
969 dev_err(&led->spmi_dev->dev,
970 "Invalid PWM channel\n");
971 return -EINVAL;
972 }
973
974 /* Initialize led for use in auto trickle charging mode */
975 rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
976 led->rgb_cfg->enable, led->rgb_cfg->enable);
977
978 return 0;
979}
980
Amy Malochef3d5a062012-08-16 19:14:11 -0700981static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
982{
983 int rc;
984
985 switch (led->id) {
986 case QPNP_ID_WLED:
987 rc = qpnp_wled_init(led);
988 if (rc)
Amy Malochea5ca5552012-10-23 13:34:46 -0700989 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700990 "WLED initialize failed(%d)\n", rc);
991 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700992 case QPNP_ID_FLASH1_LED0:
993 case QPNP_ID_FLASH1_LED1:
994 rc = qpnp_flash_init(led);
995 if (rc)
996 dev_err(&led->spmi_dev->dev,
997 "FLASH initialize failed(%d)\n", rc);
998 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700999 case QPNP_ID_RGB_RED:
1000 case QPNP_ID_RGB_GREEN:
1001 case QPNP_ID_RGB_BLUE:
1002 rc = qpnp_rgb_init(led);
1003 if (rc)
1004 dev_err(&led->spmi_dev->dev,
1005 "RGB initialize failed(%d)\n", rc);
1006 break;
Amy Malochef3d5a062012-08-16 19:14:11 -07001007 default:
Amy Malochea5ca5552012-10-23 13:34:46 -07001008 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malocheeea7b592012-10-03 15:59:36 -07001009 return -EINVAL;
Amy Malochef3d5a062012-08-16 19:14:11 -07001010 }
1011
Amy Malocheeea7b592012-10-03 15:59:36 -07001012 return 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001013}
1014
Amy Malochea5ca5552012-10-23 13:34:46 -07001015static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
1016 struct device_node *node)
1017{
1018 int rc;
Asaf Penso55ac8472013-01-21 21:17:37 +02001019 u32 val;
Amy Malochea5ca5552012-10-23 13:34:46 -07001020 const char *temp_string;
1021
1022 led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
1023 rc = of_property_read_string(node, "linux,default-trigger",
1024 &temp_string);
1025 if (!rc)
1026 led->cdev.default_trigger = temp_string;
1027 else if (rc != -EINVAL)
1028 return rc;
1029
1030 led->default_on = false;
1031 rc = of_property_read_string(node, "qcom,default-state",
1032 &temp_string);
1033 if (!rc) {
1034 if (strncmp(temp_string, "on", sizeof("on")) == 0)
1035 led->default_on = true;
1036 } else if (rc != -EINVAL)
1037 return rc;
1038
Asaf Penso55ac8472013-01-21 21:17:37 +02001039 led->turn_off_delay_ms = 0;
1040 rc = of_property_read_u32(node, "qcom,turn-off-delay-ms", &val);
1041 if (!rc)
1042 led->turn_off_delay_ms = val;
1043 else if (rc != -EINVAL)
1044 return rc;
1045
Amy Malochea5ca5552012-10-23 13:34:46 -07001046 return 0;
1047}
1048
Amy Malochef3d5a062012-08-16 19:14:11 -07001049/*
1050 * Handlers for alternative sources of platform_data
1051 */
1052static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
1053 struct device_node *node)
1054{
1055 u32 val;
1056 int rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001057
1058 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
1059 sizeof(struct wled_config_data), GFP_KERNEL);
1060 if (!led->wled_cfg) {
1061 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1062 return -ENOMEM;
1063 }
1064
Amy Malochef3d5a062012-08-16 19:14:11 -07001065 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
1066 rc = of_property_read_u32(node, "qcom,num-strings", &val);
1067 if (!rc)
1068 led->wled_cfg->num_strings = (u8) val;
1069 else if (rc != -EINVAL)
1070 return rc;
1071
1072 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
1073 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
1074 if (!rc)
1075 led->wled_cfg->ovp_val = (u8) val;
1076 else if (rc != -EINVAL)
1077 return rc;
1078
1079 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
1080 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
1081 if (!rc)
1082 led->wled_cfg->boost_curr_lim = (u8) val;
1083 else if (rc != -EINVAL)
1084 return rc;
1085
1086 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
1087 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
1088 if (!rc)
1089 led->wled_cfg->cp_select = (u8) val;
1090 else if (rc != -EINVAL)
1091 return rc;
1092
1093 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
1094 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
1095 if (!rc)
1096 led->wled_cfg->ctrl_delay_us = (u8) val;
1097 else if (rc != -EINVAL)
1098 return rc;
1099
1100 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
1101 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
1102 if (!rc)
1103 led->wled_cfg->switch_freq = (u8) val;
1104 else if (rc != -EINVAL)
1105 return rc;
1106
1107 led->wled_cfg->dig_mod_gen_en =
1108 of_property_read_bool(node, "qcom,dig-mod-gen-en");
1109
1110 led->wled_cfg->cs_out_en =
1111 of_property_read_bool(node, "qcom,cs-out-en");
1112
1113 led->wled_cfg->op_fdbck =
1114 of_property_read_bool(node, "qcom,op-fdbck");
1115
1116 return 0;
1117}
1118
Amy Maloche864a6d52012-10-03 15:58:12 -07001119static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
1120 struct device_node *node)
1121{
1122 int rc;
1123 u32 val;
1124
1125 led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
1126 sizeof(struct flash_config_data), GFP_KERNEL);
1127 if (!led->flash_cfg) {
1128 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1129 return -ENOMEM;
1130 }
1131
1132 if (led->id == QPNP_ID_FLASH1_LED0) {
1133 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1134 led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
1135 led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
1136 led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
1137 } else if (led->id == QPNP_ID_FLASH1_LED1) {
1138 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1139 led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
1140 led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
1141 led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
1142 } else {
1143 dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
1144 return -EINVAL;
1145 }
1146
1147 rc = of_property_read_u32(node, "qcom,current", &val);
1148 if (!rc)
1149 led->flash_cfg->current_prgm = (val *
1150 FLASH_MAX_LEVEL / led->max_current);
1151 else
1152 return -EINVAL;
1153
1154 rc = of_property_read_u32(node, "qcom,headroom", &val);
1155 if (!rc)
1156 led->flash_cfg->headroom = (u8) val;
1157 else if (rc == -EINVAL)
1158 led->flash_cfg->headroom = HEADROOM_300mV;
1159 else
1160 return rc;
1161
1162 rc = of_property_read_u32(node, "qcom,duration", &val);
1163 if (!rc)
1164 led->flash_cfg->duration = (((u8) val) - 10) / 10;
1165 else if (rc == -EINVAL)
1166 led->flash_cfg->duration = FLASH_DURATION_200ms;
1167 else
1168 return rc;
1169
1170 rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
1171 if (!rc)
1172 led->flash_cfg->clamp_curr = (val *
1173 FLASH_MAX_LEVEL / led->max_current);
1174 else if (rc == -EINVAL)
1175 led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
1176 else
1177 return rc;
1178
1179 rc = of_property_read_u32(node, "qcom,startup-dly", &val);
1180 if (!rc)
1181 led->flash_cfg->startup_dly = (u8) val;
1182 else if (rc == -EINVAL)
1183 led->flash_cfg->startup_dly = DELAY_32us;
1184 else
1185 return rc;
1186
1187 led->flash_cfg->safety_timer =
1188 of_property_read_bool(node, "qcom,safety-timer");
1189
1190 return 0;
1191}
1192
Amy Malocheeea7b592012-10-03 15:59:36 -07001193static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
1194 struct device_node *node)
1195{
1196 struct property *prop;
1197 int rc, i;
1198 u32 val;
1199 u8 *temp_cfg;
1200
1201 led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
1202 sizeof(struct rgb_config_data), GFP_KERNEL);
1203 if (!led->rgb_cfg) {
1204 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1205 return -ENOMEM;
1206 }
1207
1208 if (led->id == QPNP_ID_RGB_RED)
1209 led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
1210 else if (led->id == QPNP_ID_RGB_GREEN)
1211 led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
1212 else if (led->id == QPNP_ID_RGB_BLUE)
1213 led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
1214 else
1215 return -EINVAL;
1216
1217 rc = of_property_read_u32(node, "qcom,mode", &val);
1218 if (!rc)
1219 led->rgb_cfg->mode = (u8) val;
1220 else
1221 return rc;
1222
1223 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1224 if (!rc)
1225 led->rgb_cfg->pwm_channel = (u8) val;
1226 else
1227 return rc;
1228
1229 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1230 if (!rc)
1231 led->rgb_cfg->pwm_period_us = val;
1232 else
1233 return rc;
1234
1235 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1236 led->rgb_cfg->duty_cycles =
1237 devm_kzalloc(&led->spmi_dev->dev,
1238 sizeof(struct pwm_duty_cycles), GFP_KERNEL);
1239 if (!led->rgb_cfg->duty_cycles) {
1240 dev_err(&led->spmi_dev->dev,
1241 "Unable to allocate memory\n");
1242 return -ENOMEM;
1243 }
1244
1245 rc = of_property_read_u32(node, "qcom,duty-ms", &val);
1246 if (!rc)
1247 led->rgb_cfg->duty_cycles->duty_ms = (u8) val;
1248 else
1249 return rc;
1250
1251 prop = of_find_property(node, "qcom,duty-pcts",
1252 &led->rgb_cfg->duty_cycles->num_duty_pcts);
1253 if (!prop) {
1254 dev_err(&led->spmi_dev->dev, "Looking up property " \
1255 "node qcom,duty-pcts failed\n");
1256 return -ENODEV;
1257 } else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
1258 dev_err(&led->spmi_dev->dev, "Invalid length of " \
1259 "duty pcts\n");
1260 return -EINVAL;
1261 }
1262
1263 led->rgb_cfg->duty_cycles->duty_pcts =
1264 devm_kzalloc(&led->spmi_dev->dev,
1265 sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
1266 GFP_KERNEL);
1267 if (!led->rgb_cfg->duty_cycles->duty_pcts) {
1268 dev_err(&led->spmi_dev->dev,
1269 "Unable to allocate memory\n");
1270 return -ENOMEM;
1271 }
1272
1273 temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1274 led->rgb_cfg->duty_cycles->num_duty_pcts *
1275 sizeof(u8), GFP_KERNEL);
1276 if (!temp_cfg) {
1277 dev_err(&led->spmi_dev->dev, "Failed to allocate " \
1278 "memory for duty pcts\n");
1279 return -ENOMEM;
1280 }
1281
1282 memcpy(temp_cfg, prop->value,
1283 led->rgb_cfg->duty_cycles->num_duty_pcts);
1284
1285 for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
1286 led->rgb_cfg->duty_cycles->duty_pcts[i] =
1287 (int) temp_cfg[i];
1288
1289 rc = of_property_read_u32(node, "qcom,start-idx", &val);
1290 if (!rc) {
1291 led->rgb_cfg->lut_params.start_idx = (u8) val;
1292 led->rgb_cfg->duty_cycles->start_idx = (u8) val;
1293 } else
1294 return rc;
1295
1296 led->rgb_cfg->lut_params.idx_len =
1297 led->rgb_cfg->duty_cycles->num_duty_pcts;
1298 led->rgb_cfg->lut_params.lut_pause_hi = 0;
1299 led->rgb_cfg->lut_params.lut_pause_lo = 0;
1300 led->rgb_cfg->lut_params.ramp_step_ms = 255;
1301 led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
1302 }
1303
1304 return 0;
1305}
1306
Amy Malochef3d5a062012-08-16 19:14:11 -07001307static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
1308{
Amy Malochef9490c62012-11-27 19:26:04 -08001309 struct qpnp_led_data *led, *led_array;
Amy Malochef3d5a062012-08-16 19:14:11 -07001310 struct resource *led_resource;
Amy Malochea5ca5552012-10-23 13:34:46 -07001311 struct device_node *node, *temp;
Amy Malochef9490c62012-11-27 19:26:04 -08001312 int rc, i, num_leds = 0, parsed_leds = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001313 const char *led_label;
1314
Amy Malochea5ca5552012-10-23 13:34:46 -07001315 node = spmi->dev.of_node;
1316 if (node == NULL)
1317 return -ENODEV;
1318
1319 temp = NULL;
1320 while ((temp = of_get_next_child(node, temp)))
1321 num_leds++;
1322
Amy Malochef9490c62012-11-27 19:26:04 -08001323 if (!num_leds)
1324 return -ECHILD;
1325
1326 led_array = devm_kzalloc(&spmi->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001327 (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
Amy Malochef9490c62012-11-27 19:26:04 -08001328 if (!led_array) {
Amy Malochef3d5a062012-08-16 19:14:11 -07001329 dev_err(&spmi->dev, "Unable to allocate memory\n");
1330 return -ENOMEM;
1331 }
1332
Amy Malochea5ca5552012-10-23 13:34:46 -07001333 for_each_child_of_node(node, temp) {
Amy Malochef9490c62012-11-27 19:26:04 -08001334 led = &led_array[parsed_leds];
1335 led->num_leds = num_leds;
Amy Malochea5ca5552012-10-23 13:34:46 -07001336 led->spmi_dev = spmi;
Amy Malochef3d5a062012-08-16 19:14:11 -07001337
Amy Malochea5ca5552012-10-23 13:34:46 -07001338 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
1339 if (!led_resource) {
1340 dev_err(&spmi->dev, "Unable to get LED base address\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001341 rc = -ENXIO;
1342 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001343 }
1344 led->base = led_resource->start;
Amy Malochef3d5a062012-08-16 19:14:11 -07001345
Amy Malochea5ca5552012-10-23 13:34:46 -07001346 rc = of_property_read_string(temp, "label", &led_label);
Amy Malochef3d5a062012-08-16 19:14:11 -07001347 if (rc < 0) {
1348 dev_err(&led->spmi_dev->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001349 "Failure reading label, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001350 goto fail_id_check;
Amy Malochef3d5a062012-08-16 19:14:11 -07001351 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001352
1353 rc = of_property_read_string(temp, "linux,name",
1354 &led->cdev.name);
1355 if (rc < 0) {
1356 dev_err(&led->spmi_dev->dev,
1357 "Failure reading led name, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001358 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001359 }
1360
1361 rc = of_property_read_u32(temp, "qcom,max-current",
1362 &led->max_current);
1363 if (rc < 0) {
1364 dev_err(&led->spmi_dev->dev,
1365 "Failure reading max_current, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001366 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001367 }
1368
1369 rc = of_property_read_u32(temp, "qcom,id", &led->id);
1370 if (rc < 0) {
1371 dev_err(&led->spmi_dev->dev,
1372 "Failure reading led id, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001373 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001374 }
1375
1376 rc = qpnp_get_common_configs(led, temp);
1377 if (rc) {
1378 dev_err(&led->spmi_dev->dev,
1379 "Failure reading common led configuration," \
1380 " rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001381 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001382 }
1383
1384 led->cdev.brightness_set = qpnp_led_set;
1385 led->cdev.brightness_get = qpnp_led_get;
1386
1387 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
1388 rc = qpnp_get_config_wled(led, temp);
1389 if (rc < 0) {
1390 dev_err(&led->spmi_dev->dev,
1391 "Unable to read wled config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001392 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001393 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001394 } else if (strncmp(led_label, "flash", sizeof("flash"))
1395 == 0) {
1396 rc = qpnp_get_config_flash(led, temp);
1397 if (rc < 0) {
1398 dev_err(&led->spmi_dev->dev,
1399 "Unable to read flash config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001400 goto fail_id_check;
Amy Maloche864a6d52012-10-03 15:58:12 -07001401 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001402 } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
1403 rc = qpnp_get_config_rgb(led, temp);
1404 if (rc < 0) {
1405 dev_err(&led->spmi_dev->dev,
1406 "Unable to read rgb config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001407 goto fail_id_check;
Amy Malocheeea7b592012-10-03 15:59:36 -07001408 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001409 } else {
1410 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001411 rc = -EINVAL;
1412 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001413 }
1414
1415 spin_lock_init(&led->lock);
1416
1417 rc = qpnp_led_initialize(led);
1418 if (rc < 0)
1419 goto fail_id_check;
1420
1421 rc = qpnp_led_set_max_brightness(led);
1422 if (rc < 0)
1423 goto fail_id_check;
1424
1425 rc = led_classdev_register(&spmi->dev, &led->cdev);
1426 if (rc) {
1427 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
1428 led->id, rc);
1429 goto fail_id_check;
1430 }
1431 /* configure default state */
Asaf Penso55ac8472013-01-21 21:17:37 +02001432 if (led->default_on) {
Amy Malochea5ca5552012-10-23 13:34:46 -07001433 led->cdev.brightness = led->cdev.max_brightness;
Asaf Penso55ac8472013-01-21 21:17:37 +02001434 if (led->turn_off_delay_ms > 0)
1435 qpnp_led_turn_off(led);
1436 } else
Amy Malochea5ca5552012-10-23 13:34:46 -07001437 led->cdev.brightness = LED_OFF;
1438
1439 qpnp_led_set(&led->cdev, led->cdev.brightness);
Amy Malochef9490c62012-11-27 19:26:04 -08001440
1441 parsed_leds++;
Amy Malochef3d5a062012-08-16 19:14:11 -07001442 }
Amy Malochef9490c62012-11-27 19:26:04 -08001443 dev_set_drvdata(&spmi->dev, led_array);
Amy Malochef3d5a062012-08-16 19:14:11 -07001444 return 0;
1445
1446fail_id_check:
Amy Malochef9490c62012-11-27 19:26:04 -08001447 for (i = 0; i < parsed_leds; i++)
1448 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001449 return rc;
1450}
1451
1452static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
1453{
Amy Malochef9490c62012-11-27 19:26:04 -08001454 struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
1455 int i, parsed_leds = led_array->num_leds;
Amy Malochef3d5a062012-08-16 19:14:11 -07001456
Amy Malochef9490c62012-11-27 19:26:04 -08001457 for (i = 0; i < parsed_leds; i++)
1458 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001459
1460 return 0;
1461}
1462static struct of_device_id spmi_match_table[] = {
1463 { .compatible = "qcom,leds-qpnp",
1464 }
1465};
1466
1467static struct spmi_driver qpnp_leds_driver = {
1468 .driver = {
1469 .name = "qcom,leds-qpnp",
1470 .of_match_table = spmi_match_table,
1471 },
1472 .probe = qpnp_leds_probe,
1473 .remove = __devexit_p(qpnp_leds_remove),
1474};
1475
1476static int __init qpnp_led_init(void)
1477{
1478 return spmi_driver_register(&qpnp_leds_driver);
1479}
1480module_init(qpnp_led_init);
1481
1482static void __exit qpnp_led_exit(void)
1483{
1484 spmi_driver_unregister(&qpnp_leds_driver);
1485}
1486module_exit(qpnp_led_exit);
1487
1488MODULE_DESCRIPTION("QPNP LEDs driver");
1489MODULE_LICENSE("GPL v2");
1490MODULE_ALIAS("leds:leds-qpnp");
Amy Maloche864a6d52012-10-03 15:58:12 -07001491