blob: 36672964183a6298e3075ce6e9dcdf78ee226b64 [file] [log] [blame]
Amy Malochef3d5a062012-08-16 19:14:11 -07001
Amy Maloche832d90a2013-01-07 10:15:29 -08002/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Amy Malochef3d5a062012-08-16 19:14:11 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/leds.h>
19#include <linux/err.h>
Amy Malochedc3e5572012-09-25 16:39:06 -070020#include <linux/spinlock.h>
Amy Malochef3d5a062012-08-16 19:14:11 -070021#include <linux/of_platform.h>
22#include <linux/of_device.h>
23#include <linux/spmi.h>
Amy Malocheeea7b592012-10-03 15:59:36 -070024#include <linux/qpnp/pwm.h>
Asaf Penso55ac8472013-01-21 21:17:37 +020025#include <linux/workqueue.h>
Amy Malochef3d5a062012-08-16 19:14:11 -070026
27#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
28#define WLED_IDAC_DLY_REG(base, n) (WLED_MOD_EN_REG(base, n) + 0x01)
29#define WLED_FULL_SCALE_REG(base, n) (WLED_IDAC_DLY_REG(base, n) + 0x01)
Amy Maloched44516e2013-02-14 17:36:34 -080030#define WLED_MOD_SRC_SEL_REG(base, n) (WLED_FULL_SCALE_REG(base, n) + 0x01)
Amy Malochef3d5a062012-08-16 19:14:11 -070031
32/* wled control registers */
33#define WLED_BRIGHTNESS_CNTL_LSB(base, n) (base + 0x40 + 2*n)
34#define WLED_BRIGHTNESS_CNTL_MSB(base, n) (base + 0x41 + 2*n)
35#define WLED_MOD_CTRL_REG(base) (base + 0x46)
36#define WLED_SYNC_REG(base) (base + 0x47)
37#define WLED_FDBCK_CTRL_REG(base) (base + 0x48)
38#define WLED_SWITCHING_FREQ_REG(base) (base + 0x4C)
39#define WLED_OVP_CFG_REG(base) (base + 0x4D)
40#define WLED_BOOST_LIMIT_REG(base) (base + 0x4E)
41#define WLED_CURR_SINK_REG(base) (base + 0x4F)
42#define WLED_HIGH_POLE_CAP_REG(base) (base + 0x58)
43#define WLED_CURR_SINK_MASK 0xE0
44#define WLED_CURR_SINK_SHFT 0x05
45#define WLED_SWITCH_FREQ_MASK 0x02
46#define WLED_OVP_VAL_MASK 0x03
47#define WLED_OVP_VAL_BIT_SHFT 0x00
48#define WLED_BOOST_LIMIT_MASK 0x07
49#define WLED_BOOST_LIMIT_BIT_SHFT 0x00
50#define WLED_BOOST_ON 0x80
51#define WLED_BOOST_OFF 0x00
52#define WLED_EN_MASK 0x80
53#define WLED_NO_MASK 0x00
54#define WLED_CP_SELECT_MAX 0x03
55#define WLED_CP_SELECT_MASK 0x02
56#define WLED_USE_EXT_GEN_MOD_SRC 0x01
57#define WLED_CTL_DLY_STEP 200
58#define WLED_CTL_DLY_MAX 1400
59#define WLED_MAX_CURR 25
60#define WLED_MSB_MASK 0x0F
61#define WLED_MAX_CURR_MASK 0x19
62#define WLED_OP_FDBCK_MASK 0x07
63#define WLED_OP_FDBCK_BIT_SHFT 0x00
Amy Malochebd687672013-03-18 11:23:45 -070064#define WLED_OP_FDBCK_DEFAULT 0x00
Amy Malochef3d5a062012-08-16 19:14:11 -070065
Amy Maloched55fdb82013-02-26 18:11:57 -080066#define WLED_MAX_LEVEL 4095
Amy Malochef3d5a062012-08-16 19:14:11 -070067#define WLED_8_BIT_MASK 0xFF
68#define WLED_4_BIT_MASK 0x0F
69#define WLED_8_BIT_SHFT 0x08
70#define WLED_MAX_DUTY_CYCLE 0xFFF
71
72#define WLED_SYNC_VAL 0x07
73#define WLED_SYNC_RESET_VAL 0x00
74
Amy Malochef3d5a062012-08-16 19:14:11 -070075#define WLED_DEFAULT_STRINGS 0x01
76#define WLED_DEFAULT_OVP_VAL 0x02
77#define WLED_BOOST_LIM_DEFAULT 0x03
78#define WLED_CP_SEL_DEFAULT 0x00
79#define WLED_CTRL_DLY_DEFAULT 0x00
80#define WLED_SWITCH_FREQ_DEFAULT 0x02
81
Amy Maloche864a6d52012-10-03 15:58:12 -070082#define FLASH_SAFETY_TIMER(base) (base + 0x40)
83#define FLASH_MAX_CURR(base) (base + 0x41)
84#define FLASH_LED_0_CURR(base) (base + 0x42)
85#define FLASH_LED_1_CURR(base) (base + 0x43)
86#define FLASH_CLAMP_CURR(base) (base + 0x44)
87#define FLASH_LED_TMR_CTRL(base) (base + 0x48)
Amy Maloched44516e2013-02-14 17:36:34 -080088#define FLASH_HEADROOM(base) (base + 0x4A)
Amy Maloche864a6d52012-10-03 15:58:12 -070089#define FLASH_STARTUP_DELAY(base) (base + 0x4B)
90#define FLASH_MASK_ENABLE(base) (base + 0x4C)
91#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
92#define FLASH_ENABLE_CONTROL(base) (base + 0x46)
93#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
Amy Malochebc97c0d22013-03-24 22:06:16 -070094#define FLASH_LED_UNLOCK_SECURE(base) (base + 0xD0)
95#define FLASH_LED_TORCH(base) (base + 0xE4)
Amy Maloche864a6d52012-10-03 15:58:12 -070096
97#define FLASH_MAX_LEVEL 0x4F
98#define FLASH_NO_MASK 0x00
99
100#define FLASH_MASK_1 0x20
101#define FLASH_MASK_REG_MASK 0xE0
102#define FLASH_HEADROOM_MASK 0x03
103#define FLASH_SAFETY_TIMER_MASK 0x7F
104#define FLASH_CURRENT_MASK 0xFF
Amy Malochebc97c0d22013-03-24 22:06:16 -0700105#define FLASH_MAX_CURRENT_MASK 0x7F
Amy Maloche864a6d52012-10-03 15:58:12 -0700106#define FLASH_TMR_MASK 0x03
107#define FLASH_TMR_WATCHDOG 0x03
108#define FLASH_TMR_SAFETY 0x00
109
110#define FLASH_HW_VREG_OK 0x80
111#define FLASH_VREG_MASK 0xC0
112
113#define FLASH_STARTUP_DLY_MASK 0x02
114
115#define FLASH_ENABLE_ALL 0xE0
116#define FLASH_ENABLE_MODULE 0x80
117#define FLASH_ENABLE_MODULE_MASK 0x80
118#define FLASH_DISABLE_ALL 0x00
Amy Maloche38b9aae2013-02-07 12:15:34 -0800119#define FLASH_ENABLE_MASK 0xE0
Amy Maloche864a6d52012-10-03 15:58:12 -0700120#define FLASH_ENABLE_LED_0 0x40
121#define FLASH_ENABLE_LED_1 0x20
122#define FLASH_INIT_MASK 0xE0
123
Amy Malochebc97c0d22013-03-24 22:06:16 -0700124#define FLASH_STROBE_SW 0xC0
125#define FLASH_STROBE_HW 0xC4
126#define FLASH_STROBE_MASK 0xC7
Amy Maloche864a6d52012-10-03 15:58:12 -0700127#define FLASH_LED_0_OUTPUT 0x80
128#define FLASH_LED_1_OUTPUT 0x40
129
130#define FLASH_CURRENT_PRGM_MIN 1
131#define FLASH_CURRENT_PRGM_SHIFT 1
Amy Malochebc97c0d22013-03-24 22:06:16 -0700132#define FLASH_CURRENT_MAX 0x4F
133#define FLASH_CURRENT_TORCH 0x0F
Amy Maloche864a6d52012-10-03 15:58:12 -0700134
135#define FLASH_DURATION_200ms 0x13
136#define FLASH_CLAMP_200mA 0x0F
137
Amy Malochebc97c0d22013-03-24 22:06:16 -0700138#define FLASH_TORCH_MASK 0x03
139#define FLASH_LED_TORCH_ENABLE 0x00
140#define FLASH_LED_TORCH_DISABLE 0x03
141#define FLASH_UNLOCK_SECURE 0xA5
142#define FLASH_SECURE_MASK 0xFF
143
Amy Malochea5ca5552012-10-23 13:34:46 -0700144#define LED_TRIGGER_DEFAULT "none"
145
Amy Malocheeea7b592012-10-03 15:59:36 -0700146#define RGB_LED_SRC_SEL(base) (base + 0x45)
147#define RGB_LED_EN_CTL(base) (base + 0x46)
148#define RGB_LED_ATC_CTL(base) (base + 0x47)
149
150#define RGB_MAX_LEVEL LED_FULL
151#define RGB_LED_ENABLE_RED 0x80
152#define RGB_LED_ENABLE_GREEN 0x40
153#define RGB_LED_ENABLE_BLUE 0x20
154#define RGB_LED_SOURCE_VPH_PWR 0x01
155#define RGB_LED_ENABLE_MASK 0xE0
156#define RGB_LED_SRC_MASK 0x03
157#define QPNP_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
Amy Maloche013b35b2013-03-19 12:29:11 -0700158#define QPNP_LUT_RAMP_STEP_DEFAULT 255
Amy Malocheeea7b592012-10-03 15:59:36 -0700159#define PWM_LUT_MAX_SIZE 63
160#define RGB_LED_DISABLE 0x00
161
Amy Malochef3813742013-04-11 19:33:47 -0700162#define MPP_MAX_LEVEL LED_FULL
163#define LED_MPP_MODE_CTRL(base) (base + 0x40)
164#define LED_MPP_VIN_CTRL(base) (base + 0x41)
165#define LED_MPP_EN_CTRL(base) (base + 0x46)
166#define LED_MPP_SINK_CTRL(base) (base + 0x4C)
167
168#define LED_MPP_CURRENT_DEFAULT 10
169#define LED_MPP_SOURCE_SEL_DEFAULT LED_MPP_MODE_ENABLE
170
171#define LED_MPP_SINK_MASK 0x07
172#define LED_MPP_MODE_MASK 0x7F
173#define LED_MPP_EN_MASK 0x80
174
175#define LED_MPP_MODE_SINK (0x06 << 4)
176#define LED_MPP_MODE_ENABLE 0x01
177#define LED_MPP_MODE_OUTPUT 0x10
178#define LED_MPP_MODE_DISABLE 0x00
179#define LED_MPP_EN_ENABLE 0x80
180#define LED_MPP_EN_DISABLE 0x00
181
182#define MPP_SOURCE_DTEST1 0x08
Amy Malochef3d5a062012-08-16 19:14:11 -0700183/**
184 * enum qpnp_leds - QPNP supported led ids
185 * @QPNP_ID_WLED - White led backlight
186 */
187enum qpnp_leds {
Amy Maloche864a6d52012-10-03 15:58:12 -0700188 QPNP_ID_WLED = 0,
189 QPNP_ID_FLASH1_LED0,
190 QPNP_ID_FLASH1_LED1,
Amy Malocheeea7b592012-10-03 15:59:36 -0700191 QPNP_ID_RGB_RED,
192 QPNP_ID_RGB_GREEN,
193 QPNP_ID_RGB_BLUE,
Amy Malochef3813742013-04-11 19:33:47 -0700194 QPNP_ID_LED_MPP,
Amy Maloche864a6d52012-10-03 15:58:12 -0700195 QPNP_ID_MAX,
Amy Malochef3d5a062012-08-16 19:14:11 -0700196};
197
198/* current boost limit */
199enum wled_current_boost_limit {
200 WLED_CURR_LIMIT_105mA,
201 WLED_CURR_LIMIT_385mA,
202 WLED_CURR_LIMIT_525mA,
203 WLED_CURR_LIMIT_805mA,
204 WLED_CURR_LIMIT_980mA,
205 WLED_CURR_LIMIT_1260mA,
206 WLED_CURR_LIMIT_1400mA,
207 WLED_CURR_LIMIT_1680mA,
208};
209
210/* over voltage protection threshold */
211enum wled_ovp_threshold {
212 WLED_OVP_35V,
213 WLED_OVP_32V,
214 WLED_OVP_29V,
215 WLED_OVP_37V,
216};
217
218/* switch frquency */
219enum wled_switch_freq {
220 WLED_800kHz = 0,
221 WLED_960kHz,
222 WLED_1600kHz,
223 WLED_3200kHz,
224};
225
Amy Maloche864a6d52012-10-03 15:58:12 -0700226enum flash_headroom {
227 HEADROOM_250mV = 0,
228 HEADROOM_300mV,
229 HEADROOM_400mV,
230 HEADROOM_500mV,
231};
232
233enum flash_startup_dly {
234 DELAY_10us = 0,
235 DELAY_32us,
236 DELAY_64us,
237 DELAY_128us,
238};
239
Amy Malocheeea7b592012-10-03 15:59:36 -0700240enum rgb_mode {
241 RGB_MODE_PWM = 0,
242 RGB_MODE_LPG,
243};
244
Amy Malochef3d5a062012-08-16 19:14:11 -0700245static u8 wled_debug_regs[] = {
246 /* common registers */
247 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
248 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
249 /* LED1 */
250 0x60, 0x61, 0x62, 0x63, 0x66,
Amy Malochea5ca5552012-10-23 13:34:46 -0700251 /* LED2 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700252 0x70, 0x71, 0x72, 0x73, 0x76,
Amy Malochea5ca5552012-10-23 13:34:46 -0700253 /* LED3 */
Amy Malochef3d5a062012-08-16 19:14:11 -0700254 0x80, 0x81, 0x82, 0x83, 0x86,
255};
256
Amy Maloche864a6d52012-10-03 15:58:12 -0700257static u8 flash_debug_regs[] = {
258 0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
259 0x4f, 0x46, 0x47,
260};
261
Amy Malocheeea7b592012-10-03 15:59:36 -0700262static u8 rgb_pwm_debug_regs[] = {
263 0x45, 0x46, 0x47,
264};
Amy Malochef3813742013-04-11 19:33:47 -0700265
266static u8 mpp_debug_regs[] = {
267 0x40, 0x41, 0x42, 0x45, 0x46, 0x4c,
268};
269
Amy Malochef3d5a062012-08-16 19:14:11 -0700270/**
271 * wled_config_data - wled configuration data
272 * @num_strings - number of wled strings supported
273 * @ovp_val - over voltage protection threshold
274 * @boost_curr_lim - boot current limit
275 * @cp_select - high pole capacitance
276 * @ctrl_delay_us - delay in activation of led
277 * @dig_mod_gen_en - digital module generator
278 * @cs_out_en - current sink output enable
279 * @op_fdbck - selection of output as feedback for the boost
280 */
281struct wled_config_data {
282 u8 num_strings;
283 u8 ovp_val;
284 u8 boost_curr_lim;
285 u8 cp_select;
286 u8 ctrl_delay_us;
287 u8 switch_freq;
Amy Malochebd687672013-03-18 11:23:45 -0700288 u8 op_fdbck;
Amy Malochef3d5a062012-08-16 19:14:11 -0700289 bool dig_mod_gen_en;
290 bool cs_out_en;
Amy Malochef3d5a062012-08-16 19:14:11 -0700291};
292
293/**
Amy Malochef3813742013-04-11 19:33:47 -0700294 * mpp_config_data - mpp configuration data
295 * @current_setting - current setting, 5ma-40ma in 5ma increments
296 */
297struct mpp_config_data {
298 u8 current_setting;
299 u8 source_sel;
300 u8 mode_ctrl;
301};
302
303/**
Amy Maloche864a6d52012-10-03 15:58:12 -0700304 * flash_config_data - flash configuration data
305 * @current_prgm - current to be programmed, scaled by max level
306 * @clamp_curr - clamp current to use
307 * @headroom - headroom value to use
308 * @duration - duration of the flash
309 * @enable_module - enable address for particular flash
310 * @trigger_flash - trigger flash
311 * @startup_dly - startup delay for flash
Amy Malochebc97c0d22013-03-24 22:06:16 -0700312 * @strobe_type - select between sw and hw strobe
Amy Maloche864a6d52012-10-03 15:58:12 -0700313 * @current_addr - address to write for current
314 * @second_addr - address of secondary flash to be written
315 * @safety_timer - enable safety timer or watchdog timer
Amy Malochebc97c0d22013-03-24 22:06:16 -0700316 * @torch_enable - enable flash LED torch mode
Amy Maloche864a6d52012-10-03 15:58:12 -0700317 */
318struct flash_config_data {
319 u8 current_prgm;
320 u8 clamp_curr;
321 u8 headroom;
322 u8 duration;
323 u8 enable_module;
324 u8 trigger_flash;
325 u8 startup_dly;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700326 u8 strobe_type;
Amy Maloche864a6d52012-10-03 15:58:12 -0700327 u16 current_addr;
328 u16 second_addr;
329 bool safety_timer;
Amy Malochebc97c0d22013-03-24 22:06:16 -0700330 bool torch_enable;
Amy Maloche864a6d52012-10-03 15:58:12 -0700331};
332
333/**
Amy Malocheeea7b592012-10-03 15:59:36 -0700334 * rgb_config_data - rgb configuration data
335 * @lut_params - lut parameters to be used by pwm driver
336 * @pwm_device - pwm device
337 * @pwm_channel - pwm channel to be configured for led
338 * @pwm_period_us - period for pwm, in us
339 * @mode - mode the led operates in
340 */
341struct rgb_config_data {
342 struct lut_params lut_params;
343 struct pwm_device *pwm_dev;
344 int pwm_channel;
345 u32 pwm_period_us;
346 struct pwm_duty_cycles *duty_cycles;
347 u8 mode;
348 u8 enable;
349};
350
351/**
Amy Malochef3d5a062012-08-16 19:14:11 -0700352 * struct qpnp_led_data - internal led data structure
353 * @led_classdev - led class device
Asaf Penso55ac8472013-01-21 21:17:37 +0200354 * @delayed_work - delayed work for turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700355 * @id - led index
356 * @base_reg - base register given in device tree
357 * @lock - to protect the transactions
358 * @reg - cached value of led register
Amy Malochea5ca5552012-10-23 13:34:46 -0700359 * @num_leds - number of leds in the module
Amy Malochef3d5a062012-08-16 19:14:11 -0700360 * @max_current - maximum current supported by LED
361 * @default_on - true: default state max, false, default state 0
Asaf Penso55ac8472013-01-21 21:17:37 +0200362 * @turn_off_delay_ms - number of msec before turning off the LED
Amy Malochef3d5a062012-08-16 19:14:11 -0700363 */
364struct qpnp_led_data {
365 struct led_classdev cdev;
366 struct spmi_device *spmi_dev;
Asaf Penso55ac8472013-01-21 21:17:37 +0200367 struct delayed_work dwork;
Amy Malochef3d5a062012-08-16 19:14:11 -0700368 int id;
369 u16 base;
370 u8 reg;
Amy Malochea5ca5552012-10-23 13:34:46 -0700371 u8 num_leds;
Amy Malochedc3e5572012-09-25 16:39:06 -0700372 spinlock_t lock;
Amy Malochef3d5a062012-08-16 19:14:11 -0700373 struct wled_config_data *wled_cfg;
Amy Maloche864a6d52012-10-03 15:58:12 -0700374 struct flash_config_data *flash_cfg;
Amy Malocheeea7b592012-10-03 15:59:36 -0700375 struct rgb_config_data *rgb_cfg;
Amy Malochef3813742013-04-11 19:33:47 -0700376 struct mpp_config_data *mpp_cfg;
Amy Malochef3d5a062012-08-16 19:14:11 -0700377 int max_current;
378 bool default_on;
Asaf Penso55ac8472013-01-21 21:17:37 +0200379 int turn_off_delay_ms;
Amy Malochef3d5a062012-08-16 19:14:11 -0700380};
381
382static int
383qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
384{
385 int rc;
386 u8 reg;
387
388 rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
389 addr, &reg, 1);
390 if (rc) {
391 dev_err(&led->spmi_dev->dev,
392 "Unable to read from addr=%x, rc(%d)\n", addr, rc);
393 }
394
395 reg &= ~mask;
396 reg |= val;
397
398 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
399 addr, &reg, 1);
400 if (rc)
401 dev_err(&led->spmi_dev->dev,
402 "Unable to write to addr=%x, rc(%d)\n", addr, rc);
403 return rc;
404}
405
Amy Malochea5ca5552012-10-23 13:34:46 -0700406static void qpnp_dump_regs(struct qpnp_led_data *led, u8 regs[], u8 array_size)
407{
408 int i;
409 u8 val;
410
411 pr_debug("===== %s LED register dump start =====\n", led->cdev.name);
412 for (i = 0; i < array_size; i++) {
413 spmi_ext_register_readl(led->spmi_dev->ctrl,
414 led->spmi_dev->sid,
415 led->base + regs[i],
416 &val, sizeof(val));
417 pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
418 }
419 pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
420}
421
Amy Malochef3d5a062012-08-16 19:14:11 -0700422static int qpnp_wled_set(struct qpnp_led_data *led)
423{
Amy Maloched55fdb82013-02-26 18:11:57 -0800424 int rc, duty, level;
425 u8 val, i, num_wled_strings;
Amy Malochef3d5a062012-08-16 19:14:11 -0700426
427 level = led->cdev.brightness;
428
429 if (level > WLED_MAX_LEVEL)
430 level = WLED_MAX_LEVEL;
431 if (level == 0) {
432 val = WLED_BOOST_OFF;
433 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
434 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
435 &val, 1);
436 if (rc) {
437 dev_err(&led->spmi_dev->dev,
438 "WLED write ctrl reg failed(%d)\n", rc);
439 return rc;
440 }
441 } else {
442 val = WLED_BOOST_ON;
443 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
444 led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
445 &val, 1);
446 if (rc) {
447 dev_err(&led->spmi_dev->dev,
448 "WLED write ctrl reg failed(%d)\n", rc);
449 return rc;
450 }
451 }
452
453 duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
454
455 num_wled_strings = led->wled_cfg->num_strings;
456
457 /* program brightness control registers */
458 for (i = 0; i < num_wled_strings; i++) {
459 rc = qpnp_led_masked_write(led,
460 WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
461 (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
462 if (rc) {
463 dev_err(&led->spmi_dev->dev,
464 "WLED set brightness MSB failed(%d)\n", rc);
465 return rc;
466 }
467 val = duty & WLED_8_BIT_MASK;
468 rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
469 led->spmi_dev->sid,
470 WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
471 if (rc) {
472 dev_err(&led->spmi_dev->dev,
473 "WLED set brightness LSB failed(%d)\n", rc);
474 return rc;
475 }
476 }
477
478 /* sync */
479 val = WLED_SYNC_VAL;
480 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
481 WLED_SYNC_REG(led->base), &val, 1);
482 if (rc) {
483 dev_err(&led->spmi_dev->dev,
484 "WLED set sync reg failed(%d)\n", rc);
485 return rc;
486 }
487
488 val = WLED_SYNC_RESET_VAL;
489 rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
490 WLED_SYNC_REG(led->base), &val, 1);
491 if (rc) {
492 dev_err(&led->spmi_dev->dev,
493 "WLED reset sync reg failed(%d)\n", rc);
494 return rc;
495 }
496 return 0;
497}
498
Amy Malochef3813742013-04-11 19:33:47 -0700499static int qpnp_mpp_set(struct qpnp_led_data *led)
500{
501 int rc, val;
502
503 if (led->cdev.brightness) {
504 val = (led->cdev.brightness * LED_MPP_SINK_MASK) / LED_FULL;
505 rc = qpnp_led_masked_write(led,
506 LED_MPP_SINK_CTRL(led->base),
507 LED_MPP_SINK_MASK, val);
508 if (rc) {
509 dev_err(&led->spmi_dev->dev,
510 "Failed to write led enable reg\n");
511 return rc;
512 }
513
514 val = led->mpp_cfg->source_sel | led->mpp_cfg->mode_ctrl;
515
516 rc = qpnp_led_masked_write(led,
517 LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
518 val);
519 if (rc) {
520 dev_err(&led->spmi_dev->dev,
521 "Failed to write led mode reg\n");
522 return rc;
523 }
524
525 rc = qpnp_led_masked_write(led,
526 LED_MPP_EN_CTRL(led->base), LED_MPP_EN_MASK,
527 LED_MPP_EN_ENABLE);
528 if (rc) {
529 dev_err(&led->spmi_dev->dev,
530 "Failed to write led enable " \
531 "reg\n");
532 return rc;
533 }
534 } else {
535 rc = qpnp_led_masked_write(led,
536 LED_MPP_MODE_CTRL(led->base),
537 LED_MPP_MODE_MASK,
538 LED_MPP_MODE_DISABLE);
539 if (rc) {
540 dev_err(&led->spmi_dev->dev,
541 "Failed to write led mode reg\n");
542 return rc;
543 }
544
545 rc = qpnp_led_masked_write(led,
546 LED_MPP_EN_CTRL(led->base),
547 LED_MPP_EN_MASK,
548 LED_MPP_EN_DISABLE);
549 if (rc) {
550 dev_err(&led->spmi_dev->dev,
551 "Failed to write led enable reg\n");
552 return rc;
553 }
554 }
555
556 qpnp_dump_regs(led, mpp_debug_regs, ARRAY_SIZE(mpp_debug_regs));
557
558 return 0;
559}
560
Amy Maloche864a6d52012-10-03 15:58:12 -0700561static int qpnp_flash_set(struct qpnp_led_data *led)
562{
563 int rc;
564 int val = led->cdev.brightness;
565
566 led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
567 led->max_current);
568
569 led->flash_cfg->current_prgm =
570 led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
571 if (!led->flash_cfg->current_prgm)
572 led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
573
574 /* Set led current */
575 if (val > 0) {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700576 if (led->flash_cfg->torch_enable) {
577 rc = qpnp_led_masked_write(led,
578 FLASH_LED_UNLOCK_SECURE(led->base),
579 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
580 if (rc) {
581 dev_err(&led->spmi_dev->dev,
582 "Secure reg write failed(%d)\n", rc);
583 return rc;
584 }
585
586 rc = qpnp_led_masked_write(led,
587 FLASH_LED_TORCH(led->base),
588 FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
589 if (rc) {
590 dev_err(&led->spmi_dev->dev,
591 "Torch reg write failed(%d)\n", rc);
592 return rc;
593 }
594
595 qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
596 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
597 if (rc) {
598 dev_err(&led->spmi_dev->dev,
599 "Max current reg write failed(%d)\n",
600 rc);
601 return rc;
602 }
603
604 rc = qpnp_led_masked_write(led,
605 led->flash_cfg->current_addr,
606 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
607 if (rc) {
608 dev_err(&led->spmi_dev->dev,
609 "Current reg write failed(%d)\n", rc);
610 return rc;
611 }
612
613 rc = qpnp_led_masked_write(led,
614 led->flash_cfg->second_addr,
615 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
616 if (rc) {
617 dev_err(&led->spmi_dev->dev,
618 "2nd Current reg write failed(%d)\n",
619 rc);
620 return rc;
621 }
622
623 rc = qpnp_led_masked_write(led,
624 FLASH_ENABLE_CONTROL(led->base),
625 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
626 if (rc) {
627 dev_err(&led->spmi_dev->dev,
628 "Enable reg write failed(%d)\n", rc);
629 return rc;
630 }
631 } else {
632 rc = qpnp_led_masked_write(led,
633 FLASH_MAX_CURR(led->base),
634 FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
635 if (rc) {
636 dev_err(&led->spmi_dev->dev,
637 "Max current reg write failed(%d)\n",
638 rc);
639 return rc;
640 }
641
642 /* Write 0x80 to MODULE_ENABLE before writing 0xE0
643 * in order to avoid reg value goes from 0x00 to
644 * 0xE0. This causes a hardware bug.
645 */
646 rc = qpnp_led_masked_write(led,
647 FLASH_ENABLE_CONTROL(led->base),
648 FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
649 if (rc) {
650 dev_err(&led->spmi_dev->dev,
651 "Enable reg write failed(%d)\n", rc);
652 return rc;
653 }
654
655 rc = qpnp_led_masked_write(led,
656 led->flash_cfg->current_addr,
657 FLASH_CURRENT_MASK,
658 led->flash_cfg->current_prgm);
659 if (rc) {
660 dev_err(&led->spmi_dev->dev,
661 "Current reg write failed(%d)\n", rc);
662 return rc;
663 }
664
665 rc = qpnp_led_masked_write(led,
666 led->flash_cfg->second_addr,
667 FLASH_CURRENT_MASK,
668 led->flash_cfg->current_prgm);
669 if (rc) {
670 dev_err(&led->spmi_dev->dev,
671 "2nd Current reg write failed(%d)\n",
672 rc);
673 return rc;
674 }
675
676 rc = qpnp_led_masked_write(led,
677 FLASH_CLAMP_CURR(led->base),
678 FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
679 if (rc) {
680 dev_err(&led->spmi_dev->dev,
681 "Clamp Current reg write failed(%d)\n",
682 rc);
683 return rc;
684 }
685
686 rc = qpnp_led_masked_write(led,
687 FLASH_ENABLE_CONTROL(led->base),
688 FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
689 if (rc) {
690 dev_err(&led->spmi_dev->dev,
691 "Enable reg write failed(%d)\n", rc);
692 return rc;
693 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800694 }
695
Amy Malochebc97c0d22013-03-24 22:06:16 -0700696 if (!led->flash_cfg->strobe_type) {
697 rc = qpnp_led_masked_write(led,
698 FLASH_LED_STROBE_CTRL(led->base),
699 FLASH_STROBE_MASK, FLASH_STROBE_SW);
700 if (rc) {
701 dev_err(&led->spmi_dev->dev,
702 "LED %d strobe reg write failed(%d)\n",
703 led->id, rc);
704 return rc;
705 }
706 } else {
707 rc = qpnp_led_masked_write(led,
708 FLASH_LED_STROBE_CTRL(led->base),
709 FLASH_STROBE_MASK, FLASH_STROBE_HW);
710 if (rc) {
711 dev_err(&led->spmi_dev->dev,
712 "LED %d strobe reg write failed(%d)\n",
713 led->id, rc);
714 return rc;
715 }
Amy Maloche38b9aae2013-02-07 12:15:34 -0800716 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700717 } else {
Amy Malochebc97c0d22013-03-24 22:06:16 -0700718 if (led->flash_cfg->torch_enable) {
719 rc = qpnp_led_masked_write(led,
720 FLASH_LED_UNLOCK_SECURE(led->base),
721 FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
722 if (rc) {
723 dev_err(&led->spmi_dev->dev,
724 "Secure reg write failed(%d)\n", rc);
725 }
726
727 rc = qpnp_led_masked_write(led,
728 FLASH_LED_TORCH(led->base),
729 FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
730 if (rc) {
731 dev_err(&led->spmi_dev->dev,
732 "Torch reg write failed(%d)\n", rc);
733 return rc;
734 }
735
736 rc = qpnp_led_masked_write(led,
737 FLASH_SAFETY_TIMER(led->base),
738 FLASH_SAFETY_TIMER_MASK,
739 led->flash_cfg->duration);
740 if (rc) {
741 dev_err(&led->spmi_dev->dev,
742 "Safety timer reg write failed(%d)\n",
743 rc);
744 return rc;
745 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700746 }
747
748 rc = qpnp_led_masked_write(led,
749 FLASH_LED_STROBE_CTRL(led->base),
750 FLASH_STROBE_MASK,
751 FLASH_DISABLE_ALL);
752 if (rc) {
753 dev_err(&led->spmi_dev->dev,
754 "LED %d flash write failed(%d)\n", led->id, rc);
755 return rc;
756 }
Amy Malochebc97c0d22013-03-24 22:06:16 -0700757
758 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
759 FLASH_ENABLE_MASK,
760 FLASH_DISABLE_ALL);
761 if (rc) {
762 dev_err(&led->spmi_dev->dev,
763 "Enable reg write failed(%d)\n", rc);
764 return rc;
765 }
Amy Maloche864a6d52012-10-03 15:58:12 -0700766 }
767
Amy Malocheeea7b592012-10-03 15:59:36 -0700768 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
769
770 return 0;
771}
772
773static int qpnp_rgb_set(struct qpnp_led_data *led)
774{
775 int duty_us;
776 int rc;
777
778 if (led->cdev.brightness) {
779 if (led->rgb_cfg->mode == RGB_MODE_PWM) {
780 duty_us = (led->rgb_cfg->pwm_period_us *
781 led->cdev.brightness) / LED_FULL;
782 rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
783 led->rgb_cfg->pwm_period_us);
784 if (rc < 0) {
785 dev_err(&led->spmi_dev->dev, "Failed to " \
786 "configure pwm for new values\n");
787 return rc;
788 }
789 }
790 rc = qpnp_led_masked_write(led,
791 RGB_LED_EN_CTL(led->base),
792 led->rgb_cfg->enable, led->rgb_cfg->enable);
793 if (rc) {
794 dev_err(&led->spmi_dev->dev,
795 "Failed to write led enable reg\n");
796 return rc;
797 }
798 rc = pwm_enable(led->rgb_cfg->pwm_dev);
799 } else {
800 pwm_disable(led->rgb_cfg->pwm_dev);
801 rc = qpnp_led_masked_write(led,
802 RGB_LED_EN_CTL(led->base),
803 led->rgb_cfg->enable, RGB_LED_DISABLE);
804 if (rc) {
805 dev_err(&led->spmi_dev->dev,
806 "Failed to write led enable reg\n");
807 return rc;
808 }
809 }
810
811 qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
812
Amy Maloche864a6d52012-10-03 15:58:12 -0700813 return 0;
814}
815
Amy Malochef3d5a062012-08-16 19:14:11 -0700816static void qpnp_led_set(struct led_classdev *led_cdev,
817 enum led_brightness value)
818{
819 int rc;
820 struct qpnp_led_data *led;
821
822 led = container_of(led_cdev, struct qpnp_led_data, cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -0700823 if (value < LED_OFF || value > led->cdev.max_brightness) {
Amy Malochea5ca5552012-10-23 13:34:46 -0700824 dev_err(&led->spmi_dev->dev, "Invalid brightness value\n");
Amy Malochef3d5a062012-08-16 19:14:11 -0700825 return;
826 }
827
Amy Malochedc3e5572012-09-25 16:39:06 -0700828 spin_lock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700829 led->cdev.brightness = value;
830
831 switch (led->id) {
832 case QPNP_ID_WLED:
833 rc = qpnp_wled_set(led);
834 if (rc < 0)
Amy Malochea5ca5552012-10-23 13:34:46 -0700835 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -0700836 "WLED set brightness failed (%d)\n", rc);
837 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700838 case QPNP_ID_FLASH1_LED0:
839 case QPNP_ID_FLASH1_LED1:
840 rc = qpnp_flash_set(led);
841 if (rc < 0)
842 dev_err(&led->spmi_dev->dev,
843 "FLASH set brightness failed (%d)\n", rc);
844 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700845 case QPNP_ID_RGB_RED:
846 case QPNP_ID_RGB_GREEN:
847 case QPNP_ID_RGB_BLUE:
848 rc = qpnp_rgb_set(led);
849 if (rc < 0)
850 dev_err(&led->spmi_dev->dev,
851 "RGB set brightness failed (%d)\n", rc);
852 break;
Amy Malochef3813742013-04-11 19:33:47 -0700853 case QPNP_ID_LED_MPP:
854 rc = qpnp_mpp_set(led);
855 if (rc < 0)
856 dev_err(&led->spmi_dev->dev,
857 "MPP set brightness failed (%d)\n", rc);
858 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700859 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700860 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700861 break;
862 }
Amy Malochedc3e5572012-09-25 16:39:06 -0700863 spin_unlock(&led->lock);
Amy Malochef3d5a062012-08-16 19:14:11 -0700864}
865
866static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
867{
868 switch (led->id) {
869 case QPNP_ID_WLED:
870 led->cdev.max_brightness = WLED_MAX_LEVEL;
871 break;
Amy Maloche864a6d52012-10-03 15:58:12 -0700872 case QPNP_ID_FLASH1_LED0:
873 case QPNP_ID_FLASH1_LED1:
874 led->cdev.max_brightness = led->max_current;
875 break;
Amy Malocheeea7b592012-10-03 15:59:36 -0700876 case QPNP_ID_RGB_RED:
877 case QPNP_ID_RGB_GREEN:
878 case QPNP_ID_RGB_BLUE:
879 led->cdev.max_brightness = RGB_MAX_LEVEL;
880 break;
Amy Malochef3813742013-04-11 19:33:47 -0700881 case QPNP_ID_LED_MPP:
882 led->cdev.max_brightness = MPP_MAX_LEVEL;
883 break;
Amy Malochef3d5a062012-08-16 19:14:11 -0700884 default:
Amy Malochea5ca5552012-10-23 13:34:46 -0700885 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malochef3d5a062012-08-16 19:14:11 -0700886 return -EINVAL;
887 }
888
889 return 0;
890}
891
892static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
893{
894 struct qpnp_led_data *led;
895
896 led = container_of(led_cdev, struct qpnp_led_data, cdev);
897
898 return led->cdev.brightness;
899}
900
Asaf Penso55ac8472013-01-21 21:17:37 +0200901static void qpnp_led_turn_off_delayed(struct work_struct *work)
902{
903 struct delayed_work *dwork = to_delayed_work(work);
904 struct qpnp_led_data *led
905 = container_of(dwork, struct qpnp_led_data, dwork);
906
907 led->cdev.brightness = LED_OFF;
908 qpnp_led_set(&led->cdev, led->cdev.brightness);
909}
910
911static void qpnp_led_turn_off(struct qpnp_led_data *led)
912{
913 INIT_DELAYED_WORK(&led->dwork, qpnp_led_turn_off_delayed);
914 schedule_delayed_work(&led->dwork,
915 msecs_to_jiffies(led->turn_off_delay_ms));
916}
917
Amy Malochef3d5a062012-08-16 19:14:11 -0700918static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
919{
920 int rc, i;
921 u8 num_wled_strings;
922
923 num_wled_strings = led->wled_cfg->num_strings;
924
925 /* verify ranges */
926 if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
927 dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
928 return -EINVAL;
929 }
930
931 if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
932 dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
933 return -EINVAL;
934 }
935
936 if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
937 dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
938 return -EINVAL;
939 }
940
941 if ((led->max_current > WLED_MAX_CURR)) {
942 dev_err(&led->spmi_dev->dev, "Invalid max current\n");
943 return -EINVAL;
944 }
945
946 if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
947 (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
948 dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
949 return -EINVAL;
950 }
951
952 /* program over voltage protection threshold */
953 rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
954 WLED_OVP_VAL_MASK,
955 (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
956 if (rc) {
957 dev_err(&led->spmi_dev->dev,
958 "WLED OVP reg write failed(%d)\n", rc);
959 return rc;
960 }
961
962 /* program current boost limit */
963 rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
964 WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
965 if (rc) {
966 dev_err(&led->spmi_dev->dev,
967 "WLED boost limit reg write failed(%d)\n", rc);
968 return rc;
969 }
970
971 /* program output feedback */
972 rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
973 WLED_OP_FDBCK_MASK,
974 (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
975 if (rc) {
976 dev_err(&led->spmi_dev->dev,
977 "WLED fdbck ctrl reg write failed(%d)\n", rc);
978 return rc;
979 }
980
981 /* program switch frequency */
982 rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
983 WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
984 if (rc) {
985 dev_err(&led->spmi_dev->dev,
986 "WLED switch freq reg write failed(%d)\n", rc);
987 return rc;
988 }
989
990 /* program current sink */
991 if (led->wled_cfg->cs_out_en) {
992 rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
993 WLED_CURR_SINK_MASK,
Amy Maloche832d90a2013-01-07 10:15:29 -0800994 (((1 << led->wled_cfg->num_strings) - 1)
995 << WLED_CURR_SINK_SHFT));
Amy Malochef3d5a062012-08-16 19:14:11 -0700996 if (rc) {
997 dev_err(&led->spmi_dev->dev,
998 "WLED curr sink reg write failed(%d)\n", rc);
999 return rc;
1000 }
1001 }
1002
1003 /* program high pole capacitance */
1004 rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
1005 WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
1006 if (rc) {
1007 dev_err(&led->spmi_dev->dev,
1008 "WLED pole cap reg write failed(%d)\n", rc);
1009 return rc;
1010 }
1011
1012 /* program modulator, current mod src and cabc */
1013 for (i = 0; i < num_wled_strings; i++) {
1014 rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
1015 WLED_NO_MASK, WLED_EN_MASK);
1016 if (rc) {
1017 dev_err(&led->spmi_dev->dev,
1018 "WLED mod enable reg write failed(%d)\n", rc);
1019 return rc;
1020 }
1021
1022 if (led->wled_cfg->dig_mod_gen_en) {
1023 rc = qpnp_led_masked_write(led,
Amy Maloched44516e2013-02-14 17:36:34 -08001024 WLED_MOD_SRC_SEL_REG(led->base, i),
Amy Malochef3d5a062012-08-16 19:14:11 -07001025 WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
1026 if (rc) {
1027 dev_err(&led->spmi_dev->dev,
1028 "WLED dig mod en reg write failed(%d)\n", rc);
1029 }
1030 }
1031
1032 rc = qpnp_led_masked_write(led,
1033 WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
1034 led->max_current);
1035 if (rc) {
1036 dev_err(&led->spmi_dev->dev,
1037 "WLED max current reg write failed(%d)\n", rc);
1038 return rc;
1039 }
1040
1041 }
1042
1043 /* dump wled registers */
Amy Malochea5ca5552012-10-23 13:34:46 -07001044 qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
Amy Malochef3d5a062012-08-16 19:14:11 -07001045
1046 return 0;
1047}
1048
Amy Malochebc97c0d22013-03-24 22:06:16 -07001049static ssize_t led_mode_store(struct device *dev,
1050 struct device_attribute *attr,
1051 const char *buf, size_t count)
1052{
1053 struct qpnp_led_data *led;
1054 unsigned long state;
1055 struct led_classdev *led_cdev = dev_get_drvdata(dev);
1056 ssize_t ret = -EINVAL;
1057
1058 ret = kstrtoul(buf, 10, &state);
1059 if (ret)
1060 return ret;
1061
1062 led = container_of(led_cdev, struct qpnp_led_data, cdev);
1063
1064 /* '1' to enable torch mode; '0' to switch to flash mode */
1065 if (state == 1)
1066 led->flash_cfg->torch_enable = true;
1067 else
1068 led->flash_cfg->torch_enable = false;
1069
1070 return count;
1071}
1072
1073static ssize_t led_strobe_type_store(struct device *dev,
1074 struct device_attribute *attr,
1075 const char *buf, size_t count)
1076{
1077 struct qpnp_led_data *led;
1078 unsigned long state;
1079 struct led_classdev *led_cdev = dev_get_drvdata(dev);
1080 ssize_t ret = -EINVAL;
1081
1082 ret = kstrtoul(buf, 10, &state);
1083 if (ret)
1084 return ret;
1085
1086 led = container_of(led_cdev, struct qpnp_led_data, cdev);
1087
1088 /* '0' for sw strobe; '1' for hw strobe */
1089 if (state == 1)
1090 led->flash_cfg->strobe_type = 1;
1091 else
1092 led->flash_cfg->strobe_type = 0;
1093
1094 return count;
1095}
1096
1097static DEVICE_ATTR(led_mode, 0664, NULL, led_mode_store);
1098static DEVICE_ATTR(strobe, 0664, NULL, led_strobe_type_store);
1099
1100static struct attribute *led_attrs[] = {
1101 &dev_attr_led_mode.attr,
1102 &dev_attr_strobe.attr,
Amy Maloche12ad6f32013-04-02 14:39:24 -07001103 NULL
Amy Malochebc97c0d22013-03-24 22:06:16 -07001104};
1105
1106static const struct attribute_group led_attr_group = {
1107 .attrs = led_attrs,
1108};
1109
Amy Maloche864a6d52012-10-03 15:58:12 -07001110static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
1111{
1112 int rc;
1113
1114 rc = qpnp_led_masked_write(led,
1115 FLASH_LED_STROBE_CTRL(led->base),
1116 FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
1117 if (rc) {
1118 dev_err(&led->spmi_dev->dev,
1119 "LED %d flash write failed(%d)\n", led->id, rc);
1120 return rc;
1121 }
1122 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
1123 FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
1124 if (rc) {
1125 dev_err(&led->spmi_dev->dev,
1126 "Enable reg write failed(%d)\n", rc);
1127 return rc;
1128 }
1129
1130 /* Set flash safety timer */
1131 rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
1132 FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
1133 if (rc) {
1134 dev_err(&led->spmi_dev->dev,
1135 "Safety timer reg write failed(%d)\n", rc);
1136 return rc;
1137 }
1138
1139 /* Set max current */
1140 rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
1141 FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
1142 if (rc) {
1143 dev_err(&led->spmi_dev->dev,
1144 "Max current reg write failed(%d)\n", rc);
1145 return rc;
1146 }
1147 /* Set clamp current */
1148 rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
1149 FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
1150 if (rc) {
1151 dev_err(&led->spmi_dev->dev,
1152 "Clamp current reg write failed(%d)\n", rc);
1153 return rc;
1154 }
1155
1156 /* Set timer control - safety or watchdog */
1157 if (led->flash_cfg->safety_timer)
1158 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
1159 FLASH_TMR_MASK, FLASH_TMR_SAFETY);
1160 else
1161 rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
1162 FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
1163 if (rc) {
1164 dev_err(&led->spmi_dev->dev,
1165 "LED timer ctrl reg write failed(%d)\n", rc);
1166 return rc;
1167 }
1168 /* Set headroom */
1169 rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
1170 FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
1171 if (rc) {
1172 dev_err(&led->spmi_dev->dev,
1173 "Headroom reg write failed(%d)\n", rc);
1174 return rc;
1175 }
1176
1177 /* Set mask enable */
1178 rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
1179 FLASH_MASK_REG_MASK, FLASH_MASK_1);
1180 if (rc) {
1181 dev_err(&led->spmi_dev->dev,
1182 "Mask enable reg write failed(%d)\n", rc);
1183 return rc;
1184 }
1185
1186 /* Set startup delay */
1187 rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
1188 FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
1189 if (rc) {
1190 dev_err(&led->spmi_dev->dev,
1191 "Startup delay reg write failed(%d)\n", rc);
1192 return rc;
1193 }
1194
1195 rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
1196 FLASH_VREG_MASK, FLASH_HW_VREG_OK);
1197 if (rc) {
1198 dev_err(&led->spmi_dev->dev,
1199 "Vreg OK reg write failed(%d)\n", rc);
1200 return rc;
1201 }
1202
Amy Malochebc97c0d22013-03-24 22:06:16 -07001203 /* Set led current and disable module */
Amy Maloche864a6d52012-10-03 15:58:12 -07001204 rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
1205 FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
1206 if (rc) {
1207 dev_err(&led->spmi_dev->dev,
1208 "Current reg write failed(%d)\n", rc);
1209 return rc;
1210 }
1211
1212 rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
Amy Maloche38b9aae2013-02-07 12:15:34 -08001213 FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
Amy Maloche864a6d52012-10-03 15:58:12 -07001214 if (rc) {
1215 dev_err(&led->spmi_dev->dev,
1216 "Enable reg write failed(%d)\n", rc);
1217 return rc;
1218 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07001219
1220 led->flash_cfg->torch_enable = false;
1221 led->flash_cfg->strobe_type = 0;
1222
Amy Maloche864a6d52012-10-03 15:58:12 -07001223 /* dump flash registers */
1224 qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
1225
1226 return 0;
1227}
1228
Amy Malocheeea7b592012-10-03 15:59:36 -07001229static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
1230{
1231 int rc, start_idx, idx_len;
1232
1233 rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
1234 RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
1235 if (rc) {
1236 dev_err(&led->spmi_dev->dev,
1237 "Failed to write led source select register\n");
1238 return rc;
1239 }
1240
1241 if (led->rgb_cfg->pwm_channel != -1) {
1242 led->rgb_cfg->pwm_dev =
1243 pwm_request(led->rgb_cfg->pwm_channel,
1244 led->cdev.name);
1245
1246 if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
1247 dev_err(&led->spmi_dev->dev,
1248 "could not acquire PWM Channel %d, " \
1249 "error %ld\n",
1250 led->rgb_cfg->pwm_channel,
1251 PTR_ERR(led->rgb_cfg->pwm_dev));
1252 led->rgb_cfg->pwm_dev = NULL;
1253 return -ENODEV;
1254 }
1255
1256 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1257 start_idx =
1258 led->rgb_cfg->duty_cycles->start_idx;
1259 idx_len =
1260 led->rgb_cfg->duty_cycles->num_duty_pcts;
1261
1262 if (idx_len >= PWM_LUT_MAX_SIZE &&
1263 start_idx) {
1264 dev_err(&led->spmi_dev->dev,
1265 "Wrong LUT size or index\n");
1266 return -EINVAL;
1267 }
1268 if ((start_idx + idx_len) >
1269 PWM_LUT_MAX_SIZE) {
1270 dev_err(&led->spmi_dev->dev,
1271 "Exceed LUT limit\n");
1272 return -EINVAL;
1273 }
1274 rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
Amy Maloche013b35b2013-03-19 12:29:11 -07001275 PM_PWM_PERIOD_MIN, /* ignored by hardware */
Amy Malocheeea7b592012-10-03 15:59:36 -07001276 led->rgb_cfg->duty_cycles->duty_pcts,
1277 led->rgb_cfg->lut_params);
1278 if (rc < 0) {
1279 dev_err(&led->spmi_dev->dev, "Failed to " \
1280 "configure pwm LUT\n");
1281 return rc;
1282 }
1283 }
1284 } else {
1285 dev_err(&led->spmi_dev->dev,
1286 "Invalid PWM channel\n");
1287 return -EINVAL;
1288 }
1289
1290 /* Initialize led for use in auto trickle charging mode */
1291 rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
1292 led->rgb_cfg->enable, led->rgb_cfg->enable);
1293
1294 return 0;
1295}
1296
Amy Malochef3d5a062012-08-16 19:14:11 -07001297static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
1298{
1299 int rc;
1300
1301 switch (led->id) {
1302 case QPNP_ID_WLED:
1303 rc = qpnp_wled_init(led);
1304 if (rc)
Amy Malochea5ca5552012-10-23 13:34:46 -07001305 dev_err(&led->spmi_dev->dev,
Amy Malochef3d5a062012-08-16 19:14:11 -07001306 "WLED initialize failed(%d)\n", rc);
1307 break;
Amy Maloche864a6d52012-10-03 15:58:12 -07001308 case QPNP_ID_FLASH1_LED0:
1309 case QPNP_ID_FLASH1_LED1:
1310 rc = qpnp_flash_init(led);
1311 if (rc)
1312 dev_err(&led->spmi_dev->dev,
1313 "FLASH initialize failed(%d)\n", rc);
1314 break;
Amy Malocheeea7b592012-10-03 15:59:36 -07001315 case QPNP_ID_RGB_RED:
1316 case QPNP_ID_RGB_GREEN:
1317 case QPNP_ID_RGB_BLUE:
1318 rc = qpnp_rgb_init(led);
1319 if (rc)
1320 dev_err(&led->spmi_dev->dev,
1321 "RGB initialize failed(%d)\n", rc);
1322 break;
Amy Malochef3813742013-04-11 19:33:47 -07001323 case QPNP_ID_LED_MPP:
1324 break;
Amy Malochef3d5a062012-08-16 19:14:11 -07001325 default:
Amy Malochea5ca5552012-10-23 13:34:46 -07001326 dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
Amy Malocheeea7b592012-10-03 15:59:36 -07001327 return -EINVAL;
Amy Malochef3d5a062012-08-16 19:14:11 -07001328 }
1329
Amy Malocheeea7b592012-10-03 15:59:36 -07001330 return 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001331}
1332
Amy Malochea5ca5552012-10-23 13:34:46 -07001333static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
1334 struct device_node *node)
1335{
1336 int rc;
Asaf Penso55ac8472013-01-21 21:17:37 +02001337 u32 val;
Amy Malochea5ca5552012-10-23 13:34:46 -07001338 const char *temp_string;
1339
1340 led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
1341 rc = of_property_read_string(node, "linux,default-trigger",
1342 &temp_string);
1343 if (!rc)
1344 led->cdev.default_trigger = temp_string;
1345 else if (rc != -EINVAL)
1346 return rc;
1347
1348 led->default_on = false;
1349 rc = of_property_read_string(node, "qcom,default-state",
1350 &temp_string);
1351 if (!rc) {
1352 if (strncmp(temp_string, "on", sizeof("on")) == 0)
1353 led->default_on = true;
1354 } else if (rc != -EINVAL)
1355 return rc;
1356
Asaf Penso55ac8472013-01-21 21:17:37 +02001357 led->turn_off_delay_ms = 0;
1358 rc = of_property_read_u32(node, "qcom,turn-off-delay-ms", &val);
1359 if (!rc)
1360 led->turn_off_delay_ms = val;
1361 else if (rc != -EINVAL)
1362 return rc;
1363
Amy Malochea5ca5552012-10-23 13:34:46 -07001364 return 0;
1365}
1366
Amy Malochef3d5a062012-08-16 19:14:11 -07001367/*
1368 * Handlers for alternative sources of platform_data
1369 */
1370static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
1371 struct device_node *node)
1372{
1373 u32 val;
1374 int rc;
Amy Malochef3d5a062012-08-16 19:14:11 -07001375
1376 led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
1377 sizeof(struct wled_config_data), GFP_KERNEL);
1378 if (!led->wled_cfg) {
1379 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1380 return -ENOMEM;
1381 }
1382
Amy Malochef3d5a062012-08-16 19:14:11 -07001383 led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
1384 rc = of_property_read_u32(node, "qcom,num-strings", &val);
1385 if (!rc)
1386 led->wled_cfg->num_strings = (u8) val;
1387 else if (rc != -EINVAL)
1388 return rc;
1389
1390 led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
1391 rc = of_property_read_u32(node, "qcom,ovp-val", &val);
1392 if (!rc)
1393 led->wled_cfg->ovp_val = (u8) val;
1394 else if (rc != -EINVAL)
1395 return rc;
1396
1397 led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
1398 rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
1399 if (!rc)
1400 led->wled_cfg->boost_curr_lim = (u8) val;
1401 else if (rc != -EINVAL)
1402 return rc;
1403
1404 led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
1405 rc = of_property_read_u32(node, "qcom,cp-sel", &val);
1406 if (!rc)
1407 led->wled_cfg->cp_select = (u8) val;
1408 else if (rc != -EINVAL)
1409 return rc;
1410
1411 led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
1412 rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
1413 if (!rc)
1414 led->wled_cfg->ctrl_delay_us = (u8) val;
1415 else if (rc != -EINVAL)
1416 return rc;
1417
Amy Malochebd687672013-03-18 11:23:45 -07001418 led->wled_cfg->op_fdbck = WLED_OP_FDBCK_DEFAULT;
1419 rc = of_property_read_u32(node, "qcom,op-fdbck", &val);
1420 if (!rc)
1421 led->wled_cfg->op_fdbck = (u8) val;
1422 else if (rc != -EINVAL)
1423 return rc;
1424
Amy Malochef3d5a062012-08-16 19:14:11 -07001425 led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
1426 rc = of_property_read_u32(node, "qcom,switch-freq", &val);
1427 if (!rc)
1428 led->wled_cfg->switch_freq = (u8) val;
1429 else if (rc != -EINVAL)
1430 return rc;
1431
1432 led->wled_cfg->dig_mod_gen_en =
1433 of_property_read_bool(node, "qcom,dig-mod-gen-en");
1434
1435 led->wled_cfg->cs_out_en =
1436 of_property_read_bool(node, "qcom,cs-out-en");
1437
Amy Malochef3d5a062012-08-16 19:14:11 -07001438 return 0;
1439}
1440
Amy Maloche864a6d52012-10-03 15:58:12 -07001441static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
1442 struct device_node *node)
1443{
1444 int rc;
1445 u32 val;
1446
1447 led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
1448 sizeof(struct flash_config_data), GFP_KERNEL);
1449 if (!led->flash_cfg) {
1450 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1451 return -ENOMEM;
1452 }
1453
1454 if (led->id == QPNP_ID_FLASH1_LED0) {
1455 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1456 led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
1457 led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
1458 led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
1459 } else if (led->id == QPNP_ID_FLASH1_LED1) {
1460 led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
1461 led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
1462 led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
1463 led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
1464 } else {
1465 dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
1466 return -EINVAL;
1467 }
1468
1469 rc = of_property_read_u32(node, "qcom,current", &val);
1470 if (!rc)
1471 led->flash_cfg->current_prgm = (val *
1472 FLASH_MAX_LEVEL / led->max_current);
1473 else
1474 return -EINVAL;
1475
1476 rc = of_property_read_u32(node, "qcom,headroom", &val);
1477 if (!rc)
1478 led->flash_cfg->headroom = (u8) val;
1479 else if (rc == -EINVAL)
1480 led->flash_cfg->headroom = HEADROOM_300mV;
1481 else
1482 return rc;
1483
1484 rc = of_property_read_u32(node, "qcom,duration", &val);
1485 if (!rc)
1486 led->flash_cfg->duration = (((u8) val) - 10) / 10;
1487 else if (rc == -EINVAL)
1488 led->flash_cfg->duration = FLASH_DURATION_200ms;
1489 else
1490 return rc;
1491
1492 rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
1493 if (!rc)
1494 led->flash_cfg->clamp_curr = (val *
1495 FLASH_MAX_LEVEL / led->max_current);
1496 else if (rc == -EINVAL)
1497 led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
1498 else
1499 return rc;
1500
1501 rc = of_property_read_u32(node, "qcom,startup-dly", &val);
1502 if (!rc)
1503 led->flash_cfg->startup_dly = (u8) val;
1504 else if (rc == -EINVAL)
1505 led->flash_cfg->startup_dly = DELAY_32us;
1506 else
1507 return rc;
1508
1509 led->flash_cfg->safety_timer =
1510 of_property_read_bool(node, "qcom,safety-timer");
1511
1512 return 0;
1513}
1514
Amy Malocheeea7b592012-10-03 15:59:36 -07001515static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
1516 struct device_node *node)
1517{
1518 struct property *prop;
1519 int rc, i;
1520 u32 val;
1521 u8 *temp_cfg;
1522
1523 led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
1524 sizeof(struct rgb_config_data), GFP_KERNEL);
1525 if (!led->rgb_cfg) {
1526 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1527 return -ENOMEM;
1528 }
1529
1530 if (led->id == QPNP_ID_RGB_RED)
1531 led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
1532 else if (led->id == QPNP_ID_RGB_GREEN)
1533 led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
1534 else if (led->id == QPNP_ID_RGB_BLUE)
1535 led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
1536 else
1537 return -EINVAL;
1538
1539 rc = of_property_read_u32(node, "qcom,mode", &val);
1540 if (!rc)
1541 led->rgb_cfg->mode = (u8) val;
1542 else
1543 return rc;
1544
1545 rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
1546 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001547 led->rgb_cfg->pwm_channel = val;
Amy Malocheeea7b592012-10-03 15:59:36 -07001548 else
1549 return rc;
1550
Amy Maloche013b35b2013-03-19 12:29:11 -07001551 if (led->rgb_cfg->mode == RGB_MODE_PWM) {
1552 rc = of_property_read_u32(node, "qcom,pwm-us", &val);
1553 if (!rc)
1554 led->rgb_cfg->pwm_period_us = val;
1555 else
1556 return rc;
1557 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001558
1559 if (led->rgb_cfg->mode == RGB_MODE_LPG) {
1560 led->rgb_cfg->duty_cycles =
1561 devm_kzalloc(&led->spmi_dev->dev,
1562 sizeof(struct pwm_duty_cycles), GFP_KERNEL);
1563 if (!led->rgb_cfg->duty_cycles) {
1564 dev_err(&led->spmi_dev->dev,
1565 "Unable to allocate memory\n");
1566 return -ENOMEM;
1567 }
1568
Amy Malocheeea7b592012-10-03 15:59:36 -07001569 prop = of_find_property(node, "qcom,duty-pcts",
1570 &led->rgb_cfg->duty_cycles->num_duty_pcts);
1571 if (!prop) {
1572 dev_err(&led->spmi_dev->dev, "Looking up property " \
1573 "node qcom,duty-pcts failed\n");
1574 return -ENODEV;
1575 } else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
1576 dev_err(&led->spmi_dev->dev, "Invalid length of " \
1577 "duty pcts\n");
1578 return -EINVAL;
1579 }
1580
1581 led->rgb_cfg->duty_cycles->duty_pcts =
1582 devm_kzalloc(&led->spmi_dev->dev,
1583 sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
1584 GFP_KERNEL);
1585 if (!led->rgb_cfg->duty_cycles->duty_pcts) {
1586 dev_err(&led->spmi_dev->dev,
1587 "Unable to allocate memory\n");
1588 return -ENOMEM;
1589 }
1590
1591 temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1592 led->rgb_cfg->duty_cycles->num_duty_pcts *
1593 sizeof(u8), GFP_KERNEL);
1594 if (!temp_cfg) {
1595 dev_err(&led->spmi_dev->dev, "Failed to allocate " \
1596 "memory for duty pcts\n");
1597 return -ENOMEM;
1598 }
1599
1600 memcpy(temp_cfg, prop->value,
1601 led->rgb_cfg->duty_cycles->num_duty_pcts);
1602
1603 for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
1604 led->rgb_cfg->duty_cycles->duty_pcts[i] =
1605 (int) temp_cfg[i];
1606
1607 rc = of_property_read_u32(node, "qcom,start-idx", &val);
1608 if (!rc) {
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001609 led->rgb_cfg->lut_params.start_idx = val;
1610 led->rgb_cfg->duty_cycles->start_idx = val;
Amy Malocheeea7b592012-10-03 15:59:36 -07001611 } else
1612 return rc;
1613
Amy Maloche013b35b2013-03-19 12:29:11 -07001614 led->rgb_cfg->lut_params.lut_pause_hi = 0;
1615 rc = of_property_read_u32(node, "qcom,pause-hi", &val);
1616 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001617 led->rgb_cfg->lut_params.lut_pause_hi = val;
Amy Maloche013b35b2013-03-19 12:29:11 -07001618 else if (rc != -EINVAL)
1619 return rc;
1620
1621 led->rgb_cfg->lut_params.lut_pause_lo = 0;
1622 rc = of_property_read_u32(node, "qcom,pause-lo", &val);
1623 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001624 led->rgb_cfg->lut_params.lut_pause_lo = val;
Amy Maloche013b35b2013-03-19 12:29:11 -07001625 else if (rc != -EINVAL)
1626 return rc;
1627
1628 led->rgb_cfg->lut_params.ramp_step_ms =
1629 QPNP_LUT_RAMP_STEP_DEFAULT;
1630 rc = of_property_read_u32(node, "qcom,ramp-step-ms", &val);
1631 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001632 led->rgb_cfg->lut_params.ramp_step_ms = val;
Amy Maloche013b35b2013-03-19 12:29:11 -07001633 else if (rc != -EINVAL)
1634 return rc;
1635
1636 led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
1637 rc = of_property_read_u32(node, "qcom,lut-flags", &val);
1638 if (!rc)
Amy Malochef6d3f7c2013-04-11 16:34:47 -07001639 led->rgb_cfg->lut_params.flags = val;
Amy Maloche013b35b2013-03-19 12:29:11 -07001640 else if (rc != -EINVAL)
1641 return rc;
1642
Amy Malocheeea7b592012-10-03 15:59:36 -07001643 led->rgb_cfg->lut_params.idx_len =
1644 led->rgb_cfg->duty_cycles->num_duty_pcts;
Amy Malocheeea7b592012-10-03 15:59:36 -07001645 }
1646
1647 return 0;
1648}
1649
Amy Malochef3813742013-04-11 19:33:47 -07001650static int __devinit qpnp_get_config_mpp(struct qpnp_led_data *led,
1651 struct device_node *node)
1652{
1653 int rc;
1654 u32 val;
1655
1656 led->mpp_cfg = devm_kzalloc(&led->spmi_dev->dev,
1657 sizeof(struct mpp_config_data), GFP_KERNEL);
1658 if (!led->mpp_cfg) {
1659 dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
1660 return -ENOMEM;
1661 }
1662
1663 led->mpp_cfg->current_setting = LED_MPP_CURRENT_DEFAULT;
1664 rc = of_property_read_u32(node, "qcom,current-setting", &val);
1665 if (!rc)
1666 led->mpp_cfg->current_setting = (u8) val;
1667 else if (rc != -EINVAL)
1668 return rc;
1669
1670 led->mpp_cfg->source_sel = LED_MPP_SOURCE_SEL_DEFAULT;
1671 rc = of_property_read_u32(node, "qcom,source-sel", &val);
1672 if (!rc)
1673 led->mpp_cfg->source_sel = (u8) val;
1674 else if (rc != -EINVAL)
1675 return rc;
1676
1677 led->mpp_cfg->mode_ctrl = LED_MPP_MODE_SINK;
1678 rc = of_property_read_u32(node, "qcom,mode-ctrl", &val);
1679 if (!rc)
1680 led->mpp_cfg->mode_ctrl = (u8) val;
1681 else if (rc != -EINVAL)
1682 return rc;
1683
1684 return 0;
1685}
1686
Amy Malochef3d5a062012-08-16 19:14:11 -07001687static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
1688{
Amy Malochef9490c62012-11-27 19:26:04 -08001689 struct qpnp_led_data *led, *led_array;
Amy Malochef3d5a062012-08-16 19:14:11 -07001690 struct resource *led_resource;
Amy Malochea5ca5552012-10-23 13:34:46 -07001691 struct device_node *node, *temp;
Amy Malochef9490c62012-11-27 19:26:04 -08001692 int rc, i, num_leds = 0, parsed_leds = 0;
Amy Malochef3d5a062012-08-16 19:14:11 -07001693 const char *led_label;
1694
Amy Malochea5ca5552012-10-23 13:34:46 -07001695 node = spmi->dev.of_node;
1696 if (node == NULL)
1697 return -ENODEV;
1698
1699 temp = NULL;
1700 while ((temp = of_get_next_child(node, temp)))
1701 num_leds++;
1702
Amy Malochef9490c62012-11-27 19:26:04 -08001703 if (!num_leds)
1704 return -ECHILD;
1705
1706 led_array = devm_kzalloc(&spmi->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001707 (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
Amy Malochef9490c62012-11-27 19:26:04 -08001708 if (!led_array) {
Amy Malochef3d5a062012-08-16 19:14:11 -07001709 dev_err(&spmi->dev, "Unable to allocate memory\n");
1710 return -ENOMEM;
1711 }
1712
Amy Malochea5ca5552012-10-23 13:34:46 -07001713 for_each_child_of_node(node, temp) {
Amy Malochef9490c62012-11-27 19:26:04 -08001714 led = &led_array[parsed_leds];
1715 led->num_leds = num_leds;
Amy Malochea5ca5552012-10-23 13:34:46 -07001716 led->spmi_dev = spmi;
Amy Malochef3d5a062012-08-16 19:14:11 -07001717
Amy Malochea5ca5552012-10-23 13:34:46 -07001718 led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
1719 if (!led_resource) {
1720 dev_err(&spmi->dev, "Unable to get LED base address\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001721 rc = -ENXIO;
1722 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001723 }
1724 led->base = led_resource->start;
Amy Malochef3d5a062012-08-16 19:14:11 -07001725
Amy Malochea5ca5552012-10-23 13:34:46 -07001726 rc = of_property_read_string(temp, "label", &led_label);
Amy Malochef3d5a062012-08-16 19:14:11 -07001727 if (rc < 0) {
1728 dev_err(&led->spmi_dev->dev,
Amy Malochea5ca5552012-10-23 13:34:46 -07001729 "Failure reading label, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001730 goto fail_id_check;
Amy Malochef3d5a062012-08-16 19:14:11 -07001731 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001732
1733 rc = of_property_read_string(temp, "linux,name",
1734 &led->cdev.name);
1735 if (rc < 0) {
1736 dev_err(&led->spmi_dev->dev,
1737 "Failure reading led name, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001738 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001739 }
1740
1741 rc = of_property_read_u32(temp, "qcom,max-current",
1742 &led->max_current);
1743 if (rc < 0) {
1744 dev_err(&led->spmi_dev->dev,
1745 "Failure reading max_current, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001746 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001747 }
1748
1749 rc = of_property_read_u32(temp, "qcom,id", &led->id);
1750 if (rc < 0) {
1751 dev_err(&led->spmi_dev->dev,
1752 "Failure reading led id, rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001753 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001754 }
1755
1756 rc = qpnp_get_common_configs(led, temp);
1757 if (rc) {
1758 dev_err(&led->spmi_dev->dev,
1759 "Failure reading common led configuration," \
1760 " rc = %d\n", rc);
Amy Malochef9490c62012-11-27 19:26:04 -08001761 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001762 }
1763
1764 led->cdev.brightness_set = qpnp_led_set;
1765 led->cdev.brightness_get = qpnp_led_get;
1766
1767 if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
1768 rc = qpnp_get_config_wled(led, temp);
1769 if (rc < 0) {
1770 dev_err(&led->spmi_dev->dev,
1771 "Unable to read wled config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001772 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001773 }
Amy Maloche864a6d52012-10-03 15:58:12 -07001774 } else if (strncmp(led_label, "flash", sizeof("flash"))
1775 == 0) {
1776 rc = qpnp_get_config_flash(led, temp);
1777 if (rc < 0) {
1778 dev_err(&led->spmi_dev->dev,
1779 "Unable to read flash config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001780 goto fail_id_check;
Amy Maloche864a6d52012-10-03 15:58:12 -07001781 }
Amy Malocheeea7b592012-10-03 15:59:36 -07001782 } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
1783 rc = qpnp_get_config_rgb(led, temp);
1784 if (rc < 0) {
1785 dev_err(&led->spmi_dev->dev,
1786 "Unable to read rgb config data\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001787 goto fail_id_check;
Amy Malocheeea7b592012-10-03 15:59:36 -07001788 }
Amy Malochef3813742013-04-11 19:33:47 -07001789 } else if (strncmp(led_label, "mpp", sizeof("mpp")) == 0) {
1790 rc = qpnp_get_config_mpp(led, temp);
1791 if (rc < 0) {
1792 dev_err(&led->spmi_dev->dev,
1793 "Unable to read mpp config data\n");
1794 goto fail_id_check;
1795 }
Amy Malochea5ca5552012-10-23 13:34:46 -07001796 } else {
1797 dev_err(&led->spmi_dev->dev, "No LED matching label\n");
Amy Malochef9490c62012-11-27 19:26:04 -08001798 rc = -EINVAL;
1799 goto fail_id_check;
Amy Malochea5ca5552012-10-23 13:34:46 -07001800 }
1801
1802 spin_lock_init(&led->lock);
1803
1804 rc = qpnp_led_initialize(led);
1805 if (rc < 0)
1806 goto fail_id_check;
1807
1808 rc = qpnp_led_set_max_brightness(led);
1809 if (rc < 0)
1810 goto fail_id_check;
1811
1812 rc = led_classdev_register(&spmi->dev, &led->cdev);
1813 if (rc) {
1814 dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
1815 led->id, rc);
1816 goto fail_id_check;
1817 }
Amy Malochebc97c0d22013-03-24 22:06:16 -07001818
1819 if (led->id == QPNP_ID_FLASH1_LED0 ||
1820 led->id == QPNP_ID_FLASH1_LED1) {
1821 rc = sysfs_create_group(&led->cdev.dev->kobj,
1822 &led_attr_group);
1823 if (rc)
1824 goto fail_id_check;
1825
1826 }
1827
Amy Malochea5ca5552012-10-23 13:34:46 -07001828 /* configure default state */
Asaf Penso55ac8472013-01-21 21:17:37 +02001829 if (led->default_on) {
Amy Malochea5ca5552012-10-23 13:34:46 -07001830 led->cdev.brightness = led->cdev.max_brightness;
Asaf Penso55ac8472013-01-21 21:17:37 +02001831 if (led->turn_off_delay_ms > 0)
1832 qpnp_led_turn_off(led);
1833 } else
Amy Malochea5ca5552012-10-23 13:34:46 -07001834 led->cdev.brightness = LED_OFF;
1835
1836 qpnp_led_set(&led->cdev, led->cdev.brightness);
Amy Malochef9490c62012-11-27 19:26:04 -08001837
1838 parsed_leds++;
Amy Malochef3d5a062012-08-16 19:14:11 -07001839 }
Amy Malochef9490c62012-11-27 19:26:04 -08001840 dev_set_drvdata(&spmi->dev, led_array);
Amy Malochef3d5a062012-08-16 19:14:11 -07001841 return 0;
1842
1843fail_id_check:
Amy Malochef9490c62012-11-27 19:26:04 -08001844 for (i = 0; i < parsed_leds; i++)
1845 led_classdev_unregister(&led_array[i].cdev);
Amy Malochef3d5a062012-08-16 19:14:11 -07001846 return rc;
1847}
1848
1849static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
1850{
Amy Malochef9490c62012-11-27 19:26:04 -08001851 struct qpnp_led_data *led_array = dev_get_drvdata(&spmi->dev);
1852 int i, parsed_leds = led_array->num_leds;
Amy Malochef3d5a062012-08-16 19:14:11 -07001853
Amy Malochebc97c0d22013-03-24 22:06:16 -07001854 for (i = 0; i < parsed_leds; i++) {
Amy Malochef9490c62012-11-27 19:26:04 -08001855 led_classdev_unregister(&led_array[i].cdev);
Amy Malochebc97c0d22013-03-24 22:06:16 -07001856 switch (led_array[i].id) {
1857 case QPNP_ID_WLED:
1858 break;
1859 case QPNP_ID_FLASH1_LED0:
1860 case QPNP_ID_FLASH1_LED1:
1861 sysfs_remove_group(&led_array[i].cdev.dev->kobj,
1862 &led_attr_group);
1863 break;
1864 case QPNP_ID_RGB_RED:
1865 case QPNP_ID_RGB_GREEN:
1866 case QPNP_ID_RGB_BLUE:
1867 default:
1868 dev_err(&led_array[i].spmi_dev->dev,
1869 "Invalid LED(%d)\n",
1870 led_array[i].id);
1871 return -EINVAL;
1872 }
1873 }
Amy Malochef3d5a062012-08-16 19:14:11 -07001874
1875 return 0;
1876}
1877static struct of_device_id spmi_match_table[] = {
1878 { .compatible = "qcom,leds-qpnp",
1879 }
1880};
1881
1882static struct spmi_driver qpnp_leds_driver = {
1883 .driver = {
1884 .name = "qcom,leds-qpnp",
1885 .of_match_table = spmi_match_table,
1886 },
1887 .probe = qpnp_leds_probe,
1888 .remove = __devexit_p(qpnp_leds_remove),
1889};
1890
1891static int __init qpnp_led_init(void)
1892{
1893 return spmi_driver_register(&qpnp_leds_driver);
1894}
1895module_init(qpnp_led_init);
1896
1897static void __exit qpnp_led_exit(void)
1898{
1899 spmi_driver_unregister(&qpnp_leds_driver);
1900}
1901module_exit(qpnp_led_exit);
1902
1903MODULE_DESCRIPTION("QPNP LEDs driver");
1904MODULE_LICENSE("GPL v2");
1905MODULE_ALIAS("leds:leds-qpnp");
Amy Maloche864a6d52012-10-03 15:58:12 -07001906