blob: 96af169c2b20be02a6a69490338e732130957686 [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)
158#define PWM_LUT_MAX_SIZE 63
159#define RGB_LED_DISABLE 0x00
160
Amy Malochef3d5a062012-08-16 19:14:11 -0700161/**
162 * enum qpnp_leds - QPNP supported led ids
163 * @QPNP_ID_WLED - White led backlight
164 */
165enum qpnp_leds {
Amy Maloche864a6d52012-10-03 15:58:12 -0700166 QPNP_ID_WLED = 0,
167 QPNP_ID_FLASH1_LED0,
168 QPNP_ID_FLASH1_LED1,
Amy Malocheeea7b592012-10-03 15:59:36 -0700169 QPNP_ID_RGB_RED,
170 QPNP_ID_RGB_GREEN,
171 QPNP_ID_RGB_BLUE,
Amy Maloche864a6d52012-10-03 15:58:12 -0700172 QPNP_ID_MAX,
Amy Malochef3d5a062012-08-16 19:14:11 -0700173};
174
175/* current boost limit */
176enum wled_current_boost_limit {
177 WLED_CURR_LIMIT_105mA,
178 WLED_CURR_LIMIT_385mA,
179 WLED_CURR_LIMIT_525mA,
180 WLED_CURR_LIMIT_805mA,
181 WLED_CURR_LIMIT_980mA,
182 WLED_CURR_LIMIT_1260mA,
183 WLED_CURR_LIMIT_1400mA,
184 WLED_CURR_LIMIT_1680mA,
185};
186
187/* over voltage protection threshold */
188enum wled_ovp_threshold {
189 WLED_OVP_35V,
190 WLED_OVP_32V,
191 WLED_OVP_29V,
192 WLED_OVP_37V,
193};
194
195/* switch frquency */
196enum wled_switch_freq {
197 WLED_800kHz = 0,
198 WLED_960kHz,
199 WLED_1600kHz,
200 WLED_3200kHz,
201};
202
Amy Maloche864a6d52012-10-03 15:58:12 -0700203enum flash_headroom {
204 HEADROOM_250mV = 0,
205 HEADROOM_300mV,
206 HEADROOM_400mV,
207 HEADROOM_500mV,
208};
209
210enum flash_startup_dly {
211 DELAY_10us = 0,
212 DELAY_32us,
213 DELAY_64us,
214 DELAY_128us,
215};
216
Amy Malocheeea7b592012-10-03 15:59:36 -0700217enum rgb_mode {
218 RGB_MODE_PWM = 0,
219 RGB_MODE_LPG,
220};
221
Amy Malochef3d5a062012-08-16 19:14:11 -0700222static u8 wled_debug_regs[] = {
223 /* common registers */
224 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
225 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
226 /* LED1 */
227 0x60, 0x61, 0x62, 0x63, 0x66,
Amy Malochea5ca5552012-10-23 13:34:46 -0700228 /* LED2 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700229 0x70, 0x71, 0x72, 0x73, 0x76,
Amy Malochea5ca5552012-10-23 13:34:46 -0700230 /* LED3 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700231 0x80, 0x81, 0x82, 0x83, 0x86,
232};
233
Amy Maloche864a6d52012-10-03 15:58:12 -0700234static u8 flash_debug_regs[] = {
235 0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
236 0x4f, 0x46, 0x47,
237};
238
Amy Malocheeea7b592012-10-03 15:59:36 -0700239static u8 rgb_pwm_debug_regs[] = {
240 0x45, 0x46, 0x47,
241};
Amy Malochef3d5a062012-08-16 19:14:11 -0700242/**
243 * wled_config_data - wled configuration data
244 * @num_strings - number of wled strings supported
245 * @ovp_val - over voltage protection threshold
246 * @boost_curr_lim - boot current limit
247 * @cp_select - high pole capacitance
248 * @ctrl_delay_us - delay in activation of led
249 * @dig_mod_gen_en - digital module generator
250 * @cs_out_en - current sink output enable
251 * @op_fdbck - selection of output as feedback for the boost
252 */
253struct wled_config_data {
254 u8 num_strings;
255 u8 ovp_val;
256 u8 boost_curr_lim;
257 u8 cp_select;
258 u8 ctrl_delay_us;
259 u8 switch_freq;
Amy Malochebd687672013-03-18 11:23:45 -0700260 u8 op_fdbck;
Amy Malochef3d5a062012-08-16 19:14:11 -0700261 bool dig_mod_gen_en;
262 bool cs_out_en;
Amy Malochef3d5a062012-08-16 19:14:11 -0700263};
264
265/**
Amy Maloche864a6d52012-10-03 15:58:12 -0700266 * flash_config_data - flash configuration data
267 * @current_prgm - current to be programmed, scaled by max level
268 * @clamp_curr - clamp current to use
269 * @headroom - headroom value to use
270 * @duration - duration of the flash
271 * @enable_module - enable address for particular flash
272 * @trigger_flash - trigger flash
273 * @startup_dly - startup delay for flash
Amy Malochebc97c0d22013-03-24 22:06:16 -0700274 * @strobe_type - select between sw and hw strobe
Amy Maloche864a6d52012-10-03 15:58:12 -0700275 * @current_addr - address to write for current
276 * @second_addr - address of secondary flash to be written
277 * @safety_timer - enable safety timer or watchdog timer
Amy Malochebc97c0d22013-03-24 22:06:16 -0700278 * @torch_enable - enable flash LED torch mode
Amy Maloche864a6d52012-10-03 15:58:12 -0700279 */
280struct flash_config_data {
281 u8 current_prgm;
282 u8 clamp_curr;
283 u8 headroom;
284 u8 duration;
285 u8 enable_module;
286 u8 trigger_flash;
287 u8 startup_dly;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700288 u8 strobe_type;
Amy Maloche864a6d52012-10-03 15:58:12 -0700289 u16 current_addr;
290 u16 second_addr;
291 bool safety_timer;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700292 bool torch_enable;
Amy Maloche864a6d52012-10-03 15:58:12 -0700293};
294
295/**
Amy Malocheeea7b592012-10-03 15:59:36 -0700296 * rgb_config_data - rgb configuration data
297 * @lut_params - lut parameters to be used by pwm driver
298 * @pwm_device - pwm device
299 * @pwm_channel - pwm channel to be configured for led
300 * @pwm_period_us - period for pwm, in us
301 * @mode - mode the led operates in
302 */
303struct rgb_config_data {
304 struct lut_params lut_params;
305 struct pwm_device *pwm_dev;
306 int pwm_channel;
307 u32 pwm_period_us;
308 struct pwm_duty_cycles *duty_cycles;
309 u8 mode;
310 u8 enable;
311};
312
313/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700314 * struct qpnp_led_data - internal led data structure
315 * @led_classdev - led class device
Asaf Penso55ac8472013-01-21 21:17:37 +0200316 * @delayed_work - delayed work for turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700317 * @id - led index
318 * @base_reg - base register given in device tree
319 * @lock - to protect the transactions
320 * @reg - cached value of led register
Amy Malochea5ca5552012-10-23 13:34:46 -0700321 * @num_leds - number of leds in the module
Amy Malochef3d5a062012-08-16 19:14:11 -0700322 * @max_current - maximum current supported by LED
323 * @default_on - true: default state max, false, default state 0
Asaf Penso55ac8472013-01-21 21:17:37 +0200324 * @turn_off_delay_ms - number of msec before turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700325 */
326struct qpnp_led_data {
327 struct led_classdev cdev;
328 struct spmi_device *spmi_dev;
Asaf Penso55ac8472013-01-21 21:17:37 +0200329 struct delayed_work dwork;
Amy Malochef3d5a062012-08-16 19:14:11 -0700330 int id;
331 u16 base;
332 u8 reg;
Amy Malochea5ca5552012-10-23 13:34:46 -0700333 u8 num_leds;
Amy Malochedc3e5572012-09-25 16:39:06 -0700334 spinlock_t lock;
Amy Malochef3d5a062012-08-16 19:14:11 -0700335 struct wled_config_data *wled_cfg;
Amy Maloche864a6d52012-10-03 15:58:12 -0700336 struct flash_config_data *flash_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700337 struct rgb_config_data *rgb_cfg;
Amy Malochef3d5a062012-08-16 19:14:11 -0700338 int max_current;
339 bool default_on;
Asaf Penso55ac8472013-01-21 21:17:37 +0200340 int turn_off_delay_ms;
Amy Malochef3d5a062012-08-16 19:14:11 -0700341};
342
343static int
344qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
345{
346 int rc;
347 u8 reg;
348
349 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
350 addr, &reg, 1);
351 if (rc) {
352 dev_err(&led->spmi_dev->dev,
353 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
354 }
355
356 reg &= ~mask;
357 reg |= val;
358
359 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
360 addr, &reg, 1);
361 if (rc)
362 dev_err(&led->spmi_dev->dev,
363 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
364 return rc;
365}
366
Amy Malochea5ca5552012-10-23 13:34:46 -0700367static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
368{
369 int i;
370 u8 val;
371
372 pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
373 for (i = 0; i < array_size; i++) {
374 spmi_ext_register_readl(led->spmi_dev->ctrl,
375 led->spmi_dev->sid,
376 led->base + regs[i],
377 &val, sizeof(val));
378 pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
379 }
380 pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
381}
382
Amy Malochef3d5a062012-08-16 19:14:11 -0700383static int qpnp_wled_set(struct qpnp_led_data *led)
384{
Amy Maloched55fdb82013-02-26 18:11:57 -0800385 int rc, duty, level;
386 u8 val, i, num_wled_strings;
Amy Malochef3d5a062012-08-16 19:14:11 -0700387
388 level = led->cdev.brightness;
389
390 if (level > WLED_MAX_LEVEL)
391 level = WLED_MAX_LEVEL;
392 if (level == 0) {
393 val = WLED_BOOST_OFF;
394 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
395 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
396 &val, 1);
397 if (rc) {
398 dev_err(&led->spmi_dev->dev,
399 "WLED write ctrl reg failed(%d)\n", rc);
400 return rc;
401 }
402 } else {
403 val = WLED_BOOST_ON;
404 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
405 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
406 &val, 1);
407 if (rc) {
408 dev_err(&led->spmi_dev->dev,
409 "WLED write ctrl reg failed(%d)\n", rc);
410 return rc;
411 }
412 }
413
414 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
415
416 num_wled_strings = led->wled_cfg->num_strings;
417
418 /* program brightness control registers */
419 for (i = 0; i < num_wled_strings; i++) {
420 rc = qpnp_led_masked_write(led,
421 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
422 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
423 if (rc) {
424 dev_err(&led->spmi_dev->dev,
425 "WLED set brightness MSB failed(%d)\n", rc);
426 return rc;
427 }
428 val = duty & WLED_8_BIT_MASK;
429 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
430 led->spmi_dev->sid,
431 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
432 if (rc) {
433 dev_err(&led->spmi_dev->dev,
434 "WLED set brightness LSB failed(%d)\n", rc);
435 return rc;
436 }
437 }
438
439 /* sync */
440 val = WLED_SYNC_VAL;
441 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
442 WLED_SYNC_REG(led->base), &val, 1);
443 if (rc) {
444 dev_err(&led->spmi_dev->dev,
445 "WLED set sync reg failed(%d)\n", rc);
446 return rc;
447 }
448
449 val = WLED_SYNC_RESET_VAL;
450 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
451 WLED_SYNC_REG(led->base), &val, 1);
452 if (rc) {
453 dev_err(&led->spmi_dev->dev,
454 "WLED reset sync reg failed(%d)\n", rc);
455 return rc;
456 }
457 return 0;
458}
459
Amy Maloche864a6d52012-10-03 15:58:12 -0700460static int qpnp_flash_set(struct qpnp_led_data *led)
461{
462 int rc;
463 int val = led->cdev.brightness;
464
465 led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
466 led->max_current);
467
468 led->flash_cfg->current_prgm =
469 led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
470 if (!led->flash_cfg->current_prgm)
471 led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
472
473 /* Set led current */
474 if (val > 0) {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700475 if (led->flash_cfg->torch_enable) {
476 rc = qpnp_led_masked_write(led,
477 FLASH_LED_UNLOCK_SECURE(led->base),
478 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
479 if (rc) {
480 dev_err(&led->spmi_dev->dev,
481 "Secure reg write failed(%d)\n", rc);
482 return rc;
483 }
484
485 rc = qpnp_led_masked_write(led,
486 FLASH_LED_TORCH(led->base),
487 FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
488 if (rc) {
489 dev_err(&led->spmi_dev->dev,
490 "Torch reg write failed(%d)\n", rc);
491 return rc;
492 }
493
494 qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
495 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
496 if (rc) {
497 dev_err(&led->spmi_dev->dev,
498 "Max current reg write failed(%d)\n",
499 rc);
500 return rc;
501 }
502
503 rc = qpnp_led_masked_write(led,
504 led->flash_cfg->current_addr,
505 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
506 if (rc) {
507 dev_err(&led->spmi_dev->dev,
508 "Current reg write failed(%d)\n", rc);
509 return rc;
510 }
511
512 rc = qpnp_led_masked_write(led,
513 led->flash_cfg->second_addr,
514 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
515 if (rc) {
516 dev_err(&led->spmi_dev->dev,
517 "2nd Current reg write failed(%d)\n",
518 rc);
519 return rc;
520 }
521
522 rc = qpnp_led_masked_write(led,
523 FLASH_ENABLE_CONTROL(led->base),
524 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
525 if (rc) {
526 dev_err(&led->spmi_dev->dev,
527 "Enable reg write failed(%d)\n", rc);
528 return rc;
529 }
530 } else {
531 rc = qpnp_led_masked_write(led,
532 FLASH_MAX_CURR(led->base),
533 FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
534 if (rc) {
535 dev_err(&led->spmi_dev->dev,
536 "Max current reg write failed(%d)\n",
537 rc);
538 return rc;
539 }
540
541 /* Write 0x80 to MODULE_ENABLE before writing 0xE0
542 * in order to avoid reg value goes from 0x00 to
543 * 0xE0. This causes a hardware bug.
544 */
545 rc = qpnp_led_masked_write(led,
546 FLASH_ENABLE_CONTROL(led->base),
547 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
548 if (rc) {
549 dev_err(&led->spmi_dev->dev,
550 "Enable reg write failed(%d)\n", rc);
551 return rc;
552 }
553
554 rc = qpnp_led_masked_write(led,
555 led->flash_cfg->current_addr,
556 FLASH_CURRENT_MASK,
557 led->flash_cfg->current_prgm);
558 if (rc) {
559 dev_err(&led->spmi_dev->dev,
560 "Current reg write failed(%d)\n", rc);
561 return rc;
562 }
563
564 rc = qpnp_led_masked_write(led,
565 led->flash_cfg->second_addr,
566 FLASH_CURRENT_MASK,
567 led->flash_cfg->current_prgm);
568 if (rc) {
569 dev_err(&led->spmi_dev->dev,
570 "2nd Current reg write failed(%d)\n",
571 rc);
572 return rc;
573 }
574
575 rc = qpnp_led_masked_write(led,
576 FLASH_CLAMP_CURR(led->base),
577 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
578 if (rc) {
579 dev_err(&led->spmi_dev->dev,
580 "Clamp Current reg write failed(%d)\n",
581 rc);
582 return rc;
583 }
584
585 rc = qpnp_led_masked_write(led,
586 FLASH_ENABLE_CONTROL(led->base),
587 FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
588 if (rc) {
589 dev_err(&led->spmi_dev->dev,
590 "Enable reg write failed(%d)\n", rc);
591 return rc;
592 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800593 }
594
Amy Malochebc97c0d22013-03-24 22:06:16 -0700595 if (!led->flash_cfg->strobe_type) {
596 rc = qpnp_led_masked_write(led,
597 FLASH_LED_STROBE_CTRL(led->base),
598 FLASH_STROBE_MASK, FLASH_STROBE_SW);
599 if (rc) {
600 dev_err(&led->spmi_dev->dev,
601 "LED %d strobe reg write failed(%d)\n",
602 led->id, rc);
603 return rc;
604 }
605 } else {
606 rc = qpnp_led_masked_write(led,
607 FLASH_LED_STROBE_CTRL(led->base),
608 FLASH_STROBE_MASK, FLASH_STROBE_HW);
609 if (rc) {
610 dev_err(&led->spmi_dev->dev,
611 "LED %d strobe reg write failed(%d)\n",
612 led->id, rc);
613 return rc;
614 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800615 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700616 } else {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700617 if (led->flash_cfg->torch_enable) {
618 rc = qpnp_led_masked_write(led,
619 FLASH_LED_UNLOCK_SECURE(led->base),
620 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
621 if (rc) {
622 dev_err(&led->spmi_dev->dev,
623 "Secure reg write failed(%d)\n", rc);
624 }
625
626 rc = qpnp_led_masked_write(led,
627 FLASH_LED_TORCH(led->base),
628 FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
629 if (rc) {
630 dev_err(&led->spmi_dev->dev,
631 "Torch reg write failed(%d)\n", rc);
632 return rc;
633 }
634
635 rc = qpnp_led_masked_write(led,
636 FLASH_SAFETY_TIMER(led->base),
637 FLASH_SAFETY_TIMER_MASK,
638 led->flash_cfg->duration);
639 if (rc) {
640 dev_err(&led->spmi_dev->dev,
641 "Safety timer reg write failed(%d)\n",
642 rc);
643 return rc;
644 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700645 }
646
647 rc = qpnp_led_masked_write(led,
648 FLASH_LED_STROBE_CTRL(led->base),
649 FLASH_STROBE_MASK,
650 FLASH_DISABLE_ALL);
651 if (rc) {
652 dev_err(&led->spmi_dev->dev,
653 "LED %d flash write failed(%d)\n", led->id, rc);
654 return rc;
655 }
Amy Malochebc97c0d22013-03-24 22:06:16 -0700656
657 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
658 FLASH_ENABLE_MASK,
659 FLASH_DISABLE_ALL);
660 if (rc) {
661 dev_err(&led->spmi_dev->dev,
662 "Enable reg write failed(%d)\n", rc);
663 return rc;
664 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700665 }
666
Amy Malocheeea7b592012-10-03 15:59:36 -0700667 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
668
669 return 0;
670}
671
672static int qpnp_rgb_set(struct qpnp_led_data *led)
673{
674 int duty_us;
675 int rc;
676
677 if (led->cdev.brightness) {
678 if (led->rgb_cfg->mode == RGB_MODE_PWM) {
679 duty_us = (led->rgb_cfg->pwm_period_us *
680 led->cdev.brightness) / LED_FULL;
681 rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
682 led->rgb_cfg->pwm_period_us);
683 if (rc < 0) {
684 dev_err(&led->spmi_dev->dev, "Failed to " \
685 "configure pwm for new values\n");
686 return rc;
687 }
688 }
689 rc = qpnp_led_masked_write(led,
690 RGB_LED_EN_CTL(led->base),
691 led->rgb_cfg->enable, led->rgb_cfg->enable);
692 if (rc) {
693 dev_err(&led->spmi_dev->dev,
694 "Failed to write led enable reg\n");
695 return rc;
696 }
697 rc = pwm_enable(led->rgb_cfg->pwm_dev);
698 } else {
699 pwm_disable(led->rgb_cfg->pwm_dev);
700 rc = qpnp_led_masked_write(led,
701 RGB_LED_EN_CTL(led->base),
702 led->rgb_cfg->enable, RGB_LED_DISABLE);
703 if (rc) {
704 dev_err(&led->spmi_dev->dev,
705 "Failed to write led enable reg\n");
706 return rc;
707 }
708 }
709
710 qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
711
Amy Maloche864a6d52012-10-03 15:58:12 -0700712 return 0;
713}
714
Amy Malochef3d5a062012-08-16 19:14:11 -0700715static void qpnp_led_set(struct led_classdev *led_cdev,
716 enum led_brightness value)
717{
718 int rc;
719 struct qpnp_led_data *led;
720
721 led = container_of(led_cdev, struct qpnp_led_data, cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -0700722 if (value < LED_OFF || value > led->cdev.max_brightness) {
Amy Malochea5ca5552012-10-23 13:34:46 -0700723 dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
Amy Malochef3d5a062012-08-16 19:14:11 -0700724 return;
725 }
726
Amy Malochedc3e5572012-09-25 16:39:06 -0700727 spin_lock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700728 led->cdev.brightness = value;
729
730 switch (led->id) {
731 case QPNP_ID_WLED:
732 rc = qpnp_wled_set(led);
733 if (rc < 0)
Amy Malochea5ca5552012-10-23 13:34:46 -0700734 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700735 "WLED set brightness failed (%d)\n", rc);
736 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700737 case QPNP_ID_FLASH1_LED0:
738 case QPNP_ID_FLASH1_LED1:
739 rc = qpnp_flash_set(led);
740 if (rc < 0)
741 dev_err(&led->spmi_dev->dev,
742 "FLASH set brightness failed (%d)\n", rc);
743 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700744 case QPNP_ID_RGB_RED:
745 case QPNP_ID_RGB_GREEN:
746 case QPNP_ID_RGB_BLUE:
747 rc = qpnp_rgb_set(led);
748 if (rc < 0)
749 dev_err(&led->spmi_dev->dev,
750 "RGB set brightness failed (%d)\n", rc);
751 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700752 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700753 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700754 break;
755 }
Amy Malochedc3e5572012-09-25 16:39:06 -0700756 spin_unlock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700757}
758
759static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
760{
761 switch (led->id) {
762 case QPNP_ID_WLED:
763 led->cdev.max_brightness = WLED_MAX_LEVEL;
764 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700765 case QPNP_ID_FLASH1_LED0:
766 case QPNP_ID_FLASH1_LED1:
767 led->cdev.max_brightness = led->max_current;
768 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700769 case QPNP_ID_RGB_RED:
770 case QPNP_ID_RGB_GREEN:
771 case QPNP_ID_RGB_BLUE:
772 led->cdev.max_brightness = RGB_MAX_LEVEL;
773 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700774 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700775 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700776 return -EINVAL;
777 }
778
779 return 0;
780}
781
782static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
783{
784 struct qpnp_led_data *led;
785
786 led = container_of(led_cdev, struct qpnp_led_data, cdev);
787
788 return led->cdev.brightness;
789}
790
Asaf Penso55ac8472013-01-21 21:17:37 +0200791static void qpnp_led_turn_off_delayed(struct work_struct *work)
792{
793 struct delayed_work *dwork = to_delayed_work(work);
794 struct qpnp_led_data *led
795 = container_of(dwork, struct qpnp_led_data, dwork);
796
797 led->cdev.brightness = LED_OFF;
798 qpnp_led_set(&led->cdev, led->cdev.brightness);
799}
800
801static void qpnp_led_turn_off(struct qpnp_led_data *led)
802{
803 INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed);
804 schedule_delayed_work(&led->dwork,
805 msecs_to_jiffies(led->turn_off_delay_ms));
806}
807
Amy Malochef3d5a062012-08-16 19:14:11 -0700808static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
809{
810 int rc, i;
811 u8 num_wled_strings;
812
813 num_wled_strings = led->wled_cfg->num_strings;
814
815 /* verify ranges */
816 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
817 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
818 return -EINVAL;
819 }
820
821 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
822 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
823 return -EINVAL;
824 }
825
826 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
827 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
828 return -EINVAL;
829 }
830
831 if ((led->max_current > WLED_MAX_CURR)) {
832 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
833 return -EINVAL;
834 }
835
836 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
837 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
838 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
839 return -EINVAL;
840 }
841
842 /* program over voltage protection threshold */
843 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
844 WLED_OVP_VAL_MASK,
845 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
846 if (rc) {
847 dev_err(&led->spmi_dev->dev,
848 "WLED OVP reg write failed(%d)\n", rc);
849 return rc;
850 }
851
852 /* program current boost limit */
853 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
854 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
855 if (rc) {
856 dev_err(&led->spmi_dev->dev,
857 "WLED boost limit reg write failed(%d)\n", rc);
858 return rc;
859 }
860
861 /* program output feedback */
862 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
863 WLED_OP_FDBCK_MASK,
864 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
865 if (rc) {
866 dev_err(&led->spmi_dev->dev,
867 "WLED fdbck ctrl reg write failed(%d)\n", rc);
868 return rc;
869 }
870
871 /* program switch frequency */
872 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
873 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
874 if (rc) {
875 dev_err(&led->spmi_dev->dev,
876 "WLED switch freq reg write failed(%d)\n", rc);
877 return rc;
878 }
879
880 /* program current sink */
881 if (led->wled_cfg->cs_out_en) {
882 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
883 WLED_CURR_SINK_MASK,
Amy Maloche832d90a2013-01-07 10:15:29 -0800884 (((1 << led->wled_cfg->num_strings) - 1)
885 << WLED_CURR_SINK_SHFT));
Amy Malochef3d5a062012-08-16 19:14:11 -0700886 if (rc) {
887 dev_err(&led->spmi_dev->dev,
888 "WLED curr sink reg write failed(%d)\n", rc);
889 return rc;
890 }
891 }
892
893 /* program high pole capacitance */
894 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
895 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
896 if (rc) {
897 dev_err(&led->spmi_dev->dev,
898 "WLED pole cap reg write failed(%d)\n", rc);
899 return rc;
900 }
901
902 /* program modulator, current mod src and cabc */
903 for (i = 0; i < num_wled_strings; i++) {
904 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
905 WLED_NO_MASK, WLED_EN_MASK);
906 if (rc) {
907 dev_err(&led->spmi_dev->dev,
908 "WLED mod enable reg write failed(%d)\n", rc);
909 return rc;
910 }
911
912 if (led->wled_cfg->dig_mod_gen_en) {
913 rc = qpnp_led_masked_write(led,
Amy Maloched44516e2013-02-14 17:36:34 -0800914 WLED_MOD_SRC_SEL_REG(led->base, i),
Amy Malochef3d5a062012-08-16 19:14:11 -0700915 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
916 if (rc) {
917 dev_err(&led->spmi_dev->dev,
918 "WLED dig mod en reg write failed(%d)\n", rc);
919 }
920 }
921
922 rc = qpnp_led_masked_write(led,
923 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
924 led->max_current);
925 if (rc) {
926 dev_err(&led->spmi_dev->dev,
927 "WLED max current reg write failed(%d)\n", rc);
928 return rc;
929 }
930
931 }
932
933 /* dump wled registers */
Amy Malochea5ca5552012-10-23 13:34:46 -0700934 qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
Amy Malochef3d5a062012-08-16 19:14:11 -0700935
936 return 0;
937}
938
Amy Malochebc97c0d22013-03-24 22:06:16 -0700939static ssize_t led_mode_store(struct device *dev,
940 struct device_attribute *attr,
941 const char *buf, size_t count)
942{
943 struct qpnp_led_data *led;
944 unsigned long state;
945 struct led_classdev *led_cdev = dev_get_drvdata(dev);
946 ssize_t ret = -EINVAL;
947
948 ret = kstrtoul(buf, 10, &state);
949 if (ret)
950 return ret;
951
952 led = container_of(led_cdev, struct qpnp_led_data, cdev);
953
954 /* '1' to enable torch mode; '0' to switch to flash mode */
955 if (state == 1)
956 led->flash_cfg->torch_enable = true;
957 else
958 led->flash_cfg->torch_enable = false;
959
960 return count;
961}
962
963static ssize_t led_strobe_type_store(struct device *dev,
964 struct device_attribute *attr,
965 const char *buf, size_t count)
966{
967 struct qpnp_led_data *led;
968 unsigned long state;
969 struct led_classdev *led_cdev = dev_get_drvdata(dev);
970 ssize_t ret = -EINVAL;
971
972 ret = kstrtoul(buf, 10, &state);
973 if (ret)
974 return ret;
975
976 led = container_of(led_cdev, struct qpnp_led_data, cdev);
977
978 /* '0' for sw strobe; '1' for hw strobe */
979 if (state == 1)
980 led->flash_cfg->strobe_type = 1;
981 else
982 led->flash_cfg->strobe_type = 0;
983
984 return count;
985}
986
987static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
988static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
989
990static struct attribute *led_attrs[] = {
991 &dev_attr_led_mode.attr,
992 &dev_attr_strobe.attr,
993};
994
995static const struct attribute_group led_attr_group = {
996 .attrs = led_attrs,
997};
998
Amy Maloche864a6d52012-10-03 15:58:12 -0700999static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
1000{
1001 int rc;
1002
1003 rc = qpnp_led_masked_write(led,
1004 FLASH_LED_STROBE_CTRL(led->base),
1005 FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
1006 if (rc) {
1007 dev_err(&led->spmi_dev->dev,
1008 "LED %d flash write failed(%d)\n", led->id, rc);
1009 return rc;
1010 }
1011 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
1012 FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
1013 if (rc) {
1014 dev_err(&led->spmi_dev->dev,
1015 "Enable reg write failed(%d)\n", rc);
1016 return rc;
1017 }
1018
1019 /* Set flash safety timer */
1020 rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
1021 FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
1022 if (rc) {
1023 dev_err(&led->spmi_dev->dev,
1024 "Safety timer reg write failed(%d)\n", rc);
1025 return rc;
1026 }
1027
1028 /* Set max current */
1029 rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
1030 FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
1031 if (rc) {
1032 dev_err(&led->spmi_dev->dev,
1033 "Max current reg write failed(%d)\n", rc);
1034 return rc;
1035 }
1036 /* Set clamp current */
1037 rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
1038 FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
1039 if (rc) {
1040 dev_err(&led->spmi_dev->dev,
1041 "Clamp current reg write failed(%d)\n", rc);
1042 return rc;
1043 }
1044
1045 /* Set timer control - safety or watchdog */
1046 if (led->flash_cfg->safety_timer)
1047 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
1048 FLASH_TMR_MASK, FLASH_TMR_SAFETY);
1049 else
1050 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
1051 FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
1052 if (rc) {
1053 dev_err(&led->spmi_dev->dev,
1054 "LED timer ctrl reg write failed(%d)\n", rc);
1055 return rc;
1056 }
1057 /* Set headroom */
1058 rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
1059 FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
1060 if (rc) {
1061 dev_err(&led->spmi_dev->dev,
1062 "Headroom reg write failed(%d)\n", rc);
1063 return rc;
1064 }
1065
1066 /* Set mask enable */
1067 rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
1068 FLASH_MASK_REG_MASK, FLASH_MASK_1);
1069 if (rc) {
1070 dev_err(&led->spmi_dev->dev,
1071 "Mask enable reg write failed(%d)\n", rc);
1072 return rc;
1073 }
1074
1075 /* Set startup delay */
1076 rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
1077 FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
1078 if (rc) {
1079 dev_err(&led->spmi_dev->dev,
1080 "Startup delay reg write failed(%d)\n", rc);
1081 return rc;
1082 }
1083
1084 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
1085 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
1086 if (rc) {
1087 dev_err(&led->spmi_dev->dev,
1088 "Vreg OK reg write failed(%d)\n", rc);
1089 return rc;
1090 }
1091
Amy Malochebc97c0d22013-03-24 22:06:16 -07001092 /* Set led current and disable module */
Amy Maloche864a6d52012-10-03 15:58:12 -07001093 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
1094 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
1095 if (rc) {
1096 dev_err(&led->spmi_dev->dev,
1097 "Current reg write failed(%d)\n", rc);
1098 return rc;
1099 }
1100
1101 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
Amy Maloche38b9aae2013-02-07 12:15:34 -08001102 FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
Amy Maloche864a6d52012-10-03 15:58:12 -07001103 if (rc) {
1104 dev_err(&led->spmi_dev->dev,
1105 "Enable reg write failed(%d)\n", rc);
1106 return rc;
1107 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07001108
1109 led->flash_cfg->torch_enable = false;
1110 led->flash_cfg->strobe_type = 0;
1111
Amy Maloche864a6d52012-10-03 15:58:12 -07001112 /* dump flash registers */
1113 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
1114
1115 return 0;
1116}
1117
Amy Malocheeea7b592012-10-03 15:59:36 -07001118static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
1119{
1120 int rc, start_idx, idx_len;
1121
1122 rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
1123 RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
1124 if (rc) {
1125 dev_err(&led->spmi_dev->dev,
1126 "Failed to write led source select register\n");
1127 return rc;
1128 }
1129
1130 if (led->rgb_cfg->pwm_channel != -1) {
1131 led->rgb_cfg->pwm_dev =
1132 pwm_request(led->rgb_cfg->pwm_channel,
1133 led->cdev.name);
1134
1135 if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
1136 dev_err(&led->spmi_dev->dev,
1137 "could not acquire PWM Channel %d, " \
1138 "error %ld\n",
1139 led->rgb_cfg->pwm_channel,
1140 PTR_ERR(led->rgb_cfg->pwm_dev));
1141 led->rgb_cfg->pwm_dev = NULL;
1142 return -ENODEV;
1143 }
1144
1145 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1146 start_idx =
1147 led->rgb_cfg->duty_cycles->start_idx;
1148 idx_len =
1149 led->rgb_cfg->duty_cycles->num_duty_pcts;
1150
1151 if (idx_len >= PWM_LUT_MAX_SIZE &&
1152 start_idx) {
1153 dev_err(&led->spmi_dev->dev,
1154 "Wrong LUT size or index\n");
1155 return -EINVAL;
1156 }
1157 if ((start_idx + idx_len) >
1158 PWM_LUT_MAX_SIZE) {
1159 dev_err(&led->spmi_dev->dev,
1160 "Exceed LUT limit\n");
1161 return -EINVAL;
1162 }
1163 rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
1164 led->rgb_cfg->pwm_period_us,
1165 led->rgb_cfg->duty_cycles->duty_pcts,
1166 led->rgb_cfg->lut_params);
1167 if (rc < 0) {
1168 dev_err(&led->spmi_dev->dev, "Failed to " \
1169 "configure pwm LUT\n");
1170 return rc;
1171 }
1172 }
1173 } else {
1174 dev_err(&led->spmi_dev->dev,
1175 "Invalid PWM channel\n");
1176 return -EINVAL;
1177 }
1178
1179 /* Initialize led for use in auto trickle charging mode */
1180 rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
1181 led->rgb_cfg->enable, led->rgb_cfg->enable);
1182
1183 return 0;
1184}
1185
Amy Malochef3d5a062012-08-16 19:14:11 -07001186static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
1187{
1188 int rc;
1189
1190 switch (led->id) {
1191 case QPNP_ID_WLED:
1192 rc = qpnp_wled_init(led);
1193 if (rc)
Amy Malochea5ca5552012-10-23 13:34:46 -07001194 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -07001195 "WLED initialize failed(%d)\n", rc);
1196 break;
Amy Maloche864a6d52012-10-03 15:58:12 -07001197 case QPNP_ID_FLASH1_LED0:
1198 case QPNP_ID_FLASH1_LED1:
1199 rc = qpnp_flash_init(led);
1200 if (rc)
1201 dev_err(&led->spmi_dev->dev,
1202 "FLASH initialize failed(%d)\n", rc);
1203 break;
Amy Malocheeea7b592012-10-03 15:59:36 -07001204 case QPNP_ID_RGB_RED:
1205 case QPNP_ID_RGB_GREEN:
1206 case QPNP_ID_RGB_BLUE:
1207 rc = qpnp_rgb_init(led);
1208 if (rc)
1209 dev_err(&led->spmi_dev->dev,
1210 "RGB initialize failed(%d)\n", rc);
1211 break;
Amy Malochef3d5a062012-08-16 19:14:11 -07001212 default:
Amy Malochea5ca5552012-10-23 13:34:46 -07001213 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malocheeea7b592012-10-03 15:59:36 -07001214 return -EINVAL;
Amy Malochef3d5a062012-08-16 19:14:11 -07001215 }
1216
Amy Malocheeea7b592012-10-03 15:59:36 -07001217 return 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001218}
1219
Amy Malochea5ca5552012-10-23 13:34:46 -07001220static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
1221 struct device_node *node)
1222{
1223 int rc;
Asaf Penso55ac8472013-01-21 21:17:37 +02001224 u32 val;
Amy Malochea5ca5552012-10-23 13:34:46 -07001225 const char *temp_string;
1226
1227 led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
1228 rc = of_property_read_string(node, "linux,default-trigger",
1229 &temp_string);
1230 if (!rc)
1231 led->cdev.default_trigger = temp_string;
1232 else if (rc != -EINVAL)
1233 return rc;
1234
1235 led->default_on = false;
1236 rc = of_property_read_string(node, "qcom,default-state",
1237 &temp_string);
1238 if (!rc) {
1239 if (strncmp(temp_string, "on", sizeof("on")) == 0)
1240 led->default_on = true;
1241 } else if (rc != -EINVAL)
1242 return rc;
1243
Asaf Penso55ac8472013-01-21 21:17:37 +02001244 led->turn_off_delay_ms = 0;
1245 rc = of_property_read_u32(node, "qcom,turn-off-delay-ms", &val);
1246 if (!rc)
1247 led->turn_off_delay_ms = val;
1248 else if (rc != -EINVAL)
1249 return rc;
1250
Amy Malochea5ca5552012-10-23 13:34:46 -07001251 return 0;
1252}
1253
Amy Malochef3d5a062012-08-16 19:14:11 -07001254/*
1255 * Handlers for alternative sources of platform_data
1256 */
1257static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
1258 struct device_node *node)
1259{
1260 u32 val;
1261 int rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001262
1263 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
1264 sizeof(struct wled_config_data), GFP_KERNEL);
1265 if (!led->wled_cfg) {
1266 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1267 return -ENOMEM;
1268 }
1269
Amy Malochef3d5a062012-08-16 19:14:11 -07001270 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
1271 rc = of_property_read_u32(node, "qcom,num-strings", &val);
1272 if (!rc)
1273 led->wled_cfg->num_strings = (u8) val;
1274 else if (rc != -EINVAL)
1275 return rc;
1276
1277 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
1278 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
1279 if (!rc)
1280 led->wled_cfg->ovp_val = (u8) val;
1281 else if (rc != -EINVAL)
1282 return rc;
1283
1284 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
1285 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
1286 if (!rc)
1287 led->wled_cfg->boost_curr_lim = (u8) val;
1288 else if (rc != -EINVAL)
1289 return rc;
1290
1291 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
1292 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
1293 if (!rc)
1294 led->wled_cfg->cp_select = (u8) val;
1295 else if (rc != -EINVAL)
1296 return rc;
1297
1298 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
1299 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
1300 if (!rc)
1301 led->wled_cfg->ctrl_delay_us = (u8) val;
1302 else if (rc != -EINVAL)
1303 return rc;
1304
Amy Malochebd687672013-03-18 11:23:45 -07001305 led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
1306 rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
1307 if (!rc)
1308 led->wled_cfg->op_fdbck = (u8) val;
1309 else if (rc != -EINVAL)
1310 return rc;
1311
Amy Malochef3d5a062012-08-16 19:14:11 -07001312 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
1313 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
1314 if (!rc)
1315 led->wled_cfg->switch_freq = (u8) val;
1316 else if (rc != -EINVAL)
1317 return rc;
1318
1319 led->wled_cfg->dig_mod_gen_en =
1320 of_property_read_bool(node, "qcom,dig-mod-gen-en");
1321
1322 led->wled_cfg->cs_out_en =
1323 of_property_read_bool(node, "qcom,cs-out-en");
1324
Amy Malochef3d5a062012-08-16 19:14:11 -07001325 return 0;
1326}
1327
Amy Maloche864a6d52012-10-03 15:58:12 -07001328static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
1329 struct device_node *node)
1330{
1331 int rc;
1332 u32 val;
1333
1334 led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
1335 sizeof(struct flash_config_data), GFP_KERNEL);
1336 if (!led->flash_cfg) {
1337 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1338 return -ENOMEM;
1339 }
1340
1341 if (led->id == QPNP_ID_FLASH1_LED0) {
1342 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1343 led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
1344 led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
1345 led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
1346 } else if (led->id == QPNP_ID_FLASH1_LED1) {
1347 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1348 led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
1349 led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
1350 led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
1351 } else {
1352 dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
1353 return -EINVAL;
1354 }
1355
1356 rc = of_property_read_u32(node, "qcom,current", &val);
1357 if (!rc)
1358 led->flash_cfg->current_prgm = (val *
1359 FLASH_MAX_LEVEL / led->max_current);
1360 else
1361 return -EINVAL;
1362
1363 rc = of_property_read_u32(node, "qcom,headroom", &val);
1364 if (!rc)
1365 led->flash_cfg->headroom = (u8) val;
1366 else if (rc == -EINVAL)
1367 led->flash_cfg->headroom = HEADROOM_300mV;
1368 else
1369 return rc;
1370
1371 rc = of_property_read_u32(node, "qcom,duration", &val);
1372 if (!rc)
1373 led->flash_cfg->duration = (((u8) val) - 10) / 10;
1374 else if (rc == -EINVAL)
1375 led->flash_cfg->duration = FLASH_DURATION_200ms;
1376 else
1377 return rc;
1378
1379 rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
1380 if (!rc)
1381 led->flash_cfg->clamp_curr = (val *
1382 FLASH_MAX_LEVEL / led->max_current);
1383 else if (rc == -EINVAL)
1384 led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
1385 else
1386 return rc;
1387
1388 rc = of_property_read_u32(node, "qcom,startup-dly", &val);
1389 if (!rc)
1390 led->flash_cfg->startup_dly = (u8) val;
1391 else if (rc == -EINVAL)
1392 led->flash_cfg->startup_dly = DELAY_32us;
1393 else
1394 return rc;
1395
1396 led->flash_cfg->safety_timer =
1397 of_property_read_bool(node, "qcom,safety-timer");
1398
1399 return 0;
1400}
1401
Amy Malocheeea7b592012-10-03 15:59:36 -07001402static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
1403 struct device_node *node)
1404{
1405 struct property *prop;
1406 int rc, i;
1407 u32 val;
1408 u8 *temp_cfg;
1409
1410 led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
1411 sizeof(struct rgb_config_data), GFP_KERNEL);
1412 if (!led->rgb_cfg) {
1413 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1414 return -ENOMEM;
1415 }
1416
1417 if (led->id == QPNP_ID_RGB_RED)
1418 led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
1419 else if (led->id == QPNP_ID_RGB_GREEN)
1420 led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
1421 else if (led->id == QPNP_ID_RGB_BLUE)
1422 led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
1423 else
1424 return -EINVAL;
1425
1426 rc = of_property_read_u32(node, "qcom,mode", &val);
1427 if (!rc)
1428 led->rgb_cfg->mode = (u8) val;
1429 else
1430 return rc;
1431
1432 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1433 if (!rc)
1434 led->rgb_cfg->pwm_channel = (u8) val;
1435 else
1436 return rc;
1437
1438 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1439 if (!rc)
1440 led->rgb_cfg->pwm_period_us = val;
1441 else
1442 return rc;
1443
1444 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1445 led->rgb_cfg->duty_cycles =
1446 devm_kzalloc(&led->spmi_dev->dev,
1447 sizeof(struct pwm_duty_cycles), GFP_KERNEL);
1448 if (!led->rgb_cfg->duty_cycles) {
1449 dev_err(&led->spmi_dev->dev,
1450 "Unable to allocate memory\n");
1451 return -ENOMEM;
1452 }
1453
1454 rc = of_property_read_u32(node, "qcom,duty-ms", &val);
1455 if (!rc)
1456 led->rgb_cfg->duty_cycles->duty_ms = (u8) val;
1457 else
1458 return rc;
1459
1460 prop = of_find_property(node, "qcom,duty-pcts",
1461 &led->rgb_cfg->duty_cycles->num_duty_pcts);
1462 if (!prop) {
1463 dev_err(&led->spmi_dev->dev, "Looking up property " \
1464 "node qcom,duty-pcts failed\n");
1465 return -ENODEV;
1466 } else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
1467 dev_err(&led->spmi_dev->dev, "Invalid length of " \
1468 "duty pcts\n");
1469 return -EINVAL;
1470 }
1471
1472 led->rgb_cfg->duty_cycles->duty_pcts =
1473 devm_kzalloc(&led->spmi_dev->dev,
1474 sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
1475 GFP_KERNEL);
1476 if (!led->rgb_cfg->duty_cycles->duty_pcts) {
1477 dev_err(&led->spmi_dev->dev,
1478 "Unable to allocate memory\n");
1479 return -ENOMEM;
1480 }
1481
1482 temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1483 led->rgb_cfg->duty_cycles->num_duty_pcts *
1484 sizeof(u8), GFP_KERNEL);
1485 if (!temp_cfg) {
1486 dev_err(&led->spmi_dev->dev, "Failed to allocate " \
1487 "memory for duty pcts\n");
1488 return -ENOMEM;
1489 }
1490
1491 memcpy(temp_cfg, prop->value,
1492 led->rgb_cfg->duty_cycles->num_duty_pcts);
1493
1494 for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
1495 led->rgb_cfg->duty_cycles->duty_pcts[i] =
1496 (int) temp_cfg[i];
1497
1498 rc = of_property_read_u32(node, "qcom,start-idx", &val);
1499 if (!rc) {
1500 led->rgb_cfg->lut_params.start_idx = (u8) val;
1501 led->rgb_cfg->duty_cycles->start_idx = (u8) val;
1502 } else
1503 return rc;
1504
1505 led->rgb_cfg->lut_params.idx_len =
1506 led->rgb_cfg->duty_cycles->num_duty_pcts;
1507 led->rgb_cfg->lut_params.lut_pause_hi = 0;
1508 led->rgb_cfg->lut_params.lut_pause_lo = 0;
1509 led->rgb_cfg->lut_params.ramp_step_ms = 255;
1510 led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
1511 }
1512
1513 return 0;
1514}
1515
Amy Malochef3d5a062012-08-16 19:14:11 -07001516static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
1517{
Amy Malochef9490c62012-11-27 19:26:04 -08001518 struct qpnp_led_data *led, *led_array;
Amy Malochef3d5a062012-08-16 19:14:11 -07001519 struct resource *led_resource;
Amy Malochea5ca5552012-10-23 13:34:46 -07001520 struct device_node *node, *temp;
Amy Malochef9490c62012-11-27 19:26:04 -08001521 int rc, i, num_leds = 0, parsed_leds = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001522 const char *led_label;
1523
Amy Malochea5ca5552012-10-23 13:34:46 -07001524 node = spmi->dev.of_node;
1525 if (node == NULL)
1526 return -ENODEV;
1527
1528 temp = NULL;
1529 while ((temp = of_get_next_child(node, temp)))
1530 num_leds++;
1531
Amy Malochef9490c62012-11-27 19:26:04 -08001532 if (!num_leds)
1533 return -ECHILD;
1534
1535 led_array = devm_kzalloc(&spmi->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001536 (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
Amy Malochef9490c62012-11-27 19:26:04 -08001537 if (!led_array) {
Amy Malochef3d5a062012-08-16 19:14:11 -07001538 dev_err(&spmi->dev, "Unable to allocate memory\n");
1539 return -ENOMEM;
1540 }
1541
Amy Malochea5ca5552012-10-23 13:34:46 -07001542 for_each_child_of_node(node, temp) {
Amy Malochef9490c62012-11-27 19:26:04 -08001543 led = &led_array[parsed_leds];
1544 led->num_leds = num_leds;
Amy Malochea5ca5552012-10-23 13:34:46 -07001545 led->spmi_dev = spmi;
Amy Malochef3d5a062012-08-16 19:14:11 -07001546
Amy Malochea5ca5552012-10-23 13:34:46 -07001547 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
1548 if (!led_resource) {
1549 dev_err(&spmi->dev, "Unable to get LED base address\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001550 rc = -ENXIO;
1551 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001552 }
1553 led->base = led_resource->start;
Amy Malochef3d5a062012-08-16 19:14:11 -07001554
Amy Malochea5ca5552012-10-23 13:34:46 -07001555 rc = of_property_read_string(temp, "label", &led_label);
Amy Malochef3d5a062012-08-16 19:14:11 -07001556 if (rc < 0) {
1557 dev_err(&led->spmi_dev->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001558 "Failure reading label, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001559 goto fail_id_check;
Amy Malochef3d5a062012-08-16 19:14:11 -07001560 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001561
1562 rc = of_property_read_string(temp, "linux,name",
1563 &led->cdev.name);
1564 if (rc < 0) {
1565 dev_err(&led->spmi_dev->dev,
1566 "Failure reading led name, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001567 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001568 }
1569
1570 rc = of_property_read_u32(temp, "qcom,max-current",
1571 &led->max_current);
1572 if (rc < 0) {
1573 dev_err(&led->spmi_dev->dev,
1574 "Failure reading max_current, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001575 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001576 }
1577
1578 rc = of_property_read_u32(temp, "qcom,id", &led->id);
1579 if (rc < 0) {
1580 dev_err(&led->spmi_dev->dev,
1581 "Failure reading led id, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001582 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001583 }
1584
1585 rc = qpnp_get_common_configs(led, temp);
1586 if (rc) {
1587 dev_err(&led->spmi_dev->dev,
1588 "Failure reading common led configuration," \
1589 " 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 led->cdev.brightness_set = qpnp_led_set;
1594 led->cdev.brightness_get = qpnp_led_get;
1595
1596 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
1597 rc = qpnp_get_config_wled(led, temp);
1598 if (rc < 0) {
1599 dev_err(&led->spmi_dev->dev,
1600 "Unable to read wled config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001601 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001602 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001603 } else if (strncmp(led_label, "flash", sizeof("flash"))
1604 == 0) {
1605 rc = qpnp_get_config_flash(led, temp);
1606 if (rc < 0) {
1607 dev_err(&led->spmi_dev->dev,
1608 "Unable to read flash config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001609 goto fail_id_check;
Amy Maloche864a6d52012-10-03 15:58:12 -07001610 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001611 } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
1612 rc = qpnp_get_config_rgb(led, temp);
1613 if (rc < 0) {
1614 dev_err(&led->spmi_dev->dev,
1615 "Unable to read rgb config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001616 goto fail_id_check;
Amy Malocheeea7b592012-10-03 15:59:36 -07001617 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001618 } else {
1619 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001620 rc = -EINVAL;
1621 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001622 }
1623
1624 spin_lock_init(&led->lock);
1625
1626 rc = qpnp_led_initialize(led);
1627 if (rc < 0)
1628 goto fail_id_check;
1629
1630 rc = qpnp_led_set_max_brightness(led);
1631 if (rc < 0)
1632 goto fail_id_check;
1633
1634 rc = led_classdev_register(&spmi->dev, &led->cdev);
1635 if (rc) {
1636 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
1637 led->id, rc);
1638 goto fail_id_check;
1639 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07001640
1641 if (led->id == QPNP_ID_FLASH1_LED0 ||
1642 led->id == QPNP_ID_FLASH1_LED1) {
1643 rc = sysfs_create_group(&led->cdev.dev->kobj,
1644 &led_attr_group);
1645 if (rc)
1646 goto fail_id_check;
1647
1648 }
1649
Amy Malochea5ca5552012-10-23 13:34:46 -07001650 /* configure default state */
Asaf Penso55ac8472013-01-21 21:17:37 +02001651 if (led->default_on) {
Amy Malochea5ca5552012-10-23 13:34:46 -07001652 led->cdev.brightness = led->cdev.max_brightness;
Asaf Penso55ac8472013-01-21 21:17:37 +02001653 if (led->turn_off_delay_ms > 0)
1654 qpnp_led_turn_off(led);
1655 } else
Amy Malochea5ca5552012-10-23 13:34:46 -07001656 led->cdev.brightness = LED_OFF;
1657
1658 qpnp_led_set(&led->cdev, led->cdev.brightness);
Amy Malochef9490c62012-11-27 19:26:04 -08001659
1660 parsed_leds++;
Amy Malochef3d5a062012-08-16 19:14:11 -07001661 }
Amy Malochef9490c62012-11-27 19:26:04 -08001662 dev_set_drvdata(&spmi->dev, led_array);
Amy Malochef3d5a062012-08-16 19:14:11 -07001663 return 0;
1664
1665fail_id_check:
Amy Malochef9490c62012-11-27 19:26:04 -08001666 for (i = 0; i < parsed_leds; i++)
1667 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001668 return rc;
1669}
1670
1671static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
1672{
Amy Malochef9490c62012-11-27 19:26:04 -08001673 struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
1674 int i, parsed_leds = led_array->num_leds;
Amy Malochef3d5a062012-08-16 19:14:11 -07001675
Amy Malochebc97c0d22013-03-24 22:06:16 -07001676 for (i = 0; i < parsed_leds; i++) {
Amy Malochef9490c62012-11-27 19:26:04 -08001677 led_classdev_unregister(&led_array[i].cdev);
Amy Malochebc97c0d22013-03-24 22:06:16 -07001678 switch (led_array[i].id) {
1679 case QPNP_ID_WLED:
1680 break;
1681 case QPNP_ID_FLASH1_LED0:
1682 case QPNP_ID_FLASH1_LED1:
1683 sysfs_remove_group(&led_array[i].cdev.dev->kobj,
1684 &led_attr_group);
1685 break;
1686 case QPNP_ID_RGB_RED:
1687 case QPNP_ID_RGB_GREEN:
1688 case QPNP_ID_RGB_BLUE:
1689 default:
1690 dev_err(&led_array[i].spmi_dev->dev,
1691 "Invalid LED(%d)\n",
1692 led_array[i].id);
1693 return -EINVAL;
1694 }
1695 }
Amy Malochef3d5a062012-08-16 19:14:11 -07001696
1697 return 0;
1698}
1699static struct of_device_id spmi_match_table[] = {
1700 { .compatible = "qcom,leds-qpnp",
1701 }
1702};
1703
1704static struct spmi_driver qpnp_leds_driver = {
1705 .driver = {
1706 .name = "qcom,leds-qpnp",
1707 .of_match_table = spmi_match_table,
1708 },
1709 .probe = qpnp_leds_probe,
1710 .remove = __devexit_p(qpnp_leds_remove),
1711};
1712
1713static int __init qpnp_led_init(void)
1714{
1715 return spmi_driver_register(&qpnp_leds_driver);
1716}
1717module_init(qpnp_led_init);
1718
1719static void __exit qpnp_led_exit(void)
1720{
1721 spmi_driver_unregister(&qpnp_leds_driver);
1722}
1723module_exit(qpnp_led_exit);
1724
1725MODULE_DESCRIPTION("QPNP LEDs driver");
1726MODULE_LICENSE("GPL v2");
1727MODULE_ALIAS("leds:leds-qpnp");
Amy Maloche864a6d52012-10-03 15:58:12 -07001728