blob: e88e5744b627ca54bb87bd5854852c6fc8a81f20 [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)
Amy Malochebc97c0d22013-03-24 22:06:16 -070094#define FLASH_LED_UNLOCK_SECURE(base) (base + 0xD0)
95#define FLASH_LED_TORCH(base) (base + 0xE4)
Amy Maloche864a6d52012-10-03 15:58:12 -070096
97#define FLASH_MAX_LEVEL 0x4F
98#define FLASH_NO_MASK 0x00
99
100#define FLASH_MASK_1 0x20
101#define FLASH_MASK_REG_MASK 0xE0
102#define FLASH_HEADROOM_MASK 0x03
103#define FLASH_SAFETY_TIMER_MASK 0x7F
104#define FLASH_CURRENT_MASK 0xFF
Amy Malochebc97c0d22013-03-24 22:06:16 -0700105#define FLASH_MAX_CURRENT_MASK 0x7F
Amy Maloche864a6d52012-10-03 15:58:12 -0700106#define FLASH_TMR_MASK 0x03
107#define FLASH_TMR_WATCHDOG 0x03
108#define FLASH_TMR_SAFETY 0x00
109
110#define FLASH_HW_VREG_OK 0x80
111#define FLASH_VREG_MASK 0xC0
112
113#define FLASH_STARTUP_DLY_MASK 0x02
114
115#define FLASH_ENABLE_ALL 0xE0
116#define FLASH_ENABLE_MODULE 0x80
117#define FLASH_ENABLE_MODULE_MASK 0x80
118#define FLASH_DISABLE_ALL 0x00
Amy Maloche38b9aae2013-02-07 12:15:34 -0800119#define FLASH_ENABLE_MASK 0xE0
Amy Maloche864a6d52012-10-03 15:58:12 -0700120#define FLASH_ENABLE_LED_0 0x40
121#define FLASH_ENABLE_LED_1 0x20
122#define FLASH_INIT_MASK 0xE0
123
Amy Malochebc97c0d22013-03-24 22:06:16 -0700124#define FLASH_STROBE_SW 0xC0
125#define FLASH_STROBE_HW 0xC4
126#define FLASH_STROBE_MASK 0xC7
Amy Maloche864a6d52012-10-03 15:58:12 -0700127#define FLASH_LED_0_OUTPUT 0x80
128#define FLASH_LED_1_OUTPUT 0x40
129
130#define FLASH_CURRENT_PRGM_MIN 1
131#define FLASH_CURRENT_PRGM_SHIFT 1
Amy Malochebc97c0d22013-03-24 22:06:16 -0700132#define FLASH_CURRENT_MAX 0x4F
133#define FLASH_CURRENT_TORCH 0x0F
Amy Maloche864a6d52012-10-03 15:58:12 -0700134
135#define FLASH_DURATION_200ms 0x13
136#define FLASH_CLAMP_200mA 0x0F
137
Amy Malochebc97c0d22013-03-24 22:06:16 -0700138#define FLASH_TORCH_MASK 0x03
139#define FLASH_LED_TORCH_ENABLE 0x00
140#define FLASH_LED_TORCH_DISABLE 0x03
141#define FLASH_UNLOCK_SECURE 0xA5
142#define FLASH_SECURE_MASK 0xFF
143
Amy Malochea5ca5552012-10-23 13:34:46 -0700144#define LED_TRIGGER_DEFAULT "none"
145
Amy Malocheeea7b592012-10-03 15:59:36 -0700146#define RGB_LED_SRC_SEL(base) (base + 0x45)
147#define RGB_LED_EN_CTL(base) (base + 0x46)
148#define RGB_LED_ATC_CTL(base) (base + 0x47)
149
150#define RGB_MAX_LEVEL LED_FULL
151#define RGB_LED_ENABLE_RED 0x80
152#define RGB_LED_ENABLE_GREEN 0x40
153#define RGB_LED_ENABLE_BLUE 0x20
154#define RGB_LED_SOURCE_VPH_PWR 0x01
155#define RGB_LED_ENABLE_MASK 0xE0
156#define RGB_LED_SRC_MASK 0x03
157#define QPNP_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
Amy Maloche013b35b2013-03-19 12:29:11 -0700158#define QPNP_LUT_RAMP_STEP_DEFAULT 255
Amy Malocheeea7b592012-10-03 15:59:36 -0700159#define PWM_LUT_MAX_SIZE 63
160#define RGB_LED_DISABLE 0x00
161
Amy Malochef3d5a062012-08-16 19:14:11 -0700162/**
163 * enum qpnp_leds - QPNP supported led ids
164 * @QPNP_ID_WLED - White led backlight
165 */
166enum qpnp_leds {
Amy Maloche864a6d52012-10-03 15:58:12 -0700167 QPNP_ID_WLED = 0,
168 QPNP_ID_FLASH1_LED0,
169 QPNP_ID_FLASH1_LED1,
Amy Malocheeea7b592012-10-03 15:59:36 -0700170 QPNP_ID_RGB_RED,
171 QPNP_ID_RGB_GREEN,
172 QPNP_ID_RGB_BLUE,
Amy Maloche864a6d52012-10-03 15:58:12 -0700173 QPNP_ID_MAX,
Amy Malochef3d5a062012-08-16 19:14:11 -0700174};
175
176/* current boost limit */
177enum wled_current_boost_limit {
178 WLED_CURR_LIMIT_105mA,
179 WLED_CURR_LIMIT_385mA,
180 WLED_CURR_LIMIT_525mA,
181 WLED_CURR_LIMIT_805mA,
182 WLED_CURR_LIMIT_980mA,
183 WLED_CURR_LIMIT_1260mA,
184 WLED_CURR_LIMIT_1400mA,
185 WLED_CURR_LIMIT_1680mA,
186};
187
188/* over voltage protection threshold */
189enum wled_ovp_threshold {
190 WLED_OVP_35V,
191 WLED_OVP_32V,
192 WLED_OVP_29V,
193 WLED_OVP_37V,
194};
195
196/* switch frquency */
197enum wled_switch_freq {
198 WLED_800kHz = 0,
199 WLED_960kHz,
200 WLED_1600kHz,
201 WLED_3200kHz,
202};
203
Amy Maloche864a6d52012-10-03 15:58:12 -0700204enum flash_headroom {
205 HEADROOM_250mV = 0,
206 HEADROOM_300mV,
207 HEADROOM_400mV,
208 HEADROOM_500mV,
209};
210
211enum flash_startup_dly {
212 DELAY_10us = 0,
213 DELAY_32us,
214 DELAY_64us,
215 DELAY_128us,
216};
217
Amy Malocheeea7b592012-10-03 15:59:36 -0700218enum rgb_mode {
219 RGB_MODE_PWM = 0,
220 RGB_MODE_LPG,
221};
222
Amy Malochef3d5a062012-08-16 19:14:11 -0700223static u8 wled_debug_regs[] = {
224 /* common registers */
225 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
226 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
227 /* LED1 */
228 0x60, 0x61, 0x62, 0x63, 0x66,
Amy Malochea5ca5552012-10-23 13:34:46 -0700229 /* LED2 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700230 0x70, 0x71, 0x72, 0x73, 0x76,
Amy Malochea5ca5552012-10-23 13:34:46 -0700231 /* LED3 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700232 0x80, 0x81, 0x82, 0x83, 0x86,
233};
234
Amy Maloche864a6d52012-10-03 15:58:12 -0700235static u8 flash_debug_regs[] = {
236 0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
237 0x4f, 0x46, 0x47,
238};
239
Amy Malocheeea7b592012-10-03 15:59:36 -0700240static u8 rgb_pwm_debug_regs[] = {
241 0x45, 0x46, 0x47,
242};
Amy Malochef3d5a062012-08-16 19:14:11 -0700243/**
244 * wled_config_data - wled configuration data
245 * @num_strings - number of wled strings supported
246 * @ovp_val - over voltage protection threshold
247 * @boost_curr_lim - boot current limit
248 * @cp_select - high pole capacitance
249 * @ctrl_delay_us - delay in activation of led
250 * @dig_mod_gen_en - digital module generator
251 * @cs_out_en - current sink output enable
252 * @op_fdbck - selection of output as feedback for the boost
253 */
254struct wled_config_data {
255 u8 num_strings;
256 u8 ovp_val;
257 u8 boost_curr_lim;
258 u8 cp_select;
259 u8 ctrl_delay_us;
260 u8 switch_freq;
Amy Malochebd687672013-03-18 11:23:45 -0700261 u8 op_fdbck;
Amy Malochef3d5a062012-08-16 19:14:11 -0700262 bool dig_mod_gen_en;
263 bool cs_out_en;
Amy Malochef3d5a062012-08-16 19:14:11 -0700264};
265
266/**
Amy Maloche864a6d52012-10-03 15:58:12 -0700267 * flash_config_data - flash configuration data
268 * @current_prgm - current to be programmed, scaled by max level
269 * @clamp_curr - clamp current to use
270 * @headroom - headroom value to use
271 * @duration - duration of the flash
272 * @enable_module - enable address for particular flash
273 * @trigger_flash - trigger flash
274 * @startup_dly - startup delay for flash
Amy Malochebc97c0d22013-03-24 22:06:16 -0700275 * @strobe_type - select between sw and hw strobe
Amy Maloche864a6d52012-10-03 15:58:12 -0700276 * @current_addr - address to write for current
277 * @second_addr - address of secondary flash to be written
278 * @safety_timer - enable safety timer or watchdog timer
Amy Malochebc97c0d22013-03-24 22:06:16 -0700279 * @torch_enable - enable flash LED torch mode
Amy Maloche864a6d52012-10-03 15:58:12 -0700280 */
281struct flash_config_data {
282 u8 current_prgm;
283 u8 clamp_curr;
284 u8 headroom;
285 u8 duration;
286 u8 enable_module;
287 u8 trigger_flash;
288 u8 startup_dly;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700289 u8 strobe_type;
Amy Maloche864a6d52012-10-03 15:58:12 -0700290 u16 current_addr;
291 u16 second_addr;
292 bool safety_timer;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700293 bool torch_enable;
Amy Maloche864a6d52012-10-03 15:58:12 -0700294};
295
296/**
Amy Malocheeea7b592012-10-03 15:59:36 -0700297 * rgb_config_data - rgb configuration data
298 * @lut_params - lut parameters to be used by pwm driver
299 * @pwm_device - pwm device
300 * @pwm_channel - pwm channel to be configured for led
301 * @pwm_period_us - period for pwm, in us
302 * @mode - mode the led operates in
303 */
304struct rgb_config_data {
305 struct lut_params lut_params;
306 struct pwm_device *pwm_dev;
307 int pwm_channel;
308 u32 pwm_period_us;
309 struct pwm_duty_cycles *duty_cycles;
310 u8 mode;
311 u8 enable;
312};
313
314/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700315 * struct qpnp_led_data - internal led data structure
316 * @led_classdev - led class device
Asaf Penso55ac8472013-01-21 21:17:37 +0200317 * @delayed_work - delayed work for turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700318 * @id - led index
319 * @base_reg - base register given in device tree
320 * @lock - to protect the transactions
321 * @reg - cached value of led register
Amy Malochea5ca5552012-10-23 13:34:46 -0700322 * @num_leds - number of leds in the module
Amy Malochef3d5a062012-08-16 19:14:11 -0700323 * @max_current - maximum current supported by LED
324 * @default_on - true: default state max, false, default state 0
Asaf Penso55ac8472013-01-21 21:17:37 +0200325 * @turn_off_delay_ms - number of msec before turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700326 */
327struct qpnp_led_data {
328 struct led_classdev cdev;
329 struct spmi_device *spmi_dev;
Asaf Penso55ac8472013-01-21 21:17:37 +0200330 struct delayed_work dwork;
Amy Malochef3d5a062012-08-16 19:14:11 -0700331 int id;
332 u16 base;
333 u8 reg;
Amy Malochea5ca5552012-10-23 13:34:46 -0700334 u8 num_leds;
Amy Malochedc3e5572012-09-25 16:39:06 -0700335 spinlock_t lock;
Amy Malochef3d5a062012-08-16 19:14:11 -0700336 struct wled_config_data *wled_cfg;
Amy Maloche864a6d52012-10-03 15:58:12 -0700337 struct flash_config_data *flash_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700338 struct rgb_config_data *rgb_cfg;
Amy Malochef3d5a062012-08-16 19:14:11 -0700339 int max_current;
340 bool default_on;
Asaf Penso55ac8472013-01-21 21:17:37 +0200341 int turn_off_delay_ms;
Amy Malochef3d5a062012-08-16 19:14:11 -0700342};
343
344static int
345qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
346{
347 int rc;
348 u8 reg;
349
350 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
351 addr, &reg, 1);
352 if (rc) {
353 dev_err(&led->spmi_dev->dev,
354 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
355 }
356
357 reg &= ~mask;
358 reg |= val;
359
360 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
361 addr, &reg, 1);
362 if (rc)
363 dev_err(&led->spmi_dev->dev,
364 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
365 return rc;
366}
367
Amy Malochea5ca5552012-10-23 13:34:46 -0700368static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
369{
370 int i;
371 u8 val;
372
373 pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
374 for (i = 0; i < array_size; i++) {
375 spmi_ext_register_readl(led->spmi_dev->ctrl,
376 led->spmi_dev->sid,
377 led->base + regs[i],
378 &val, sizeof(val));
379 pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
380 }
381 pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
382}
383
Amy Malochef3d5a062012-08-16 19:14:11 -0700384static int qpnp_wled_set(struct qpnp_led_data *led)
385{
Amy Maloched55fdb82013-02-26 18:11:57 -0800386 int rc, duty, level;
387 u8 val, i, num_wled_strings;
Amy Malochef3d5a062012-08-16 19:14:11 -0700388
389 level = led->cdev.brightness;
390
391 if (level > WLED_MAX_LEVEL)
392 level = WLED_MAX_LEVEL;
393 if (level == 0) {
394 val = WLED_BOOST_OFF;
395 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
396 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
397 &val, 1);
398 if (rc) {
399 dev_err(&led->spmi_dev->dev,
400 "WLED write ctrl reg failed(%d)\n", rc);
401 return rc;
402 }
403 } else {
404 val = WLED_BOOST_ON;
405 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
406 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
407 &val, 1);
408 if (rc) {
409 dev_err(&led->spmi_dev->dev,
410 "WLED write ctrl reg failed(%d)\n", rc);
411 return rc;
412 }
413 }
414
415 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
416
417 num_wled_strings = led->wled_cfg->num_strings;
418
419 /* program brightness control registers */
420 for (i = 0; i < num_wled_strings; i++) {
421 rc = qpnp_led_masked_write(led,
422 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
423 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
424 if (rc) {
425 dev_err(&led->spmi_dev->dev,
426 "WLED set brightness MSB failed(%d)\n", rc);
427 return rc;
428 }
429 val = duty & WLED_8_BIT_MASK;
430 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
431 led->spmi_dev->sid,
432 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
433 if (rc) {
434 dev_err(&led->spmi_dev->dev,
435 "WLED set brightness LSB failed(%d)\n", rc);
436 return rc;
437 }
438 }
439
440 /* sync */
441 val = WLED_SYNC_VAL;
442 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
443 WLED_SYNC_REG(led->base), &val, 1);
444 if (rc) {
445 dev_err(&led->spmi_dev->dev,
446 "WLED set sync reg failed(%d)\n", rc);
447 return rc;
448 }
449
450 val = WLED_SYNC_RESET_VAL;
451 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
452 WLED_SYNC_REG(led->base), &val, 1);
453 if (rc) {
454 dev_err(&led->spmi_dev->dev,
455 "WLED reset sync reg failed(%d)\n", rc);
456 return rc;
457 }
458 return 0;
459}
460
Amy Maloche864a6d52012-10-03 15:58:12 -0700461static int qpnp_flash_set(struct qpnp_led_data *led)
462{
463 int rc;
464 int val = led->cdev.brightness;
465
466 led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
467 led->max_current);
468
469 led->flash_cfg->current_prgm =
470 led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
471 if (!led->flash_cfg->current_prgm)
472 led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
473
474 /* Set led current */
475 if (val > 0) {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700476 if (led->flash_cfg->torch_enable) {
477 rc = qpnp_led_masked_write(led,
478 FLASH_LED_UNLOCK_SECURE(led->base),
479 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
480 if (rc) {
481 dev_err(&led->spmi_dev->dev,
482 "Secure reg write failed(%d)\n", rc);
483 return rc;
484 }
485
486 rc = qpnp_led_masked_write(led,
487 FLASH_LED_TORCH(led->base),
488 FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
489 if (rc) {
490 dev_err(&led->spmi_dev->dev,
491 "Torch reg write failed(%d)\n", rc);
492 return rc;
493 }
494
495 qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
496 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
497 if (rc) {
498 dev_err(&led->spmi_dev->dev,
499 "Max current reg write failed(%d)\n",
500 rc);
501 return rc;
502 }
503
504 rc = qpnp_led_masked_write(led,
505 led->flash_cfg->current_addr,
506 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
507 if (rc) {
508 dev_err(&led->spmi_dev->dev,
509 "Current reg write failed(%d)\n", rc);
510 return rc;
511 }
512
513 rc = qpnp_led_masked_write(led,
514 led->flash_cfg->second_addr,
515 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
516 if (rc) {
517 dev_err(&led->spmi_dev->dev,
518 "2nd Current reg write failed(%d)\n",
519 rc);
520 return rc;
521 }
522
523 rc = qpnp_led_masked_write(led,
524 FLASH_ENABLE_CONTROL(led->base),
525 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
526 if (rc) {
527 dev_err(&led->spmi_dev->dev,
528 "Enable reg write failed(%d)\n", rc);
529 return rc;
530 }
531 } else {
532 rc = qpnp_led_masked_write(led,
533 FLASH_MAX_CURR(led->base),
534 FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
535 if (rc) {
536 dev_err(&led->spmi_dev->dev,
537 "Max current reg write failed(%d)\n",
538 rc);
539 return rc;
540 }
541
542 /* Write 0x80 to MODULE_ENABLE before writing 0xE0
543 * in order to avoid reg value goes from 0x00 to
544 * 0xE0. This causes a hardware bug.
545 */
546 rc = qpnp_led_masked_write(led,
547 FLASH_ENABLE_CONTROL(led->base),
548 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
549 if (rc) {
550 dev_err(&led->spmi_dev->dev,
551 "Enable reg write failed(%d)\n", rc);
552 return rc;
553 }
554
555 rc = qpnp_led_masked_write(led,
556 led->flash_cfg->current_addr,
557 FLASH_CURRENT_MASK,
558 led->flash_cfg->current_prgm);
559 if (rc) {
560 dev_err(&led->spmi_dev->dev,
561 "Current reg write failed(%d)\n", rc);
562 return rc;
563 }
564
565 rc = qpnp_led_masked_write(led,
566 led->flash_cfg->second_addr,
567 FLASH_CURRENT_MASK,
568 led->flash_cfg->current_prgm);
569 if (rc) {
570 dev_err(&led->spmi_dev->dev,
571 "2nd Current reg write failed(%d)\n",
572 rc);
573 return rc;
574 }
575
576 rc = qpnp_led_masked_write(led,
577 FLASH_CLAMP_CURR(led->base),
578 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
579 if (rc) {
580 dev_err(&led->spmi_dev->dev,
581 "Clamp Current reg write failed(%d)\n",
582 rc);
583 return rc;
584 }
585
586 rc = qpnp_led_masked_write(led,
587 FLASH_ENABLE_CONTROL(led->base),
588 FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
589 if (rc) {
590 dev_err(&led->spmi_dev->dev,
591 "Enable reg write failed(%d)\n", rc);
592 return rc;
593 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800594 }
595
Amy Malochebc97c0d22013-03-24 22:06:16 -0700596 if (!led->flash_cfg->strobe_type) {
597 rc = qpnp_led_masked_write(led,
598 FLASH_LED_STROBE_CTRL(led->base),
599 FLASH_STROBE_MASK, FLASH_STROBE_SW);
600 if (rc) {
601 dev_err(&led->spmi_dev->dev,
602 "LED %d strobe reg write failed(%d)\n",
603 led->id, rc);
604 return rc;
605 }
606 } else {
607 rc = qpnp_led_masked_write(led,
608 FLASH_LED_STROBE_CTRL(led->base),
609 FLASH_STROBE_MASK, FLASH_STROBE_HW);
610 if (rc) {
611 dev_err(&led->spmi_dev->dev,
612 "LED %d strobe reg write failed(%d)\n",
613 led->id, rc);
614 return rc;
615 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800616 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700617 } else {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700618 if (led->flash_cfg->torch_enable) {
619 rc = qpnp_led_masked_write(led,
620 FLASH_LED_UNLOCK_SECURE(led->base),
621 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
622 if (rc) {
623 dev_err(&led->spmi_dev->dev,
624 "Secure reg write failed(%d)\n", rc);
625 }
626
627 rc = qpnp_led_masked_write(led,
628 FLASH_LED_TORCH(led->base),
629 FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
630 if (rc) {
631 dev_err(&led->spmi_dev->dev,
632 "Torch reg write failed(%d)\n", rc);
633 return rc;
634 }
635
636 rc = qpnp_led_masked_write(led,
637 FLASH_SAFETY_TIMER(led->base),
638 FLASH_SAFETY_TIMER_MASK,
639 led->flash_cfg->duration);
640 if (rc) {
641 dev_err(&led->spmi_dev->dev,
642 "Safety timer reg write failed(%d)\n",
643 rc);
644 return rc;
645 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700646 }
647
648 rc = qpnp_led_masked_write(led,
649 FLASH_LED_STROBE_CTRL(led->base),
650 FLASH_STROBE_MASK,
651 FLASH_DISABLE_ALL);
652 if (rc) {
653 dev_err(&led->spmi_dev->dev,
654 "LED %d flash write failed(%d)\n", led->id, rc);
655 return rc;
656 }
Amy Malochebc97c0d22013-03-24 22:06:16 -0700657
658 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
659 FLASH_ENABLE_MASK,
660 FLASH_DISABLE_ALL);
661 if (rc) {
662 dev_err(&led->spmi_dev->dev,
663 "Enable reg write failed(%d)\n", rc);
664 return rc;
665 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700666 }
667
Amy Malocheeea7b592012-10-03 15:59:36 -0700668 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
669
670 return 0;
671}
672
673static int qpnp_rgb_set(struct qpnp_led_data *led)
674{
675 int duty_us;
676 int rc;
677
678 if (led->cdev.brightness) {
679 if (led->rgb_cfg->mode == RGB_MODE_PWM) {
680 duty_us = (led->rgb_cfg->pwm_period_us *
681 led->cdev.brightness) / LED_FULL;
682 rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
683 led->rgb_cfg->pwm_period_us);
684 if (rc < 0) {
685 dev_err(&led->spmi_dev->dev, "Failed to " \
686 "configure pwm for new values\n");
687 return rc;
688 }
689 }
690 rc = qpnp_led_masked_write(led,
691 RGB_LED_EN_CTL(led->base),
692 led->rgb_cfg->enable, led->rgb_cfg->enable);
693 if (rc) {
694 dev_err(&led->spmi_dev->dev,
695 "Failed to write led enable reg\n");
696 return rc;
697 }
698 rc = pwm_enable(led->rgb_cfg->pwm_dev);
699 } else {
700 pwm_disable(led->rgb_cfg->pwm_dev);
701 rc = qpnp_led_masked_write(led,
702 RGB_LED_EN_CTL(led->base),
703 led->rgb_cfg->enable, RGB_LED_DISABLE);
704 if (rc) {
705 dev_err(&led->spmi_dev->dev,
706 "Failed to write led enable reg\n");
707 return rc;
708 }
709 }
710
711 qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
712
Amy Maloche864a6d52012-10-03 15:58:12 -0700713 return 0;
714}
715
Amy Malochef3d5a062012-08-16 19:14:11 -0700716static void qpnp_led_set(struct led_classdev *led_cdev,
717 enum led_brightness value)
718{
719 int rc;
720 struct qpnp_led_data *led;
721
722 led = container_of(led_cdev, struct qpnp_led_data, cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -0700723 if (value < LED_OFF || value > led->cdev.max_brightness) {
Amy Malochea5ca5552012-10-23 13:34:46 -0700724 dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
Amy Malochef3d5a062012-08-16 19:14:11 -0700725 return;
726 }
727
Amy Malochedc3e5572012-09-25 16:39:06 -0700728 spin_lock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700729 led->cdev.brightness = value;
730
731 switch (led->id) {
732 case QPNP_ID_WLED:
733 rc = qpnp_wled_set(led);
734 if (rc < 0)
Amy Malochea5ca5552012-10-23 13:34:46 -0700735 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700736 "WLED set brightness failed (%d)\n", rc);
737 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700738 case QPNP_ID_FLASH1_LED0:
739 case QPNP_ID_FLASH1_LED1:
740 rc = qpnp_flash_set(led);
741 if (rc < 0)
742 dev_err(&led->spmi_dev->dev,
743 "FLASH set brightness failed (%d)\n", rc);
744 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700745 case QPNP_ID_RGB_RED:
746 case QPNP_ID_RGB_GREEN:
747 case QPNP_ID_RGB_BLUE:
748 rc = qpnp_rgb_set(led);
749 if (rc < 0)
750 dev_err(&led->spmi_dev->dev,
751 "RGB set brightness failed (%d)\n", rc);
752 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700753 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700754 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700755 break;
756 }
Amy Malochedc3e5572012-09-25 16:39:06 -0700757 spin_unlock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700758}
759
760static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
761{
762 switch (led->id) {
763 case QPNP_ID_WLED:
764 led->cdev.max_brightness = WLED_MAX_LEVEL;
765 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700766 case QPNP_ID_FLASH1_LED0:
767 case QPNP_ID_FLASH1_LED1:
768 led->cdev.max_brightness = led->max_current;
769 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700770 case QPNP_ID_RGB_RED:
771 case QPNP_ID_RGB_GREEN:
772 case QPNP_ID_RGB_BLUE:
773 led->cdev.max_brightness = RGB_MAX_LEVEL;
774 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700775 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700776 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700777 return -EINVAL;
778 }
779
780 return 0;
781}
782
783static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
784{
785 struct qpnp_led_data *led;
786
787 led = container_of(led_cdev, struct qpnp_led_data, cdev);
788
789 return led->cdev.brightness;
790}
791
Asaf Penso55ac8472013-01-21 21:17:37 +0200792static void qpnp_led_turn_off_delayed(struct work_struct *work)
793{
794 struct delayed_work *dwork = to_delayed_work(work);
795 struct qpnp_led_data *led
796 = container_of(dwork, struct qpnp_led_data, dwork);
797
798 led->cdev.brightness = LED_OFF;
799 qpnp_led_set(&led->cdev, led->cdev.brightness);
800}
801
802static void qpnp_led_turn_off(struct qpnp_led_data *led)
803{
804 INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed);
805 schedule_delayed_work(&led->dwork,
806 msecs_to_jiffies(led->turn_off_delay_ms));
807}
808
Amy Malochef3d5a062012-08-16 19:14:11 -0700809static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
810{
811 int rc, i;
812 u8 num_wled_strings;
813
814 num_wled_strings = led->wled_cfg->num_strings;
815
816 /* verify ranges */
817 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
818 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
819 return -EINVAL;
820 }
821
822 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
823 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
824 return -EINVAL;
825 }
826
827 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
828 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
829 return -EINVAL;
830 }
831
832 if ((led->max_current > WLED_MAX_CURR)) {
833 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
834 return -EINVAL;
835 }
836
837 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
838 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
839 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
840 return -EINVAL;
841 }
842
843 /* program over voltage protection threshold */
844 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
845 WLED_OVP_VAL_MASK,
846 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
847 if (rc) {
848 dev_err(&led->spmi_dev->dev,
849 "WLED OVP reg write failed(%d)\n", rc);
850 return rc;
851 }
852
853 /* program current boost limit */
854 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
855 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
856 if (rc) {
857 dev_err(&led->spmi_dev->dev,
858 "WLED boost limit reg write failed(%d)\n", rc);
859 return rc;
860 }
861
862 /* program output feedback */
863 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
864 WLED_OP_FDBCK_MASK,
865 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
866 if (rc) {
867 dev_err(&led->spmi_dev->dev,
868 "WLED fdbck ctrl reg write failed(%d)\n", rc);
869 return rc;
870 }
871
872 /* program switch frequency */
873 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
874 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
875 if (rc) {
876 dev_err(&led->spmi_dev->dev,
877 "WLED switch freq reg write failed(%d)\n", rc);
878 return rc;
879 }
880
881 /* program current sink */
882 if (led->wled_cfg->cs_out_en) {
883 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
884 WLED_CURR_SINK_MASK,
Amy Maloche832d90a2013-01-07 10:15:29 -0800885 (((1 << led->wled_cfg->num_strings) - 1)
886 << WLED_CURR_SINK_SHFT));
Amy Malochef3d5a062012-08-16 19:14:11 -0700887 if (rc) {
888 dev_err(&led->spmi_dev->dev,
889 "WLED curr sink reg write failed(%d)\n", rc);
890 return rc;
891 }
892 }
893
894 /* program high pole capacitance */
895 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
896 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
897 if (rc) {
898 dev_err(&led->spmi_dev->dev,
899 "WLED pole cap reg write failed(%d)\n", rc);
900 return rc;
901 }
902
903 /* program modulator, current mod src and cabc */
904 for (i = 0; i < num_wled_strings; i++) {
905 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
906 WLED_NO_MASK, WLED_EN_MASK);
907 if (rc) {
908 dev_err(&led->spmi_dev->dev,
909 "WLED mod enable reg write failed(%d)\n", rc);
910 return rc;
911 }
912
913 if (led->wled_cfg->dig_mod_gen_en) {
914 rc = qpnp_led_masked_write(led,
Amy Maloched44516e2013-02-14 17:36:34 -0800915 WLED_MOD_SRC_SEL_REG(led->base, i),
Amy Malochef3d5a062012-08-16 19:14:11 -0700916 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
917 if (rc) {
918 dev_err(&led->spmi_dev->dev,
919 "WLED dig mod en reg write failed(%d)\n", rc);
920 }
921 }
922
923 rc = qpnp_led_masked_write(led,
924 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
925 led->max_current);
926 if (rc) {
927 dev_err(&led->spmi_dev->dev,
928 "WLED max current reg write failed(%d)\n", rc);
929 return rc;
930 }
931
932 }
933
934 /* dump wled registers */
Amy Malochea5ca5552012-10-23 13:34:46 -0700935 qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
Amy Malochef3d5a062012-08-16 19:14:11 -0700936
937 return 0;
938}
939
Amy Malochebc97c0d22013-03-24 22:06:16 -0700940static ssize_t led_mode_store(struct device *dev,
941 struct device_attribute *attr,
942 const char *buf, size_t count)
943{
944 struct qpnp_led_data *led;
945 unsigned long state;
946 struct led_classdev *led_cdev = dev_get_drvdata(dev);
947 ssize_t ret = -EINVAL;
948
949 ret = kstrtoul(buf, 10, &state);
950 if (ret)
951 return ret;
952
953 led = container_of(led_cdev, struct qpnp_led_data, cdev);
954
955 /* '1' to enable torch mode; '0' to switch to flash mode */
956 if (state == 1)
957 led->flash_cfg->torch_enable = true;
958 else
959 led->flash_cfg->torch_enable = false;
960
961 return count;
962}
963
964static ssize_t led_strobe_type_store(struct device *dev,
965 struct device_attribute *attr,
966 const char *buf, size_t count)
967{
968 struct qpnp_led_data *led;
969 unsigned long state;
970 struct led_classdev *led_cdev = dev_get_drvdata(dev);
971 ssize_t ret = -EINVAL;
972
973 ret = kstrtoul(buf, 10, &state);
974 if (ret)
975 return ret;
976
977 led = container_of(led_cdev, struct qpnp_led_data, cdev);
978
979 /* '0' for sw strobe; '1' for hw strobe */
980 if (state == 1)
981 led->flash_cfg->strobe_type = 1;
982 else
983 led->flash_cfg->strobe_type = 0;
984
985 return count;
986}
987
988static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
989static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
990
991static struct attribute *led_attrs[] = {
992 &dev_attr_led_mode.attr,
993 &dev_attr_strobe.attr,
Amy Maloche12ad6f32013-04-02 14:39:24 -0700994 NULL
Amy Malochebc97c0d22013-03-24 22:06:16 -0700995};
996
997static const struct attribute_group led_attr_group = {
998 .attrs = led_attrs,
999};
1000
Amy Maloche864a6d52012-10-03 15:58:12 -07001001static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
1002{
1003 int rc;
1004
1005 rc = qpnp_led_masked_write(led,
1006 FLASH_LED_STROBE_CTRL(led->base),
1007 FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
1008 if (rc) {
1009 dev_err(&led->spmi_dev->dev,
1010 "LED %d flash write failed(%d)\n", led->id, rc);
1011 return rc;
1012 }
1013 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
1014 FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
1015 if (rc) {
1016 dev_err(&led->spmi_dev->dev,
1017 "Enable reg write failed(%d)\n", rc);
1018 return rc;
1019 }
1020
1021 /* Set flash safety timer */
1022 rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
1023 FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
1024 if (rc) {
1025 dev_err(&led->spmi_dev->dev,
1026 "Safety timer reg write failed(%d)\n", rc);
1027 return rc;
1028 }
1029
1030 /* Set max current */
1031 rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
1032 FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
1033 if (rc) {
1034 dev_err(&led->spmi_dev->dev,
1035 "Max current reg write failed(%d)\n", rc);
1036 return rc;
1037 }
1038 /* Set clamp current */
1039 rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
1040 FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
1041 if (rc) {
1042 dev_err(&led->spmi_dev->dev,
1043 "Clamp current reg write failed(%d)\n", rc);
1044 return rc;
1045 }
1046
1047 /* Set timer control - safety or watchdog */
1048 if (led->flash_cfg->safety_timer)
1049 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
1050 FLASH_TMR_MASK, FLASH_TMR_SAFETY);
1051 else
1052 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
1053 FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
1054 if (rc) {
1055 dev_err(&led->spmi_dev->dev,
1056 "LED timer ctrl reg write failed(%d)\n", rc);
1057 return rc;
1058 }
1059 /* Set headroom */
1060 rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
1061 FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
1062 if (rc) {
1063 dev_err(&led->spmi_dev->dev,
1064 "Headroom reg write failed(%d)\n", rc);
1065 return rc;
1066 }
1067
1068 /* Set mask enable */
1069 rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
1070 FLASH_MASK_REG_MASK, FLASH_MASK_1);
1071 if (rc) {
1072 dev_err(&led->spmi_dev->dev,
1073 "Mask enable reg write failed(%d)\n", rc);
1074 return rc;
1075 }
1076
1077 /* Set startup delay */
1078 rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
1079 FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
1080 if (rc) {
1081 dev_err(&led->spmi_dev->dev,
1082 "Startup delay reg write failed(%d)\n", rc);
1083 return rc;
1084 }
1085
1086 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
1087 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
1088 if (rc) {
1089 dev_err(&led->spmi_dev->dev,
1090 "Vreg OK reg write failed(%d)\n", rc);
1091 return rc;
1092 }
1093
Amy Malochebc97c0d22013-03-24 22:06:16 -07001094 /* Set led current and disable module */
Amy Maloche864a6d52012-10-03 15:58:12 -07001095 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
1096 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
1097 if (rc) {
1098 dev_err(&led->spmi_dev->dev,
1099 "Current reg write failed(%d)\n", rc);
1100 return rc;
1101 }
1102
1103 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
Amy Maloche38b9aae2013-02-07 12:15:34 -08001104 FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
Amy Maloche864a6d52012-10-03 15:58:12 -07001105 if (rc) {
1106 dev_err(&led->spmi_dev->dev,
1107 "Enable reg write failed(%d)\n", rc);
1108 return rc;
1109 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07001110
1111 led->flash_cfg->torch_enable = false;
1112 led->flash_cfg->strobe_type = 0;
1113
Amy Maloche864a6d52012-10-03 15:58:12 -07001114 /* dump flash registers */
1115 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
1116
1117 return 0;
1118}
1119
Amy Malocheeea7b592012-10-03 15:59:36 -07001120static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
1121{
1122 int rc, start_idx, idx_len;
1123
1124 rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
1125 RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
1126 if (rc) {
1127 dev_err(&led->spmi_dev->dev,
1128 "Failed to write led source select register\n");
1129 return rc;
1130 }
1131
1132 if (led->rgb_cfg->pwm_channel != -1) {
1133 led->rgb_cfg->pwm_dev =
1134 pwm_request(led->rgb_cfg->pwm_channel,
1135 led->cdev.name);
1136
1137 if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
1138 dev_err(&led->spmi_dev->dev,
1139 "could not acquire PWM Channel %d, " \
1140 "error %ld\n",
1141 led->rgb_cfg->pwm_channel,
1142 PTR_ERR(led->rgb_cfg->pwm_dev));
1143 led->rgb_cfg->pwm_dev = NULL;
1144 return -ENODEV;
1145 }
1146
1147 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1148 start_idx =
1149 led->rgb_cfg->duty_cycles->start_idx;
1150 idx_len =
1151 led->rgb_cfg->duty_cycles->num_duty_pcts;
1152
1153 if (idx_len >= PWM_LUT_MAX_SIZE &&
1154 start_idx) {
1155 dev_err(&led->spmi_dev->dev,
1156 "Wrong LUT size or index\n");
1157 return -EINVAL;
1158 }
1159 if ((start_idx + idx_len) >
1160 PWM_LUT_MAX_SIZE) {
1161 dev_err(&led->spmi_dev->dev,
1162 "Exceed LUT limit\n");
1163 return -EINVAL;
1164 }
1165 rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
Amy Maloche013b35b2013-03-19 12:29:11 -07001166 PM_PWM_PERIOD_MIN, /* ignored by hardware */
Amy Malocheeea7b592012-10-03 15:59:36 -07001167 led->rgb_cfg->duty_cycles->duty_pcts,
1168 led->rgb_cfg->lut_params);
1169 if (rc < 0) {
1170 dev_err(&led->spmi_dev->dev, "Failed to " \
1171 "configure pwm LUT\n");
1172 return rc;
1173 }
1174 }
1175 } else {
1176 dev_err(&led->spmi_dev->dev,
1177 "Invalid PWM channel\n");
1178 return -EINVAL;
1179 }
1180
1181 /* Initialize led for use in auto trickle charging mode */
1182 rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
1183 led->rgb_cfg->enable, led->rgb_cfg->enable);
1184
1185 return 0;
1186}
1187
Amy Malochef3d5a062012-08-16 19:14:11 -07001188static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
1189{
1190 int rc;
1191
1192 switch (led->id) {
1193 case QPNP_ID_WLED:
1194 rc = qpnp_wled_init(led);
1195 if (rc)
Amy Malochea5ca5552012-10-23 13:34:46 -07001196 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -07001197 "WLED initialize failed(%d)\n", rc);
1198 break;
Amy Maloche864a6d52012-10-03 15:58:12 -07001199 case QPNP_ID_FLASH1_LED0:
1200 case QPNP_ID_FLASH1_LED1:
1201 rc = qpnp_flash_init(led);
1202 if (rc)
1203 dev_err(&led->spmi_dev->dev,
1204 "FLASH initialize failed(%d)\n", rc);
1205 break;
Amy Malocheeea7b592012-10-03 15:59:36 -07001206 case QPNP_ID_RGB_RED:
1207 case QPNP_ID_RGB_GREEN:
1208 case QPNP_ID_RGB_BLUE:
1209 rc = qpnp_rgb_init(led);
1210 if (rc)
1211 dev_err(&led->spmi_dev->dev,
1212 "RGB initialize failed(%d)\n", rc);
1213 break;
Amy Malochef3d5a062012-08-16 19:14:11 -07001214 default:
Amy Malochea5ca5552012-10-23 13:34:46 -07001215 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malocheeea7b592012-10-03 15:59:36 -07001216 return -EINVAL;
Amy Malochef3d5a062012-08-16 19:14:11 -07001217 }
1218
Amy Malocheeea7b592012-10-03 15:59:36 -07001219 return 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001220}
1221
Amy Malochea5ca5552012-10-23 13:34:46 -07001222static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
1223 struct device_node *node)
1224{
1225 int rc;
Asaf Penso55ac8472013-01-21 21:17:37 +02001226 u32 val;
Amy Malochea5ca5552012-10-23 13:34:46 -07001227 const char *temp_string;
1228
1229 led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
1230 rc = of_property_read_string(node, "linux,default-trigger",
1231 &temp_string);
1232 if (!rc)
1233 led->cdev.default_trigger = temp_string;
1234 else if (rc != -EINVAL)
1235 return rc;
1236
1237 led->default_on = false;
1238 rc = of_property_read_string(node, "qcom,default-state",
1239 &temp_string);
1240 if (!rc) {
1241 if (strncmp(temp_string, "on", sizeof("on")) == 0)
1242 led->default_on = true;
1243 } else if (rc != -EINVAL)
1244 return rc;
1245
Asaf Penso55ac8472013-01-21 21:17:37 +02001246 led->turn_off_delay_ms = 0;
1247 rc = of_property_read_u32(node, "qcom,turn-off-delay-ms", &val);
1248 if (!rc)
1249 led->turn_off_delay_ms = val;
1250 else if (rc != -EINVAL)
1251 return rc;
1252
Amy Malochea5ca5552012-10-23 13:34:46 -07001253 return 0;
1254}
1255
Amy Malochef3d5a062012-08-16 19:14:11 -07001256/*
1257 * Handlers for alternative sources of platform_data
1258 */
1259static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
1260 struct device_node *node)
1261{
1262 u32 val;
1263 int rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001264
1265 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
1266 sizeof(struct wled_config_data), GFP_KERNEL);
1267 if (!led->wled_cfg) {
1268 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1269 return -ENOMEM;
1270 }
1271
Amy Malochef3d5a062012-08-16 19:14:11 -07001272 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
1273 rc = of_property_read_u32(node, "qcom,num-strings", &val);
1274 if (!rc)
1275 led->wled_cfg->num_strings = (u8) val;
1276 else if (rc != -EINVAL)
1277 return rc;
1278
1279 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
1280 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
1281 if (!rc)
1282 led->wled_cfg->ovp_val = (u8) val;
1283 else if (rc != -EINVAL)
1284 return rc;
1285
1286 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
1287 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
1288 if (!rc)
1289 led->wled_cfg->boost_curr_lim = (u8) val;
1290 else if (rc != -EINVAL)
1291 return rc;
1292
1293 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
1294 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
1295 if (!rc)
1296 led->wled_cfg->cp_select = (u8) val;
1297 else if (rc != -EINVAL)
1298 return rc;
1299
1300 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
1301 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
1302 if (!rc)
1303 led->wled_cfg->ctrl_delay_us = (u8) val;
1304 else if (rc != -EINVAL)
1305 return rc;
1306
Amy Malochebd687672013-03-18 11:23:45 -07001307 led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
1308 rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
1309 if (!rc)
1310 led->wled_cfg->op_fdbck = (u8) val;
1311 else if (rc != -EINVAL)
1312 return rc;
1313
Amy Malochef3d5a062012-08-16 19:14:11 -07001314 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
1315 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
1316 if (!rc)
1317 led->wled_cfg->switch_freq = (u8) val;
1318 else if (rc != -EINVAL)
1319 return rc;
1320
1321 led->wled_cfg->dig_mod_gen_en =
1322 of_property_read_bool(node, "qcom,dig-mod-gen-en");
1323
1324 led->wled_cfg->cs_out_en =
1325 of_property_read_bool(node, "qcom,cs-out-en");
1326
Amy Malochef3d5a062012-08-16 19:14:11 -07001327 return 0;
1328}
1329
Amy Maloche864a6d52012-10-03 15:58:12 -07001330static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
1331 struct device_node *node)
1332{
1333 int rc;
1334 u32 val;
1335
1336 led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
1337 sizeof(struct flash_config_data), GFP_KERNEL);
1338 if (!led->flash_cfg) {
1339 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1340 return -ENOMEM;
1341 }
1342
1343 if (led->id == QPNP_ID_FLASH1_LED0) {
1344 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1345 led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
1346 led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
1347 led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
1348 } else if (led->id == QPNP_ID_FLASH1_LED1) {
1349 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1350 led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
1351 led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
1352 led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
1353 } else {
1354 dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
1355 return -EINVAL;
1356 }
1357
1358 rc = of_property_read_u32(node, "qcom,current", &val);
1359 if (!rc)
1360 led->flash_cfg->current_prgm = (val *
1361 FLASH_MAX_LEVEL / led->max_current);
1362 else
1363 return -EINVAL;
1364
1365 rc = of_property_read_u32(node, "qcom,headroom", &val);
1366 if (!rc)
1367 led->flash_cfg->headroom = (u8) val;
1368 else if (rc == -EINVAL)
1369 led->flash_cfg->headroom = HEADROOM_300mV;
1370 else
1371 return rc;
1372
1373 rc = of_property_read_u32(node, "qcom,duration", &val);
1374 if (!rc)
1375 led->flash_cfg->duration = (((u8) val) - 10) / 10;
1376 else if (rc == -EINVAL)
1377 led->flash_cfg->duration = FLASH_DURATION_200ms;
1378 else
1379 return rc;
1380
1381 rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
1382 if (!rc)
1383 led->flash_cfg->clamp_curr = (val *
1384 FLASH_MAX_LEVEL / led->max_current);
1385 else if (rc == -EINVAL)
1386 led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
1387 else
1388 return rc;
1389
1390 rc = of_property_read_u32(node, "qcom,startup-dly", &val);
1391 if (!rc)
1392 led->flash_cfg->startup_dly = (u8) val;
1393 else if (rc == -EINVAL)
1394 led->flash_cfg->startup_dly = DELAY_32us;
1395 else
1396 return rc;
1397
1398 led->flash_cfg->safety_timer =
1399 of_property_read_bool(node, "qcom,safety-timer");
1400
1401 return 0;
1402}
1403
Amy Malocheeea7b592012-10-03 15:59:36 -07001404static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
1405 struct device_node *node)
1406{
1407 struct property *prop;
1408 int rc, i;
1409 u32 val;
1410 u8 *temp_cfg;
1411
1412 led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
1413 sizeof(struct rgb_config_data), GFP_KERNEL);
1414 if (!led->rgb_cfg) {
1415 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1416 return -ENOMEM;
1417 }
1418
1419 if (led->id == QPNP_ID_RGB_RED)
1420 led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
1421 else if (led->id == QPNP_ID_RGB_GREEN)
1422 led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
1423 else if (led->id == QPNP_ID_RGB_BLUE)
1424 led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
1425 else
1426 return -EINVAL;
1427
1428 rc = of_property_read_u32(node, "qcom,mode", &val);
1429 if (!rc)
1430 led->rgb_cfg->mode = (u8) val;
1431 else
1432 return rc;
1433
1434 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1435 if (!rc)
1436 led->rgb_cfg->pwm_channel = (u8) val;
1437 else
1438 return rc;
1439
Amy Maloche013b35b2013-03-19 12:29:11 -07001440 if (led->rgb_cfg->mode == RGB_MODE_PWM) {
1441 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1442 if (!rc)
1443 led->rgb_cfg->pwm_period_us = val;
1444 else
1445 return rc;
1446 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001447
1448 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1449 led->rgb_cfg->duty_cycles =
1450 devm_kzalloc(&led->spmi_dev->dev,
1451 sizeof(struct pwm_duty_cycles), GFP_KERNEL);
1452 if (!led->rgb_cfg->duty_cycles) {
1453 dev_err(&led->spmi_dev->dev,
1454 "Unable to allocate memory\n");
1455 return -ENOMEM;
1456 }
1457
Amy Malocheeea7b592012-10-03 15:59:36 -07001458 prop = of_find_property(node, "qcom,duty-pcts",
1459 &led->rgb_cfg->duty_cycles->num_duty_pcts);
1460 if (!prop) {
1461 dev_err(&led->spmi_dev->dev, "Looking up property " \
1462 "node qcom,duty-pcts failed\n");
1463 return -ENODEV;
1464 } else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
1465 dev_err(&led->spmi_dev->dev, "Invalid length of " \
1466 "duty pcts\n");
1467 return -EINVAL;
1468 }
1469
1470 led->rgb_cfg->duty_cycles->duty_pcts =
1471 devm_kzalloc(&led->spmi_dev->dev,
1472 sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
1473 GFP_KERNEL);
1474 if (!led->rgb_cfg->duty_cycles->duty_pcts) {
1475 dev_err(&led->spmi_dev->dev,
1476 "Unable to allocate memory\n");
1477 return -ENOMEM;
1478 }
1479
1480 temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1481 led->rgb_cfg->duty_cycles->num_duty_pcts *
1482 sizeof(u8), GFP_KERNEL);
1483 if (!temp_cfg) {
1484 dev_err(&led->spmi_dev->dev, "Failed to allocate " \
1485 "memory for duty pcts\n");
1486 return -ENOMEM;
1487 }
1488
1489 memcpy(temp_cfg, prop->value,
1490 led->rgb_cfg->duty_cycles->num_duty_pcts);
1491
1492 for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
1493 led->rgb_cfg->duty_cycles->duty_pcts[i] =
1494 (int) temp_cfg[i];
1495
1496 rc = of_property_read_u32(node, "qcom,start-idx", &val);
1497 if (!rc) {
1498 led->rgb_cfg->lut_params.start_idx = (u8) val;
1499 led->rgb_cfg->duty_cycles->start_idx = (u8) val;
1500 } else
1501 return rc;
1502
Amy Maloche013b35b2013-03-19 12:29:11 -07001503 led->rgb_cfg->lut_params.lut_pause_hi = 0;
1504 rc = of_property_read_u32(node, "qcom,pause-hi", &val);
1505 if (!rc)
1506 led->rgb_cfg->lut_params.lut_pause_hi = (u8) val;
1507 else if (rc != -EINVAL)
1508 return rc;
1509
1510 led->rgb_cfg->lut_params.lut_pause_lo = 0;
1511 rc = of_property_read_u32(node, "qcom,pause-lo", &val);
1512 if (!rc)
1513 led->rgb_cfg->lut_params.lut_pause_lo = (u8) val;
1514 else if (rc != -EINVAL)
1515 return rc;
1516
1517 led->rgb_cfg->lut_params.ramp_step_ms =
1518 QPNP_LUT_RAMP_STEP_DEFAULT;
1519 rc = of_property_read_u32(node, "qcom,ramp-step-ms", &val);
1520 if (!rc)
1521 led->rgb_cfg->lut_params.ramp_step_ms = (u8) val;
1522 else if (rc != -EINVAL)
1523 return rc;
1524
1525 led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
1526 rc = of_property_read_u32(node, "qcom,lut-flags", &val);
1527 if (!rc)
1528 led->rgb_cfg->lut_params.flags = (u8) val;
1529 else if (rc != -EINVAL)
1530 return rc;
1531
Amy Malocheeea7b592012-10-03 15:59:36 -07001532 led->rgb_cfg->lut_params.idx_len =
1533 led->rgb_cfg->duty_cycles->num_duty_pcts;
Amy Malocheeea7b592012-10-03 15:59:36 -07001534 }
1535
1536 return 0;
1537}
1538
Amy Malochef3d5a062012-08-16 19:14:11 -07001539static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
1540{
Amy Malochef9490c62012-11-27 19:26:04 -08001541 struct qpnp_led_data *led, *led_array;
Amy Malochef3d5a062012-08-16 19:14:11 -07001542 struct resource *led_resource;
Amy Malochea5ca5552012-10-23 13:34:46 -07001543 struct device_node *node, *temp;
Amy Malochef9490c62012-11-27 19:26:04 -08001544 int rc, i, num_leds = 0, parsed_leds = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001545 const char *led_label;
1546
Amy Malochea5ca5552012-10-23 13:34:46 -07001547 node = spmi->dev.of_node;
1548 if (node == NULL)
1549 return -ENODEV;
1550
1551 temp = NULL;
1552 while ((temp = of_get_next_child(node, temp)))
1553 num_leds++;
1554
Amy Malochef9490c62012-11-27 19:26:04 -08001555 if (!num_leds)
1556 return -ECHILD;
1557
1558 led_array = devm_kzalloc(&spmi->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001559 (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
Amy Malochef9490c62012-11-27 19:26:04 -08001560 if (!led_array) {
Amy Malochef3d5a062012-08-16 19:14:11 -07001561 dev_err(&spmi->dev, "Unable to allocate memory\n");
1562 return -ENOMEM;
1563 }
1564
Amy Malochea5ca5552012-10-23 13:34:46 -07001565 for_each_child_of_node(node, temp) {
Amy Malochef9490c62012-11-27 19:26:04 -08001566 led = &led_array[parsed_leds];
1567 led->num_leds = num_leds;
Amy Malochea5ca5552012-10-23 13:34:46 -07001568 led->spmi_dev = spmi;
Amy Malochef3d5a062012-08-16 19:14:11 -07001569
Amy Malochea5ca5552012-10-23 13:34:46 -07001570 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
1571 if (!led_resource) {
1572 dev_err(&spmi->dev, "Unable to get LED base address\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001573 rc = -ENXIO;
1574 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001575 }
1576 led->base = led_resource->start;
Amy Malochef3d5a062012-08-16 19:14:11 -07001577
Amy Malochea5ca5552012-10-23 13:34:46 -07001578 rc = of_property_read_string(temp, "label", &led_label);
Amy Malochef3d5a062012-08-16 19:14:11 -07001579 if (rc < 0) {
1580 dev_err(&led->spmi_dev->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001581 "Failure reading label, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001582 goto fail_id_check;
Amy Malochef3d5a062012-08-16 19:14:11 -07001583 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001584
1585 rc = of_property_read_string(temp, "linux,name",
1586 &led->cdev.name);
1587 if (rc < 0) {
1588 dev_err(&led->spmi_dev->dev,
1589 "Failure reading led name, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001590 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001591 }
1592
1593 rc = of_property_read_u32(temp, "qcom,max-current",
1594 &led->max_current);
1595 if (rc < 0) {
1596 dev_err(&led->spmi_dev->dev,
1597 "Failure reading max_current, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001598 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001599 }
1600
1601 rc = of_property_read_u32(temp, "qcom,id", &led->id);
1602 if (rc < 0) {
1603 dev_err(&led->spmi_dev->dev,
1604 "Failure reading led id, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001605 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001606 }
1607
1608 rc = qpnp_get_common_configs(led, temp);
1609 if (rc) {
1610 dev_err(&led->spmi_dev->dev,
1611 "Failure reading common led configuration," \
1612 " rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001613 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001614 }
1615
1616 led->cdev.brightness_set = qpnp_led_set;
1617 led->cdev.brightness_get = qpnp_led_get;
1618
1619 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
1620 rc = qpnp_get_config_wled(led, temp);
1621 if (rc < 0) {
1622 dev_err(&led->spmi_dev->dev,
1623 "Unable to read wled config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001624 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001625 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001626 } else if (strncmp(led_label, "flash", sizeof("flash"))
1627 == 0) {
1628 rc = qpnp_get_config_flash(led, temp);
1629 if (rc < 0) {
1630 dev_err(&led->spmi_dev->dev,
1631 "Unable to read flash config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001632 goto fail_id_check;
Amy Maloche864a6d52012-10-03 15:58:12 -07001633 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001634 } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
1635 rc = qpnp_get_config_rgb(led, temp);
1636 if (rc < 0) {
1637 dev_err(&led->spmi_dev->dev,
1638 "Unable to read rgb config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001639 goto fail_id_check;
Amy Malocheeea7b592012-10-03 15:59:36 -07001640 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001641 } else {
1642 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001643 rc = -EINVAL;
1644 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001645 }
1646
1647 spin_lock_init(&led->lock);
1648
1649 rc = qpnp_led_initialize(led);
1650 if (rc < 0)
1651 goto fail_id_check;
1652
1653 rc = qpnp_led_set_max_brightness(led);
1654 if (rc < 0)
1655 goto fail_id_check;
1656
1657 rc = led_classdev_register(&spmi->dev, &led->cdev);
1658 if (rc) {
1659 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
1660 led->id, rc);
1661 goto fail_id_check;
1662 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07001663
1664 if (led->id == QPNP_ID_FLASH1_LED0 ||
1665 led->id == QPNP_ID_FLASH1_LED1) {
1666 rc = sysfs_create_group(&led->cdev.dev->kobj,
1667 &led_attr_group);
1668 if (rc)
1669 goto fail_id_check;
1670
1671 }
1672
Amy Malochea5ca5552012-10-23 13:34:46 -07001673 /* configure default state */
Asaf Penso55ac8472013-01-21 21:17:37 +02001674 if (led->default_on) {
Amy Malochea5ca5552012-10-23 13:34:46 -07001675 led->cdev.brightness = led->cdev.max_brightness;
Asaf Penso55ac8472013-01-21 21:17:37 +02001676 if (led->turn_off_delay_ms > 0)
1677 qpnp_led_turn_off(led);
1678 } else
Amy Malochea5ca5552012-10-23 13:34:46 -07001679 led->cdev.brightness = LED_OFF;
1680
1681 qpnp_led_set(&led->cdev, led->cdev.brightness);
Amy Malochef9490c62012-11-27 19:26:04 -08001682
1683 parsed_leds++;
Amy Malochef3d5a062012-08-16 19:14:11 -07001684 }
Amy Malochef9490c62012-11-27 19:26:04 -08001685 dev_set_drvdata(&spmi->dev, led_array);
Amy Malochef3d5a062012-08-16 19:14:11 -07001686 return 0;
1687
1688fail_id_check:
Amy Malochef9490c62012-11-27 19:26:04 -08001689 for (i = 0; i < parsed_leds; i++)
1690 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001691 return rc;
1692}
1693
1694static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
1695{
Amy Malochef9490c62012-11-27 19:26:04 -08001696 struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
1697 int i, parsed_leds = led_array->num_leds;
Amy Malochef3d5a062012-08-16 19:14:11 -07001698
Amy Malochebc97c0d22013-03-24 22:06:16 -07001699 for (i = 0; i < parsed_leds; i++) {
Amy Malochef9490c62012-11-27 19:26:04 -08001700 led_classdev_unregister(&led_array[i].cdev);
Amy Malochebc97c0d22013-03-24 22:06:16 -07001701 switch (led_array[i].id) {
1702 case QPNP_ID_WLED:
1703 break;
1704 case QPNP_ID_FLASH1_LED0:
1705 case QPNP_ID_FLASH1_LED1:
1706 sysfs_remove_group(&led_array[i].cdev.dev->kobj,
1707 &led_attr_group);
1708 break;
1709 case QPNP_ID_RGB_RED:
1710 case QPNP_ID_RGB_GREEN:
1711 case QPNP_ID_RGB_BLUE:
1712 default:
1713 dev_err(&led_array[i].spmi_dev->dev,
1714 "Invalid LED(%d)\n",
1715 led_array[i].id);
1716 return -EINVAL;
1717 }
1718 }
Amy Malochef3d5a062012-08-16 19:14:11 -07001719
1720 return 0;
1721}
1722static struct of_device_id spmi_match_table[] = {
1723 { .compatible = "qcom,leds-qpnp",
1724 }
1725};
1726
1727static struct spmi_driver qpnp_leds_driver = {
1728 .driver = {
1729 .name = "qcom,leds-qpnp",
1730 .of_match_table = spmi_match_table,
1731 },
1732 .probe = qpnp_leds_probe,
1733 .remove = __devexit_p(qpnp_leds_remove),
1734};
1735
1736static int __init qpnp_led_init(void)
1737{
1738 return spmi_driver_register(&qpnp_leds_driver);
1739}
1740module_init(qpnp_led_init);
1741
1742static void __exit qpnp_led_exit(void)
1743{
1744 spmi_driver_unregister(&qpnp_leds_driver);
1745}
1746module_exit(qpnp_led_exit);
1747
1748MODULE_DESCRIPTION("QPNP LEDs driver");
1749MODULE_LICENSE("GPL v2");
1750MODULE_ALIAS("leds:leds-qpnp");
Amy Maloche864a6d52012-10-03 15:58:12 -07001751