blob: d70b670fe93c359c222c9fd50cb2ecfe47638d00 [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)
Amy Maloched44516e2013-02-14 17:36:34 -080030#define WLED_MOD_SRC_SEL_REG(base, n) (WLED_FULL_SCALE_REG(base, n) + 0x01)
Amy Malochef3d5a062012-08-16 19:14:11 -070031
32/* wled control registers */
33#define WLED_BRIGHTNESS_CNTL_LSB(base, n) (base + 0x40 + 2*n)
34#define WLED_BRIGHTNESS_CNTL_MSB(base, n) (base + 0x41 + 2*n)
35#define WLED_MOD_CTRL_REG(base) (base + 0x46)
36#define WLED_SYNC_REG(base) (base + 0x47)
37#define WLED_FDBCK_CTRL_REG(base) (base + 0x48)
38#define WLED_SWITCHING_FREQ_REG(base) (base + 0x4C)
39#define WLED_OVP_CFG_REG(base) (base + 0x4D)
40#define WLED_BOOST_LIMIT_REG(base) (base + 0x4E)
41#define WLED_CURR_SINK_REG(base) (base + 0x4F)
42#define WLED_HIGH_POLE_CAP_REG(base) (base + 0x58)
43#define WLED_CURR_SINK_MASK 0xE0
44#define WLED_CURR_SINK_SHFT 0x05
45#define WLED_SWITCH_FREQ_MASK 0x02
46#define WLED_OVP_VAL_MASK 0x03
47#define WLED_OVP_VAL_BIT_SHFT 0x00
48#define WLED_BOOST_LIMIT_MASK 0x07
49#define WLED_BOOST_LIMIT_BIT_SHFT 0x00
50#define WLED_BOOST_ON 0x80
51#define WLED_BOOST_OFF 0x00
52#define WLED_EN_MASK 0x80
53#define WLED_NO_MASK 0x00
54#define WLED_CP_SELECT_MAX 0x03
55#define WLED_CP_SELECT_MASK 0x02
56#define WLED_USE_EXT_GEN_MOD_SRC 0x01
57#define WLED_CTL_DLY_STEP 200
58#define WLED_CTL_DLY_MAX 1400
59#define WLED_MAX_CURR 25
60#define WLED_MSB_MASK 0x0F
61#define WLED_MAX_CURR_MASK 0x19
62#define WLED_OP_FDBCK_MASK 0x07
63#define WLED_OP_FDBCK_BIT_SHFT 0x00
Amy Malochebd687672013-03-18 11:23:45 -070064#define WLED_OP_FDBCK_DEFAULT 0x00
Amy Malochef3d5a062012-08-16 19:14:11 -070065
Amy Maloched55fdb82013-02-26 18:11:57 -080066#define WLED_MAX_LEVEL 4095
Amy Malochef3d5a062012-08-16 19:14:11 -070067#define WLED_8_BIT_MASK 0xFF
68#define WLED_4_BIT_MASK 0x0F
69#define WLED_8_BIT_SHFT 0x08
70#define WLED_MAX_DUTY_CYCLE 0xFFF
71
72#define WLED_SYNC_VAL 0x07
73#define WLED_SYNC_RESET_VAL 0x00
74
Amy Malochef3d5a062012-08-16 19:14:11 -070075#define WLED_DEFAULT_STRINGS 0x01
76#define WLED_DEFAULT_OVP_VAL 0x02
77#define WLED_BOOST_LIM_DEFAULT 0x03
78#define WLED_CP_SEL_DEFAULT 0x00
79#define WLED_CTRL_DLY_DEFAULT 0x00
80#define WLED_SWITCH_FREQ_DEFAULT 0x02
81
Amy Maloche864a6d52012-10-03 15:58:12 -070082#define FLASH_SAFETY_TIMER(base) (base + 0x40)
83#define FLASH_MAX_CURR(base) (base + 0x41)
84#define FLASH_LED_0_CURR(base) (base + 0x42)
85#define FLASH_LED_1_CURR(base) (base + 0x43)
86#define FLASH_CLAMP_CURR(base) (base + 0x44)
87#define FLASH_LED_TMR_CTRL(base) (base + 0x48)
Amy Maloched44516e2013-02-14 17:36:34 -080088#define FLASH_HEADROOM(base) (base + 0x4A)
Amy Maloche864a6d52012-10-03 15:58:12 -070089#define FLASH_STARTUP_DELAY(base) (base + 0x4B)
90#define FLASH_MASK_ENABLE(base) (base + 0x4C)
91#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
92#define FLASH_ENABLE_CONTROL(base) (base + 0x46)
93#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
94
95#define FLASH_MAX_LEVEL 0x4F
96#define FLASH_NO_MASK 0x00
97
98#define FLASH_MASK_1 0x20
99#define FLASH_MASK_REG_MASK 0xE0
100#define FLASH_HEADROOM_MASK 0x03
101#define FLASH_SAFETY_TIMER_MASK 0x7F
102#define FLASH_CURRENT_MASK 0xFF
103#define FLASH_TMR_MASK 0x03
104#define FLASH_TMR_WATCHDOG 0x03
105#define FLASH_TMR_SAFETY 0x00
106
107#define FLASH_HW_VREG_OK 0x80
108#define FLASH_VREG_MASK 0xC0
109
110#define FLASH_STARTUP_DLY_MASK 0x02
111
112#define FLASH_ENABLE_ALL 0xE0
113#define FLASH_ENABLE_MODULE 0x80
114#define FLASH_ENABLE_MODULE_MASK 0x80
115#define FLASH_DISABLE_ALL 0x00
Amy Maloche38b9aae2013-02-07 12:15:34 -0800116#define FLASH_ENABLE_MASK 0xE0
Amy Maloche864a6d52012-10-03 15:58:12 -0700117#define FLASH_ENABLE_LED_0 0x40
118#define FLASH_ENABLE_LED_1 0x20
119#define FLASH_INIT_MASK 0xE0
120
121#define FLASH_STROBE_ALL 0xC0
122#define FLASH_STROBE_MASK 0xC0
123#define FLASH_LED_0_OUTPUT 0x80
124#define FLASH_LED_1_OUTPUT 0x40
125
126#define FLASH_CURRENT_PRGM_MIN 1
127#define FLASH_CURRENT_PRGM_SHIFT 1
128
129#define FLASH_DURATION_200ms 0x13
130#define FLASH_CLAMP_200mA 0x0F
131
Amy Malochea5ca5552012-10-23 13:34:46 -0700132#define LED_TRIGGER_DEFAULT "none"
133
Amy Malocheeea7b592012-10-03 15:59:36 -0700134#define RGB_LED_SRC_SEL(base) (base + 0x45)
135#define RGB_LED_EN_CTL(base) (base + 0x46)
136#define RGB_LED_ATC_CTL(base) (base + 0x47)
137
138#define RGB_MAX_LEVEL LED_FULL
139#define RGB_LED_ENABLE_RED 0x80
140#define RGB_LED_ENABLE_GREEN 0x40
141#define RGB_LED_ENABLE_BLUE 0x20
142#define RGB_LED_SOURCE_VPH_PWR 0x01
143#define RGB_LED_ENABLE_MASK 0xE0
144#define RGB_LED_SRC_MASK 0x03
145#define QPNP_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
146#define PWM_LUT_MAX_SIZE 63
147#define RGB_LED_DISABLE 0x00
148
Amy Malochef3d5a062012-08-16 19:14:11 -0700149/**
150 * enum qpnp_leds - QPNP supported led ids
151 * @QPNP_ID_WLED - White led backlight
152 */
153enum qpnp_leds {
Amy Maloche864a6d52012-10-03 15:58:12 -0700154 QPNP_ID_WLED = 0,
155 QPNP_ID_FLASH1_LED0,
156 QPNP_ID_FLASH1_LED1,
Amy Malocheeea7b592012-10-03 15:59:36 -0700157 QPNP_ID_RGB_RED,
158 QPNP_ID_RGB_GREEN,
159 QPNP_ID_RGB_BLUE,
Amy Maloche864a6d52012-10-03 15:58:12 -0700160 QPNP_ID_MAX,
Amy Malochef3d5a062012-08-16 19:14:11 -0700161};
162
163/* current boost limit */
164enum wled_current_boost_limit {
165 WLED_CURR_LIMIT_105mA,
166 WLED_CURR_LIMIT_385mA,
167 WLED_CURR_LIMIT_525mA,
168 WLED_CURR_LIMIT_805mA,
169 WLED_CURR_LIMIT_980mA,
170 WLED_CURR_LIMIT_1260mA,
171 WLED_CURR_LIMIT_1400mA,
172 WLED_CURR_LIMIT_1680mA,
173};
174
175/* over voltage protection threshold */
176enum wled_ovp_threshold {
177 WLED_OVP_35V,
178 WLED_OVP_32V,
179 WLED_OVP_29V,
180 WLED_OVP_37V,
181};
182
183/* switch frquency */
184enum wled_switch_freq {
185 WLED_800kHz = 0,
186 WLED_960kHz,
187 WLED_1600kHz,
188 WLED_3200kHz,
189};
190
Amy Maloche864a6d52012-10-03 15:58:12 -0700191enum flash_headroom {
192 HEADROOM_250mV = 0,
193 HEADROOM_300mV,
194 HEADROOM_400mV,
195 HEADROOM_500mV,
196};
197
198enum flash_startup_dly {
199 DELAY_10us = 0,
200 DELAY_32us,
201 DELAY_64us,
202 DELAY_128us,
203};
204
Amy Malocheeea7b592012-10-03 15:59:36 -0700205enum rgb_mode {
206 RGB_MODE_PWM = 0,
207 RGB_MODE_LPG,
208};
209
Amy Malochef3d5a062012-08-16 19:14:11 -0700210static u8 wled_debug_regs[] = {
211 /* common registers */
212 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
213 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
214 /* LED1 */
215 0x60, 0x61, 0x62, 0x63, 0x66,
Amy Malochea5ca5552012-10-23 13:34:46 -0700216 /* LED2 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700217 0x70, 0x71, 0x72, 0x73, 0x76,
Amy Malochea5ca5552012-10-23 13:34:46 -0700218 /* LED3 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700219 0x80, 0x81, 0x82, 0x83, 0x86,
220};
221
Amy Maloche864a6d52012-10-03 15:58:12 -0700222static u8 flash_debug_regs[] = {
223 0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
224 0x4f, 0x46, 0x47,
225};
226
Amy Malocheeea7b592012-10-03 15:59:36 -0700227static u8 rgb_pwm_debug_regs[] = {
228 0x45, 0x46, 0x47,
229};
Amy Malochef3d5a062012-08-16 19:14:11 -0700230/**
231 * wled_config_data - wled configuration data
232 * @num_strings - number of wled strings supported
233 * @ovp_val - over voltage protection threshold
234 * @boost_curr_lim - boot current limit
235 * @cp_select - high pole capacitance
236 * @ctrl_delay_us - delay in activation of led
237 * @dig_mod_gen_en - digital module generator
238 * @cs_out_en - current sink output enable
239 * @op_fdbck - selection of output as feedback for the boost
240 */
241struct wled_config_data {
242 u8 num_strings;
243 u8 ovp_val;
244 u8 boost_curr_lim;
245 u8 cp_select;
246 u8 ctrl_delay_us;
247 u8 switch_freq;
Amy Malochebd687672013-03-18 11:23:45 -0700248 u8 op_fdbck;
Amy Malochef3d5a062012-08-16 19:14:11 -0700249 bool dig_mod_gen_en;
250 bool cs_out_en;
Amy Malochef3d5a062012-08-16 19:14:11 -0700251};
252
253/**
Amy Maloche864a6d52012-10-03 15:58:12 -0700254 * flash_config_data - flash configuration data
255 * @current_prgm - current to be programmed, scaled by max level
256 * @clamp_curr - clamp current to use
257 * @headroom - headroom value to use
258 * @duration - duration of the flash
259 * @enable_module - enable address for particular flash
260 * @trigger_flash - trigger flash
261 * @startup_dly - startup delay for flash
262 * @current_addr - address to write for current
263 * @second_addr - address of secondary flash to be written
264 * @safety_timer - enable safety timer or watchdog timer
265 */
266struct flash_config_data {
267 u8 current_prgm;
268 u8 clamp_curr;
269 u8 headroom;
270 u8 duration;
271 u8 enable_module;
272 u8 trigger_flash;
273 u8 startup_dly;
274 u16 current_addr;
275 u16 second_addr;
276 bool safety_timer;
277};
278
279/**
Amy Malocheeea7b592012-10-03 15:59:36 -0700280 * rgb_config_data - rgb configuration data
281 * @lut_params - lut parameters to be used by pwm driver
282 * @pwm_device - pwm device
283 * @pwm_channel - pwm channel to be configured for led
284 * @pwm_period_us - period for pwm, in us
285 * @mode - mode the led operates in
286 */
287struct rgb_config_data {
288 struct lut_params lut_params;
289 struct pwm_device *pwm_dev;
290 int pwm_channel;
291 u32 pwm_period_us;
292 struct pwm_duty_cycles *duty_cycles;
293 u8 mode;
294 u8 enable;
295};
296
297/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700298 * struct qpnp_led_data - internal led data structure
299 * @led_classdev - led class device
Asaf Penso55ac8472013-01-21 21:17:37 +0200300 * @delayed_work - delayed work for turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700301 * @id - led index
302 * @base_reg - base register given in device tree
303 * @lock - to protect the transactions
304 * @reg - cached value of led register
Amy Malochea5ca5552012-10-23 13:34:46 -0700305 * @num_leds - number of leds in the module
Amy Malochef3d5a062012-08-16 19:14:11 -0700306 * @max_current - maximum current supported by LED
307 * @default_on - true: default state max, false, default state 0
Asaf Penso55ac8472013-01-21 21:17:37 +0200308 * @turn_off_delay_ms - number of msec before turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700309 */
310struct qpnp_led_data {
311 struct led_classdev cdev;
312 struct spmi_device *spmi_dev;
Asaf Penso55ac8472013-01-21 21:17:37 +0200313 struct delayed_work dwork;
Amy Malochef3d5a062012-08-16 19:14:11 -0700314 int id;
315 u16 base;
316 u8 reg;
Amy Malochea5ca5552012-10-23 13:34:46 -0700317 u8 num_leds;
Amy Malochedc3e5572012-09-25 16:39:06 -0700318 spinlock_t lock;
Amy Malochef3d5a062012-08-16 19:14:11 -0700319 struct wled_config_data *wled_cfg;
Amy Maloche864a6d52012-10-03 15:58:12 -0700320 struct flash_config_data *flash_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700321 struct rgb_config_data *rgb_cfg;
Amy Malochef3d5a062012-08-16 19:14:11 -0700322 int max_current;
323 bool default_on;
Asaf Penso55ac8472013-01-21 21:17:37 +0200324 int turn_off_delay_ms;
Amy Malochef3d5a062012-08-16 19:14:11 -0700325};
326
327static int
328qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
329{
330 int rc;
331 u8 reg;
332
333 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
334 addr, &reg, 1);
335 if (rc) {
336 dev_err(&led->spmi_dev->dev,
337 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
338 }
339
340 reg &= ~mask;
341 reg |= val;
342
343 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
344 addr, &reg, 1);
345 if (rc)
346 dev_err(&led->spmi_dev->dev,
347 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
348 return rc;
349}
350
Amy Malochea5ca5552012-10-23 13:34:46 -0700351static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
352{
353 int i;
354 u8 val;
355
356 pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
357 for (i = 0; i < array_size; i++) {
358 spmi_ext_register_readl(led->spmi_dev->ctrl,
359 led->spmi_dev->sid,
360 led->base + regs[i],
361 &val, sizeof(val));
362 pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
363 }
364 pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
365}
366
Amy Malochef3d5a062012-08-16 19:14:11 -0700367static int qpnp_wled_set(struct qpnp_led_data *led)
368{
Amy Maloched55fdb82013-02-26 18:11:57 -0800369 int rc, duty, level;
370 u8 val, i, num_wled_strings;
Amy Malochef3d5a062012-08-16 19:14:11 -0700371
372 level = led->cdev.brightness;
373
374 if (level > WLED_MAX_LEVEL)
375 level = WLED_MAX_LEVEL;
376 if (level == 0) {
377 val = WLED_BOOST_OFF;
378 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
379 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
380 &val, 1);
381 if (rc) {
382 dev_err(&led->spmi_dev->dev,
383 "WLED write ctrl reg failed(%d)\n", rc);
384 return rc;
385 }
386 } else {
387 val = WLED_BOOST_ON;
388 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
389 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
390 &val, 1);
391 if (rc) {
392 dev_err(&led->spmi_dev->dev,
393 "WLED write ctrl reg failed(%d)\n", rc);
394 return rc;
395 }
396 }
397
398 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
399
400 num_wled_strings = led->wled_cfg->num_strings;
401
402 /* program brightness control registers */
403 for (i = 0; i < num_wled_strings; i++) {
404 rc = qpnp_led_masked_write(led,
405 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
406 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
407 if (rc) {
408 dev_err(&led->spmi_dev->dev,
409 "WLED set brightness MSB failed(%d)\n", rc);
410 return rc;
411 }
412 val = duty & WLED_8_BIT_MASK;
413 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
414 led->spmi_dev->sid,
415 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
416 if (rc) {
417 dev_err(&led->spmi_dev->dev,
418 "WLED set brightness LSB failed(%d)\n", rc);
419 return rc;
420 }
421 }
422
423 /* sync */
424 val = WLED_SYNC_VAL;
425 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
426 WLED_SYNC_REG(led->base), &val, 1);
427 if (rc) {
428 dev_err(&led->spmi_dev->dev,
429 "WLED set sync reg failed(%d)\n", rc);
430 return rc;
431 }
432
433 val = WLED_SYNC_RESET_VAL;
434 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
435 WLED_SYNC_REG(led->base), &val, 1);
436 if (rc) {
437 dev_err(&led->spmi_dev->dev,
438 "WLED reset sync reg failed(%d)\n", rc);
439 return rc;
440 }
441 return 0;
442}
443
Amy Maloche864a6d52012-10-03 15:58:12 -0700444static int qpnp_flash_set(struct qpnp_led_data *led)
445{
446 int rc;
447 int val = led->cdev.brightness;
448
449 led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
450 led->max_current);
451
452 led->flash_cfg->current_prgm =
453 led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
454 if (!led->flash_cfg->current_prgm)
455 led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
456
457 /* Set led current */
458 if (val > 0) {
Amy Maloche38b9aae2013-02-07 12:15:34 -0800459 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
460 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
461 if (rc) {
462 dev_err(&led->spmi_dev->dev,
463 "Enable reg write failed(%d)\n", rc);
464 return rc;
465 }
466
Amy Maloche864a6d52012-10-03 15:58:12 -0700467 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
468 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
469 if (rc) {
470 dev_err(&led->spmi_dev->dev,
471 "Current reg write failed(%d)\n", rc);
472 return rc;
473 }
474
475 rc = qpnp_led_masked_write(led, led->flash_cfg->second_addr,
476 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
477 if (rc) {
478 dev_err(&led->spmi_dev->dev,
479 "Current reg write failed(%d)\n", rc);
480 return rc;
481 }
482
483 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
484 FLASH_ENABLE_MASK,
485 FLASH_ENABLE_ALL);
486 if (rc) {
487 dev_err(&led->spmi_dev->dev,
488 "Enable reg write failed(%d)\n", rc);
489 return rc;
490 }
491 rc = qpnp_led_masked_write(led,
492 FLASH_LED_STROBE_CTRL(led->base),
493 FLASH_STROBE_MASK, FLASH_STROBE_ALL);
494
495 if (rc) {
496 dev_err(&led->spmi_dev->dev,
497 "LED %d flash write failed(%d)\n", led->id, rc);
498 return rc;
499 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800500 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
501 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
502 if (rc) {
503 dev_err(&led->spmi_dev->dev,
504 "Vreg OK reg write failed(%d)\n", rc);
505 return rc;
506 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700507 } else {
508 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
509 FLASH_ENABLE_MASK,
510 FLASH_DISABLE_ALL);
511 if (rc) {
512 dev_err(&led->spmi_dev->dev,
513 "Enable reg write failed(%d)\n", rc);
514 return rc;
515 }
516
517 rc = qpnp_led_masked_write(led,
518 FLASH_LED_STROBE_CTRL(led->base),
519 FLASH_STROBE_MASK,
520 FLASH_DISABLE_ALL);
521 if (rc) {
522 dev_err(&led->spmi_dev->dev,
523 "LED %d flash write failed(%d)\n", led->id, rc);
524 return rc;
525 }
526 }
527
Amy Malocheeea7b592012-10-03 15:59:36 -0700528 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
529
530 return 0;
531}
532
533static int qpnp_rgb_set(struct qpnp_led_data *led)
534{
535 int duty_us;
536 int rc;
537
538 if (led->cdev.brightness) {
539 if (led->rgb_cfg->mode == RGB_MODE_PWM) {
540 duty_us = (led->rgb_cfg->pwm_period_us *
541 led->cdev.brightness) / LED_FULL;
542 rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
543 led->rgb_cfg->pwm_period_us);
544 if (rc < 0) {
545 dev_err(&led->spmi_dev->dev, "Failed to " \
546 "configure pwm for new values\n");
547 return rc;
548 }
549 }
550 rc = qpnp_led_masked_write(led,
551 RGB_LED_EN_CTL(led->base),
552 led->rgb_cfg->enable, led->rgb_cfg->enable);
553 if (rc) {
554 dev_err(&led->spmi_dev->dev,
555 "Failed to write led enable reg\n");
556 return rc;
557 }
558 rc = pwm_enable(led->rgb_cfg->pwm_dev);
559 } else {
560 pwm_disable(led->rgb_cfg->pwm_dev);
561 rc = qpnp_led_masked_write(led,
562 RGB_LED_EN_CTL(led->base),
563 led->rgb_cfg->enable, RGB_LED_DISABLE);
564 if (rc) {
565 dev_err(&led->spmi_dev->dev,
566 "Failed to write led enable reg\n");
567 return rc;
568 }
569 }
570
571 qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
572
Amy Maloche864a6d52012-10-03 15:58:12 -0700573 return 0;
574}
575
Amy Malochef3d5a062012-08-16 19:14:11 -0700576static void qpnp_led_set(struct led_classdev *led_cdev,
577 enum led_brightness value)
578{
579 int rc;
580 struct qpnp_led_data *led;
581
582 led = container_of(led_cdev, struct qpnp_led_data, cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -0700583 if (value < LED_OFF || value > led->cdev.max_brightness) {
Amy Malochea5ca5552012-10-23 13:34:46 -0700584 dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
Amy Malochef3d5a062012-08-16 19:14:11 -0700585 return;
586 }
587
Amy Malochedc3e5572012-09-25 16:39:06 -0700588 spin_lock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700589 led->cdev.brightness = value;
590
591 switch (led->id) {
592 case QPNP_ID_WLED:
593 rc = qpnp_wled_set(led);
594 if (rc < 0)
Amy Malochea5ca5552012-10-23 13:34:46 -0700595 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700596 "WLED set brightness failed (%d)\n", rc);
597 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700598 case QPNP_ID_FLASH1_LED0:
599 case QPNP_ID_FLASH1_LED1:
600 rc = qpnp_flash_set(led);
601 if (rc < 0)
602 dev_err(&led->spmi_dev->dev,
603 "FLASH set brightness failed (%d)\n", rc);
604 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700605 case QPNP_ID_RGB_RED:
606 case QPNP_ID_RGB_GREEN:
607 case QPNP_ID_RGB_BLUE:
608 rc = qpnp_rgb_set(led);
609 if (rc < 0)
610 dev_err(&led->spmi_dev->dev,
611 "RGB set brightness failed (%d)\n", rc);
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 break;
616 }
Amy Malochedc3e5572012-09-25 16:39:06 -0700617 spin_unlock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700618}
619
620static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
621{
622 switch (led->id) {
623 case QPNP_ID_WLED:
624 led->cdev.max_brightness = WLED_MAX_LEVEL;
625 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700626 case QPNP_ID_FLASH1_LED0:
627 case QPNP_ID_FLASH1_LED1:
628 led->cdev.max_brightness = led->max_current;
629 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700630 case QPNP_ID_RGB_RED:
631 case QPNP_ID_RGB_GREEN:
632 case QPNP_ID_RGB_BLUE:
633 led->cdev.max_brightness = RGB_MAX_LEVEL;
634 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700635 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700636 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700637 return -EINVAL;
638 }
639
640 return 0;
641}
642
643static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
644{
645 struct qpnp_led_data *led;
646
647 led = container_of(led_cdev, struct qpnp_led_data, cdev);
648
649 return led->cdev.brightness;
650}
651
Asaf Penso55ac8472013-01-21 21:17:37 +0200652static void qpnp_led_turn_off_delayed(struct work_struct *work)
653{
654 struct delayed_work *dwork = to_delayed_work(work);
655 struct qpnp_led_data *led
656 = container_of(dwork, struct qpnp_led_data, dwork);
657
658 led->cdev.brightness = LED_OFF;
659 qpnp_led_set(&led->cdev, led->cdev.brightness);
660}
661
662static void qpnp_led_turn_off(struct qpnp_led_data *led)
663{
664 INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed);
665 schedule_delayed_work(&led->dwork,
666 msecs_to_jiffies(led->turn_off_delay_ms));
667}
668
Amy Malochef3d5a062012-08-16 19:14:11 -0700669static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
670{
671 int rc, i;
672 u8 num_wled_strings;
673
674 num_wled_strings = led->wled_cfg->num_strings;
675
676 /* verify ranges */
677 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
678 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
679 return -EINVAL;
680 }
681
682 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
683 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
684 return -EINVAL;
685 }
686
687 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
688 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
689 return -EINVAL;
690 }
691
692 if ((led->max_current > WLED_MAX_CURR)) {
693 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
694 return -EINVAL;
695 }
696
697 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
698 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
699 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
700 return -EINVAL;
701 }
702
703 /* program over voltage protection threshold */
704 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
705 WLED_OVP_VAL_MASK,
706 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
707 if (rc) {
708 dev_err(&led->spmi_dev->dev,
709 "WLED OVP reg write failed(%d)\n", rc);
710 return rc;
711 }
712
713 /* program current boost limit */
714 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
715 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
716 if (rc) {
717 dev_err(&led->spmi_dev->dev,
718 "WLED boost limit reg write failed(%d)\n", rc);
719 return rc;
720 }
721
722 /* program output feedback */
723 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
724 WLED_OP_FDBCK_MASK,
725 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
726 if (rc) {
727 dev_err(&led->spmi_dev->dev,
728 "WLED fdbck ctrl reg write failed(%d)\n", rc);
729 return rc;
730 }
731
732 /* program switch frequency */
733 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
734 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
735 if (rc) {
736 dev_err(&led->spmi_dev->dev,
737 "WLED switch freq reg write failed(%d)\n", rc);
738 return rc;
739 }
740
741 /* program current sink */
742 if (led->wled_cfg->cs_out_en) {
743 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
744 WLED_CURR_SINK_MASK,
Amy Maloche832d90a2013-01-07 10:15:29 -0800745 (((1 << led->wled_cfg->num_strings) - 1)
746 << WLED_CURR_SINK_SHFT));
Amy Malochef3d5a062012-08-16 19:14:11 -0700747 if (rc) {
748 dev_err(&led->spmi_dev->dev,
749 "WLED curr sink reg write failed(%d)\n", rc);
750 return rc;
751 }
752 }
753
754 /* program high pole capacitance */
755 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
756 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
757 if (rc) {
758 dev_err(&led->spmi_dev->dev,
759 "WLED pole cap reg write failed(%d)\n", rc);
760 return rc;
761 }
762
763 /* program modulator, current mod src and cabc */
764 for (i = 0; i < num_wled_strings; i++) {
765 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
766 WLED_NO_MASK, WLED_EN_MASK);
767 if (rc) {
768 dev_err(&led->spmi_dev->dev,
769 "WLED mod enable reg write failed(%d)\n", rc);
770 return rc;
771 }
772
773 if (led->wled_cfg->dig_mod_gen_en) {
774 rc = qpnp_led_masked_write(led,
Amy Maloched44516e2013-02-14 17:36:34 -0800775 WLED_MOD_SRC_SEL_REG(led->base, i),
Amy Malochef3d5a062012-08-16 19:14:11 -0700776 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
777 if (rc) {
778 dev_err(&led->spmi_dev->dev,
779 "WLED dig mod en reg write failed(%d)\n", rc);
780 }
781 }
782
783 rc = qpnp_led_masked_write(led,
784 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
785 led->max_current);
786 if (rc) {
787 dev_err(&led->spmi_dev->dev,
788 "WLED max current reg write failed(%d)\n", rc);
789 return rc;
790 }
791
792 }
793
794 /* dump wled registers */
Amy Malochea5ca5552012-10-23 13:34:46 -0700795 qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
Amy Malochef3d5a062012-08-16 19:14:11 -0700796
797 return 0;
798}
799
Amy Maloche864a6d52012-10-03 15:58:12 -0700800static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
801{
802 int rc;
803
804 rc = qpnp_led_masked_write(led,
805 FLASH_LED_STROBE_CTRL(led->base),
806 FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
807 if (rc) {
808 dev_err(&led->spmi_dev->dev,
809 "LED %d flash write failed(%d)\n", led->id, rc);
810 return rc;
811 }
812 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
813 FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
814 if (rc) {
815 dev_err(&led->spmi_dev->dev,
816 "Enable reg write failed(%d)\n", rc);
817 return rc;
818 }
819
820 /* Set flash safety timer */
821 rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
822 FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
823 if (rc) {
824 dev_err(&led->spmi_dev->dev,
825 "Safety timer reg write failed(%d)\n", rc);
826 return rc;
827 }
828
829 /* Set max current */
830 rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
831 FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
832 if (rc) {
833 dev_err(&led->spmi_dev->dev,
834 "Max current reg write failed(%d)\n", rc);
835 return rc;
836 }
837 /* Set clamp current */
838 rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
839 FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
840 if (rc) {
841 dev_err(&led->spmi_dev->dev,
842 "Clamp current reg write failed(%d)\n", rc);
843 return rc;
844 }
845
846 /* Set timer control - safety or watchdog */
847 if (led->flash_cfg->safety_timer)
848 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
849 FLASH_TMR_MASK, FLASH_TMR_SAFETY);
850 else
851 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
852 FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
853 if (rc) {
854 dev_err(&led->spmi_dev->dev,
855 "LED timer ctrl reg write failed(%d)\n", rc);
856 return rc;
857 }
858 /* Set headroom */
859 rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
860 FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
861 if (rc) {
862 dev_err(&led->spmi_dev->dev,
863 "Headroom reg write failed(%d)\n", rc);
864 return rc;
865 }
866
867 /* Set mask enable */
868 rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
869 FLASH_MASK_REG_MASK, FLASH_MASK_1);
870 if (rc) {
871 dev_err(&led->spmi_dev->dev,
872 "Mask enable reg write failed(%d)\n", rc);
873 return rc;
874 }
875
876 /* Set startup delay */
877 rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
878 FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
879 if (rc) {
880 dev_err(&led->spmi_dev->dev,
881 "Startup delay reg write failed(%d)\n", rc);
882 return rc;
883 }
884
885 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
886 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
887 if (rc) {
888 dev_err(&led->spmi_dev->dev,
889 "Vreg OK reg write failed(%d)\n", rc);
890 return rc;
891 }
892
893 /* Set led current and enable module */
894 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
895 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
896 if (rc) {
897 dev_err(&led->spmi_dev->dev,
898 "Current reg write failed(%d)\n", rc);
899 return rc;
900 }
901
902 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
Amy Maloche38b9aae2013-02-07 12:15:34 -0800903 FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
Amy Maloche864a6d52012-10-03 15:58:12 -0700904 if (rc) {
905 dev_err(&led->spmi_dev->dev,
906 "Enable reg write failed(%d)\n", rc);
907 return rc;
908 }
909 /* dump flash registers */
910 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
911
912 return 0;
913}
914
Amy Malocheeea7b592012-10-03 15:59:36 -0700915static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
916{
917 int rc, start_idx, idx_len;
918
919 rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
920 RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
921 if (rc) {
922 dev_err(&led->spmi_dev->dev,
923 "Failed to write led source select register\n");
924 return rc;
925 }
926
927 if (led->rgb_cfg->pwm_channel != -1) {
928 led->rgb_cfg->pwm_dev =
929 pwm_request(led->rgb_cfg->pwm_channel,
930 led->cdev.name);
931
932 if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
933 dev_err(&led->spmi_dev->dev,
934 "could not acquire PWM Channel %d, " \
935 "error %ld\n",
936 led->rgb_cfg->pwm_channel,
937 PTR_ERR(led->rgb_cfg->pwm_dev));
938 led->rgb_cfg->pwm_dev = NULL;
939 return -ENODEV;
940 }
941
942 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
943 start_idx =
944 led->rgb_cfg->duty_cycles->start_idx;
945 idx_len =
946 led->rgb_cfg->duty_cycles->num_duty_pcts;
947
948 if (idx_len >= PWM_LUT_MAX_SIZE &&
949 start_idx) {
950 dev_err(&led->spmi_dev->dev,
951 "Wrong LUT size or index\n");
952 return -EINVAL;
953 }
954 if ((start_idx + idx_len) >
955 PWM_LUT_MAX_SIZE) {
956 dev_err(&led->spmi_dev->dev,
957 "Exceed LUT limit\n");
958 return -EINVAL;
959 }
960 rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
961 led->rgb_cfg->pwm_period_us,
962 led->rgb_cfg->duty_cycles->duty_pcts,
963 led->rgb_cfg->lut_params);
964 if (rc < 0) {
965 dev_err(&led->spmi_dev->dev, "Failed to " \
966 "configure pwm LUT\n");
967 return rc;
968 }
969 }
970 } else {
971 dev_err(&led->spmi_dev->dev,
972 "Invalid PWM channel\n");
973 return -EINVAL;
974 }
975
976 /* Initialize led for use in auto trickle charging mode */
977 rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
978 led->rgb_cfg->enable, led->rgb_cfg->enable);
979
980 return 0;
981}
982
Amy Malochef3d5a062012-08-16 19:14:11 -0700983static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
984{
985 int rc;
986
987 switch (led->id) {
988 case QPNP_ID_WLED:
989 rc = qpnp_wled_init(led);
990 if (rc)
Amy Malochea5ca5552012-10-23 13:34:46 -0700991 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700992 "WLED initialize failed(%d)\n", rc);
993 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700994 case QPNP_ID_FLASH1_LED0:
995 case QPNP_ID_FLASH1_LED1:
996 rc = qpnp_flash_init(led);
997 if (rc)
998 dev_err(&led->spmi_dev->dev,
999 "FLASH initialize failed(%d)\n", rc);
1000 break;
Amy Malocheeea7b592012-10-03 15:59:36 -07001001 case QPNP_ID_RGB_RED:
1002 case QPNP_ID_RGB_GREEN:
1003 case QPNP_ID_RGB_BLUE:
1004 rc = qpnp_rgb_init(led);
1005 if (rc)
1006 dev_err(&led->spmi_dev->dev,
1007 "RGB initialize failed(%d)\n", rc);
1008 break;
Amy Malochef3d5a062012-08-16 19:14:11 -07001009 default:
Amy Malochea5ca5552012-10-23 13:34:46 -07001010 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malocheeea7b592012-10-03 15:59:36 -07001011 return -EINVAL;
Amy Malochef3d5a062012-08-16 19:14:11 -07001012 }
1013
Amy Malocheeea7b592012-10-03 15:59:36 -07001014 return 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001015}
1016
Amy Malochea5ca5552012-10-23 13:34:46 -07001017static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
1018 struct device_node *node)
1019{
1020 int rc;
Asaf Penso55ac8472013-01-21 21:17:37 +02001021 u32 val;
Amy Malochea5ca5552012-10-23 13:34:46 -07001022 const char *temp_string;
1023
1024 led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
1025 rc = of_property_read_string(node, "linux,default-trigger",
1026 &temp_string);
1027 if (!rc)
1028 led->cdev.default_trigger = temp_string;
1029 else if (rc != -EINVAL)
1030 return rc;
1031
1032 led->default_on = false;
1033 rc = of_property_read_string(node, "qcom,default-state",
1034 &temp_string);
1035 if (!rc) {
1036 if (strncmp(temp_string, "on", sizeof("on")) == 0)
1037 led->default_on = true;
1038 } else if (rc != -EINVAL)
1039 return rc;
1040
Asaf Penso55ac8472013-01-21 21:17:37 +02001041 led->turn_off_delay_ms = 0;
1042 rc = of_property_read_u32(node, "qcom,turn-off-delay-ms", &val);
1043 if (!rc)
1044 led->turn_off_delay_ms = val;
1045 else if (rc != -EINVAL)
1046 return rc;
1047
Amy Malochea5ca5552012-10-23 13:34:46 -07001048 return 0;
1049}
1050
Amy Malochef3d5a062012-08-16 19:14:11 -07001051/*
1052 * Handlers for alternative sources of platform_data
1053 */
1054static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
1055 struct device_node *node)
1056{
1057 u32 val;
1058 int rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001059
1060 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
1061 sizeof(struct wled_config_data), GFP_KERNEL);
1062 if (!led->wled_cfg) {
1063 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1064 return -ENOMEM;
1065 }
1066
Amy Malochef3d5a062012-08-16 19:14:11 -07001067 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
1068 rc = of_property_read_u32(node, "qcom,num-strings", &val);
1069 if (!rc)
1070 led->wled_cfg->num_strings = (u8) val;
1071 else if (rc != -EINVAL)
1072 return rc;
1073
1074 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
1075 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
1076 if (!rc)
1077 led->wled_cfg->ovp_val = (u8) val;
1078 else if (rc != -EINVAL)
1079 return rc;
1080
1081 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
1082 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
1083 if (!rc)
1084 led->wled_cfg->boost_curr_lim = (u8) val;
1085 else if (rc != -EINVAL)
1086 return rc;
1087
1088 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
1089 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
1090 if (!rc)
1091 led->wled_cfg->cp_select = (u8) val;
1092 else if (rc != -EINVAL)
1093 return rc;
1094
1095 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
1096 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
1097 if (!rc)
1098 led->wled_cfg->ctrl_delay_us = (u8) val;
1099 else if (rc != -EINVAL)
1100 return rc;
1101
Amy Malochebd687672013-03-18 11:23:45 -07001102 led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
1103 rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
1104 if (!rc)
1105 led->wled_cfg->op_fdbck = (u8) val;
1106 else if (rc != -EINVAL)
1107 return rc;
1108
Amy Malochef3d5a062012-08-16 19:14:11 -07001109 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
1110 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
1111 if (!rc)
1112 led->wled_cfg->switch_freq = (u8) val;
1113 else if (rc != -EINVAL)
1114 return rc;
1115
1116 led->wled_cfg->dig_mod_gen_en =
1117 of_property_read_bool(node, "qcom,dig-mod-gen-en");
1118
1119 led->wled_cfg->cs_out_en =
1120 of_property_read_bool(node, "qcom,cs-out-en");
1121
Amy Malochef3d5a062012-08-16 19:14:11 -07001122 return 0;
1123}
1124
Amy Maloche864a6d52012-10-03 15:58:12 -07001125static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
1126 struct device_node *node)
1127{
1128 int rc;
1129 u32 val;
1130
1131 led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
1132 sizeof(struct flash_config_data), GFP_KERNEL);
1133 if (!led->flash_cfg) {
1134 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1135 return -ENOMEM;
1136 }
1137
1138 if (led->id == QPNP_ID_FLASH1_LED0) {
1139 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1140 led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
1141 led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
1142 led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
1143 } else if (led->id == QPNP_ID_FLASH1_LED1) {
1144 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1145 led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
1146 led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
1147 led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
1148 } else {
1149 dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
1150 return -EINVAL;
1151 }
1152
1153 rc = of_property_read_u32(node, "qcom,current", &val);
1154 if (!rc)
1155 led->flash_cfg->current_prgm = (val *
1156 FLASH_MAX_LEVEL / led->max_current);
1157 else
1158 return -EINVAL;
1159
1160 rc = of_property_read_u32(node, "qcom,headroom", &val);
1161 if (!rc)
1162 led->flash_cfg->headroom = (u8) val;
1163 else if (rc == -EINVAL)
1164 led->flash_cfg->headroom = HEADROOM_300mV;
1165 else
1166 return rc;
1167
1168 rc = of_property_read_u32(node, "qcom,duration", &val);
1169 if (!rc)
1170 led->flash_cfg->duration = (((u8) val) - 10) / 10;
1171 else if (rc == -EINVAL)
1172 led->flash_cfg->duration = FLASH_DURATION_200ms;
1173 else
1174 return rc;
1175
1176 rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
1177 if (!rc)
1178 led->flash_cfg->clamp_curr = (val *
1179 FLASH_MAX_LEVEL / led->max_current);
1180 else if (rc == -EINVAL)
1181 led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
1182 else
1183 return rc;
1184
1185 rc = of_property_read_u32(node, "qcom,startup-dly", &val);
1186 if (!rc)
1187 led->flash_cfg->startup_dly = (u8) val;
1188 else if (rc == -EINVAL)
1189 led->flash_cfg->startup_dly = DELAY_32us;
1190 else
1191 return rc;
1192
1193 led->flash_cfg->safety_timer =
1194 of_property_read_bool(node, "qcom,safety-timer");
1195
1196 return 0;
1197}
1198
Amy Malocheeea7b592012-10-03 15:59:36 -07001199static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
1200 struct device_node *node)
1201{
1202 struct property *prop;
1203 int rc, i;
1204 u32 val;
1205 u8 *temp_cfg;
1206
1207 led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
1208 sizeof(struct rgb_config_data), GFP_KERNEL);
1209 if (!led->rgb_cfg) {
1210 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1211 return -ENOMEM;
1212 }
1213
1214 if (led->id == QPNP_ID_RGB_RED)
1215 led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
1216 else if (led->id == QPNP_ID_RGB_GREEN)
1217 led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
1218 else if (led->id == QPNP_ID_RGB_BLUE)
1219 led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
1220 else
1221 return -EINVAL;
1222
1223 rc = of_property_read_u32(node, "qcom,mode", &val);
1224 if (!rc)
1225 led->rgb_cfg->mode = (u8) val;
1226 else
1227 return rc;
1228
1229 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1230 if (!rc)
1231 led->rgb_cfg->pwm_channel = (u8) val;
1232 else
1233 return rc;
1234
1235 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1236 if (!rc)
1237 led->rgb_cfg->pwm_period_us = val;
1238 else
1239 return rc;
1240
1241 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1242 led->rgb_cfg->duty_cycles =
1243 devm_kzalloc(&led->spmi_dev->dev,
1244 sizeof(struct pwm_duty_cycles), GFP_KERNEL);
1245 if (!led->rgb_cfg->duty_cycles) {
1246 dev_err(&led->spmi_dev->dev,
1247 "Unable to allocate memory\n");
1248 return -ENOMEM;
1249 }
1250
1251 rc = of_property_read_u32(node, "qcom,duty-ms", &val);
1252 if (!rc)
1253 led->rgb_cfg->duty_cycles->duty_ms = (u8) val;
1254 else
1255 return rc;
1256
1257 prop = of_find_property(node, "qcom,duty-pcts",
1258 &led->rgb_cfg->duty_cycles->num_duty_pcts);
1259 if (!prop) {
1260 dev_err(&led->spmi_dev->dev, "Looking up property " \
1261 "node qcom,duty-pcts failed\n");
1262 return -ENODEV;
1263 } else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
1264 dev_err(&led->spmi_dev->dev, "Invalid length of " \
1265 "duty pcts\n");
1266 return -EINVAL;
1267 }
1268
1269 led->rgb_cfg->duty_cycles->duty_pcts =
1270 devm_kzalloc(&led->spmi_dev->dev,
1271 sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
1272 GFP_KERNEL);
1273 if (!led->rgb_cfg->duty_cycles->duty_pcts) {
1274 dev_err(&led->spmi_dev->dev,
1275 "Unable to allocate memory\n");
1276 return -ENOMEM;
1277 }
1278
1279 temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1280 led->rgb_cfg->duty_cycles->num_duty_pcts *
1281 sizeof(u8), GFP_KERNEL);
1282 if (!temp_cfg) {
1283 dev_err(&led->spmi_dev->dev, "Failed to allocate " \
1284 "memory for duty pcts\n");
1285 return -ENOMEM;
1286 }
1287
1288 memcpy(temp_cfg, prop->value,
1289 led->rgb_cfg->duty_cycles->num_duty_pcts);
1290
1291 for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
1292 led->rgb_cfg->duty_cycles->duty_pcts[i] =
1293 (int) temp_cfg[i];
1294
1295 rc = of_property_read_u32(node, "qcom,start-idx", &val);
1296 if (!rc) {
1297 led->rgb_cfg->lut_params.start_idx = (u8) val;
1298 led->rgb_cfg->duty_cycles->start_idx = (u8) val;
1299 } else
1300 return rc;
1301
1302 led->rgb_cfg->lut_params.idx_len =
1303 led->rgb_cfg->duty_cycles->num_duty_pcts;
1304 led->rgb_cfg->lut_params.lut_pause_hi = 0;
1305 led->rgb_cfg->lut_params.lut_pause_lo = 0;
1306 led->rgb_cfg->lut_params.ramp_step_ms = 255;
1307 led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
1308 }
1309
1310 return 0;
1311}
1312
Amy Malochef3d5a062012-08-16 19:14:11 -07001313static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
1314{
Amy Malochef9490c62012-11-27 19:26:04 -08001315 struct qpnp_led_data *led, *led_array;
Amy Malochef3d5a062012-08-16 19:14:11 -07001316 struct resource *led_resource;
Amy Malochea5ca5552012-10-23 13:34:46 -07001317 struct device_node *node, *temp;
Amy Malochef9490c62012-11-27 19:26:04 -08001318 int rc, i, num_leds = 0, parsed_leds = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001319 const char *led_label;
1320
Amy Malochea5ca5552012-10-23 13:34:46 -07001321 node = spmi->dev.of_node;
1322 if (node == NULL)
1323 return -ENODEV;
1324
1325 temp = NULL;
1326 while ((temp = of_get_next_child(node, temp)))
1327 num_leds++;
1328
Amy Malochef9490c62012-11-27 19:26:04 -08001329 if (!num_leds)
1330 return -ECHILD;
1331
1332 led_array = devm_kzalloc(&spmi->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001333 (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
Amy Malochef9490c62012-11-27 19:26:04 -08001334 if (!led_array) {
Amy Malochef3d5a062012-08-16 19:14:11 -07001335 dev_err(&spmi->dev, "Unable to allocate memory\n");
1336 return -ENOMEM;
1337 }
1338
Amy Malochea5ca5552012-10-23 13:34:46 -07001339 for_each_child_of_node(node, temp) {
Amy Malochef9490c62012-11-27 19:26:04 -08001340 led = &led_array[parsed_leds];
1341 led->num_leds = num_leds;
Amy Malochea5ca5552012-10-23 13:34:46 -07001342 led->spmi_dev = spmi;
Amy Malochef3d5a062012-08-16 19:14:11 -07001343
Amy Malochea5ca5552012-10-23 13:34:46 -07001344 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
1345 if (!led_resource) {
1346 dev_err(&spmi->dev, "Unable to get LED base address\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001347 rc = -ENXIO;
1348 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001349 }
1350 led->base = led_resource->start;
Amy Malochef3d5a062012-08-16 19:14:11 -07001351
Amy Malochea5ca5552012-10-23 13:34:46 -07001352 rc = of_property_read_string(temp, "label", &led_label);
Amy Malochef3d5a062012-08-16 19:14:11 -07001353 if (rc < 0) {
1354 dev_err(&led->spmi_dev->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001355 "Failure reading label, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001356 goto fail_id_check;
Amy Malochef3d5a062012-08-16 19:14:11 -07001357 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001358
1359 rc = of_property_read_string(temp, "linux,name",
1360 &led->cdev.name);
1361 if (rc < 0) {
1362 dev_err(&led->spmi_dev->dev,
1363 "Failure reading led name, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001364 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001365 }
1366
1367 rc = of_property_read_u32(temp, "qcom,max-current",
1368 &led->max_current);
1369 if (rc < 0) {
1370 dev_err(&led->spmi_dev->dev,
1371 "Failure reading max_current, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001372 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001373 }
1374
1375 rc = of_property_read_u32(temp, "qcom,id", &led->id);
1376 if (rc < 0) {
1377 dev_err(&led->spmi_dev->dev,
1378 "Failure reading led id, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001379 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001380 }
1381
1382 rc = qpnp_get_common_configs(led, temp);
1383 if (rc) {
1384 dev_err(&led->spmi_dev->dev,
1385 "Failure reading common led configuration," \
1386 " rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001387 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001388 }
1389
1390 led->cdev.brightness_set = qpnp_led_set;
1391 led->cdev.brightness_get = qpnp_led_get;
1392
1393 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
1394 rc = qpnp_get_config_wled(led, temp);
1395 if (rc < 0) {
1396 dev_err(&led->spmi_dev->dev,
1397 "Unable to read wled config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001398 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001399 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001400 } else if (strncmp(led_label, "flash", sizeof("flash"))
1401 == 0) {
1402 rc = qpnp_get_config_flash(led, temp);
1403 if (rc < 0) {
1404 dev_err(&led->spmi_dev->dev,
1405 "Unable to read flash config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001406 goto fail_id_check;
Amy Maloche864a6d52012-10-03 15:58:12 -07001407 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001408 } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
1409 rc = qpnp_get_config_rgb(led, temp);
1410 if (rc < 0) {
1411 dev_err(&led->spmi_dev->dev,
1412 "Unable to read rgb config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001413 goto fail_id_check;
Amy Malocheeea7b592012-10-03 15:59:36 -07001414 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001415 } else {
1416 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001417 rc = -EINVAL;
1418 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001419 }
1420
1421 spin_lock_init(&led->lock);
1422
1423 rc = qpnp_led_initialize(led);
1424 if (rc < 0)
1425 goto fail_id_check;
1426
1427 rc = qpnp_led_set_max_brightness(led);
1428 if (rc < 0)
1429 goto fail_id_check;
1430
1431 rc = led_classdev_register(&spmi->dev, &led->cdev);
1432 if (rc) {
1433 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
1434 led->id, rc);
1435 goto fail_id_check;
1436 }
1437 /* configure default state */
Asaf Penso55ac8472013-01-21 21:17:37 +02001438 if (led->default_on) {
Amy Malochea5ca5552012-10-23 13:34:46 -07001439 led->cdev.brightness = led->cdev.max_brightness;
Asaf Penso55ac8472013-01-21 21:17:37 +02001440 if (led->turn_off_delay_ms > 0)
1441 qpnp_led_turn_off(led);
1442 } else
Amy Malochea5ca5552012-10-23 13:34:46 -07001443 led->cdev.brightness = LED_OFF;
1444
1445 qpnp_led_set(&led->cdev, led->cdev.brightness);
Amy Malochef9490c62012-11-27 19:26:04 -08001446
1447 parsed_leds++;
Amy Malochef3d5a062012-08-16 19:14:11 -07001448 }
Amy Malochef9490c62012-11-27 19:26:04 -08001449 dev_set_drvdata(&spmi->dev, led_array);
Amy Malochef3d5a062012-08-16 19:14:11 -07001450 return 0;
1451
1452fail_id_check:
Amy Malochef9490c62012-11-27 19:26:04 -08001453 for (i = 0; i < parsed_leds; i++)
1454 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001455 return rc;
1456}
1457
1458static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
1459{
Amy Malochef9490c62012-11-27 19:26:04 -08001460 struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
1461 int i, parsed_leds = led_array->num_leds;
Amy Malochef3d5a062012-08-16 19:14:11 -07001462
Amy Malochef9490c62012-11-27 19:26:04 -08001463 for (i = 0; i < parsed_leds; i++)
1464 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001465
1466 return 0;
1467}
1468static struct of_device_id spmi_match_table[] = {
1469 { .compatible = "qcom,leds-qpnp",
1470 }
1471};
1472
1473static struct spmi_driver qpnp_leds_driver = {
1474 .driver = {
1475 .name = "qcom,leds-qpnp",
1476 .of_match_table = spmi_match_table,
1477 },
1478 .probe = qpnp_leds_probe,
1479 .remove = __devexit_p(qpnp_leds_remove),
1480};
1481
1482static int __init qpnp_led_init(void)
1483{
1484 return spmi_driver_register(&qpnp_leds_driver);
1485}
1486module_init(qpnp_led_init);
1487
1488static void __exit qpnp_led_exit(void)
1489{
1490 spmi_driver_unregister(&qpnp_leds_driver);
1491}
1492module_exit(qpnp_led_exit);
1493
1494MODULE_DESCRIPTION("QPNP LEDs driver");
1495MODULE_LICENSE("GPL v2");
1496MODULE_ALIAS("leds:leds-qpnp");
Amy Maloche864a6d52012-10-03 15:58:12 -07001497