blob: 9101a3d5aa14bab77277b29de363e67cfdcde4ce [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)
Chun Zhange8954cf2013-05-02 11:14:34 -070096#define FLASH_FAULT_DETECT(base) (base + 0x51)
Amy Maloche864a6d52012-10-03 15:58:12 -070097
98#define FLASH_MAX_LEVEL 0x4F
99#define FLASH_NO_MASK 0x00
100
101#define FLASH_MASK_1 0x20
102#define FLASH_MASK_REG_MASK 0xE0
103#define FLASH_HEADROOM_MASK 0x03
104#define FLASH_SAFETY_TIMER_MASK 0x7F
105#define FLASH_CURRENT_MASK 0xFF
Amy Malochebc97c0d22013-03-24 22:06:16 -0700106#define FLASH_MAX_CURRENT_MASK 0x7F
Amy Maloche864a6d52012-10-03 15:58:12 -0700107#define FLASH_TMR_MASK 0x03
108#define FLASH_TMR_WATCHDOG 0x03
109#define FLASH_TMR_SAFETY 0x00
Chun Zhange8954cf2013-05-02 11:14:34 -0700110#define FLASH_FAULT_DETECT_MASK 0X80
Amy Maloche864a6d52012-10-03 15:58:12 -0700111#define FLASH_HW_VREG_OK 0x80
112#define FLASH_VREG_MASK 0xC0
Amy Maloche864a6d52012-10-03 15:58:12 -0700113#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
Chun Zhange8954cf2013-05-02 11:14:34 -0700123#define FLASH_SELFCHECK_ENABLE 0x80
Amy Maloche864a6d52012-10-03 15:58:12 -0700124
Amy Malochebc97c0d22013-03-24 22:06:16 -0700125#define FLASH_STROBE_SW 0xC0
126#define FLASH_STROBE_HW 0xC4
127#define FLASH_STROBE_MASK 0xC7
Amy Maloche864a6d52012-10-03 15:58:12 -0700128#define FLASH_LED_0_OUTPUT 0x80
129#define FLASH_LED_1_OUTPUT 0x40
130
131#define FLASH_CURRENT_PRGM_MIN 1
132#define FLASH_CURRENT_PRGM_SHIFT 1
Amy Malochebc97c0d22013-03-24 22:06:16 -0700133#define FLASH_CURRENT_MAX 0x4F
Chun Zhange8954cf2013-05-02 11:14:34 -0700134#define FLASH_CURRENT_TORCH 0x07
Amy Maloche864a6d52012-10-03 15:58:12 -0700135
136#define FLASH_DURATION_200ms 0x13
137#define FLASH_CLAMP_200mA 0x0F
138
Amy Malochebc97c0d22013-03-24 22:06:16 -0700139#define FLASH_TORCH_MASK 0x03
140#define FLASH_LED_TORCH_ENABLE 0x00
141#define FLASH_LED_TORCH_DISABLE 0x03
142#define FLASH_UNLOCK_SECURE 0xA5
143#define FLASH_SECURE_MASK 0xFF
144
Amy Malochea5ca5552012-10-23 13:34:46 -0700145#define LED_TRIGGER_DEFAULT "none"
146
Amy Malocheeea7b592012-10-03 15:59:36 -0700147#define RGB_LED_SRC_SEL(base) (base + 0x45)
148#define RGB_LED_EN_CTL(base) (base + 0x46)
149#define RGB_LED_ATC_CTL(base) (base + 0x47)
150
151#define RGB_MAX_LEVEL LED_FULL
152#define RGB_LED_ENABLE_RED 0x80
153#define RGB_LED_ENABLE_GREEN 0x40
154#define RGB_LED_ENABLE_BLUE 0x20
155#define RGB_LED_SOURCE_VPH_PWR 0x01
156#define RGB_LED_ENABLE_MASK 0xE0
157#define RGB_LED_SRC_MASK 0x03
158#define QPNP_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
Amy Maloche013b35b2013-03-19 12:29:11 -0700159#define QPNP_LUT_RAMP_STEP_DEFAULT 255
Amy Malocheeea7b592012-10-03 15:59:36 -0700160#define PWM_LUT_MAX_SIZE 63
161#define RGB_LED_DISABLE 0x00
162
Amy Malochef3813742013-04-11 19:33:47 -0700163#define MPP_MAX_LEVEL LED_FULL
164#define LED_MPP_MODE_CTRL(base) (base + 0x40)
165#define LED_MPP_VIN_CTRL(base) (base + 0x41)
166#define LED_MPP_EN_CTRL(base) (base + 0x46)
167#define LED_MPP_SINK_CTRL(base) (base + 0x4C)
168
Amy Malochea2726f02013-05-10 10:19:03 -0700169#define LED_MPP_CURRENT_DEFAULT 5
170#define LED_MPP_CURRENT_PER_SETTING 5
Amy Malochef3813742013-04-11 19:33:47 -0700171#define LED_MPP_SOURCE_SEL_DEFAULT LED_MPP_MODE_ENABLE
172
173#define LED_MPP_SINK_MASK 0x07
174#define LED_MPP_MODE_MASK 0x7F
175#define LED_MPP_EN_MASK 0x80
Amy Malochece59f662013-05-02 10:59:53 -0700176#define LED_MPP_SRC_MASK 0x0F
177#define LED_MPP_MODE_CTRL_MASK 0x70
Amy Malochef3813742013-04-11 19:33:47 -0700178
179#define LED_MPP_MODE_SINK (0x06 << 4)
180#define LED_MPP_MODE_ENABLE 0x01
181#define LED_MPP_MODE_OUTPUT 0x10
182#define LED_MPP_MODE_DISABLE 0x00
183#define LED_MPP_EN_ENABLE 0x80
184#define LED_MPP_EN_DISABLE 0x00
185
186#define MPP_SOURCE_DTEST1 0x08
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530187
188#define KPDBL_MAX_LEVEL LED_FULL
189#define KPDBL_ROW_SRC_SEL(base) (base + 0x40)
190#define KPDBL_ENABLE(base) (base + 0x46)
191#define KPDBL_ROW_SRC(base) (base + 0xE5)
192
193#define KPDBL_ROW_SRC_SEL_VAL_MASK 0x0F
194#define KPDBL_ROW_SCAN_EN_MASK 0x80
195#define KPDBL_ROW_SCAN_VAL_MASK 0x0F
196#define KPDBL_ROW_SCAN_EN_SHIFT 7
197#define KPDBL_MODULE_EN 0x80
198#define KPDBL_MODULE_DIS 0x00
199#define KPDBL_MODULE_EN_MASK 0x80
200
Amy Malochef3d5a062012-08-16 19:14:11 -0700201/**
202 * enum qpnp_leds - QPNP supported led ids
203 * @QPNP_ID_WLED - White led backlight
204 */
205enum qpnp_leds {
Amy Maloche864a6d52012-10-03 15:58:12 -0700206 QPNP_ID_WLED = 0,
207 QPNP_ID_FLASH1_LED0,
208 QPNP_ID_FLASH1_LED1,
Amy Malocheeea7b592012-10-03 15:59:36 -0700209 QPNP_ID_RGB_RED,
210 QPNP_ID_RGB_GREEN,
211 QPNP_ID_RGB_BLUE,
Amy Malochef3813742013-04-11 19:33:47 -0700212 QPNP_ID_LED_MPP,
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530213 QPNP_ID_KPDBL,
Amy Maloche864a6d52012-10-03 15:58:12 -0700214 QPNP_ID_MAX,
Amy Malochef3d5a062012-08-16 19:14:11 -0700215};
216
217/* current boost limit */
218enum wled_current_boost_limit {
219 WLED_CURR_LIMIT_105mA,
220 WLED_CURR_LIMIT_385mA,
221 WLED_CURR_LIMIT_525mA,
222 WLED_CURR_LIMIT_805mA,
223 WLED_CURR_LIMIT_980mA,
224 WLED_CURR_LIMIT_1260mA,
225 WLED_CURR_LIMIT_1400mA,
226 WLED_CURR_LIMIT_1680mA,
227};
228
229/* over voltage protection threshold */
230enum wled_ovp_threshold {
231 WLED_OVP_35V,
232 WLED_OVP_32V,
233 WLED_OVP_29V,
234 WLED_OVP_37V,
235};
236
237/* switch frquency */
238enum wled_switch_freq {
239 WLED_800kHz = 0,
240 WLED_960kHz,
241 WLED_1600kHz,
242 WLED_3200kHz,
243};
244
Amy Maloche864a6d52012-10-03 15:58:12 -0700245enum flash_headroom {
246 HEADROOM_250mV = 0,
247 HEADROOM_300mV,
248 HEADROOM_400mV,
249 HEADROOM_500mV,
250};
251
252enum flash_startup_dly {
253 DELAY_10us = 0,
254 DELAY_32us,
255 DELAY_64us,
256 DELAY_128us,
257};
258
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530259enum led_mode {
260 PWM_MODE = 0,
261 LPG_MODE,
Amy Malochea2726f02013-05-10 10:19:03 -0700262 MANUAL_MODE,
Amy Malocheeea7b592012-10-03 15:59:36 -0700263};
264
Amy Malochef3d5a062012-08-16 19:14:11 -0700265static u8 wled_debug_regs[] = {
266 /* common registers */
267 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
268 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
269 /* LED1 */
270 0x60, 0x61, 0x62, 0x63, 0x66,
Amy Malochea5ca5552012-10-23 13:34:46 -0700271 /* LED2 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700272 0x70, 0x71, 0x72, 0x73, 0x76,
Amy Malochea5ca5552012-10-23 13:34:46 -0700273 /* LED3 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700274 0x80, 0x81, 0x82, 0x83, 0x86,
275};
276
Amy Maloche864a6d52012-10-03 15:58:12 -0700277static u8 flash_debug_regs[] = {
278 0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
279 0x4f, 0x46, 0x47,
280};
281
Amy Malocheeea7b592012-10-03 15:59:36 -0700282static u8 rgb_pwm_debug_regs[] = {
283 0x45, 0x46, 0x47,
284};
Amy Malochef3813742013-04-11 19:33:47 -0700285
286static u8 mpp_debug_regs[] = {
287 0x40, 0x41, 0x42, 0x45, 0x46, 0x4c,
288};
289
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530290static u8 kpdbl_debug_regs[] = {
291 0x40, 0x46, 0xb1, 0xb3, 0xb4, 0xe5,
292};
293
Amy Malochef3d5a062012-08-16 19:14:11 -0700294/**
Amy Malochea2726f02013-05-10 10:19:03 -0700295 * pwm_config_data - pwm configuration data
296 * @lut_params - lut parameters to be used by pwm driver
297 * @pwm_device - pwm device
298 * @pwm_channel - pwm channel to be configured for led
299 * @pwm_period_us - period for pwm, in us
300 * @mode - mode the led operates in
301 */
302struct pwm_config_data {
303 struct lut_params lut_params;
304 struct pwm_device *pwm_dev;
305 int pwm_channel;
306 u32 pwm_period_us;
307 struct pwm_duty_cycles *duty_cycles;
308 u8 mode;
309 u8 enable;
310};
311
312/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700313 * wled_config_data - wled configuration data
314 * @num_strings - number of wled strings supported
315 * @ovp_val - over voltage protection threshold
316 * @boost_curr_lim - boot current limit
317 * @cp_select - high pole capacitance
318 * @ctrl_delay_us - delay in activation of led
319 * @dig_mod_gen_en - digital module generator
320 * @cs_out_en - current sink output enable
321 * @op_fdbck - selection of output as feedback for the boost
322 */
323struct wled_config_data {
324 u8 num_strings;
325 u8 ovp_val;
326 u8 boost_curr_lim;
327 u8 cp_select;
328 u8 ctrl_delay_us;
329 u8 switch_freq;
Amy Malochebd687672013-03-18 11:23:45 -0700330 u8 op_fdbck;
Amy Malochef3d5a062012-08-16 19:14:11 -0700331 bool dig_mod_gen_en;
332 bool cs_out_en;
Amy Malochef3d5a062012-08-16 19:14:11 -0700333};
334
335/**
Amy Malochef3813742013-04-11 19:33:47 -0700336 * mpp_config_data - mpp configuration data
Amy Malochea2726f02013-05-10 10:19:03 -0700337 * @pwm_cfg - device pwm configuration
Amy Malochef3813742013-04-11 19:33:47 -0700338 * @current_setting - current setting, 5ma-40ma in 5ma increments
Amy Malochea2726f02013-05-10 10:19:03 -0700339 * @source_sel - source selection
340 * @mode_ctrl - mode control
341 * @pwm_mode - pwm mode in use
Amy Malochef3813742013-04-11 19:33:47 -0700342 */
343struct mpp_config_data {
Amy Malochea2726f02013-05-10 10:19:03 -0700344 struct pwm_config_data *pwm_cfg;
Amy Malochef3813742013-04-11 19:33:47 -0700345 u8 current_setting;
346 u8 source_sel;
347 u8 mode_ctrl;
Amy Malochea2726f02013-05-10 10:19:03 -0700348 u8 pwm_mode;
Amy Malochef3813742013-04-11 19:33:47 -0700349};
350
351/**
Amy Maloche864a6d52012-10-03 15:58:12 -0700352 * flash_config_data - flash configuration data
353 * @current_prgm - current to be programmed, scaled by max level
354 * @clamp_curr - clamp current to use
355 * @headroom - headroom value to use
356 * @duration - duration of the flash
357 * @enable_module - enable address for particular flash
358 * @trigger_flash - trigger flash
359 * @startup_dly - startup delay for flash
Amy Malochebc97c0d22013-03-24 22:06:16 -0700360 * @strobe_type - select between sw and hw strobe
Amy Maloche864a6d52012-10-03 15:58:12 -0700361 * @current_addr - address to write for current
362 * @second_addr - address of secondary flash to be written
363 * @safety_timer - enable safety timer or watchdog timer
Amy Malochebc97c0d22013-03-24 22:06:16 -0700364 * @torch_enable - enable flash LED torch mode
Amy Maloche864a6d52012-10-03 15:58:12 -0700365 */
366struct flash_config_data {
367 u8 current_prgm;
368 u8 clamp_curr;
369 u8 headroom;
370 u8 duration;
371 u8 enable_module;
372 u8 trigger_flash;
373 u8 startup_dly;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700374 u8 strobe_type;
Amy Maloche864a6d52012-10-03 15:58:12 -0700375 u16 current_addr;
376 u16 second_addr;
377 bool safety_timer;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700378 bool torch_enable;
Amy Maloche864a6d52012-10-03 15:58:12 -0700379};
380
381/**
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530382 * kpdbl_config_data - kpdbl configuration data
Amy Malochea2726f02013-05-10 10:19:03 -0700383 * @pwm_cfg - device pwm configuration
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530384 * @row_src_sel_val - select source, 0 for vph_pwr and 1 for vbst
385 * @row_scan_en - enable row scan
386 * @row_scan_val - map to enable needed rows
387 */
388struct kpdbl_config_data {
Amy Malochea2726f02013-05-10 10:19:03 -0700389 struct pwm_config_data *pwm_cfg;
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530390 u32 row_src_sel_val;
391 u32 row_scan_en;
392 u32 row_scan_val;
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530393};
394
395/**
Amy Malocheeea7b592012-10-03 15:59:36 -0700396 * rgb_config_data - rgb configuration data
Amy Malochea2726f02013-05-10 10:19:03 -0700397 * @pwm_cfg - device pwm configuration
398 * @enable - bits to enable led
Amy Malocheeea7b592012-10-03 15:59:36 -0700399 */
400struct rgb_config_data {
Amy Malochea2726f02013-05-10 10:19:03 -0700401 struct pwm_config_data *pwm_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700402 u8 enable;
403};
404
405/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700406 * struct qpnp_led_data - internal led data structure
407 * @led_classdev - led class device
Asaf Penso55ac8472013-01-21 21:17:37 +0200408 * @delayed_work - delayed work for turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700409 * @id - led index
410 * @base_reg - base register given in device tree
411 * @lock - to protect the transactions
412 * @reg - cached value of led register
Amy Malochea5ca5552012-10-23 13:34:46 -0700413 * @num_leds - number of leds in the module
Amy Malochef3d5a062012-08-16 19:14:11 -0700414 * @max_current - maximum current supported by LED
415 * @default_on - true: default state max, false, default state 0
Asaf Penso55ac8472013-01-21 21:17:37 +0200416 * @turn_off_delay_ms - number of msec before turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700417 */
418struct qpnp_led_data {
419 struct led_classdev cdev;
420 struct spmi_device *spmi_dev;
Asaf Penso55ac8472013-01-21 21:17:37 +0200421 struct delayed_work dwork;
Amy Malochef3d5a062012-08-16 19:14:11 -0700422 int id;
423 u16 base;
424 u8 reg;
Amy Malochea5ca5552012-10-23 13:34:46 -0700425 u8 num_leds;
Amy Malochedc3e5572012-09-25 16:39:06 -0700426 spinlock_t lock;
Amy Malochef3d5a062012-08-16 19:14:11 -0700427 struct wled_config_data *wled_cfg;
Amy Maloche864a6d52012-10-03 15:58:12 -0700428 struct flash_config_data *flash_cfg;
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530429 struct kpdbl_config_data *kpdbl_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700430 struct rgb_config_data *rgb_cfg;
Amy Malochef3813742013-04-11 19:33:47 -0700431 struct mpp_config_data *mpp_cfg;
Amy Malochef3d5a062012-08-16 19:14:11 -0700432 int max_current;
433 bool default_on;
Asaf Penso55ac8472013-01-21 21:17:37 +0200434 int turn_off_delay_ms;
Amy Malochef3d5a062012-08-16 19:14:11 -0700435};
436
437static int
438qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
439{
440 int rc;
441 u8 reg;
442
443 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
444 addr, &reg, 1);
445 if (rc) {
446 dev_err(&led->spmi_dev->dev,
447 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
448 }
449
450 reg &= ~mask;
451 reg |= val;
452
453 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
454 addr, &reg, 1);
455 if (rc)
456 dev_err(&led->spmi_dev->dev,
457 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
458 return rc;
459}
460
Amy Malochea5ca5552012-10-23 13:34:46 -0700461static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
462{
463 int i;
464 u8 val;
465
466 pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
467 for (i = 0; i < array_size; i++) {
468 spmi_ext_register_readl(led->spmi_dev->ctrl,
469 led->spmi_dev->sid,
470 led->base + regs[i],
471 &val, sizeof(val));
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530472 pr_debug("%s: 0x%x = 0x%x\n", led->cdev.name,
473 led->base + regs[i], val);
Amy Malochea5ca5552012-10-23 13:34:46 -0700474 }
475 pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
476}
477
Amy Malochef3d5a062012-08-16 19:14:11 -0700478static int qpnp_wled_set(struct qpnp_led_data *led)
479{
Amy Maloched55fdb82013-02-26 18:11:57 -0800480 int rc, duty, level;
481 u8 val, i, num_wled_strings;
Amy Malochef3d5a062012-08-16 19:14:11 -0700482
483 level = led->cdev.brightness;
484
485 if (level > WLED_MAX_LEVEL)
486 level = WLED_MAX_LEVEL;
487 if (level == 0) {
488 val = WLED_BOOST_OFF;
489 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
490 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
491 &val, 1);
492 if (rc) {
493 dev_err(&led->spmi_dev->dev,
494 "WLED write ctrl reg failed(%d)\n", rc);
495 return rc;
496 }
497 } else {
498 val = WLED_BOOST_ON;
499 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
500 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
501 &val, 1);
502 if (rc) {
503 dev_err(&led->spmi_dev->dev,
504 "WLED write ctrl reg failed(%d)\n", rc);
505 return rc;
506 }
507 }
508
509 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
510
511 num_wled_strings = led->wled_cfg->num_strings;
512
513 /* program brightness control registers */
514 for (i = 0; i < num_wled_strings; i++) {
515 rc = qpnp_led_masked_write(led,
516 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
517 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
518 if (rc) {
519 dev_err(&led->spmi_dev->dev,
520 "WLED set brightness MSB failed(%d)\n", rc);
521 return rc;
522 }
523 val = duty & WLED_8_BIT_MASK;
524 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
525 led->spmi_dev->sid,
526 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
527 if (rc) {
528 dev_err(&led->spmi_dev->dev,
529 "WLED set brightness LSB failed(%d)\n", rc);
530 return rc;
531 }
532 }
533
534 /* sync */
535 val = WLED_SYNC_VAL;
536 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
537 WLED_SYNC_REG(led->base), &val, 1);
538 if (rc) {
539 dev_err(&led->spmi_dev->dev,
540 "WLED set sync reg failed(%d)\n", rc);
541 return rc;
542 }
543
544 val = WLED_SYNC_RESET_VAL;
545 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
546 WLED_SYNC_REG(led->base), &val, 1);
547 if (rc) {
548 dev_err(&led->spmi_dev->dev,
549 "WLED reset sync reg failed(%d)\n", rc);
550 return rc;
551 }
552 return 0;
553}
554
Amy Malochef3813742013-04-11 19:33:47 -0700555static int qpnp_mpp_set(struct qpnp_led_data *led)
556{
557 int rc, val;
Amy Malochea2726f02013-05-10 10:19:03 -0700558 int duty_us;
Amy Malochef3813742013-04-11 19:33:47 -0700559
560 if (led->cdev.brightness) {
Amy Malochea2726f02013-05-10 10:19:03 -0700561 if (led->mpp_cfg->pwm_mode == PWM_MODE) {
562 pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
563 duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
564 led->cdev.brightness) / LED_FULL;
565 /*config pwm for brightness scaling*/
566 rc = pwm_config(led->mpp_cfg->pwm_cfg->pwm_dev,
567 duty_us,
568 led->mpp_cfg->pwm_cfg->pwm_period_us);
569 if (rc < 0) {
570 dev_err(&led->spmi_dev->dev, "Failed to " \
571 "configure pwm for new values\n");
572 return rc;
573 }
Amy Malochef3813742013-04-11 19:33:47 -0700574 }
575
Amy Malochea2726f02013-05-10 10:19:03 -0700576 if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
577 pwm_enable(led->mpp_cfg->pwm_cfg->pwm_dev);
578
Amy Malochece59f662013-05-02 10:59:53 -0700579 val = (led->mpp_cfg->source_sel & LED_MPP_SRC_MASK) |
580 (led->mpp_cfg->mode_ctrl & LED_MPP_MODE_CTRL_MASK);
Amy Malochef3813742013-04-11 19:33:47 -0700581
582 rc = qpnp_led_masked_write(led,
Amy Malochea2726f02013-05-10 10:19:03 -0700583 LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
584 val);
Amy Malochef3813742013-04-11 19:33:47 -0700585 if (rc) {
586 dev_err(&led->spmi_dev->dev,
587 "Failed to write led mode reg\n");
588 return rc;
589 }
590
591 rc = qpnp_led_masked_write(led,
592 LED_MPP_EN_CTRL(led->base), LED_MPP_EN_MASK,
593 LED_MPP_EN_ENABLE);
Amy Malochea2726f02013-05-10 10:19:03 -0700594 if (rc) {
595 dev_err(&led->spmi_dev->dev,
596 "Failed to write led enable " \
597 "reg\n");
598 return rc;
599 }
Amy Malochef3813742013-04-11 19:33:47 -0700600 } else {
Amy Malochea2726f02013-05-10 10:19:03 -0700601 if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
602 pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
Amy Malochef3813742013-04-11 19:33:47 -0700603 rc = qpnp_led_masked_write(led,
604 LED_MPP_MODE_CTRL(led->base),
605 LED_MPP_MODE_MASK,
606 LED_MPP_MODE_DISABLE);
607 if (rc) {
608 dev_err(&led->spmi_dev->dev,
609 "Failed to write led mode reg\n");
610 return rc;
611 }
612
613 rc = qpnp_led_masked_write(led,
614 LED_MPP_EN_CTRL(led->base),
615 LED_MPP_EN_MASK,
616 LED_MPP_EN_DISABLE);
617 if (rc) {
618 dev_err(&led->spmi_dev->dev,
619 "Failed to write led enable reg\n");
620 return rc;
621 }
622 }
623
624 qpnp_dump_regs(led, mpp_debug_regs, ARRAY_SIZE(mpp_debug_regs));
625
626 return 0;
627}
628
Amy Maloche864a6d52012-10-03 15:58:12 -0700629static int qpnp_flash_set(struct qpnp_led_data *led)
630{
631 int rc;
632 int val = led->cdev.brightness;
633
634 led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
635 led->max_current);
636
637 led->flash_cfg->current_prgm =
638 led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
639 if (!led->flash_cfg->current_prgm)
640 led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
641
642 /* Set led current */
643 if (val > 0) {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700644 if (led->flash_cfg->torch_enable) {
645 rc = qpnp_led_masked_write(led,
646 FLASH_LED_UNLOCK_SECURE(led->base),
647 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
648 if (rc) {
649 dev_err(&led->spmi_dev->dev,
650 "Secure reg write failed(%d)\n", rc);
651 return rc;
652 }
653
654 rc = qpnp_led_masked_write(led,
655 FLASH_LED_TORCH(led->base),
656 FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
657 if (rc) {
658 dev_err(&led->spmi_dev->dev,
659 "Torch reg write failed(%d)\n", rc);
660 return rc;
661 }
662
Amy Malochebc97c0d22013-03-24 22:06:16 -0700663 rc = qpnp_led_masked_write(led,
664 led->flash_cfg->current_addr,
Chun Zhange8954cf2013-05-02 11:14:34 -0700665 FLASH_CURRENT_MASK,
666 led->flash_cfg->current_prgm);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700667 if (rc) {
668 dev_err(&led->spmi_dev->dev,
669 "Current reg write failed(%d)\n", rc);
670 return rc;
671 }
672
673 rc = qpnp_led_masked_write(led,
674 led->flash_cfg->second_addr,
Chun Zhange8954cf2013-05-02 11:14:34 -0700675 FLASH_CURRENT_MASK,
676 led->flash_cfg->current_prgm);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700677 if (rc) {
678 dev_err(&led->spmi_dev->dev,
679 "2nd Current reg write failed(%d)\n",
680 rc);
681 return rc;
682 }
683
Chun Zhange8954cf2013-05-02 11:14:34 -0700684 qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
685 FLASH_CURRENT_MASK,
686 led->max_current);
687 if (rc) {
688 dev_err(&led->spmi_dev->dev,
689 "Max current reg write failed(%d)\n",
690 rc);
691 return rc;
692 }
693
Amy Malochebc97c0d22013-03-24 22:06:16 -0700694 rc = qpnp_led_masked_write(led,
695 FLASH_ENABLE_CONTROL(led->base),
696 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
697 if (rc) {
698 dev_err(&led->spmi_dev->dev,
699 "Enable reg write failed(%d)\n", rc);
700 return rc;
701 }
702 } else {
Chun Zhange8954cf2013-05-02 11:14:34 -0700703 /* Set flash safety timer */
Amy Malochebc97c0d22013-03-24 22:06:16 -0700704 rc = qpnp_led_masked_write(led,
Chun Zhange8954cf2013-05-02 11:14:34 -0700705 FLASH_SAFETY_TIMER(led->base),
706 FLASH_SAFETY_TIMER_MASK,
707 led->flash_cfg->duration);
708 if (rc) {
709 dev_err(&led->spmi_dev->dev,
710 "Safety timer reg write failed(%d)\n",
711 rc);
712 return rc;
713 }
714
715 /* Set max current */
716 rc = qpnp_led_masked_write(led,
717 FLASH_MAX_CURR(led->base), FLASH_CURRENT_MASK,
718 FLASH_MAX_LEVEL);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700719 if (rc) {
720 dev_err(&led->spmi_dev->dev,
721 "Max current reg write failed(%d)\n",
722 rc);
723 return rc;
724 }
725
Chun Zhange8954cf2013-05-02 11:14:34 -0700726 /* Set clamp current */
727 rc = qpnp_led_masked_write(led,
728 FLASH_CLAMP_CURR(led->base),
729 FLASH_CURRENT_MASK,
730 led->flash_cfg->clamp_curr);
731 if (rc) {
732 dev_err(&led->spmi_dev->dev,
733 "Clamp current reg write failed(%d)\n",
734 rc);
735 return rc;
736 }
737
Amy Malochebc97c0d22013-03-24 22:06:16 -0700738 /* Write 0x80 to MODULE_ENABLE before writing 0xE0
739 * in order to avoid reg value goes from 0x00 to
740 * 0xE0. This causes a hardware bug.
741 */
742 rc = qpnp_led_masked_write(led,
743 FLASH_ENABLE_CONTROL(led->base),
744 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
745 if (rc) {
746 dev_err(&led->spmi_dev->dev,
747 "Enable reg write failed(%d)\n", rc);
748 return rc;
749 }
750
751 rc = qpnp_led_masked_write(led,
752 led->flash_cfg->current_addr,
753 FLASH_CURRENT_MASK,
754 led->flash_cfg->current_prgm);
755 if (rc) {
756 dev_err(&led->spmi_dev->dev,
757 "Current reg write failed(%d)\n", rc);
758 return rc;
759 }
760
761 rc = qpnp_led_masked_write(led,
762 led->flash_cfg->second_addr,
763 FLASH_CURRENT_MASK,
764 led->flash_cfg->current_prgm);
765 if (rc) {
766 dev_err(&led->spmi_dev->dev,
767 "2nd Current reg write failed(%d)\n",
768 rc);
769 return rc;
770 }
771
772 rc = qpnp_led_masked_write(led,
Amy Malochebc97c0d22013-03-24 22:06:16 -0700773 FLASH_ENABLE_CONTROL(led->base),
774 FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
775 if (rc) {
776 dev_err(&led->spmi_dev->dev,
777 "Enable reg write failed(%d)\n", rc);
778 return rc;
779 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800780 }
781
Amy Malochebc97c0d22013-03-24 22:06:16 -0700782 if (!led->flash_cfg->strobe_type) {
783 rc = qpnp_led_masked_write(led,
784 FLASH_LED_STROBE_CTRL(led->base),
785 FLASH_STROBE_MASK, FLASH_STROBE_SW);
786 if (rc) {
787 dev_err(&led->spmi_dev->dev,
788 "LED %d strobe reg write failed(%d)\n",
789 led->id, rc);
790 return rc;
791 }
792 } else {
793 rc = qpnp_led_masked_write(led,
794 FLASH_LED_STROBE_CTRL(led->base),
795 FLASH_STROBE_MASK, FLASH_STROBE_HW);
796 if (rc) {
797 dev_err(&led->spmi_dev->dev,
798 "LED %d strobe reg write failed(%d)\n",
799 led->id, rc);
800 return rc;
801 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800802 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700803 } else {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700804 if (led->flash_cfg->torch_enable) {
805 rc = qpnp_led_masked_write(led,
806 FLASH_LED_UNLOCK_SECURE(led->base),
807 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
808 if (rc) {
809 dev_err(&led->spmi_dev->dev,
810 "Secure reg write failed(%d)\n", rc);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700811 return rc;
812 }
813
814 rc = qpnp_led_masked_write(led,
Chun Zhange8954cf2013-05-02 11:14:34 -0700815 FLASH_LED_TORCH(led->base),
816 FLASH_TORCH_MASK,
817 FLASH_LED_TORCH_DISABLE);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700818 if (rc) {
819 dev_err(&led->spmi_dev->dev,
Chun Zhange8954cf2013-05-02 11:14:34 -0700820 "Torch reg write failed(%d)\n", rc);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700821 return rc;
822 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700823 }
824
825 rc = qpnp_led_masked_write(led,
826 FLASH_LED_STROBE_CTRL(led->base),
827 FLASH_STROBE_MASK,
828 FLASH_DISABLE_ALL);
829 if (rc) {
830 dev_err(&led->spmi_dev->dev,
831 "LED %d flash write failed(%d)\n", led->id, rc);
832 return rc;
833 }
Amy Malochebc97c0d22013-03-24 22:06:16 -0700834
835 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
836 FLASH_ENABLE_MASK,
837 FLASH_DISABLE_ALL);
838 if (rc) {
839 dev_err(&led->spmi_dev->dev,
840 "Enable reg write failed(%d)\n", rc);
841 return rc;
842 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700843 }
844
Amy Malocheeea7b592012-10-03 15:59:36 -0700845 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
846
847 return 0;
848}
849
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530850static int qpnp_kpdbl_set(struct qpnp_led_data *led)
851{
852 int duty_us;
853 int rc;
854
855 if (led->cdev.brightness) {
856 rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
857 KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
Amy Malochea2726f02013-05-10 10:19:03 -0700858 duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530859 led->cdev.brightness) / KPDBL_MAX_LEVEL;
Amy Malochea2726f02013-05-10 10:19:03 -0700860 rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev, duty_us,
861 led->kpdbl_cfg->pwm_cfg->pwm_period_us);
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530862 if (rc < 0) {
863 dev_err(&led->spmi_dev->dev, "pwm config failed\n");
864 return rc;
865 }
Amy Malochea2726f02013-05-10 10:19:03 -0700866 rc = pwm_enable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530867 if (rc < 0) {
868 dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
869 return rc;
870 }
871 } else {
Amy Malochea2726f02013-05-10 10:19:03 -0700872 pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530873 rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
874 KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
875 if (rc) {
876 dev_err(&led->spmi_dev->dev,
877 "Failed to write led enable reg\n");
878 return rc;
879 }
880 }
881
882 qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
883
884 return 0;
885}
886
Amy Malocheeea7b592012-10-03 15:59:36 -0700887static int qpnp_rgb_set(struct qpnp_led_data *led)
888{
889 int duty_us;
890 int rc;
891
892 if (led->cdev.brightness) {
Amy Malochea2726f02013-05-10 10:19:03 -0700893 if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
894 duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
Amy Malocheeea7b592012-10-03 15:59:36 -0700895 led->cdev.brightness) / LED_FULL;
Amy Malochea2726f02013-05-10 10:19:03 -0700896 rc = pwm_config(led->rgb_cfg->pwm_cfg->pwm_dev, duty_us,
897 led->rgb_cfg->pwm_cfg->pwm_period_us);
Amy Malocheeea7b592012-10-03 15:59:36 -0700898 if (rc < 0) {
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530899 dev_err(&led->spmi_dev->dev,
900 "pwm config failed\n");
Amy Malocheeea7b592012-10-03 15:59:36 -0700901 return rc;
902 }
903 }
904 rc = qpnp_led_masked_write(led,
905 RGB_LED_EN_CTL(led->base),
906 led->rgb_cfg->enable, led->rgb_cfg->enable);
907 if (rc) {
908 dev_err(&led->spmi_dev->dev,
909 "Failed to write led enable reg\n");
910 return rc;
911 }
Amy Malochea2726f02013-05-10 10:19:03 -0700912
913 rc = pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530914 if (rc < 0) {
915 dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
916 return rc;
917 }
Amy Malocheeea7b592012-10-03 15:59:36 -0700918 } else {
Amy Malochea2726f02013-05-10 10:19:03 -0700919 pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
Amy Malocheeea7b592012-10-03 15:59:36 -0700920 rc = qpnp_led_masked_write(led,
921 RGB_LED_EN_CTL(led->base),
922 led->rgb_cfg->enable, RGB_LED_DISABLE);
923 if (rc) {
924 dev_err(&led->spmi_dev->dev,
925 "Failed to write led enable reg\n");
926 return rc;
927 }
928 }
929
930 qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
931
Amy Maloche864a6d52012-10-03 15:58:12 -0700932 return 0;
933}
934
Amy Malochef3d5a062012-08-16 19:14:11 -0700935static void qpnp_led_set(struct led_classdev *led_cdev,
936 enum led_brightness value)
937{
938 int rc;
939 struct qpnp_led_data *led;
940
941 led = container_of(led_cdev, struct qpnp_led_data, cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -0700942 if (value < LED_OFF || value > led->cdev.max_brightness) {
Amy Malochea5ca5552012-10-23 13:34:46 -0700943 dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
Amy Malochef3d5a062012-08-16 19:14:11 -0700944 return;
945 }
946
Amy Malochedc3e5572012-09-25 16:39:06 -0700947 spin_lock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700948 led->cdev.brightness = value;
949
950 switch (led->id) {
951 case QPNP_ID_WLED:
952 rc = qpnp_wled_set(led);
953 if (rc < 0)
Amy Malochea5ca5552012-10-23 13:34:46 -0700954 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700955 "WLED set brightness failed (%d)\n", rc);
956 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700957 case QPNP_ID_FLASH1_LED0:
958 case QPNP_ID_FLASH1_LED1:
959 rc = qpnp_flash_set(led);
960 if (rc < 0)
961 dev_err(&led->spmi_dev->dev,
962 "FLASH set brightness failed (%d)\n", rc);
963 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700964 case QPNP_ID_RGB_RED:
965 case QPNP_ID_RGB_GREEN:
966 case QPNP_ID_RGB_BLUE:
967 rc = qpnp_rgb_set(led);
968 if (rc < 0)
969 dev_err(&led->spmi_dev->dev,
970 "RGB set brightness failed (%d)\n", rc);
971 break;
Amy Malochef3813742013-04-11 19:33:47 -0700972 case QPNP_ID_LED_MPP:
973 rc = qpnp_mpp_set(led);
974 if (rc < 0)
975 dev_err(&led->spmi_dev->dev,
976 "MPP set brightness failed (%d)\n", rc);
Amy Maloche14c9eb32013-05-06 13:37:58 -0700977 break;
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530978 case QPNP_ID_KPDBL:
979 rc = qpnp_kpdbl_set(led);
980 if (rc < 0)
981 dev_err(&led->spmi_dev->dev,
982 "KPDBL set brightness failed (%d)\n", rc);
Amy Malochef3813742013-04-11 19:33:47 -0700983 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700984 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700985 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700986 break;
987 }
Amy Malochedc3e5572012-09-25 16:39:06 -0700988 spin_unlock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700989}
990
991static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
992{
993 switch (led->id) {
994 case QPNP_ID_WLED:
995 led->cdev.max_brightness = WLED_MAX_LEVEL;
996 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700997 case QPNP_ID_FLASH1_LED0:
998 case QPNP_ID_FLASH1_LED1:
999 led->cdev.max_brightness = led->max_current;
1000 break;
Amy Malocheeea7b592012-10-03 15:59:36 -07001001 case QPNP_ID_RGB_RED:
1002 case QPNP_ID_RGB_GREEN:
1003 case QPNP_ID_RGB_BLUE:
1004 led->cdev.max_brightness = RGB_MAX_LEVEL;
1005 break;
Amy Malochef3813742013-04-11 19:33:47 -07001006 case QPNP_ID_LED_MPP:
1007 led->cdev.max_brightness = MPP_MAX_LEVEL;
1008 break;
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301009 case QPNP_ID_KPDBL:
1010 led->cdev.max_brightness = KPDBL_MAX_LEVEL;
1011 break;
Amy Malochef3d5a062012-08-16 19:14:11 -07001012 default:
Amy Malochea5ca5552012-10-23 13:34:46 -07001013 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -07001014 return -EINVAL;
1015 }
1016
1017 return 0;
1018}
1019
1020static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
1021{
1022 struct qpnp_led_data *led;
1023
1024 led = container_of(led_cdev, struct qpnp_led_data, cdev);
1025
1026 return led->cdev.brightness;
1027}
1028
Asaf Penso55ac8472013-01-21 21:17:37 +02001029static void qpnp_led_turn_off_delayed(struct work_struct *work)
1030{
1031 struct delayed_work *dwork = to_delayed_work(work);
1032 struct qpnp_led_data *led
1033 = container_of(dwork, struct qpnp_led_data, dwork);
1034
1035 led->cdev.brightness = LED_OFF;
1036 qpnp_led_set(&led->cdev, led->cdev.brightness);
1037}
1038
1039static void qpnp_led_turn_off(struct qpnp_led_data *led)
1040{
1041 INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed);
1042 schedule_delayed_work(&led->dwork,
1043 msecs_to_jiffies(led->turn_off_delay_ms));
1044}
1045
Amy Malochef3d5a062012-08-16 19:14:11 -07001046static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
1047{
1048 int rc, i;
1049 u8 num_wled_strings;
1050
1051 num_wled_strings = led->wled_cfg->num_strings;
1052
1053 /* verify ranges */
1054 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
1055 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
1056 return -EINVAL;
1057 }
1058
1059 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
1060 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
1061 return -EINVAL;
1062 }
1063
1064 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
1065 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
1066 return -EINVAL;
1067 }
1068
1069 if ((led->max_current > WLED_MAX_CURR)) {
1070 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
1071 return -EINVAL;
1072 }
1073
1074 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
1075 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
1076 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
1077 return -EINVAL;
1078 }
1079
1080 /* program over voltage protection threshold */
1081 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
1082 WLED_OVP_VAL_MASK,
1083 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
1084 if (rc) {
1085 dev_err(&led->spmi_dev->dev,
1086 "WLED OVP reg write failed(%d)\n", rc);
1087 return rc;
1088 }
1089
1090 /* program current boost limit */
1091 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
1092 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
1093 if (rc) {
1094 dev_err(&led->spmi_dev->dev,
1095 "WLED boost limit reg write failed(%d)\n", rc);
1096 return rc;
1097 }
1098
1099 /* program output feedback */
1100 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
1101 WLED_OP_FDBCK_MASK,
1102 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
1103 if (rc) {
1104 dev_err(&led->spmi_dev->dev,
1105 "WLED fdbck ctrl reg write failed(%d)\n", rc);
1106 return rc;
1107 }
1108
1109 /* program switch frequency */
1110 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
1111 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
1112 if (rc) {
1113 dev_err(&led->spmi_dev->dev,
1114 "WLED switch freq reg write failed(%d)\n", rc);
1115 return rc;
1116 }
1117
1118 /* program current sink */
1119 if (led->wled_cfg->cs_out_en) {
1120 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
1121 WLED_CURR_SINK_MASK,
Amy Maloche832d90a2013-01-07 10:15:29 -08001122 (((1 << led->wled_cfg->num_strings) - 1)
1123 << WLED_CURR_SINK_SHFT));
Amy Malochef3d5a062012-08-16 19:14:11 -07001124 if (rc) {
1125 dev_err(&led->spmi_dev->dev,
1126 "WLED curr sink reg write failed(%d)\n", rc);
1127 return rc;
1128 }
1129 }
1130
1131 /* program high pole capacitance */
1132 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
1133 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
1134 if (rc) {
1135 dev_err(&led->spmi_dev->dev,
1136 "WLED pole cap reg write failed(%d)\n", rc);
1137 return rc;
1138 }
1139
1140 /* program modulator, current mod src and cabc */
1141 for (i = 0; i < num_wled_strings; i++) {
1142 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
1143 WLED_NO_MASK, WLED_EN_MASK);
1144 if (rc) {
1145 dev_err(&led->spmi_dev->dev,
1146 "WLED mod enable reg write failed(%d)\n", rc);
1147 return rc;
1148 }
1149
1150 if (led->wled_cfg->dig_mod_gen_en) {
1151 rc = qpnp_led_masked_write(led,
Amy Maloched44516e2013-02-14 17:36:34 -08001152 WLED_MOD_SRC_SEL_REG(led->base, i),
Amy Malochef3d5a062012-08-16 19:14:11 -07001153 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
1154 if (rc) {
1155 dev_err(&led->spmi_dev->dev,
1156 "WLED dig mod en reg write failed(%d)\n", rc);
1157 }
1158 }
1159
1160 rc = qpnp_led_masked_write(led,
1161 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
1162 led->max_current);
1163 if (rc) {
1164 dev_err(&led->spmi_dev->dev,
1165 "WLED max current reg write failed(%d)\n", rc);
1166 return rc;
1167 }
1168
1169 }
1170
1171 /* dump wled registers */
Amy Malochea5ca5552012-10-23 13:34:46 -07001172 qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
Amy Malochef3d5a062012-08-16 19:14:11 -07001173
1174 return 0;
1175}
1176
Amy Malochebc97c0d22013-03-24 22:06:16 -07001177static ssize_t led_mode_store(struct device *dev,
1178 struct device_attribute *attr,
1179 const char *buf, size_t count)
1180{
1181 struct qpnp_led_data *led;
1182 unsigned long state;
1183 struct led_classdev *led_cdev = dev_get_drvdata(dev);
1184 ssize_t ret = -EINVAL;
1185
1186 ret = kstrtoul(buf, 10, &state);
1187 if (ret)
1188 return ret;
1189
1190 led = container_of(led_cdev, struct qpnp_led_data, cdev);
1191
1192 /* '1' to enable torch mode; '0' to switch to flash mode */
1193 if (state == 1)
1194 led->flash_cfg->torch_enable = true;
1195 else
1196 led->flash_cfg->torch_enable = false;
1197
1198 return count;
1199}
1200
1201static ssize_t led_strobe_type_store(struct device *dev,
1202 struct device_attribute *attr,
1203 const char *buf, size_t count)
1204{
1205 struct qpnp_led_data *led;
1206 unsigned long state;
1207 struct led_classdev *led_cdev = dev_get_drvdata(dev);
1208 ssize_t ret = -EINVAL;
1209
1210 ret = kstrtoul(buf, 10, &state);
1211 if (ret)
1212 return ret;
1213
1214 led = container_of(led_cdev, struct qpnp_led_data, cdev);
1215
1216 /* '0' for sw strobe; '1' for hw strobe */
1217 if (state == 1)
1218 led->flash_cfg->strobe_type = 1;
1219 else
1220 led->flash_cfg->strobe_type = 0;
1221
1222 return count;
1223}
1224
1225static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
1226static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
1227
1228static struct attribute *led_attrs[] = {
1229 &dev_attr_led_mode.attr,
1230 &dev_attr_strobe.attr,
Amy Maloche12ad6f32013-04-02 14:39:24 -07001231 NULL
Amy Malochebc97c0d22013-03-24 22:06:16 -07001232};
1233
1234static const struct attribute_group led_attr_group = {
1235 .attrs = led_attrs,
1236};
1237
Amy Maloche864a6d52012-10-03 15:58:12 -07001238static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
1239{
1240 int rc;
1241
1242 rc = qpnp_led_masked_write(led,
1243 FLASH_LED_STROBE_CTRL(led->base),
1244 FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
1245 if (rc) {
1246 dev_err(&led->spmi_dev->dev,
1247 "LED %d flash write failed(%d)\n", led->id, rc);
1248 return rc;
1249 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001250
Amy Maloche864a6d52012-10-03 15:58:12 -07001251 /* Set headroom */
1252 rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
1253 FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
1254 if (rc) {
1255 dev_err(&led->spmi_dev->dev,
1256 "Headroom reg write failed(%d)\n", rc);
1257 return rc;
1258 }
1259
Chun Zhange8954cf2013-05-02 11:14:34 -07001260 /* Set startup delay */
1261 rc = qpnp_led_masked_write(led,
1262 FLASH_STARTUP_DELAY(led->base), FLASH_STARTUP_DLY_MASK,
1263 led->flash_cfg->startup_dly);
1264 if (rc) {
1265 dev_err(&led->spmi_dev->dev,
1266 "Startup delay reg write failed(%d)\n", rc);
1267 return rc;
1268 }
1269
1270 /* Set timer control - safety or watchdog */
1271 if (led->flash_cfg->safety_timer) {
1272 rc = qpnp_led_masked_write(led,
1273 FLASH_LED_TMR_CTRL(led->base),
1274 FLASH_TMR_MASK, FLASH_TMR_SAFETY);
1275 if (rc) {
1276 dev_err(&led->spmi_dev->dev,
1277 "LED timer ctrl reg write failed(%d)\n",
1278 rc);
1279 return rc;
1280 }
1281 }
1282
1283 /* Set Vreg force */
1284 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
1285 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
1286 if (rc) {
1287 dev_err(&led->spmi_dev->dev,
1288 "Vreg OK reg write failed(%d)\n", rc);
1289 return rc;
1290 }
1291
1292 /* Set self fault check */
1293 rc = qpnp_led_masked_write(led, FLASH_FAULT_DETECT(led->base),
1294 FLASH_FAULT_DETECT_MASK, FLASH_SELFCHECK_ENABLE);
1295 if (rc) {
1296 dev_err(&led->spmi_dev->dev,
1297 "Fault detect reg write failed(%d)\n", rc);
1298 return rc;
1299 }
1300
Amy Maloche864a6d52012-10-03 15:58:12 -07001301 /* Set mask enable */
1302 rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
1303 FLASH_MASK_REG_MASK, FLASH_MASK_1);
1304 if (rc) {
1305 dev_err(&led->spmi_dev->dev,
1306 "Mask enable reg write failed(%d)\n", rc);
1307 return rc;
1308 }
1309
Chun Zhange8954cf2013-05-02 11:14:34 -07001310 /* Disable flash LED module */
Amy Maloche864a6d52012-10-03 15:58:12 -07001311 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
Amy Maloche38b9aae2013-02-07 12:15:34 -08001312 FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
Amy Maloche864a6d52012-10-03 15:58:12 -07001313 if (rc) {
1314 dev_err(&led->spmi_dev->dev,
1315 "Enable reg write failed(%d)\n", rc);
1316 return rc;
1317 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07001318
Amy Malochebc97c0d22013-03-24 22:06:16 -07001319 led->flash_cfg->strobe_type = 0;
1320
Amy Maloche864a6d52012-10-03 15:58:12 -07001321 /* dump flash registers */
1322 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
1323
1324 return 0;
1325}
1326
Amy Malochea2726f02013-05-10 10:19:03 -07001327static int __devinit qpnp_pwm_init(struct pwm_config_data *pwm_cfg,
1328 struct spmi_device *spmi_dev,
1329 const char *name)
1330{
1331 int rc, start_idx, idx_len;
1332
1333 if (pwm_cfg->pwm_channel != -1) {
1334 pwm_cfg->pwm_dev =
1335 pwm_request(pwm_cfg->pwm_channel, name);
1336
1337 if (IS_ERR_OR_NULL(pwm_cfg->pwm_dev)) {
1338 dev_err(&spmi_dev->dev,
1339 "could not acquire PWM Channel %d, " \
1340 "error %ld\n",
1341 pwm_cfg->pwm_channel,
1342 PTR_ERR(pwm_cfg->pwm_dev));
1343 pwm_cfg->pwm_dev = NULL;
1344 return -ENODEV;
1345 }
1346
1347 if (pwm_cfg->mode == LPG_MODE) {
1348 start_idx =
1349 pwm_cfg->duty_cycles->start_idx;
1350 idx_len =
1351 pwm_cfg->duty_cycles->num_duty_pcts;
1352
1353 if (idx_len >= PWM_LUT_MAX_SIZE &&
1354 start_idx) {
1355 dev_err(&spmi_dev->dev,
1356 "Wrong LUT size or index\n");
1357 return -EINVAL;
1358 }
1359 if ((start_idx + idx_len) >
1360 PWM_LUT_MAX_SIZE) {
1361 dev_err(&spmi_dev->dev,
1362 "Exceed LUT limit\n");
1363 return -EINVAL;
1364 }
1365 rc = pwm_lut_config(pwm_cfg->pwm_dev,
1366 PM_PWM_PERIOD_MIN, /* ignored by hardware */
1367 pwm_cfg->duty_cycles->duty_pcts,
1368 pwm_cfg->lut_params);
1369 if (rc < 0) {
1370 dev_err(&spmi_dev->dev, "Failed to " \
1371 "configure pwm LUT\n");
1372 return rc;
1373 }
1374 }
1375 } else {
1376 dev_err(&spmi_dev->dev,
1377 "Invalid PWM channel\n");
1378 return -EINVAL;
1379 }
1380
1381 return 0;
1382}
1383
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301384static int __devinit qpnp_kpdbl_init(struct qpnp_led_data *led)
1385{
1386 int rc;
1387 u8 val;
1388
1389 /* enable row source selct */
1390 rc = qpnp_led_masked_write(led, KPDBL_ROW_SRC_SEL(led->base),
1391 KPDBL_ROW_SRC_SEL_VAL_MASK, led->kpdbl_cfg->row_src_sel_val);
1392 if (rc) {
1393 dev_err(&led->spmi_dev->dev,
1394 "Enable row src sel write failed(%d)\n", rc);
1395 return rc;
1396 }
1397
1398 /* row source */
1399 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
1400 KPDBL_ROW_SRC(led->base), &val, 1);
1401 if (rc) {
1402 dev_err(&led->spmi_dev->dev,
1403 "Unable to read from addr=%x, rc(%d)\n",
1404 KPDBL_ROW_SRC(led->base), rc);
1405 return rc;
1406 }
1407
1408 val &= ~KPDBL_ROW_SCAN_VAL_MASK;
1409 val |= led->kpdbl_cfg->row_scan_val;
1410
1411 led->kpdbl_cfg->row_scan_en <<= KPDBL_ROW_SCAN_EN_SHIFT;
1412 val &= ~KPDBL_ROW_SCAN_EN_MASK;
1413 val |= led->kpdbl_cfg->row_scan_en;
1414
1415 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
1416 KPDBL_ROW_SRC(led->base), &val, 1);
1417 if (rc) {
1418 dev_err(&led->spmi_dev->dev,
1419 "Unable to write to addr=%x, rc(%d)\n",
1420 KPDBL_ROW_SRC(led->base), rc);
1421 return rc;
1422 }
1423
1424 /* enable module */
1425 rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
1426 KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
1427 if (rc) {
1428 dev_err(&led->spmi_dev->dev,
1429 "Enable module write failed(%d)\n", rc);
1430 return rc;
1431 }
1432
Amy Malochea2726f02013-05-10 10:19:03 -07001433 rc = qpnp_pwm_init(led->kpdbl_cfg->pwm_cfg, led->spmi_dev,
1434 led->cdev.name);
1435 if (rc) {
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301436 dev_err(&led->spmi_dev->dev,
Amy Malochea2726f02013-05-10 10:19:03 -07001437 "Failed to initialize pwm\n");
1438 return rc;
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301439 }
1440
1441 /* dump kpdbl registers */
1442 qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
1443
1444 return 0;
1445}
1446
Amy Malocheeea7b592012-10-03 15:59:36 -07001447static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
1448{
Amy Malochea2726f02013-05-10 10:19:03 -07001449 int rc;
Amy Malocheeea7b592012-10-03 15:59:36 -07001450
1451 rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
1452 RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
1453 if (rc) {
1454 dev_err(&led->spmi_dev->dev,
1455 "Failed to write led source select register\n");
1456 return rc;
1457 }
1458
Amy Malochea2726f02013-05-10 10:19:03 -07001459 rc = qpnp_pwm_init(led->rgb_cfg->pwm_cfg, led->spmi_dev,
1460 led->cdev.name);
1461 if (rc) {
Amy Malocheeea7b592012-10-03 15:59:36 -07001462 dev_err(&led->spmi_dev->dev,
Amy Malochea2726f02013-05-10 10:19:03 -07001463 "Failed to initialize pwm\n");
1464 return rc;
Amy Malocheeea7b592012-10-03 15:59:36 -07001465 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001466 /* Initialize led for use in auto trickle charging mode */
1467 rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
1468 led->rgb_cfg->enable, led->rgb_cfg->enable);
1469
1470 return 0;
1471}
1472
Amy Malochea2726f02013-05-10 10:19:03 -07001473static int __devinit qpnp_mpp_init(struct qpnp_led_data *led)
1474{
1475 int rc, val;
1476
1477 val = (led->mpp_cfg->current_setting / LED_MPP_CURRENT_PER_SETTING) - 1;
1478
1479 if (val < 0)
1480 val = 0;
1481
1482 rc = qpnp_led_masked_write(led, LED_MPP_SINK_CTRL(led->base),
1483 LED_MPP_SINK_MASK, val);
1484 if (rc) {
1485 dev_err(&led->spmi_dev->dev,
1486 "Failed to write led enable reg\n");
1487 return rc;
1488 }
1489
1490 if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
1491 rc = qpnp_pwm_init(led->mpp_cfg->pwm_cfg, led->spmi_dev,
1492 led->cdev.name);
1493 if (rc) {
1494 dev_err(&led->spmi_dev->dev,
1495 "Failed to initialize pwm\n");
1496 return rc;
1497 }
1498 }
1499
1500 return 0;
1501}
1502
Amy Malochef3d5a062012-08-16 19:14:11 -07001503static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
1504{
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301505 int rc = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001506
1507 switch (led->id) {
1508 case QPNP_ID_WLED:
1509 rc = qpnp_wled_init(led);
1510 if (rc)
Amy Malochea5ca5552012-10-23 13:34:46 -07001511 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -07001512 "WLED initialize failed(%d)\n", rc);
1513 break;
Amy Maloche864a6d52012-10-03 15:58:12 -07001514 case QPNP_ID_FLASH1_LED0:
1515 case QPNP_ID_FLASH1_LED1:
1516 rc = qpnp_flash_init(led);
1517 if (rc)
1518 dev_err(&led->spmi_dev->dev,
1519 "FLASH initialize failed(%d)\n", rc);
1520 break;
Amy Malocheeea7b592012-10-03 15:59:36 -07001521 case QPNP_ID_RGB_RED:
1522 case QPNP_ID_RGB_GREEN:
1523 case QPNP_ID_RGB_BLUE:
1524 rc = qpnp_rgb_init(led);
1525 if (rc)
1526 dev_err(&led->spmi_dev->dev,
1527 "RGB initialize failed(%d)\n", rc);
1528 break;
Amy Malochef3813742013-04-11 19:33:47 -07001529 case QPNP_ID_LED_MPP:
Amy Malochea2726f02013-05-10 10:19:03 -07001530 rc = qpnp_mpp_init(led);
1531 if (rc)
1532 dev_err(&led->spmi_dev->dev,
1533 "MPP initialize failed(%d)\n", rc);
Amy Malochef3813742013-04-11 19:33:47 -07001534 break;
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301535 case QPNP_ID_KPDBL:
1536 rc = qpnp_kpdbl_init(led);
1537 if (rc)
1538 dev_err(&led->spmi_dev->dev,
1539 "KPDBL initialize failed(%d)\n", rc);
1540 break;
Amy Malochef3d5a062012-08-16 19:14:11 -07001541 default:
Amy Malochea5ca5552012-10-23 13:34:46 -07001542 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malocheeea7b592012-10-03 15:59:36 -07001543 return -EINVAL;
Amy Malochef3d5a062012-08-16 19:14:11 -07001544 }
1545
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301546 return rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001547}
1548
Amy Malochea5ca5552012-10-23 13:34:46 -07001549static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
1550 struct device_node *node)
1551{
1552 int rc;
Asaf Penso55ac8472013-01-21 21:17:37 +02001553 u32 val;
Amy Malochea5ca5552012-10-23 13:34:46 -07001554 const char *temp_string;
1555
1556 led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
1557 rc = of_property_read_string(node, "linux,default-trigger",
1558 &temp_string);
1559 if (!rc)
1560 led->cdev.default_trigger = temp_string;
1561 else if (rc != -EINVAL)
1562 return rc;
1563
1564 led->default_on = false;
1565 rc = of_property_read_string(node, "qcom,default-state",
1566 &temp_string);
1567 if (!rc) {
1568 if (strncmp(temp_string, "on", sizeof("on")) == 0)
1569 led->default_on = true;
1570 } else if (rc != -EINVAL)
1571 return rc;
1572
Asaf Penso55ac8472013-01-21 21:17:37 +02001573 led->turn_off_delay_ms = 0;
1574 rc = of_property_read_u32(node, "qcom,turn-off-delay-ms", &val);
1575 if (!rc)
1576 led->turn_off_delay_ms = val;
1577 else if (rc != -EINVAL)
1578 return rc;
1579
Amy Malochea5ca5552012-10-23 13:34:46 -07001580 return 0;
1581}
1582
Amy Malochef3d5a062012-08-16 19:14:11 -07001583/*
1584 * Handlers for alternative sources of platform_data
1585 */
1586static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
1587 struct device_node *node)
1588{
1589 u32 val;
1590 int rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001591
1592 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
1593 sizeof(struct wled_config_data), GFP_KERNEL);
1594 if (!led->wled_cfg) {
1595 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1596 return -ENOMEM;
1597 }
1598
Amy Malochef3d5a062012-08-16 19:14:11 -07001599 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
1600 rc = of_property_read_u32(node, "qcom,num-strings", &val);
1601 if (!rc)
1602 led->wled_cfg->num_strings = (u8) val;
1603 else if (rc != -EINVAL)
1604 return rc;
1605
1606 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
1607 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
1608 if (!rc)
1609 led->wled_cfg->ovp_val = (u8) val;
1610 else if (rc != -EINVAL)
1611 return rc;
1612
1613 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
1614 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
1615 if (!rc)
1616 led->wled_cfg->boost_curr_lim = (u8) val;
1617 else if (rc != -EINVAL)
1618 return rc;
1619
1620 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
1621 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
1622 if (!rc)
1623 led->wled_cfg->cp_select = (u8) val;
1624 else if (rc != -EINVAL)
1625 return rc;
1626
1627 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
1628 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
1629 if (!rc)
1630 led->wled_cfg->ctrl_delay_us = (u8) val;
1631 else if (rc != -EINVAL)
1632 return rc;
1633
Amy Malochebd687672013-03-18 11:23:45 -07001634 led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
1635 rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
1636 if (!rc)
1637 led->wled_cfg->op_fdbck = (u8) val;
1638 else if (rc != -EINVAL)
1639 return rc;
1640
Amy Malochef3d5a062012-08-16 19:14:11 -07001641 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
1642 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
1643 if (!rc)
1644 led->wled_cfg->switch_freq = (u8) val;
1645 else if (rc != -EINVAL)
1646 return rc;
1647
1648 led->wled_cfg->dig_mod_gen_en =
1649 of_property_read_bool(node, "qcom,dig-mod-gen-en");
1650
1651 led->wled_cfg->cs_out_en =
1652 of_property_read_bool(node, "qcom,cs-out-en");
1653
Amy Malochef3d5a062012-08-16 19:14:11 -07001654 return 0;
1655}
1656
Amy Maloche864a6d52012-10-03 15:58:12 -07001657static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
1658 struct device_node *node)
1659{
1660 int rc;
1661 u32 val;
1662
1663 led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
1664 sizeof(struct flash_config_data), GFP_KERNEL);
1665 if (!led->flash_cfg) {
1666 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1667 return -ENOMEM;
1668 }
1669
1670 if (led->id == QPNP_ID_FLASH1_LED0) {
1671 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1672 led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
1673 led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
1674 led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
1675 } else if (led->id == QPNP_ID_FLASH1_LED1) {
1676 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1677 led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
1678 led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
1679 led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
1680 } else {
1681 dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
1682 return -EINVAL;
1683 }
1684
1685 rc = of_property_read_u32(node, "qcom,current", &val);
1686 if (!rc)
1687 led->flash_cfg->current_prgm = (val *
1688 FLASH_MAX_LEVEL / led->max_current);
1689 else
1690 return -EINVAL;
1691
1692 rc = of_property_read_u32(node, "qcom,headroom", &val);
1693 if (!rc)
1694 led->flash_cfg->headroom = (u8) val;
1695 else if (rc == -EINVAL)
Amy Maloche62571b22013-04-17 17:23:10 -07001696 led->flash_cfg->headroom = HEADROOM_500mV;
Amy Maloche864a6d52012-10-03 15:58:12 -07001697 else
1698 return rc;
1699
1700 rc = of_property_read_u32(node, "qcom,duration", &val);
1701 if (!rc)
1702 led->flash_cfg->duration = (((u8) val) - 10) / 10;
1703 else if (rc == -EINVAL)
1704 led->flash_cfg->duration = FLASH_DURATION_200ms;
1705 else
1706 return rc;
1707
1708 rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
1709 if (!rc)
1710 led->flash_cfg->clamp_curr = (val *
1711 FLASH_MAX_LEVEL / led->max_current);
1712 else if (rc == -EINVAL)
1713 led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
1714 else
1715 return rc;
1716
1717 rc = of_property_read_u32(node, "qcom,startup-dly", &val);
1718 if (!rc)
1719 led->flash_cfg->startup_dly = (u8) val;
1720 else if (rc == -EINVAL)
Amy Maloche62571b22013-04-17 17:23:10 -07001721 led->flash_cfg->startup_dly = DELAY_128us;
Amy Maloche864a6d52012-10-03 15:58:12 -07001722 else
1723 return rc;
1724
1725 led->flash_cfg->safety_timer =
1726 of_property_read_bool(node, "qcom,safety-timer");
1727
Chun Zhange8954cf2013-05-02 11:14:34 -07001728 led->flash_cfg->torch_enable =
1729 of_property_read_bool(node, "qcom,torch-enable");
1730
Amy Maloche864a6d52012-10-03 15:58:12 -07001731 return 0;
1732}
1733
Amy Malochea2726f02013-05-10 10:19:03 -07001734static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
1735 struct spmi_device *spmi_dev,
1736 struct device_node *node)
1737{
1738 struct property *prop;
1739 int rc, i;
1740 u32 val;
1741 u8 *temp_cfg;
1742
1743 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1744 if (!rc)
1745 pwm_cfg->pwm_channel = val;
1746 else
1747 return rc;
1748
1749 if (pwm_cfg->mode == PWM_MODE) {
1750 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1751 if (!rc)
1752 pwm_cfg->pwm_period_us = val;
1753 else
1754 return rc;
1755 }
1756
1757 if (pwm_cfg->mode == LPG_MODE) {
1758 pwm_cfg->duty_cycles =
1759 devm_kzalloc(&spmi_dev->dev,
1760 sizeof(struct pwm_duty_cycles), GFP_KERNEL);
1761 if (!pwm_cfg->duty_cycles) {
1762 dev_err(&spmi_dev->dev,
1763 "Unable to allocate memory\n");
1764 return -ENOMEM;
1765 }
1766
1767 prop = of_find_property(node, "qcom,duty-pcts",
1768 &pwm_cfg->duty_cycles->num_duty_pcts);
1769 if (!prop) {
1770 dev_err(&spmi_dev->dev, "Looking up property " \
1771 "node qcom,duty-pcts failed\n");
1772 return -ENODEV;
1773 } else if (!pwm_cfg->duty_cycles->num_duty_pcts) {
1774 dev_err(&spmi_dev->dev, "Invalid length of " \
1775 "duty pcts\n");
1776 return -EINVAL;
1777 }
1778
1779 pwm_cfg->duty_cycles->duty_pcts =
1780 devm_kzalloc(&spmi_dev->dev,
1781 sizeof(int) * pwm_cfg->duty_cycles->num_duty_pcts,
1782 GFP_KERNEL);
1783 if (!pwm_cfg->duty_cycles->duty_pcts) {
1784 dev_err(&spmi_dev->dev,
1785 "Unable to allocate memory\n");
1786 return -ENOMEM;
1787 }
1788
1789 temp_cfg = devm_kzalloc(&spmi_dev->dev,
1790 pwm_cfg->duty_cycles->num_duty_pcts *
1791 sizeof(u8), GFP_KERNEL);
1792 if (!temp_cfg) {
1793 dev_err(&spmi_dev->dev, "Failed to allocate " \
1794 "memory for duty pcts\n");
1795 return -ENOMEM;
1796 }
1797
1798 memcpy(temp_cfg, prop->value,
1799 pwm_cfg->duty_cycles->num_duty_pcts);
1800
1801 for (i = 0; i < pwm_cfg->duty_cycles->num_duty_pcts; i++)
1802 pwm_cfg->duty_cycles->duty_pcts[i] =
1803 (int) temp_cfg[i];
1804
1805 rc = of_property_read_u32(node, "qcom,start-idx", &val);
1806 if (!rc) {
1807 pwm_cfg->lut_params.start_idx = val;
1808 pwm_cfg->duty_cycles->start_idx = val;
1809 } else
1810 return rc;
1811
1812 pwm_cfg->lut_params.lut_pause_hi = 0;
1813 rc = of_property_read_u32(node, "qcom,pause-hi", &val);
1814 if (!rc)
1815 pwm_cfg->lut_params.lut_pause_hi = val;
1816 else if (rc != -EINVAL)
1817 return rc;
1818
1819 pwm_cfg->lut_params.lut_pause_lo = 0;
1820 rc = of_property_read_u32(node, "qcom,pause-lo", &val);
1821 if (!rc)
1822 pwm_cfg->lut_params.lut_pause_lo = val;
1823 else if (rc != -EINVAL)
1824 return rc;
1825
1826 pwm_cfg->lut_params.ramp_step_ms =
1827 QPNP_LUT_RAMP_STEP_DEFAULT;
1828 rc = of_property_read_u32(node, "qcom,ramp-step-ms", &val);
1829 if (!rc)
1830 pwm_cfg->lut_params.ramp_step_ms = val;
1831 else if (rc != -EINVAL)
1832 return rc;
1833
1834 pwm_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
1835 rc = of_property_read_u32(node, "qcom,lut-flags", &val);
1836 if (!rc)
1837 pwm_cfg->lut_params.flags = (u8) val;
1838 else if (rc != -EINVAL)
1839 return rc;
1840
1841 pwm_cfg->lut_params.idx_len =
1842 pwm_cfg->duty_cycles->num_duty_pcts;
1843 }
1844 return 0;
1845};
1846
1847static int qpnp_led_get_mode(const char *mode)
1848{
1849 if (strncmp(mode, "manual", strlen(mode)) == 0)
1850 return MANUAL_MODE;
1851 else if (strncmp(mode, "pwm", strlen(mode)) == 0)
1852 return PWM_MODE;
1853 else if (strncmp(mode, "lpg", strlen(mode)) == 0)
1854 return LPG_MODE;
1855 else
1856 return -EINVAL;
1857};
1858
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301859static int __devinit qpnp_get_config_kpdbl(struct qpnp_led_data *led,
1860 struct device_node *node)
1861{
1862 int rc;
1863 u32 val;
Amy Malochea2726f02013-05-10 10:19:03 -07001864 u8 led_mode;
1865 const char *mode;
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301866
1867 led->kpdbl_cfg = devm_kzalloc(&led->spmi_dev->dev,
1868 sizeof(struct kpdbl_config_data), GFP_KERNEL);
1869 if (!led->kpdbl_cfg) {
1870 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1871 return -ENOMEM;
1872 }
Amy Malochea2726f02013-05-10 10:19:03 -07001873 rc = of_property_read_string(node, "qcom,mode", &mode);
1874 if (!rc) {
1875 led_mode = qpnp_led_get_mode(mode);
1876 if ((led_mode == MANUAL_MODE) || (led_mode == -EINVAL)) {
1877 dev_err(&led->spmi_dev->dev, "Selected mode not " \
1878 "supported for kpdbl.\n");
1879 return -EINVAL;
1880 }
1881 led->kpdbl_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
1882 sizeof(struct pwm_config_data),
1883 GFP_KERNEL);
1884 if (!led->kpdbl_cfg->pwm_cfg) {
1885 dev_err(&led->spmi_dev->dev,
1886 "Unable to allocate memory\n");
1887 return -ENOMEM;
1888 }
1889 led->kpdbl_cfg->pwm_cfg->mode = led_mode;
1890 } else
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301891 return rc;
1892
Amy Malochea2726f02013-05-10 10:19:03 -07001893 rc = qpnp_get_config_pwm(led->kpdbl_cfg->pwm_cfg, led->spmi_dev, node);
1894 if (rc < 0)
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301895 return rc;
1896
1897 rc = of_property_read_u32(node, "qcom,row-src-sel-val", &val);
1898 if (!rc)
1899 led->kpdbl_cfg->row_src_sel_val = val;
1900 else
1901 return rc;
1902
1903 rc = of_property_read_u32(node, "qcom,row-scan-val", &val);
1904 if (!rc)
1905 led->kpdbl_cfg->row_scan_val = val;
1906 else
1907 return rc;
1908
1909 rc = of_property_read_u32(node, "qcom,row-scan-en", &val);
1910 if (!rc)
1911 led->kpdbl_cfg->row_scan_en = val;
1912 else
1913 return rc;
1914
1915 return 0;
1916}
1917
Amy Malocheeea7b592012-10-03 15:59:36 -07001918static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
1919 struct device_node *node)
1920{
Amy Malochea2726f02013-05-10 10:19:03 -07001921 int rc;
1922 u8 led_mode;
1923 const char *mode;
Amy Malocheeea7b592012-10-03 15:59:36 -07001924
1925 led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
1926 sizeof(struct rgb_config_data), GFP_KERNEL);
1927 if (!led->rgb_cfg) {
1928 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1929 return -ENOMEM;
1930 }
1931
1932 if (led->id == QPNP_ID_RGB_RED)
1933 led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
1934 else if (led->id == QPNP_ID_RGB_GREEN)
1935 led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
1936 else if (led->id == QPNP_ID_RGB_BLUE)
1937 led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
1938 else
1939 return -EINVAL;
1940
Amy Malochea2726f02013-05-10 10:19:03 -07001941 rc = of_property_read_string(node, "qcom,mode", &mode);
1942 if (!rc) {
1943 led_mode = qpnp_led_get_mode(mode);
1944 if ((led_mode == MANUAL_MODE) || (led_mode == -EINVAL)) {
1945 dev_err(&led->spmi_dev->dev, "Selected mode not " \
1946 "supported for rgb.\n");
Amy Malocheeea7b592012-10-03 15:59:36 -07001947 return -EINVAL;
1948 }
Amy Malochea2726f02013-05-10 10:19:03 -07001949 led->rgb_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
1950 sizeof(struct pwm_config_data),
1951 GFP_KERNEL);
1952 if (!led->rgb_cfg->pwm_cfg) {
Amy Malocheeea7b592012-10-03 15:59:36 -07001953 dev_err(&led->spmi_dev->dev,
1954 "Unable to allocate memory\n");
1955 return -ENOMEM;
1956 }
Amy Malochea2726f02013-05-10 10:19:03 -07001957 led->rgb_cfg->pwm_cfg->mode = led_mode;
1958 } else
1959 return rc;
Amy Malocheeea7b592012-10-03 15:59:36 -07001960
Amy Malochea2726f02013-05-10 10:19:03 -07001961 rc = qpnp_get_config_pwm(led->rgb_cfg->pwm_cfg, led->spmi_dev, node);
1962 if (rc < 0)
1963 return rc;
Amy Malocheeea7b592012-10-03 15:59:36 -07001964
1965 return 0;
1966}
1967
Amy Malochef3813742013-04-11 19:33:47 -07001968static int __devinit qpnp_get_config_mpp(struct qpnp_led_data *led,
1969 struct device_node *node)
1970{
1971 int rc;
1972 u32 val;
Amy Malochea2726f02013-05-10 10:19:03 -07001973 u8 led_mode;
1974 const char *mode;
Amy Malochef3813742013-04-11 19:33:47 -07001975
1976 led->mpp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1977 sizeof(struct mpp_config_data), GFP_KERNEL);
1978 if (!led->mpp_cfg) {
1979 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1980 return -ENOMEM;
1981 }
1982
1983 led->mpp_cfg->current_setting = LED_MPP_CURRENT_DEFAULT;
1984 rc = of_property_read_u32(node, "qcom,current-setting", &val);
1985 if (!rc)
1986 led->mpp_cfg->current_setting = (u8) val;
1987 else if (rc != -EINVAL)
1988 return rc;
1989
1990 led->mpp_cfg->source_sel = LED_MPP_SOURCE_SEL_DEFAULT;
1991 rc = of_property_read_u32(node, "qcom,source-sel", &val);
1992 if (!rc)
1993 led->mpp_cfg->source_sel = (u8) val;
1994 else if (rc != -EINVAL)
1995 return rc;
1996
1997 led->mpp_cfg->mode_ctrl = LED_MPP_MODE_SINK;
1998 rc = of_property_read_u32(node, "qcom,mode-ctrl", &val);
1999 if (!rc)
2000 led->mpp_cfg->mode_ctrl = (u8) val;
2001 else if (rc != -EINVAL)
2002 return rc;
2003
Amy Malochea2726f02013-05-10 10:19:03 -07002004 rc = of_property_read_string(node, "qcom,mode", &mode);
2005 if (!rc) {
2006 led_mode = qpnp_led_get_mode(mode);
2007 led->mpp_cfg->pwm_mode = led_mode;
2008 if (led_mode == MANUAL_MODE)
2009 return MANUAL_MODE;
2010 else if (led_mode == -EINVAL) {
2011 dev_err(&led->spmi_dev->dev, "Selected mode not " \
2012 "supported for mpp.\n");
2013 return -EINVAL;
2014 }
2015 led->mpp_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
2016 sizeof(struct pwm_config_data),
2017 GFP_KERNEL);
2018 if (!led->mpp_cfg->pwm_cfg) {
2019 dev_err(&led->spmi_dev->dev,
2020 "Unable to allocate memory\n");
2021 return -ENOMEM;
2022 }
2023 led->mpp_cfg->pwm_cfg->mode = led_mode;
2024 } else
2025 return rc;
2026
2027 rc = qpnp_get_config_pwm(led->mpp_cfg->pwm_cfg, led->spmi_dev, node);
2028 if (rc < 0)
2029 return rc;
2030
Amy Malochef3813742013-04-11 19:33:47 -07002031 return 0;
2032}
2033
Amy Malochef3d5a062012-08-16 19:14:11 -07002034static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
2035{
Amy Malochef9490c62012-11-27 19:26:04 -08002036 struct qpnp_led_data *led, *led_array;
Amy Malochef3d5a062012-08-16 19:14:11 -07002037 struct resource *led_resource;
Amy Malochea5ca5552012-10-23 13:34:46 -07002038 struct device_node *node, *temp;
Amy Malochef9490c62012-11-27 19:26:04 -08002039 int rc, i, num_leds = 0, parsed_leds = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07002040 const char *led_label;
2041
Amy Malochea5ca5552012-10-23 13:34:46 -07002042 node = spmi->dev.of_node;
2043 if (node == NULL)
2044 return -ENODEV;
2045
2046 temp = NULL;
2047 while ((temp = of_get_next_child(node, temp)))
2048 num_leds++;
2049
Amy Malochef9490c62012-11-27 19:26:04 -08002050 if (!num_leds)
2051 return -ECHILD;
2052
2053 led_array = devm_kzalloc(&spmi->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07002054 (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
Amy Malochef9490c62012-11-27 19:26:04 -08002055 if (!led_array) {
Amy Malochef3d5a062012-08-16 19:14:11 -07002056 dev_err(&spmi->dev, "Unable to allocate memory\n");
2057 return -ENOMEM;
2058 }
2059
Amy Malochea5ca5552012-10-23 13:34:46 -07002060 for_each_child_of_node(node, temp) {
Amy Malochef9490c62012-11-27 19:26:04 -08002061 led = &led_array[parsed_leds];
2062 led->num_leds = num_leds;
Amy Malochea5ca5552012-10-23 13:34:46 -07002063 led->spmi_dev = spmi;
Amy Malochef3d5a062012-08-16 19:14:11 -07002064
Amy Malochea5ca5552012-10-23 13:34:46 -07002065 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
2066 if (!led_resource) {
2067 dev_err(&spmi->dev, "Unable to get LED base address\n");
Amy Malochef9490c62012-11-27 19:26:04 -08002068 rc = -ENXIO;
2069 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07002070 }
2071 led->base = led_resource->start;
Amy Malochef3d5a062012-08-16 19:14:11 -07002072
Amy Malochea5ca5552012-10-23 13:34:46 -07002073 rc = of_property_read_string(temp, "label", &led_label);
Amy Malochef3d5a062012-08-16 19:14:11 -07002074 if (rc < 0) {
2075 dev_err(&led->spmi_dev->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07002076 "Failure reading label, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08002077 goto fail_id_check;
Amy Malochef3d5a062012-08-16 19:14:11 -07002078 }
Amy Malochea5ca5552012-10-23 13:34:46 -07002079
2080 rc = of_property_read_string(temp, "linux,name",
2081 &led->cdev.name);
2082 if (rc < 0) {
2083 dev_err(&led->spmi_dev->dev,
2084 "Failure reading led name, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08002085 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07002086 }
2087
2088 rc = of_property_read_u32(temp, "qcom,max-current",
2089 &led->max_current);
2090 if (rc < 0) {
2091 dev_err(&led->spmi_dev->dev,
2092 "Failure reading max_current, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08002093 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07002094 }
2095
2096 rc = of_property_read_u32(temp, "qcom,id", &led->id);
2097 if (rc < 0) {
2098 dev_err(&led->spmi_dev->dev,
2099 "Failure reading led id, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08002100 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07002101 }
2102
2103 rc = qpnp_get_common_configs(led, temp);
2104 if (rc) {
2105 dev_err(&led->spmi_dev->dev,
2106 "Failure reading common led configuration," \
2107 " rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08002108 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07002109 }
2110
2111 led->cdev.brightness_set = qpnp_led_set;
2112 led->cdev.brightness_get = qpnp_led_get;
2113
2114 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
2115 rc = qpnp_get_config_wled(led, temp);
2116 if (rc < 0) {
2117 dev_err(&led->spmi_dev->dev,
2118 "Unable to read wled config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08002119 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07002120 }
Amy Maloche864a6d52012-10-03 15:58:12 -07002121 } else if (strncmp(led_label, "flash", sizeof("flash"))
2122 == 0) {
2123 rc = qpnp_get_config_flash(led, temp);
2124 if (rc < 0) {
2125 dev_err(&led->spmi_dev->dev,
2126 "Unable to read flash config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08002127 goto fail_id_check;
Amy Maloche864a6d52012-10-03 15:58:12 -07002128 }
Amy Malocheeea7b592012-10-03 15:59:36 -07002129 } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
2130 rc = qpnp_get_config_rgb(led, temp);
2131 if (rc < 0) {
2132 dev_err(&led->spmi_dev->dev,
2133 "Unable to read rgb config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08002134 goto fail_id_check;
Amy Malocheeea7b592012-10-03 15:59:36 -07002135 }
Amy Malochef3813742013-04-11 19:33:47 -07002136 } else if (strncmp(led_label, "mpp", sizeof("mpp")) == 0) {
2137 rc = qpnp_get_config_mpp(led, temp);
2138 if (rc < 0) {
2139 dev_err(&led->spmi_dev->dev,
2140 "Unable to read mpp config data\n");
Amy Malochea2726f02013-05-10 10:19:03 -07002141 goto fail_id_check;
Mohan Pallaka1f46f022013-03-15 14:56:50 +05302142 }
2143 } else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
2144 rc = qpnp_get_config_kpdbl(led, temp);
2145 if (rc < 0) {
2146 dev_err(&led->spmi_dev->dev,
2147 "Unable to read kpdbl config data\n");
Amy Malochef3813742013-04-11 19:33:47 -07002148 goto fail_id_check;
2149 }
Amy Malochea5ca5552012-10-23 13:34:46 -07002150 } else {
2151 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
Amy Malochef9490c62012-11-27 19:26:04 -08002152 rc = -EINVAL;
2153 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07002154 }
2155
2156 spin_lock_init(&led->lock);
2157
2158 rc = qpnp_led_initialize(led);
2159 if (rc < 0)
2160 goto fail_id_check;
2161
2162 rc = qpnp_led_set_max_brightness(led);
2163 if (rc < 0)
2164 goto fail_id_check;
2165
2166 rc = led_classdev_register(&spmi->dev, &led->cdev);
2167 if (rc) {
2168 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
2169 led->id, rc);
2170 goto fail_id_check;
2171 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07002172
2173 if (led->id == QPNP_ID_FLASH1_LED0 ||
2174 led->id == QPNP_ID_FLASH1_LED1) {
2175 rc = sysfs_create_group(&led->cdev.dev->kobj,
2176 &led_attr_group);
2177 if (rc)
2178 goto fail_id_check;
2179
2180 }
2181
Amy Malochea5ca5552012-10-23 13:34:46 -07002182 /* configure default state */
Asaf Penso55ac8472013-01-21 21:17:37 +02002183 if (led->default_on) {
Amy Malochea5ca5552012-10-23 13:34:46 -07002184 led->cdev.brightness = led->cdev.max_brightness;
Asaf Penso55ac8472013-01-21 21:17:37 +02002185 if (led->turn_off_delay_ms > 0)
2186 qpnp_led_turn_off(led);
2187 } else
Amy Malochea5ca5552012-10-23 13:34:46 -07002188 led->cdev.brightness = LED_OFF;
2189
2190 qpnp_led_set(&led->cdev, led->cdev.brightness);
Amy Malochef9490c62012-11-27 19:26:04 -08002191
2192 parsed_leds++;
Amy Malochef3d5a062012-08-16 19:14:11 -07002193 }
Amy Malochef9490c62012-11-27 19:26:04 -08002194 dev_set_drvdata(&spmi->dev, led_array);
Amy Malochef3d5a062012-08-16 19:14:11 -07002195 return 0;
2196
2197fail_id_check:
Amy Malochef9490c62012-11-27 19:26:04 -08002198 for (i = 0; i < parsed_leds; i++)
2199 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07002200 return rc;
2201}
2202
2203static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
2204{
Amy Malochef9490c62012-11-27 19:26:04 -08002205 struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
2206 int i, parsed_leds = led_array->num_leds;
Amy Malochef3d5a062012-08-16 19:14:11 -07002207
Amy Malochebc97c0d22013-03-24 22:06:16 -07002208 for (i = 0; i < parsed_leds; i++) {
Amy Malochef9490c62012-11-27 19:26:04 -08002209 led_classdev_unregister(&led_array[i].cdev);
Amy Malochebc97c0d22013-03-24 22:06:16 -07002210 switch (led_array[i].id) {
2211 case QPNP_ID_WLED:
2212 break;
2213 case QPNP_ID_FLASH1_LED0:
2214 case QPNP_ID_FLASH1_LED1:
2215 sysfs_remove_group(&led_array[i].cdev.dev->kobj,
2216 &led_attr_group);
2217 break;
2218 case QPNP_ID_RGB_RED:
2219 case QPNP_ID_RGB_GREEN:
2220 case QPNP_ID_RGB_BLUE:
2221 default:
2222 dev_err(&led_array[i].spmi_dev->dev,
2223 "Invalid LED(%d)\n",
2224 led_array[i].id);
2225 return -EINVAL;
2226 }
2227 }
Amy Malochef3d5a062012-08-16 19:14:11 -07002228
2229 return 0;
2230}
2231static struct of_device_id spmi_match_table[] = {
2232 { .compatible = "qcom,leds-qpnp",
2233 }
2234};
2235
2236static struct spmi_driver qpnp_leds_driver = {
2237 .driver = {
2238 .name = "qcom,leds-qpnp",
2239 .of_match_table = spmi_match_table,
2240 },
2241 .probe = qpnp_leds_probe,
2242 .remove = __devexit_p(qpnp_leds_remove),
2243};
2244
2245static int __init qpnp_led_init(void)
2246{
2247 return spmi_driver_register(&qpnp_leds_driver);
2248}
2249module_init(qpnp_led_init);
2250
2251static void __exit qpnp_led_exit(void)
2252{
2253 spmi_driver_unregister(&qpnp_leds_driver);
2254}
2255module_exit(qpnp_led_exit);
2256
2257MODULE_DESCRIPTION("QPNP LEDs driver");
2258MODULE_LICENSE("GPL v2");
2259MODULE_ALIAS("leds:leds-qpnp");
Amy Maloche864a6d52012-10-03 15:58:12 -07002260