blob: cc5472d4577f9c5b6563b89c67f90b15a29ffe4b [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
169#define LED_MPP_CURRENT_DEFAULT 10
170#define LED_MPP_SOURCE_SEL_DEFAULT LED_MPP_MODE_ENABLE
171
172#define LED_MPP_SINK_MASK 0x07
173#define LED_MPP_MODE_MASK 0x7F
174#define LED_MPP_EN_MASK 0x80
175
176#define LED_MPP_MODE_SINK (0x06 << 4)
177#define LED_MPP_MODE_ENABLE 0x01
178#define LED_MPP_MODE_OUTPUT 0x10
179#define LED_MPP_MODE_DISABLE 0x00
180#define LED_MPP_EN_ENABLE 0x80
181#define LED_MPP_EN_DISABLE 0x00
182
183#define MPP_SOURCE_DTEST1 0x08
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530184
185#define KPDBL_MAX_LEVEL LED_FULL
186#define KPDBL_ROW_SRC_SEL(base) (base + 0x40)
187#define KPDBL_ENABLE(base) (base + 0x46)
188#define KPDBL_ROW_SRC(base) (base + 0xE5)
189
190#define KPDBL_ROW_SRC_SEL_VAL_MASK 0x0F
191#define KPDBL_ROW_SCAN_EN_MASK 0x80
192#define KPDBL_ROW_SCAN_VAL_MASK 0x0F
193#define KPDBL_ROW_SCAN_EN_SHIFT 7
194#define KPDBL_MODULE_EN 0x80
195#define KPDBL_MODULE_DIS 0x00
196#define KPDBL_MODULE_EN_MASK 0x80
197
Amy Malochef3d5a062012-08-16 19:14:11 -0700198/**
199 * enum qpnp_leds - QPNP supported led ids
200 * @QPNP_ID_WLED - White led backlight
201 */
202enum qpnp_leds {
Amy Maloche864a6d52012-10-03 15:58:12 -0700203 QPNP_ID_WLED = 0,
204 QPNP_ID_FLASH1_LED0,
205 QPNP_ID_FLASH1_LED1,
Amy Malocheeea7b592012-10-03 15:59:36 -0700206 QPNP_ID_RGB_RED,
207 QPNP_ID_RGB_GREEN,
208 QPNP_ID_RGB_BLUE,
Amy Malochef3813742013-04-11 19:33:47 -0700209 QPNP_ID_LED_MPP,
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530210 QPNP_ID_KPDBL,
Amy Maloche864a6d52012-10-03 15:58:12 -0700211 QPNP_ID_MAX,
Amy Malochef3d5a062012-08-16 19:14:11 -0700212};
213
214/* current boost limit */
215enum wled_current_boost_limit {
216 WLED_CURR_LIMIT_105mA,
217 WLED_CURR_LIMIT_385mA,
218 WLED_CURR_LIMIT_525mA,
219 WLED_CURR_LIMIT_805mA,
220 WLED_CURR_LIMIT_980mA,
221 WLED_CURR_LIMIT_1260mA,
222 WLED_CURR_LIMIT_1400mA,
223 WLED_CURR_LIMIT_1680mA,
224};
225
226/* over voltage protection threshold */
227enum wled_ovp_threshold {
228 WLED_OVP_35V,
229 WLED_OVP_32V,
230 WLED_OVP_29V,
231 WLED_OVP_37V,
232};
233
234/* switch frquency */
235enum wled_switch_freq {
236 WLED_800kHz = 0,
237 WLED_960kHz,
238 WLED_1600kHz,
239 WLED_3200kHz,
240};
241
Amy Maloche864a6d52012-10-03 15:58:12 -0700242enum flash_headroom {
243 HEADROOM_250mV = 0,
244 HEADROOM_300mV,
245 HEADROOM_400mV,
246 HEADROOM_500mV,
247};
248
249enum flash_startup_dly {
250 DELAY_10us = 0,
251 DELAY_32us,
252 DELAY_64us,
253 DELAY_128us,
254};
255
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530256enum led_mode {
257 PWM_MODE = 0,
258 LPG_MODE,
Amy Malocheeea7b592012-10-03 15:59:36 -0700259};
260
Amy Malochef3d5a062012-08-16 19:14:11 -0700261static u8 wled_debug_regs[] = {
262 /* common registers */
263 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
264 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
265 /* LED1 */
266 0x60, 0x61, 0x62, 0x63, 0x66,
Amy Malochea5ca5552012-10-23 13:34:46 -0700267 /* LED2 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700268 0x70, 0x71, 0x72, 0x73, 0x76,
Amy Malochea5ca5552012-10-23 13:34:46 -0700269 /* LED3 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700270 0x80, 0x81, 0x82, 0x83, 0x86,
271};
272
Amy Maloche864a6d52012-10-03 15:58:12 -0700273static u8 flash_debug_regs[] = {
274 0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
275 0x4f, 0x46, 0x47,
276};
277
Amy Malocheeea7b592012-10-03 15:59:36 -0700278static u8 rgb_pwm_debug_regs[] = {
279 0x45, 0x46, 0x47,
280};
Amy Malochef3813742013-04-11 19:33:47 -0700281
282static u8 mpp_debug_regs[] = {
283 0x40, 0x41, 0x42, 0x45, 0x46, 0x4c,
284};
285
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530286static u8 kpdbl_debug_regs[] = {
287 0x40, 0x46, 0xb1, 0xb3, 0xb4, 0xe5,
288};
289
Amy Malochef3d5a062012-08-16 19:14:11 -0700290/**
291 * wled_config_data - wled configuration data
292 * @num_strings - number of wled strings supported
293 * @ovp_val - over voltage protection threshold
294 * @boost_curr_lim - boot current limit
295 * @cp_select - high pole capacitance
296 * @ctrl_delay_us - delay in activation of led
297 * @dig_mod_gen_en - digital module generator
298 * @cs_out_en - current sink output enable
299 * @op_fdbck - selection of output as feedback for the boost
300 */
301struct wled_config_data {
302 u8 num_strings;
303 u8 ovp_val;
304 u8 boost_curr_lim;
305 u8 cp_select;
306 u8 ctrl_delay_us;
307 u8 switch_freq;
Amy Malochebd687672013-03-18 11:23:45 -0700308 u8 op_fdbck;
Amy Malochef3d5a062012-08-16 19:14:11 -0700309 bool dig_mod_gen_en;
310 bool cs_out_en;
Amy Malochef3d5a062012-08-16 19:14:11 -0700311};
312
313/**
Amy Malochef3813742013-04-11 19:33:47 -0700314 * mpp_config_data - mpp configuration data
315 * @current_setting - current setting, 5ma-40ma in 5ma increments
316 */
317struct mpp_config_data {
318 u8 current_setting;
319 u8 source_sel;
320 u8 mode_ctrl;
321};
322
323/**
Amy Maloche864a6d52012-10-03 15:58:12 -0700324 * flash_config_data - flash configuration data
325 * @current_prgm - current to be programmed, scaled by max level
326 * @clamp_curr - clamp current to use
327 * @headroom - headroom value to use
328 * @duration - duration of the flash
329 * @enable_module - enable address for particular flash
330 * @trigger_flash - trigger flash
331 * @startup_dly - startup delay for flash
Amy Malochebc97c0d22013-03-24 22:06:16 -0700332 * @strobe_type - select between sw and hw strobe
Amy Maloche864a6d52012-10-03 15:58:12 -0700333 * @current_addr - address to write for current
334 * @second_addr - address of secondary flash to be written
335 * @safety_timer - enable safety timer or watchdog timer
Amy Malochebc97c0d22013-03-24 22:06:16 -0700336 * @torch_enable - enable flash LED torch mode
Amy Maloche864a6d52012-10-03 15:58:12 -0700337 */
338struct flash_config_data {
339 u8 current_prgm;
340 u8 clamp_curr;
341 u8 headroom;
342 u8 duration;
343 u8 enable_module;
344 u8 trigger_flash;
345 u8 startup_dly;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700346 u8 strobe_type;
Amy Maloche864a6d52012-10-03 15:58:12 -0700347 u16 current_addr;
348 u16 second_addr;
349 bool safety_timer;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700350 bool torch_enable;
Amy Maloche864a6d52012-10-03 15:58:12 -0700351};
352
353/**
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530354 * kpdbl_config_data - kpdbl configuration data
355 * @pwm_device - pwm device
356 * @pwm_channel - pwm channel to be configured for led
357 * @pwm_period_us - period for pwm, in us
358 * @row_src_sel_val - select source, 0 for vph_pwr and 1 for vbst
359 * @row_scan_en - enable row scan
360 * @row_scan_val - map to enable needed rows
361 */
362struct kpdbl_config_data {
363 struct pwm_device *pwm_dev;
364 int pwm_channel;
365 u32 pwm_period_us;
366 u32 row_src_sel_val;
367 u32 row_scan_en;
368 u32 row_scan_val;
369 u8 mode;
370};
371
372/**
Amy Malocheeea7b592012-10-03 15:59:36 -0700373 * rgb_config_data - rgb configuration data
374 * @lut_params - lut parameters to be used by pwm driver
375 * @pwm_device - pwm device
376 * @pwm_channel - pwm channel to be configured for led
377 * @pwm_period_us - period for pwm, in us
378 * @mode - mode the led operates in
379 */
380struct rgb_config_data {
381 struct lut_params lut_params;
382 struct pwm_device *pwm_dev;
383 int pwm_channel;
384 u32 pwm_period_us;
385 struct pwm_duty_cycles *duty_cycles;
386 u8 mode;
387 u8 enable;
388};
389
390/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700391 * struct qpnp_led_data - internal led data structure
392 * @led_classdev - led class device
Asaf Penso55ac8472013-01-21 21:17:37 +0200393 * @delayed_work - delayed work for turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700394 * @id - led index
395 * @base_reg - base register given in device tree
396 * @lock - to protect the transactions
397 * @reg - cached value of led register
Amy Malochea5ca5552012-10-23 13:34:46 -0700398 * @num_leds - number of leds in the module
Amy Malochef3d5a062012-08-16 19:14:11 -0700399 * @max_current - maximum current supported by LED
400 * @default_on - true: default state max, false, default state 0
Asaf Penso55ac8472013-01-21 21:17:37 +0200401 * @turn_off_delay_ms - number of msec before turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700402 */
403struct qpnp_led_data {
404 struct led_classdev cdev;
405 struct spmi_device *spmi_dev;
Asaf Penso55ac8472013-01-21 21:17:37 +0200406 struct delayed_work dwork;
Amy Malochef3d5a062012-08-16 19:14:11 -0700407 int id;
408 u16 base;
409 u8 reg;
Amy Malochea5ca5552012-10-23 13:34:46 -0700410 u8 num_leds;
Amy Malochedc3e5572012-09-25 16:39:06 -0700411 spinlock_t lock;
Amy Malochef3d5a062012-08-16 19:14:11 -0700412 struct wled_config_data *wled_cfg;
Amy Maloche864a6d52012-10-03 15:58:12 -0700413 struct flash_config_data *flash_cfg;
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530414 struct kpdbl_config_data *kpdbl_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700415 struct rgb_config_data *rgb_cfg;
Amy Malochef3813742013-04-11 19:33:47 -0700416 struct mpp_config_data *mpp_cfg;
Amy Malochef3d5a062012-08-16 19:14:11 -0700417 int max_current;
418 bool default_on;
Asaf Penso55ac8472013-01-21 21:17:37 +0200419 int turn_off_delay_ms;
Amy Malochef3d5a062012-08-16 19:14:11 -0700420};
421
422static int
423qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
424{
425 int rc;
426 u8 reg;
427
428 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
429 addr, &reg, 1);
430 if (rc) {
431 dev_err(&led->spmi_dev->dev,
432 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
433 }
434
435 reg &= ~mask;
436 reg |= val;
437
438 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
439 addr, &reg, 1);
440 if (rc)
441 dev_err(&led->spmi_dev->dev,
442 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
443 return rc;
444}
445
Amy Malochea5ca5552012-10-23 13:34:46 -0700446static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
447{
448 int i;
449 u8 val;
450
451 pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
452 for (i = 0; i < array_size; i++) {
453 spmi_ext_register_readl(led->spmi_dev->ctrl,
454 led->spmi_dev->sid,
455 led->base + regs[i],
456 &val, sizeof(val));
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530457 pr_debug("%s: 0x%x = 0x%x\n", led->cdev.name,
458 led->base + regs[i], val);
Amy Malochea5ca5552012-10-23 13:34:46 -0700459 }
460 pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
461}
462
Amy Malochef3d5a062012-08-16 19:14:11 -0700463static int qpnp_wled_set(struct qpnp_led_data *led)
464{
Amy Maloched55fdb82013-02-26 18:11:57 -0800465 int rc, duty, level;
466 u8 val, i, num_wled_strings;
Amy Malochef3d5a062012-08-16 19:14:11 -0700467
468 level = led->cdev.brightness;
469
470 if (level > WLED_MAX_LEVEL)
471 level = WLED_MAX_LEVEL;
472 if (level == 0) {
473 val = WLED_BOOST_OFF;
474 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
475 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
476 &val, 1);
477 if (rc) {
478 dev_err(&led->spmi_dev->dev,
479 "WLED write ctrl reg failed(%d)\n", rc);
480 return rc;
481 }
482 } else {
483 val = WLED_BOOST_ON;
484 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
485 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
486 &val, 1);
487 if (rc) {
488 dev_err(&led->spmi_dev->dev,
489 "WLED write ctrl reg failed(%d)\n", rc);
490 return rc;
491 }
492 }
493
494 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
495
496 num_wled_strings = led->wled_cfg->num_strings;
497
498 /* program brightness control registers */
499 for (i = 0; i < num_wled_strings; i++) {
500 rc = qpnp_led_masked_write(led,
501 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
502 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
503 if (rc) {
504 dev_err(&led->spmi_dev->dev,
505 "WLED set brightness MSB failed(%d)\n", rc);
506 return rc;
507 }
508 val = duty & WLED_8_BIT_MASK;
509 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
510 led->spmi_dev->sid,
511 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
512 if (rc) {
513 dev_err(&led->spmi_dev->dev,
514 "WLED set brightness LSB failed(%d)\n", rc);
515 return rc;
516 }
517 }
518
519 /* sync */
520 val = WLED_SYNC_VAL;
521 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
522 WLED_SYNC_REG(led->base), &val, 1);
523 if (rc) {
524 dev_err(&led->spmi_dev->dev,
525 "WLED set sync reg failed(%d)\n", rc);
526 return rc;
527 }
528
529 val = WLED_SYNC_RESET_VAL;
530 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
531 WLED_SYNC_REG(led->base), &val, 1);
532 if (rc) {
533 dev_err(&led->spmi_dev->dev,
534 "WLED reset sync reg failed(%d)\n", rc);
535 return rc;
536 }
537 return 0;
538}
539
Amy Malochef3813742013-04-11 19:33:47 -0700540static int qpnp_mpp_set(struct qpnp_led_data *led)
541{
542 int rc, val;
543
544 if (led->cdev.brightness) {
545 val = (led->cdev.brightness * LED_MPP_SINK_MASK) / LED_FULL;
546 rc = qpnp_led_masked_write(led,
547 LED_MPP_SINK_CTRL(led->base),
548 LED_MPP_SINK_MASK, val);
549 if (rc) {
550 dev_err(&led->spmi_dev->dev,
551 "Failed to write led enable reg\n");
552 return rc;
553 }
554
555 val = led->mpp_cfg->source_sel | led->mpp_cfg->mode_ctrl;
556
557 rc = qpnp_led_masked_write(led,
558 LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
559 val);
560 if (rc) {
561 dev_err(&led->spmi_dev->dev,
562 "Failed to write led mode reg\n");
563 return rc;
564 }
565
566 rc = qpnp_led_masked_write(led,
567 LED_MPP_EN_CTRL(led->base), LED_MPP_EN_MASK,
568 LED_MPP_EN_ENABLE);
569 if (rc) {
570 dev_err(&led->spmi_dev->dev,
571 "Failed to write led enable " \
572 "reg\n");
573 return rc;
574 }
575 } else {
576 rc = qpnp_led_masked_write(led,
577 LED_MPP_MODE_CTRL(led->base),
578 LED_MPP_MODE_MASK,
579 LED_MPP_MODE_DISABLE);
580 if (rc) {
581 dev_err(&led->spmi_dev->dev,
582 "Failed to write led mode reg\n");
583 return rc;
584 }
585
586 rc = qpnp_led_masked_write(led,
587 LED_MPP_EN_CTRL(led->base),
588 LED_MPP_EN_MASK,
589 LED_MPP_EN_DISABLE);
590 if (rc) {
591 dev_err(&led->spmi_dev->dev,
592 "Failed to write led enable reg\n");
593 return rc;
594 }
595 }
596
597 qpnp_dump_regs(led, mpp_debug_regs, ARRAY_SIZE(mpp_debug_regs));
598
599 return 0;
600}
601
Amy Maloche864a6d52012-10-03 15:58:12 -0700602static int qpnp_flash_set(struct qpnp_led_data *led)
603{
604 int rc;
605 int val = led->cdev.brightness;
606
607 led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
608 led->max_current);
609
610 led->flash_cfg->current_prgm =
611 led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
612 if (!led->flash_cfg->current_prgm)
613 led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
614
615 /* Set led current */
616 if (val > 0) {
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 return rc;
625 }
626
627 rc = qpnp_led_masked_write(led,
628 FLASH_LED_TORCH(led->base),
629 FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
630 if (rc) {
631 dev_err(&led->spmi_dev->dev,
632 "Torch reg write failed(%d)\n", rc);
633 return rc;
634 }
635
Amy Malochebc97c0d22013-03-24 22:06:16 -0700636 rc = qpnp_led_masked_write(led,
637 led->flash_cfg->current_addr,
Chun Zhange8954cf2013-05-02 11:14:34 -0700638 FLASH_CURRENT_MASK,
639 led->flash_cfg->current_prgm);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700640 if (rc) {
641 dev_err(&led->spmi_dev->dev,
642 "Current reg write failed(%d)\n", rc);
643 return rc;
644 }
645
646 rc = qpnp_led_masked_write(led,
647 led->flash_cfg->second_addr,
Chun Zhange8954cf2013-05-02 11:14:34 -0700648 FLASH_CURRENT_MASK,
649 led->flash_cfg->current_prgm);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700650 if (rc) {
651 dev_err(&led->spmi_dev->dev,
652 "2nd Current reg write failed(%d)\n",
653 rc);
654 return rc;
655 }
656
Chun Zhange8954cf2013-05-02 11:14:34 -0700657 qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
658 FLASH_CURRENT_MASK,
659 led->max_current);
660 if (rc) {
661 dev_err(&led->spmi_dev->dev,
662 "Max current reg write failed(%d)\n",
663 rc);
664 return rc;
665 }
666
Amy Malochebc97c0d22013-03-24 22:06:16 -0700667 rc = qpnp_led_masked_write(led,
668 FLASH_ENABLE_CONTROL(led->base),
669 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
670 if (rc) {
671 dev_err(&led->spmi_dev->dev,
672 "Enable reg write failed(%d)\n", rc);
673 return rc;
674 }
675 } else {
Chun Zhange8954cf2013-05-02 11:14:34 -0700676 /* Set flash safety timer */
Amy Malochebc97c0d22013-03-24 22:06:16 -0700677 rc = qpnp_led_masked_write(led,
Chun Zhange8954cf2013-05-02 11:14:34 -0700678 FLASH_SAFETY_TIMER(led->base),
679 FLASH_SAFETY_TIMER_MASK,
680 led->flash_cfg->duration);
681 if (rc) {
682 dev_err(&led->spmi_dev->dev,
683 "Safety timer reg write failed(%d)\n",
684 rc);
685 return rc;
686 }
687
688 /* Set max current */
689 rc = qpnp_led_masked_write(led,
690 FLASH_MAX_CURR(led->base), FLASH_CURRENT_MASK,
691 FLASH_MAX_LEVEL);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700692 if (rc) {
693 dev_err(&led->spmi_dev->dev,
694 "Max current reg write failed(%d)\n",
695 rc);
696 return rc;
697 }
698
Chun Zhange8954cf2013-05-02 11:14:34 -0700699 /* Set clamp current */
700 rc = qpnp_led_masked_write(led,
701 FLASH_CLAMP_CURR(led->base),
702 FLASH_CURRENT_MASK,
703 led->flash_cfg->clamp_curr);
704 if (rc) {
705 dev_err(&led->spmi_dev->dev,
706 "Clamp current reg write failed(%d)\n",
707 rc);
708 return rc;
709 }
710
Amy Malochebc97c0d22013-03-24 22:06:16 -0700711 /* Write 0x80 to MODULE_ENABLE before writing 0xE0
712 * in order to avoid reg value goes from 0x00 to
713 * 0xE0. This causes a hardware bug.
714 */
715 rc = qpnp_led_masked_write(led,
716 FLASH_ENABLE_CONTROL(led->base),
717 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
718 if (rc) {
719 dev_err(&led->spmi_dev->dev,
720 "Enable reg write failed(%d)\n", rc);
721 return rc;
722 }
723
724 rc = qpnp_led_masked_write(led,
725 led->flash_cfg->current_addr,
726 FLASH_CURRENT_MASK,
727 led->flash_cfg->current_prgm);
728 if (rc) {
729 dev_err(&led->spmi_dev->dev,
730 "Current reg write failed(%d)\n", rc);
731 return rc;
732 }
733
734 rc = qpnp_led_masked_write(led,
735 led->flash_cfg->second_addr,
736 FLASH_CURRENT_MASK,
737 led->flash_cfg->current_prgm);
738 if (rc) {
739 dev_err(&led->spmi_dev->dev,
740 "2nd Current reg write failed(%d)\n",
741 rc);
742 return rc;
743 }
744
745 rc = qpnp_led_masked_write(led,
Amy Malochebc97c0d22013-03-24 22:06:16 -0700746 FLASH_ENABLE_CONTROL(led->base),
747 FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
748 if (rc) {
749 dev_err(&led->spmi_dev->dev,
750 "Enable reg write failed(%d)\n", rc);
751 return rc;
752 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800753 }
754
Amy Malochebc97c0d22013-03-24 22:06:16 -0700755 if (!led->flash_cfg->strobe_type) {
756 rc = qpnp_led_masked_write(led,
757 FLASH_LED_STROBE_CTRL(led->base),
758 FLASH_STROBE_MASK, FLASH_STROBE_SW);
759 if (rc) {
760 dev_err(&led->spmi_dev->dev,
761 "LED %d strobe reg write failed(%d)\n",
762 led->id, rc);
763 return rc;
764 }
765 } else {
766 rc = qpnp_led_masked_write(led,
767 FLASH_LED_STROBE_CTRL(led->base),
768 FLASH_STROBE_MASK, FLASH_STROBE_HW);
769 if (rc) {
770 dev_err(&led->spmi_dev->dev,
771 "LED %d strobe reg write failed(%d)\n",
772 led->id, rc);
773 return rc;
774 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800775 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700776 } else {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700777 if (led->flash_cfg->torch_enable) {
778 rc = qpnp_led_masked_write(led,
779 FLASH_LED_UNLOCK_SECURE(led->base),
780 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
781 if (rc) {
782 dev_err(&led->spmi_dev->dev,
783 "Secure reg write failed(%d)\n", rc);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700784 return rc;
785 }
786
787 rc = qpnp_led_masked_write(led,
Chun Zhange8954cf2013-05-02 11:14:34 -0700788 FLASH_LED_TORCH(led->base),
789 FLASH_TORCH_MASK,
790 FLASH_LED_TORCH_DISABLE);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700791 if (rc) {
792 dev_err(&led->spmi_dev->dev,
Chun Zhange8954cf2013-05-02 11:14:34 -0700793 "Torch reg write failed(%d)\n", rc);
Amy Malochebc97c0d22013-03-24 22:06:16 -0700794 return rc;
795 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700796 }
797
798 rc = qpnp_led_masked_write(led,
799 FLASH_LED_STROBE_CTRL(led->base),
800 FLASH_STROBE_MASK,
801 FLASH_DISABLE_ALL);
802 if (rc) {
803 dev_err(&led->spmi_dev->dev,
804 "LED %d flash write failed(%d)\n", led->id, rc);
805 return rc;
806 }
Amy Malochebc97c0d22013-03-24 22:06:16 -0700807
808 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
809 FLASH_ENABLE_MASK,
810 FLASH_DISABLE_ALL);
811 if (rc) {
812 dev_err(&led->spmi_dev->dev,
813 "Enable reg write failed(%d)\n", rc);
814 return rc;
815 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700816 }
817
Amy Malocheeea7b592012-10-03 15:59:36 -0700818 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
819
820 return 0;
821}
822
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530823static int qpnp_kpdbl_set(struct qpnp_led_data *led)
824{
825 int duty_us;
826 int rc;
827
828 if (led->cdev.brightness) {
829 rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
830 KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
831 duty_us = (led->kpdbl_cfg->pwm_period_us *
832 led->cdev.brightness) / KPDBL_MAX_LEVEL;
833 rc = pwm_config(led->kpdbl_cfg->pwm_dev, duty_us,
834 led->kpdbl_cfg->pwm_period_us);
835 if (rc < 0) {
836 dev_err(&led->spmi_dev->dev, "pwm config failed\n");
837 return rc;
838 }
839 rc = pwm_enable(led->kpdbl_cfg->pwm_dev);
840 if (rc < 0) {
841 dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
842 return rc;
843 }
844 } else {
845 pwm_disable(led->kpdbl_cfg->pwm_dev);
846 rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
847 KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
848 if (rc) {
849 dev_err(&led->spmi_dev->dev,
850 "Failed to write led enable reg\n");
851 return rc;
852 }
853 }
854
855 qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
856
857 return 0;
858}
859
Amy Malocheeea7b592012-10-03 15:59:36 -0700860static int qpnp_rgb_set(struct qpnp_led_data *led)
861{
862 int duty_us;
863 int rc;
864
865 if (led->cdev.brightness) {
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530866 if (led->rgb_cfg->mode == PWM_MODE) {
Amy Malocheeea7b592012-10-03 15:59:36 -0700867 duty_us = (led->rgb_cfg->pwm_period_us *
868 led->cdev.brightness) / LED_FULL;
869 rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
870 led->rgb_cfg->pwm_period_us);
871 if (rc < 0) {
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530872 dev_err(&led->spmi_dev->dev,
873 "pwm config failed\n");
Amy Malocheeea7b592012-10-03 15:59:36 -0700874 return rc;
875 }
876 }
877 rc = qpnp_led_masked_write(led,
878 RGB_LED_EN_CTL(led->base),
879 led->rgb_cfg->enable, led->rgb_cfg->enable);
880 if (rc) {
881 dev_err(&led->spmi_dev->dev,
882 "Failed to write led enable reg\n");
883 return rc;
884 }
885 rc = pwm_enable(led->rgb_cfg->pwm_dev);
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530886 if (rc < 0) {
887 dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
888 return rc;
889 }
Amy Malocheeea7b592012-10-03 15:59:36 -0700890 } else {
891 pwm_disable(led->rgb_cfg->pwm_dev);
892 rc = qpnp_led_masked_write(led,
893 RGB_LED_EN_CTL(led->base),
894 led->rgb_cfg->enable, RGB_LED_DISABLE);
895 if (rc) {
896 dev_err(&led->spmi_dev->dev,
897 "Failed to write led enable reg\n");
898 return rc;
899 }
900 }
901
902 qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
903
Amy Maloche864a6d52012-10-03 15:58:12 -0700904 return 0;
905}
906
Amy Malochef3d5a062012-08-16 19:14:11 -0700907static void qpnp_led_set(struct led_classdev *led_cdev,
908 enum led_brightness value)
909{
910 int rc;
911 struct qpnp_led_data *led;
912
913 led = container_of(led_cdev, struct qpnp_led_data, cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -0700914 if (value < LED_OFF || value > led->cdev.max_brightness) {
Amy Malochea5ca5552012-10-23 13:34:46 -0700915 dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
Amy Malochef3d5a062012-08-16 19:14:11 -0700916 return;
917 }
918
Amy Malochedc3e5572012-09-25 16:39:06 -0700919 spin_lock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700920 led->cdev.brightness = value;
921
922 switch (led->id) {
923 case QPNP_ID_WLED:
924 rc = qpnp_wled_set(led);
925 if (rc < 0)
Amy Malochea5ca5552012-10-23 13:34:46 -0700926 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700927 "WLED set brightness failed (%d)\n", rc);
928 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700929 case QPNP_ID_FLASH1_LED0:
930 case QPNP_ID_FLASH1_LED1:
931 rc = qpnp_flash_set(led);
932 if (rc < 0)
933 dev_err(&led->spmi_dev->dev,
934 "FLASH set brightness failed (%d)\n", rc);
935 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700936 case QPNP_ID_RGB_RED:
937 case QPNP_ID_RGB_GREEN:
938 case QPNP_ID_RGB_BLUE:
939 rc = qpnp_rgb_set(led);
940 if (rc < 0)
941 dev_err(&led->spmi_dev->dev,
942 "RGB set brightness failed (%d)\n", rc);
943 break;
Amy Malochef3813742013-04-11 19:33:47 -0700944 case QPNP_ID_LED_MPP:
945 rc = qpnp_mpp_set(led);
946 if (rc < 0)
947 dev_err(&led->spmi_dev->dev,
948 "MPP set brightness failed (%d)\n", rc);
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530949 case QPNP_ID_KPDBL:
950 rc = qpnp_kpdbl_set(led);
951 if (rc < 0)
952 dev_err(&led->spmi_dev->dev,
953 "KPDBL set brightness failed (%d)\n", rc);
Amy Malochef3813742013-04-11 19:33:47 -0700954 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700955 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700956 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700957 break;
958 }
Amy Malochedc3e5572012-09-25 16:39:06 -0700959 spin_unlock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700960}
961
962static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
963{
964 switch (led->id) {
965 case QPNP_ID_WLED:
966 led->cdev.max_brightness = WLED_MAX_LEVEL;
967 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700968 case QPNP_ID_FLASH1_LED0:
969 case QPNP_ID_FLASH1_LED1:
970 led->cdev.max_brightness = led->max_current;
971 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700972 case QPNP_ID_RGB_RED:
973 case QPNP_ID_RGB_GREEN:
974 case QPNP_ID_RGB_BLUE:
975 led->cdev.max_brightness = RGB_MAX_LEVEL;
976 break;
Amy Malochef3813742013-04-11 19:33:47 -0700977 case QPNP_ID_LED_MPP:
978 led->cdev.max_brightness = MPP_MAX_LEVEL;
979 break;
Mohan Pallaka1f46f022013-03-15 14:56:50 +0530980 case QPNP_ID_KPDBL:
981 led->cdev.max_brightness = KPDBL_MAX_LEVEL;
982 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700983 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700984 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700985 return -EINVAL;
986 }
987
988 return 0;
989}
990
991static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
992{
993 struct qpnp_led_data *led;
994
995 led = container_of(led_cdev, struct qpnp_led_data, cdev);
996
997 return led->cdev.brightness;
998}
999
Asaf Penso55ac8472013-01-21 21:17:37 +02001000static void qpnp_led_turn_off_delayed(struct work_struct *work)
1001{
1002 struct delayed_work *dwork = to_delayed_work(work);
1003 struct qpnp_led_data *led
1004 = container_of(dwork, struct qpnp_led_data, dwork);
1005
1006 led->cdev.brightness = LED_OFF;
1007 qpnp_led_set(&led->cdev, led->cdev.brightness);
1008}
1009
1010static void qpnp_led_turn_off(struct qpnp_led_data *led)
1011{
1012 INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed);
1013 schedule_delayed_work(&led->dwork,
1014 msecs_to_jiffies(led->turn_off_delay_ms));
1015}
1016
Amy Malochef3d5a062012-08-16 19:14:11 -07001017static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
1018{
1019 int rc, i;
1020 u8 num_wled_strings;
1021
1022 num_wled_strings = led->wled_cfg->num_strings;
1023
1024 /* verify ranges */
1025 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
1026 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
1027 return -EINVAL;
1028 }
1029
1030 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
1031 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
1032 return -EINVAL;
1033 }
1034
1035 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
1036 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
1037 return -EINVAL;
1038 }
1039
1040 if ((led->max_current > WLED_MAX_CURR)) {
1041 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
1042 return -EINVAL;
1043 }
1044
1045 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
1046 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
1047 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
1048 return -EINVAL;
1049 }
1050
1051 /* program over voltage protection threshold */
1052 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
1053 WLED_OVP_VAL_MASK,
1054 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
1055 if (rc) {
1056 dev_err(&led->spmi_dev->dev,
1057 "WLED OVP reg write failed(%d)\n", rc);
1058 return rc;
1059 }
1060
1061 /* program current boost limit */
1062 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
1063 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
1064 if (rc) {
1065 dev_err(&led->spmi_dev->dev,
1066 "WLED boost limit reg write failed(%d)\n", rc);
1067 return rc;
1068 }
1069
1070 /* program output feedback */
1071 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
1072 WLED_OP_FDBCK_MASK,
1073 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
1074 if (rc) {
1075 dev_err(&led->spmi_dev->dev,
1076 "WLED fdbck ctrl reg write failed(%d)\n", rc);
1077 return rc;
1078 }
1079
1080 /* program switch frequency */
1081 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
1082 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
1083 if (rc) {
1084 dev_err(&led->spmi_dev->dev,
1085 "WLED switch freq reg write failed(%d)\n", rc);
1086 return rc;
1087 }
1088
1089 /* program current sink */
1090 if (led->wled_cfg->cs_out_en) {
1091 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
1092 WLED_CURR_SINK_MASK,
Amy Maloche832d90a2013-01-07 10:15:29 -08001093 (((1 << led->wled_cfg->num_strings) - 1)
1094 << WLED_CURR_SINK_SHFT));
Amy Malochef3d5a062012-08-16 19:14:11 -07001095 if (rc) {
1096 dev_err(&led->spmi_dev->dev,
1097 "WLED curr sink reg write failed(%d)\n", rc);
1098 return rc;
1099 }
1100 }
1101
1102 /* program high pole capacitance */
1103 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
1104 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
1105 if (rc) {
1106 dev_err(&led->spmi_dev->dev,
1107 "WLED pole cap reg write failed(%d)\n", rc);
1108 return rc;
1109 }
1110
1111 /* program modulator, current mod src and cabc */
1112 for (i = 0; i < num_wled_strings; i++) {
1113 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
1114 WLED_NO_MASK, WLED_EN_MASK);
1115 if (rc) {
1116 dev_err(&led->spmi_dev->dev,
1117 "WLED mod enable reg write failed(%d)\n", rc);
1118 return rc;
1119 }
1120
1121 if (led->wled_cfg->dig_mod_gen_en) {
1122 rc = qpnp_led_masked_write(led,
Amy Maloched44516e2013-02-14 17:36:34 -08001123 WLED_MOD_SRC_SEL_REG(led->base, i),
Amy Malochef3d5a062012-08-16 19:14:11 -07001124 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
1125 if (rc) {
1126 dev_err(&led->spmi_dev->dev,
1127 "WLED dig mod en reg write failed(%d)\n", rc);
1128 }
1129 }
1130
1131 rc = qpnp_led_masked_write(led,
1132 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
1133 led->max_current);
1134 if (rc) {
1135 dev_err(&led->spmi_dev->dev,
1136 "WLED max current reg write failed(%d)\n", rc);
1137 return rc;
1138 }
1139
1140 }
1141
1142 /* dump wled registers */
Amy Malochea5ca5552012-10-23 13:34:46 -07001143 qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
Amy Malochef3d5a062012-08-16 19:14:11 -07001144
1145 return 0;
1146}
1147
Amy Malochebc97c0d22013-03-24 22:06:16 -07001148static ssize_t led_mode_store(struct device *dev,
1149 struct device_attribute *attr,
1150 const char *buf, size_t count)
1151{
1152 struct qpnp_led_data *led;
1153 unsigned long state;
1154 struct led_classdev *led_cdev = dev_get_drvdata(dev);
1155 ssize_t ret = -EINVAL;
1156
1157 ret = kstrtoul(buf, 10, &state);
1158 if (ret)
1159 return ret;
1160
1161 led = container_of(led_cdev, struct qpnp_led_data, cdev);
1162
1163 /* '1' to enable torch mode; '0' to switch to flash mode */
1164 if (state == 1)
1165 led->flash_cfg->torch_enable = true;
1166 else
1167 led->flash_cfg->torch_enable = false;
1168
1169 return count;
1170}
1171
1172static ssize_t led_strobe_type_store(struct device *dev,
1173 struct device_attribute *attr,
1174 const char *buf, size_t count)
1175{
1176 struct qpnp_led_data *led;
1177 unsigned long state;
1178 struct led_classdev *led_cdev = dev_get_drvdata(dev);
1179 ssize_t ret = -EINVAL;
1180
1181 ret = kstrtoul(buf, 10, &state);
1182 if (ret)
1183 return ret;
1184
1185 led = container_of(led_cdev, struct qpnp_led_data, cdev);
1186
1187 /* '0' for sw strobe; '1' for hw strobe */
1188 if (state == 1)
1189 led->flash_cfg->strobe_type = 1;
1190 else
1191 led->flash_cfg->strobe_type = 0;
1192
1193 return count;
1194}
1195
1196static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
1197static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
1198
1199static struct attribute *led_attrs[] = {
1200 &dev_attr_led_mode.attr,
1201 &dev_attr_strobe.attr,
Amy Maloche12ad6f32013-04-02 14:39:24 -07001202 NULL
Amy Malochebc97c0d22013-03-24 22:06:16 -07001203};
1204
1205static const struct attribute_group led_attr_group = {
1206 .attrs = led_attrs,
1207};
1208
Amy Maloche864a6d52012-10-03 15:58:12 -07001209static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
1210{
1211 int rc;
1212
1213 rc = qpnp_led_masked_write(led,
1214 FLASH_LED_STROBE_CTRL(led->base),
1215 FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
1216 if (rc) {
1217 dev_err(&led->spmi_dev->dev,
1218 "LED %d flash write failed(%d)\n", led->id, rc);
1219 return rc;
1220 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001221
Amy Maloche864a6d52012-10-03 15:58:12 -07001222 /* Set headroom */
1223 rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
1224 FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
1225 if (rc) {
1226 dev_err(&led->spmi_dev->dev,
1227 "Headroom reg write failed(%d)\n", rc);
1228 return rc;
1229 }
1230
Chun Zhange8954cf2013-05-02 11:14:34 -07001231 /* Set startup delay */
1232 rc = qpnp_led_masked_write(led,
1233 FLASH_STARTUP_DELAY(led->base), FLASH_STARTUP_DLY_MASK,
1234 led->flash_cfg->startup_dly);
1235 if (rc) {
1236 dev_err(&led->spmi_dev->dev,
1237 "Startup delay reg write failed(%d)\n", rc);
1238 return rc;
1239 }
1240
1241 /* Set timer control - safety or watchdog */
1242 if (led->flash_cfg->safety_timer) {
1243 rc = qpnp_led_masked_write(led,
1244 FLASH_LED_TMR_CTRL(led->base),
1245 FLASH_TMR_MASK, FLASH_TMR_SAFETY);
1246 if (rc) {
1247 dev_err(&led->spmi_dev->dev,
1248 "LED timer ctrl reg write failed(%d)\n",
1249 rc);
1250 return rc;
1251 }
1252 }
1253
1254 /* Set Vreg force */
1255 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
1256 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
1257 if (rc) {
1258 dev_err(&led->spmi_dev->dev,
1259 "Vreg OK reg write failed(%d)\n", rc);
1260 return rc;
1261 }
1262
1263 /* Set self fault check */
1264 rc = qpnp_led_masked_write(led, FLASH_FAULT_DETECT(led->base),
1265 FLASH_FAULT_DETECT_MASK, FLASH_SELFCHECK_ENABLE);
1266 if (rc) {
1267 dev_err(&led->spmi_dev->dev,
1268 "Fault detect reg write failed(%d)\n", rc);
1269 return rc;
1270 }
1271
Amy Maloche864a6d52012-10-03 15:58:12 -07001272 /* Set mask enable */
1273 rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
1274 FLASH_MASK_REG_MASK, FLASH_MASK_1);
1275 if (rc) {
1276 dev_err(&led->spmi_dev->dev,
1277 "Mask enable reg write failed(%d)\n", rc);
1278 return rc;
1279 }
1280
Chun Zhange8954cf2013-05-02 11:14:34 -07001281 /* Disable flash LED module */
Amy Maloche864a6d52012-10-03 15:58:12 -07001282 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
Amy Maloche38b9aae2013-02-07 12:15:34 -08001283 FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
Amy Maloche864a6d52012-10-03 15:58:12 -07001284 if (rc) {
1285 dev_err(&led->spmi_dev->dev,
1286 "Enable reg write failed(%d)\n", rc);
1287 return rc;
1288 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07001289
Amy Malochebc97c0d22013-03-24 22:06:16 -07001290 led->flash_cfg->strobe_type = 0;
1291
Amy Maloche864a6d52012-10-03 15:58:12 -07001292 /* dump flash registers */
1293 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
1294
1295 return 0;
1296}
1297
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301298static int __devinit qpnp_kpdbl_init(struct qpnp_led_data *led)
1299{
1300 int rc;
1301 u8 val;
1302
1303 /* enable row source selct */
1304 rc = qpnp_led_masked_write(led, KPDBL_ROW_SRC_SEL(led->base),
1305 KPDBL_ROW_SRC_SEL_VAL_MASK, led->kpdbl_cfg->row_src_sel_val);
1306 if (rc) {
1307 dev_err(&led->spmi_dev->dev,
1308 "Enable row src sel write failed(%d)\n", rc);
1309 return rc;
1310 }
1311
1312 /* row source */
1313 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
1314 KPDBL_ROW_SRC(led->base), &val, 1);
1315 if (rc) {
1316 dev_err(&led->spmi_dev->dev,
1317 "Unable to read from addr=%x, rc(%d)\n",
1318 KPDBL_ROW_SRC(led->base), rc);
1319 return rc;
1320 }
1321
1322 val &= ~KPDBL_ROW_SCAN_VAL_MASK;
1323 val |= led->kpdbl_cfg->row_scan_val;
1324
1325 led->kpdbl_cfg->row_scan_en <<= KPDBL_ROW_SCAN_EN_SHIFT;
1326 val &= ~KPDBL_ROW_SCAN_EN_MASK;
1327 val |= led->kpdbl_cfg->row_scan_en;
1328
1329 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
1330 KPDBL_ROW_SRC(led->base), &val, 1);
1331 if (rc) {
1332 dev_err(&led->spmi_dev->dev,
1333 "Unable to write to addr=%x, rc(%d)\n",
1334 KPDBL_ROW_SRC(led->base), rc);
1335 return rc;
1336 }
1337
1338 /* enable module */
1339 rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
1340 KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
1341 if (rc) {
1342 dev_err(&led->spmi_dev->dev,
1343 "Enable module write failed(%d)\n", rc);
1344 return rc;
1345 }
1346
1347 if (led->kpdbl_cfg->pwm_channel != -1) {
1348 led->kpdbl_cfg->pwm_dev =
1349 pwm_request(led->kpdbl_cfg->pwm_channel,
1350 led->cdev.name);
1351
1352 if (IS_ERR_OR_NULL(led->kpdbl_cfg->pwm_dev)) {
1353 dev_err(&led->spmi_dev->dev,
1354 "could not acquire PWM Channel %d, " \
1355 "error %ld\n",
1356 led->kpdbl_cfg->pwm_channel,
1357 PTR_ERR(led->kpdbl_cfg->pwm_dev));
1358 led->kpdbl_cfg->pwm_dev = NULL;
1359 return -ENODEV;
1360 }
1361 } else {
1362 dev_err(&led->spmi_dev->dev,
1363 "Invalid PWM channel\n");
1364 return -EINVAL;
1365 }
1366
1367 /* dump kpdbl registers */
1368 qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
1369
1370 return 0;
1371}
1372
Amy Malocheeea7b592012-10-03 15:59:36 -07001373static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
1374{
1375 int rc, start_idx, idx_len;
1376
1377 rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
1378 RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
1379 if (rc) {
1380 dev_err(&led->spmi_dev->dev,
1381 "Failed to write led source select register\n");
1382 return rc;
1383 }
1384
1385 if (led->rgb_cfg->pwm_channel != -1) {
1386 led->rgb_cfg->pwm_dev =
1387 pwm_request(led->rgb_cfg->pwm_channel,
1388 led->cdev.name);
1389
1390 if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
1391 dev_err(&led->spmi_dev->dev,
1392 "could not acquire PWM Channel %d, " \
1393 "error %ld\n",
1394 led->rgb_cfg->pwm_channel,
1395 PTR_ERR(led->rgb_cfg->pwm_dev));
1396 led->rgb_cfg->pwm_dev = NULL;
1397 return -ENODEV;
1398 }
1399
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301400 if (led->rgb_cfg->mode == LPG_MODE) {
Amy Malocheeea7b592012-10-03 15:59:36 -07001401 start_idx =
1402 led->rgb_cfg->duty_cycles->start_idx;
1403 idx_len =
1404 led->rgb_cfg->duty_cycles->num_duty_pcts;
1405
1406 if (idx_len >= PWM_LUT_MAX_SIZE &&
1407 start_idx) {
1408 dev_err(&led->spmi_dev->dev,
1409 "Wrong LUT size or index\n");
1410 return -EINVAL;
1411 }
1412 if ((start_idx + idx_len) >
1413 PWM_LUT_MAX_SIZE) {
1414 dev_err(&led->spmi_dev->dev,
1415 "Exceed LUT limit\n");
1416 return -EINVAL;
1417 }
1418 rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
Amy Maloche013b35b2013-03-19 12:29:11 -07001419 PM_PWM_PERIOD_MIN, /* ignored by hardware */
Amy Malocheeea7b592012-10-03 15:59:36 -07001420 led->rgb_cfg->duty_cycles->duty_pcts,
1421 led->rgb_cfg->lut_params);
1422 if (rc < 0) {
1423 dev_err(&led->spmi_dev->dev, "Failed to " \
1424 "configure pwm LUT\n");
1425 return rc;
1426 }
1427 }
1428 } else {
1429 dev_err(&led->spmi_dev->dev,
1430 "Invalid PWM channel\n");
1431 return -EINVAL;
1432 }
1433
1434 /* Initialize led for use in auto trickle charging mode */
1435 rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
1436 led->rgb_cfg->enable, led->rgb_cfg->enable);
1437
1438 return 0;
1439}
1440
Amy Malochef3d5a062012-08-16 19:14:11 -07001441static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
1442{
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301443 int rc = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001444
1445 switch (led->id) {
1446 case QPNP_ID_WLED:
1447 rc = qpnp_wled_init(led);
1448 if (rc)
Amy Malochea5ca5552012-10-23 13:34:46 -07001449 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -07001450 "WLED initialize failed(%d)\n", rc);
1451 break;
Amy Maloche864a6d52012-10-03 15:58:12 -07001452 case QPNP_ID_FLASH1_LED0:
1453 case QPNP_ID_FLASH1_LED1:
1454 rc = qpnp_flash_init(led);
1455 if (rc)
1456 dev_err(&led->spmi_dev->dev,
1457 "FLASH initialize failed(%d)\n", rc);
1458 break;
Amy Malocheeea7b592012-10-03 15:59:36 -07001459 case QPNP_ID_RGB_RED:
1460 case QPNP_ID_RGB_GREEN:
1461 case QPNP_ID_RGB_BLUE:
1462 rc = qpnp_rgb_init(led);
1463 if (rc)
1464 dev_err(&led->spmi_dev->dev,
1465 "RGB initialize failed(%d)\n", rc);
1466 break;
Amy Malochef3813742013-04-11 19:33:47 -07001467 case QPNP_ID_LED_MPP:
1468 break;
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301469 case QPNP_ID_KPDBL:
1470 rc = qpnp_kpdbl_init(led);
1471 if (rc)
1472 dev_err(&led->spmi_dev->dev,
1473 "KPDBL initialize failed(%d)\n", rc);
1474 break;
Amy Malochef3d5a062012-08-16 19:14:11 -07001475 default:
Amy Malochea5ca5552012-10-23 13:34:46 -07001476 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malocheeea7b592012-10-03 15:59:36 -07001477 return -EINVAL;
Amy Malochef3d5a062012-08-16 19:14:11 -07001478 }
1479
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301480 return rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001481}
1482
Amy Malochea5ca5552012-10-23 13:34:46 -07001483static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
1484 struct device_node *node)
1485{
1486 int rc;
Asaf Penso55ac8472013-01-21 21:17:37 +02001487 u32 val;
Amy Malochea5ca5552012-10-23 13:34:46 -07001488 const char *temp_string;
1489
1490 led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
1491 rc = of_property_read_string(node, "linux,default-trigger",
1492 &temp_string);
1493 if (!rc)
1494 led->cdev.default_trigger = temp_string;
1495 else if (rc != -EINVAL)
1496 return rc;
1497
1498 led->default_on = false;
1499 rc = of_property_read_string(node, "qcom,default-state",
1500 &temp_string);
1501 if (!rc) {
1502 if (strncmp(temp_string, "on", sizeof("on")) == 0)
1503 led->default_on = true;
1504 } else if (rc != -EINVAL)
1505 return rc;
1506
Asaf Penso55ac8472013-01-21 21:17:37 +02001507 led->turn_off_delay_ms = 0;
1508 rc = of_property_read_u32(node, "qcom,turn-off-delay-ms", &val);
1509 if (!rc)
1510 led->turn_off_delay_ms = val;
1511 else if (rc != -EINVAL)
1512 return rc;
1513
Amy Malochea5ca5552012-10-23 13:34:46 -07001514 return 0;
1515}
1516
Amy Malochef3d5a062012-08-16 19:14:11 -07001517/*
1518 * Handlers for alternative sources of platform_data
1519 */
1520static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
1521 struct device_node *node)
1522{
1523 u32 val;
1524 int rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001525
1526 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
1527 sizeof(struct wled_config_data), GFP_KERNEL);
1528 if (!led->wled_cfg) {
1529 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1530 return -ENOMEM;
1531 }
1532
Amy Malochef3d5a062012-08-16 19:14:11 -07001533 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
1534 rc = of_property_read_u32(node, "qcom,num-strings", &val);
1535 if (!rc)
1536 led->wled_cfg->num_strings = (u8) val;
1537 else if (rc != -EINVAL)
1538 return rc;
1539
1540 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
1541 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
1542 if (!rc)
1543 led->wled_cfg->ovp_val = (u8) val;
1544 else if (rc != -EINVAL)
1545 return rc;
1546
1547 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
1548 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
1549 if (!rc)
1550 led->wled_cfg->boost_curr_lim = (u8) val;
1551 else if (rc != -EINVAL)
1552 return rc;
1553
1554 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
1555 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
1556 if (!rc)
1557 led->wled_cfg->cp_select = (u8) val;
1558 else if (rc != -EINVAL)
1559 return rc;
1560
1561 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
1562 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
1563 if (!rc)
1564 led->wled_cfg->ctrl_delay_us = (u8) val;
1565 else if (rc != -EINVAL)
1566 return rc;
1567
Amy Malochebd687672013-03-18 11:23:45 -07001568 led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
1569 rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
1570 if (!rc)
1571 led->wled_cfg->op_fdbck = (u8) val;
1572 else if (rc != -EINVAL)
1573 return rc;
1574
Amy Malochef3d5a062012-08-16 19:14:11 -07001575 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
1576 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
1577 if (!rc)
1578 led->wled_cfg->switch_freq = (u8) val;
1579 else if (rc != -EINVAL)
1580 return rc;
1581
1582 led->wled_cfg->dig_mod_gen_en =
1583 of_property_read_bool(node, "qcom,dig-mod-gen-en");
1584
1585 led->wled_cfg->cs_out_en =
1586 of_property_read_bool(node, "qcom,cs-out-en");
1587
Amy Malochef3d5a062012-08-16 19:14:11 -07001588 return 0;
1589}
1590
Amy Maloche864a6d52012-10-03 15:58:12 -07001591static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
1592 struct device_node *node)
1593{
1594 int rc;
1595 u32 val;
1596
1597 led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
1598 sizeof(struct flash_config_data), GFP_KERNEL);
1599 if (!led->flash_cfg) {
1600 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1601 return -ENOMEM;
1602 }
1603
1604 if (led->id == QPNP_ID_FLASH1_LED0) {
1605 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1606 led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
1607 led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
1608 led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
1609 } else if (led->id == QPNP_ID_FLASH1_LED1) {
1610 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1611 led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
1612 led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
1613 led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
1614 } else {
1615 dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
1616 return -EINVAL;
1617 }
1618
1619 rc = of_property_read_u32(node, "qcom,current", &val);
1620 if (!rc)
1621 led->flash_cfg->current_prgm = (val *
1622 FLASH_MAX_LEVEL / led->max_current);
1623 else
1624 return -EINVAL;
1625
1626 rc = of_property_read_u32(node, "qcom,headroom", &val);
1627 if (!rc)
1628 led->flash_cfg->headroom = (u8) val;
1629 else if (rc == -EINVAL)
1630 led->flash_cfg->headroom = HEADROOM_300mV;
1631 else
1632 return rc;
1633
1634 rc = of_property_read_u32(node, "qcom,duration", &val);
1635 if (!rc)
1636 led->flash_cfg->duration = (((u8) val) - 10) / 10;
1637 else if (rc == -EINVAL)
1638 led->flash_cfg->duration = FLASH_DURATION_200ms;
1639 else
1640 return rc;
1641
1642 rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
1643 if (!rc)
1644 led->flash_cfg->clamp_curr = (val *
1645 FLASH_MAX_LEVEL / led->max_current);
1646 else if (rc == -EINVAL)
1647 led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
1648 else
1649 return rc;
1650
1651 rc = of_property_read_u32(node, "qcom,startup-dly", &val);
1652 if (!rc)
1653 led->flash_cfg->startup_dly = (u8) val;
1654 else if (rc == -EINVAL)
1655 led->flash_cfg->startup_dly = DELAY_32us;
1656 else
1657 return rc;
1658
1659 led->flash_cfg->safety_timer =
1660 of_property_read_bool(node, "qcom,safety-timer");
1661
Chun Zhange8954cf2013-05-02 11:14:34 -07001662 led->flash_cfg->torch_enable =
1663 of_property_read_bool(node, "qcom,torch-enable");
1664
Amy Maloche864a6d52012-10-03 15:58:12 -07001665 return 0;
1666}
1667
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301668static int __devinit qpnp_get_config_kpdbl(struct qpnp_led_data *led,
1669 struct device_node *node)
1670{
1671 int rc;
1672 u32 val;
1673
1674 led->kpdbl_cfg = devm_kzalloc(&led->spmi_dev->dev,
1675 sizeof(struct kpdbl_config_data), GFP_KERNEL);
1676 if (!led->kpdbl_cfg) {
1677 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1678 return -ENOMEM;
1679 }
1680
1681 rc = of_property_read_u32(node, "qcom,mode", &val);
1682 if (!rc)
1683 led->kpdbl_cfg->mode = (u8) val;
1684 else
1685 return rc;
1686
1687 if (led->kpdbl_cfg->mode == LPG_MODE) {
1688 dev_err(&led->spmi_dev->dev, "LPG mode not supported\n");
1689 return -EINVAL;
1690 }
1691
1692 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1693 if (!rc)
1694 led->kpdbl_cfg->pwm_channel = (u8) val;
1695 else
1696 return rc;
1697
1698 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1699 if (!rc)
1700 led->kpdbl_cfg->pwm_period_us = val;
1701 else
1702 return rc;
1703
1704 rc = of_property_read_u32(node, "qcom,row-src-sel-val", &val);
1705 if (!rc)
1706 led->kpdbl_cfg->row_src_sel_val = val;
1707 else
1708 return rc;
1709
1710 rc = of_property_read_u32(node, "qcom,row-scan-val", &val);
1711 if (!rc)
1712 led->kpdbl_cfg->row_scan_val = val;
1713 else
1714 return rc;
1715
1716 rc = of_property_read_u32(node, "qcom,row-scan-en", &val);
1717 if (!rc)
1718 led->kpdbl_cfg->row_scan_en = val;
1719 else
1720 return rc;
1721
1722 return 0;
1723}
1724
Amy Malocheeea7b592012-10-03 15:59:36 -07001725static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
1726 struct device_node *node)
1727{
1728 struct property *prop;
1729 int rc, i;
1730 u32 val;
1731 u8 *temp_cfg;
1732
1733 led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
1734 sizeof(struct rgb_config_data), GFP_KERNEL);
1735 if (!led->rgb_cfg) {
1736 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1737 return -ENOMEM;
1738 }
1739
1740 if (led->id == QPNP_ID_RGB_RED)
1741 led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
1742 else if (led->id == QPNP_ID_RGB_GREEN)
1743 led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
1744 else if (led->id == QPNP_ID_RGB_BLUE)
1745 led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
1746 else
1747 return -EINVAL;
1748
1749 rc = of_property_read_u32(node, "qcom,mode", &val);
1750 if (!rc)
1751 led->rgb_cfg->mode = (u8) val;
1752 else
1753 return rc;
1754
1755 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1756 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001757 led->rgb_cfg->pwm_channel = val;
Amy Malocheeea7b592012-10-03 15:59:36 -07001758 else
1759 return rc;
1760
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301761 if (led->rgb_cfg->mode == PWM_MODE) {
Amy Maloche013b35b2013-03-19 12:29:11 -07001762 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1763 if (!rc)
1764 led->rgb_cfg->pwm_period_us = val;
1765 else
1766 return rc;
1767 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001768
Mohan Pallaka1f46f022013-03-15 14:56:50 +05301769 if (led->rgb_cfg->mode == LPG_MODE) {
Amy Malocheeea7b592012-10-03 15:59:36 -07001770 led->rgb_cfg->duty_cycles =
1771 devm_kzalloc(&led->spmi_dev->dev,
1772 sizeof(struct pwm_duty_cycles), GFP_KERNEL);
1773 if (!led->rgb_cfg->duty_cycles) {
1774 dev_err(&led->spmi_dev->dev,
1775 "Unable to allocate memory\n");
1776 return -ENOMEM;
1777 }
1778
Amy Malocheeea7b592012-10-03 15:59:36 -07001779 prop = of_find_property(node, "qcom,duty-pcts",
1780 &led->rgb_cfg->duty_cycles->num_duty_pcts);
1781 if (!prop) {
1782 dev_err(&led->spmi_dev->dev, "Looking up property " \
1783 "node qcom,duty-pcts failed\n");
1784 return -ENODEV;
1785 } else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
1786 dev_err(&led->spmi_dev->dev, "Invalid length of " \
1787 "duty pcts\n");
1788 return -EINVAL;
1789 }
1790
1791 led->rgb_cfg->duty_cycles->duty_pcts =
1792 devm_kzalloc(&led->spmi_dev->dev,
1793 sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
1794 GFP_KERNEL);
1795 if (!led->rgb_cfg->duty_cycles->duty_pcts) {
1796 dev_err(&led->spmi_dev->dev,
1797 "Unable to allocate memory\n");
1798 return -ENOMEM;
1799 }
1800
1801 temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1802 led->rgb_cfg->duty_cycles->num_duty_pcts *
1803 sizeof(u8), GFP_KERNEL);
1804 if (!temp_cfg) {
1805 dev_err(&led->spmi_dev->dev, "Failed to allocate " \
1806 "memory for duty pcts\n");
1807 return -ENOMEM;
1808 }
1809
1810 memcpy(temp_cfg, prop->value,
1811 led->rgb_cfg->duty_cycles->num_duty_pcts);
1812
1813 for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
1814 led->rgb_cfg->duty_cycles->duty_pcts[i] =
1815 (int) temp_cfg[i];
1816
1817 rc = of_property_read_u32(node, "qcom,start-idx", &val);
1818 if (!rc) {
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001819 led->rgb_cfg->lut_params.start_idx = val;
1820 led->rgb_cfg->duty_cycles->start_idx = val;
Amy Malocheeea7b592012-10-03 15:59:36 -07001821 } else
1822 return rc;
1823
Amy Maloche013b35b2013-03-19 12:29:11 -07001824 led->rgb_cfg->lut_params.lut_pause_hi = 0;
1825 rc = of_property_read_u32(node, "qcom,pause-hi", &val);
1826 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001827 led->rgb_cfg->lut_params.lut_pause_hi = val;
Amy Maloche013b35b2013-03-19 12:29:11 -07001828 else if (rc != -EINVAL)
1829 return rc;
1830
1831 led->rgb_cfg->lut_params.lut_pause_lo = 0;
1832 rc = of_property_read_u32(node, "qcom,pause-lo", &val);
1833 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001834 led->rgb_cfg->lut_params.lut_pause_lo = val;
Amy Maloche013b35b2013-03-19 12:29:11 -07001835 else if (rc != -EINVAL)
1836 return rc;
1837
1838 led->rgb_cfg->lut_params.ramp_step_ms =
1839 QPNP_LUT_RAMP_STEP_DEFAULT;
1840 rc = of_property_read_u32(node, "qcom,ramp-step-ms", &val);
1841 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001842 led->rgb_cfg->lut_params.ramp_step_ms = val;
Amy Maloche013b35b2013-03-19 12:29:11 -07001843 else if (rc != -EINVAL)
1844 return rc;
1845
1846 led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
1847 rc = of_property_read_u32(node, "qcom,lut-flags", &val);
1848 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001849 led->rgb_cfg->lut_params.flags = val;
Amy Maloche013b35b2013-03-19 12:29:11 -07001850 else if (rc != -EINVAL)
1851 return rc;
1852
Amy Malocheeea7b592012-10-03 15:59:36 -07001853 led->rgb_cfg->lut_params.idx_len =
1854 led->rgb_cfg->duty_cycles->num_duty_pcts;
Amy Malocheeea7b592012-10-03 15:59:36 -07001855 }
1856
1857 return 0;
1858}
1859
Amy Malochef3813742013-04-11 19:33:47 -07001860static int __devinit qpnp_get_config_mpp(struct qpnp_led_data *led,
1861 struct device_node *node)
1862{
1863 int rc;
1864 u32 val;
1865
1866 led->mpp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1867 sizeof(struct mpp_config_data), GFP_KERNEL);
1868 if (!led->mpp_cfg) {
1869 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1870 return -ENOMEM;
1871 }
1872
1873 led->mpp_cfg->current_setting = LED_MPP_CURRENT_DEFAULT;
1874 rc = of_property_read_u32(node, "qcom,current-setting", &val);
1875 if (!rc)
1876 led->mpp_cfg->current_setting = (u8) val;
1877 else if (rc != -EINVAL)
1878 return rc;
1879
1880 led->mpp_cfg->source_sel = LED_MPP_SOURCE_SEL_DEFAULT;
1881 rc = of_property_read_u32(node, "qcom,source-sel", &val);
1882 if (!rc)
1883 led->mpp_cfg->source_sel = (u8) val;
1884 else if (rc != -EINVAL)
1885 return rc;
1886
1887 led->mpp_cfg->mode_ctrl = LED_MPP_MODE_SINK;
1888 rc = of_property_read_u32(node, "qcom,mode-ctrl", &val);
1889 if (!rc)
1890 led->mpp_cfg->mode_ctrl = (u8) val;
1891 else if (rc != -EINVAL)
1892 return rc;
1893
1894 return 0;
1895}
1896
Amy Malochef3d5a062012-08-16 19:14:11 -07001897static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
1898{
Amy Malochef9490c62012-11-27 19:26:04 -08001899 struct qpnp_led_data *led, *led_array;
Amy Malochef3d5a062012-08-16 19:14:11 -07001900 struct resource *led_resource;
Amy Malochea5ca5552012-10-23 13:34:46 -07001901 struct device_node *node, *temp;
Amy Malochef9490c62012-11-27 19:26:04 -08001902 int rc, i, num_leds = 0, parsed_leds = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001903 const char *led_label;
1904
Amy Malochea5ca5552012-10-23 13:34:46 -07001905 node = spmi->dev.of_node;
1906 if (node == NULL)
1907 return -ENODEV;
1908
1909 temp = NULL;
1910 while ((temp = of_get_next_child(node, temp)))
1911 num_leds++;
1912
Amy Malochef9490c62012-11-27 19:26:04 -08001913 if (!num_leds)
1914 return -ECHILD;
1915
1916 led_array = devm_kzalloc(&spmi->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001917 (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
Amy Malochef9490c62012-11-27 19:26:04 -08001918 if (!led_array) {
Amy Malochef3d5a062012-08-16 19:14:11 -07001919 dev_err(&spmi->dev, "Unable to allocate memory\n");
1920 return -ENOMEM;
1921 }
1922
Amy Malochea5ca5552012-10-23 13:34:46 -07001923 for_each_child_of_node(node, temp) {
Amy Malochef9490c62012-11-27 19:26:04 -08001924 led = &led_array[parsed_leds];
1925 led->num_leds = num_leds;
Amy Malochea5ca5552012-10-23 13:34:46 -07001926 led->spmi_dev = spmi;
Amy Malochef3d5a062012-08-16 19:14:11 -07001927
Amy Malochea5ca5552012-10-23 13:34:46 -07001928 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
1929 if (!led_resource) {
1930 dev_err(&spmi->dev, "Unable to get LED base address\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001931 rc = -ENXIO;
1932 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001933 }
1934 led->base = led_resource->start;
Amy Malochef3d5a062012-08-16 19:14:11 -07001935
Amy Malochea5ca5552012-10-23 13:34:46 -07001936 rc = of_property_read_string(temp, "label", &led_label);
Amy Malochef3d5a062012-08-16 19:14:11 -07001937 if (rc < 0) {
1938 dev_err(&led->spmi_dev->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001939 "Failure reading label, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001940 goto fail_id_check;
Amy Malochef3d5a062012-08-16 19:14:11 -07001941 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001942
1943 rc = of_property_read_string(temp, "linux,name",
1944 &led->cdev.name);
1945 if (rc < 0) {
1946 dev_err(&led->spmi_dev->dev,
1947 "Failure reading led name, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001948 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001949 }
1950
1951 rc = of_property_read_u32(temp, "qcom,max-current",
1952 &led->max_current);
1953 if (rc < 0) {
1954 dev_err(&led->spmi_dev->dev,
1955 "Failure reading max_current, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001956 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001957 }
1958
1959 rc = of_property_read_u32(temp, "qcom,id", &led->id);
1960 if (rc < 0) {
1961 dev_err(&led->spmi_dev->dev,
1962 "Failure reading led id, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001963 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001964 }
1965
1966 rc = qpnp_get_common_configs(led, temp);
1967 if (rc) {
1968 dev_err(&led->spmi_dev->dev,
1969 "Failure reading common led configuration," \
1970 " rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001971 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001972 }
1973
1974 led->cdev.brightness_set = qpnp_led_set;
1975 led->cdev.brightness_get = qpnp_led_get;
1976
1977 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
1978 rc = qpnp_get_config_wled(led, temp);
1979 if (rc < 0) {
1980 dev_err(&led->spmi_dev->dev,
1981 "Unable to read wled config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001982 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001983 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001984 } else if (strncmp(led_label, "flash", sizeof("flash"))
1985 == 0) {
1986 rc = qpnp_get_config_flash(led, temp);
1987 if (rc < 0) {
1988 dev_err(&led->spmi_dev->dev,
1989 "Unable to read flash config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001990 goto fail_id_check;
Amy Maloche864a6d52012-10-03 15:58:12 -07001991 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001992 } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
1993 rc = qpnp_get_config_rgb(led, temp);
1994 if (rc < 0) {
1995 dev_err(&led->spmi_dev->dev,
1996 "Unable to read rgb config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001997 goto fail_id_check;
Amy Malocheeea7b592012-10-03 15:59:36 -07001998 }
Amy Malochef3813742013-04-11 19:33:47 -07001999 } else if (strncmp(led_label, "mpp", sizeof("mpp")) == 0) {
2000 rc = qpnp_get_config_mpp(led, temp);
2001 if (rc < 0) {
2002 dev_err(&led->spmi_dev->dev,
2003 "Unable to read mpp config data\n");
Mohan Pallaka1f46f022013-03-15 14:56:50 +05302004 }
2005 } else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
2006 rc = qpnp_get_config_kpdbl(led, temp);
2007 if (rc < 0) {
2008 dev_err(&led->spmi_dev->dev,
2009 "Unable to read kpdbl config data\n");
Amy Malochef3813742013-04-11 19:33:47 -07002010 goto fail_id_check;
2011 }
Amy Malochea5ca5552012-10-23 13:34:46 -07002012 } else {
2013 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
Amy Malochef9490c62012-11-27 19:26:04 -08002014 rc = -EINVAL;
2015 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07002016 }
2017
2018 spin_lock_init(&led->lock);
2019
2020 rc = qpnp_led_initialize(led);
2021 if (rc < 0)
2022 goto fail_id_check;
2023
2024 rc = qpnp_led_set_max_brightness(led);
2025 if (rc < 0)
2026 goto fail_id_check;
2027
2028 rc = led_classdev_register(&spmi->dev, &led->cdev);
2029 if (rc) {
2030 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
2031 led->id, rc);
2032 goto fail_id_check;
2033 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07002034
2035 if (led->id == QPNP_ID_FLASH1_LED0 ||
2036 led->id == QPNP_ID_FLASH1_LED1) {
2037 rc = sysfs_create_group(&led->cdev.dev->kobj,
2038 &led_attr_group);
2039 if (rc)
2040 goto fail_id_check;
2041
2042 }
2043
Amy Malochea5ca5552012-10-23 13:34:46 -07002044 /* configure default state */
Asaf Penso55ac8472013-01-21 21:17:37 +02002045 if (led->default_on) {
Amy Malochea5ca5552012-10-23 13:34:46 -07002046 led->cdev.brightness = led->cdev.max_brightness;
Asaf Penso55ac8472013-01-21 21:17:37 +02002047 if (led->turn_off_delay_ms > 0)
2048 qpnp_led_turn_off(led);
2049 } else
Amy Malochea5ca5552012-10-23 13:34:46 -07002050 led->cdev.brightness = LED_OFF;
2051
2052 qpnp_led_set(&led->cdev, led->cdev.brightness);
Amy Malochef9490c62012-11-27 19:26:04 -08002053
2054 parsed_leds++;
Amy Malochef3d5a062012-08-16 19:14:11 -07002055 }
Amy Malochef9490c62012-11-27 19:26:04 -08002056 dev_set_drvdata(&spmi->dev, led_array);
Amy Malochef3d5a062012-08-16 19:14:11 -07002057 return 0;
2058
2059fail_id_check:
Amy Malochef9490c62012-11-27 19:26:04 -08002060 for (i = 0; i < parsed_leds; i++)
2061 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07002062 return rc;
2063}
2064
2065static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
2066{
Amy Malochef9490c62012-11-27 19:26:04 -08002067 struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
2068 int i, parsed_leds = led_array->num_leds;
Amy Malochef3d5a062012-08-16 19:14:11 -07002069
Amy Malochebc97c0d22013-03-24 22:06:16 -07002070 for (i = 0; i < parsed_leds; i++) {
Amy Malochef9490c62012-11-27 19:26:04 -08002071 led_classdev_unregister(&led_array[i].cdev);
Amy Malochebc97c0d22013-03-24 22:06:16 -07002072 switch (led_array[i].id) {
2073 case QPNP_ID_WLED:
2074 break;
2075 case QPNP_ID_FLASH1_LED0:
2076 case QPNP_ID_FLASH1_LED1:
2077 sysfs_remove_group(&led_array[i].cdev.dev->kobj,
2078 &led_attr_group);
2079 break;
2080 case QPNP_ID_RGB_RED:
2081 case QPNP_ID_RGB_GREEN:
2082 case QPNP_ID_RGB_BLUE:
2083 default:
2084 dev_err(&led_array[i].spmi_dev->dev,
2085 "Invalid LED(%d)\n",
2086 led_array[i].id);
2087 return -EINVAL;
2088 }
2089 }
Amy Malochef3d5a062012-08-16 19:14:11 -07002090
2091 return 0;
2092}
2093static struct of_device_id spmi_match_table[] = {
2094 { .compatible = "qcom,leds-qpnp",
2095 }
2096};
2097
2098static struct spmi_driver qpnp_leds_driver = {
2099 .driver = {
2100 .name = "qcom,leds-qpnp",
2101 .of_match_table = spmi_match_table,
2102 },
2103 .probe = qpnp_leds_probe,
2104 .remove = __devexit_p(qpnp_leds_remove),
2105};
2106
2107static int __init qpnp_led_init(void)
2108{
2109 return spmi_driver_register(&qpnp_leds_driver);
2110}
2111module_init(qpnp_led_init);
2112
2113static void __exit qpnp_led_exit(void)
2114{
2115 spmi_driver_unregister(&qpnp_leds_driver);
2116}
2117module_exit(qpnp_led_exit);
2118
2119MODULE_DESCRIPTION("QPNP LEDs driver");
2120MODULE_LICENSE("GPL v2");
2121MODULE_ALIAS("leds:leds-qpnp");
Amy Maloche864a6d52012-10-03 15:58:12 -07002122