blob: 60942f5603466b8bdd56618032ed32c3aeaf71d8 [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jay Chokshi219fcfc2012-07-27 17:39:15 -07002
Jay Chokshi12cc1dd2012-04-30 17:07:35 -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 * Qualcomm QPNP Pulse Width Modulation (PWM) driver
15 *
16 * The HW module is also called LPG (Light Pattern Generator).
17 */
18
19#define pr_fmt(fmt) "%s: " fmt, __func__
20
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/err.h>
24#include <linux/spmi.h>
25#include <linux/of.h>
26#include <linux/of_device.h>
27#include <linux/radix-tree.h>
28#include <linux/qpnp/pwm.h>
29
30#define QPNP_LPG_DRIVER_NAME "qcom,qpnp-pwm"
Jay Chokshi219fcfc2012-07-27 17:39:15 -070031#define QPNP_LPG_CHANNEL_BASE "qpnp-lpg-channel-base"
32#define QPNP_LPG_LUT_BASE "qpnp-lpg-lut-base"
Jay Chokshi12cc1dd2012-04-30 17:07:35 -070033
34/* LPG Control for LPG_PATTERN_CONFIG */
35#define QPNP_RAMP_DIRECTION_SHIFT 4
36#define QPNP_RAMP_DIRECTION_MASK 0x10
37#define QPNP_PATTERN_REPEAT_SHIFT 3
38#define QPNP_PATTERN_REPEAT_MASK 0x08
39#define QPNP_RAMP_TOGGLE_SHIFT 2
40#define QPNP_RAMP_TOGGLE_MASK 0x04
41#define QPNP_EN_PAUSE_HI_SHIFT 1
42#define QPNP_EN_PAUSE_HI_MASK 0x02
43#define QPNP_EN_PAUSE_LO_MASK 0x01
44
45/* LPG Control for LPG_PWM_SIZE_CLK */
46#define QPNP_PWM_SIZE_SHIFT 4
47#define QPNP_PWM_SIZE_MASK 0x30
48#define QPNP_PWM_FREQ_CLK_SELECT_SHIFT 0
49#define QPNP_PWM_FREQ_CLK_SELECT_MASK 0x03
50#define QPNP_PWM_SIZE_9_BIT 0x03
51
52#define QPNP_SET_PWM_CLK(val, clk, pwm_size) \
53do { \
54 val = (clk + 1) & QPNP_PWM_FREQ_CLK_SELECT_MASK; \
55 val |= ((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT : 0) << \
56 QPNP_PWM_SIZE_SHIFT) & QPNP_PWM_SIZE_MASK; \
57} while (0)
58
59#define QPNP_GET_PWM_SIZE(reg) ((reg & QPNP_PWM_SIZE_MASK) \
60 >> QPNP_PWM_SIZE_SHIFT)
61
62/* LPG Control for LPG_PWM_FREQ_PREDIV_CLK */
63#define QPNP_PWM_FREQ_PRE_DIVIDE_SHIFT 5
64#define QPNP_PWM_FREQ_PRE_DIVIDE_MASK 0x60
65#define QPNP_PWM_FREQ_EXP_MASK 0x07
66
67#define QPNP_SET_PWM_FREQ_PREDIV(val, pre_div, pre_div_exp) \
68do { \
69 val = (pre_div << QPNP_PWM_FREQ_PRE_DIVIDE_SHIFT) & \
70 QPNP_PWM_FREQ_PRE_DIVIDE_MASK; \
71 val |= pre_div_exp & QPNP_PWM_FREQ_EXP_MASK; \
72} while (0)
73
74/* LPG Control for LPG_PWM_TYPE_CONFIG */
75#define QPNP_EN_GLITCH_REMOVAL_SHIFT 5
76#define QPNP_EN_GLITCH_REMOVAL_MASK 0x20
77#define QPNP_EN_FULL_SCALE_SHIFT 3
78#define QPNP_EN_FULL_SCALE_MASK 0x08
79#define QPNP_EN_PHASE_STAGGER_SHIFT 2
80#define QPNP_EN_PHASE_STAGGER_MASK 0x04
81#define QPNP_PHASE_STAGGER_MASK 0x03
82
83/* LPG Control for PWM_VALUE_LSB */
84#define QPNP_PWM_VALUE_LSB_MASK 0xFF
85
86/* LPG Control for PWM_VALUE_MSB */
87#define QPNP_PWM_VALUE_MSB_SHIFT 8
88#define QPNP_PWM_VALUE_MSB_MASK 0x01
89
90/* LPG Control for ENABLE_CONTROL */
91#define QPNP_EN_PWM_HIGH_SHIFT 7
92#define QPNP_EN_PWM_HIGH_MASK 0x80
93#define QPNP_EN_PWM_LO_SHIFT 6
94#define QPNP_EN_PWM_LO_MASK 0x40
95#define QPNP_EN_PWM_OUTPUT_SHIFT 5
96#define QPNP_EN_PWM_OUTPUT_MASK 0x20
97#define QPNP_PWM_SRC_SELECT_SHIFT 2
98#define QPNP_PWM_SRC_SELECT_MASK 0x04
99#define QPNP_PWM_EN_RAMP_GEN_SHIFT 1
100#define QPNP_PWM_EN_RAMP_GEN_MASK 0x02
101
102#define QPNP_ENABLE_PWM(value) \
103 (value |= (1 << QPNP_EN_PWM_OUTPUT_SHIFT) & QPNP_EN_PWM_OUTPUT_MASK)
104
105#define QPNP_DISABLE_PWM(value) (value &= ~QPNP_EN_PWM_OUTPUT_MASK)
106
107/* LPG Control for RAMP_CONTROL */
108#define QPNP_RAMP_START_MASK 0x01
109
110#define QPNP_ENABLE_LUT(value) (value |= QPNP_RAMP_START_MASK)
111#define QPNP_DISABLE_LUT(value) (value &= ~QPNP_RAMP_START_MASK)
112
113/* LPG Control for RAMP_STEP_DURATION_LSB */
114#define QPNP_RAMP_STEP_DURATION_LSB_MASK 0xFF
115
116/* LPG Control for RAMP_STEP_DURATION_MSB */
117#define QPNP_RAMP_STEP_DURATION_MSB_SHIFT 8
118#define QPNP_RAMP_STEP_DURATION_MSB_MASK 0x01
119
120#define QPNP_PWM_1KHZ 1024
121#define QPNP_GET_RAMP_STEP_DURATION(ramp_time_ms) \
122 ((ramp_time_ms * QPNP_PWM_1KHZ) / 1000)
123
124/* LPG Control for PAUSE_HI_MULTIPLIER_LSB */
125#define QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK 0xFF
126
127/* LPG Control for PAUSE_HI_MULTIPLIER_MSB */
128#define QPNP_PAUSE_HI_MULTIPLIER_MSB_SHIFT 8
129#define QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK 0x1F
130
131/* LPG Control for PAUSE_LO_MULTIPLIER_LSB */
132#define QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK 0xFF
133
134/* LPG Control for PAUSE_LO_MULTIPLIER_MSB */
135#define QPNP_PAUSE_LO_MULTIPLIER_MSB_SHIFT 8
136#define QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK 0x1F
137
138/* LPG Control for HI_INDEX */
139#define QPNP_HI_INDEX_MASK 0x3F
140
141/* LPG Control for LO_INDEX */
142#define QPNP_LO_INDEX_MASK 0x3F
143
144#define NUM_CLOCKS 3
145#define QPNP_PWM_M_MAX 7
146#define NSEC_1024HZ (NSEC_PER_SEC / 1024)
147#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
148#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
149
150#define NUM_LPG_PRE_DIVIDE 4
151
152#define PRE_DIVIDE_1 1
153#define PRE_DIVIDE_3 3
154#define PRE_DIVIDE_5 5
155#define PRE_DIVIDE_6 6
156
157#define SPMI_LPG_REG_ADDR_BASE 0x40
158#define SPMI_LPG_REG_ADDR(b, n) (b + SPMI_LPG_REG_ADDR_BASE + (n))
159#define SPMI_MAX_BUF_LEN 8
160
161/* SPMI LPG registers */
162enum qpnp_lpg_registers_list {
163 QPNP_LPG_PATTERN_CONFIG,
164 QPNP_LPG_PWM_SIZE_CLK,
165 QPNP_LPG_PWM_FREQ_PREDIV_CLK,
166 QPNP_LPG_PWM_TYPE_CONFIG,
167 QPNP_PWM_VALUE_LSB,
168 QPNP_PWM_VALUE_MSB,
169 QPNP_ENABLE_CONTROL,
170 QPNP_RAMP_CONTROL,
171 QPNP_RAMP_STEP_DURATION_LSB = QPNP_RAMP_CONTROL + 9,
172 QPNP_RAMP_STEP_DURATION_MSB,
173 QPNP_PAUSE_HI_MULTIPLIER_LSB,
174 QPNP_PAUSE_HI_MULTIPLIER_MSB,
175 QPNP_PAUSE_LO_MULTIPLIER_LSB,
176 QPNP_PAUSE_LO_MULTIPLIER_MSB,
177 QPNP_HI_INDEX,
178 QPNP_LO_INDEX,
179 QPNP_TOTAL_LPG_SPMI_REGISTERS
180};
181
182/*
183 * Formula from HSID,
184 * pause_time (hi/lo) = (pause_cnt- 1)*(ramp_ms)
185 * OR,
186 * pause_cnt = (pause_time / ramp_ms) + 1
187 */
188#define QPNP_SET_PAUSE_CNT(to_pause_cnt, from_pause, ramp_ms) \
189 (to_pause_cnt = (from_pause / (ramp_ms ? ramp_ms : 1)) + 1)
190
191
192static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
193 { PRE_DIVIDE_1 * NSEC_1024HZ,
194 PRE_DIVIDE_1 * NSEC_32768HZ,
195 PRE_DIVIDE_1 * NSEC_19P2MHZ,
196 },
197 { PRE_DIVIDE_3 * NSEC_1024HZ,
198 PRE_DIVIDE_3 * NSEC_32768HZ,
199 PRE_DIVIDE_3 * NSEC_19P2MHZ,
200 },
201 { PRE_DIVIDE_5 * NSEC_1024HZ,
202 PRE_DIVIDE_5 * NSEC_32768HZ,
203 PRE_DIVIDE_5 * NSEC_19P2MHZ,
204 },
205 { PRE_DIVIDE_6 * NSEC_1024HZ,
206 PRE_DIVIDE_6 * NSEC_32768HZ,
207 PRE_DIVIDE_6 * NSEC_19P2MHZ,
208 },
209};
210
211static RADIX_TREE(lpg_dev_tree, GFP_KERNEL);
212
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700213struct qpnp_lut_config {
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700214 u8 *duty_pct_list;
215 int list_len;
216 int lo_index;
217 int hi_index;
218 int lut_pause_hi_cnt;
219 int lut_pause_lo_cnt;
220 int ramp_step_ms;
221 bool ramp_direction;
222 bool pattern_repeat;
223 bool ramp_toggle;
224 bool enable_pause_hi;
225 bool enable_pause_lo;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700226};
227
228struct qpnp_lpg_config {
229 struct qpnp_lut_config lut_config;
230 u16 base_addr;
231 u16 lut_base_addr;
232 u16 lut_size;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700233};
234
235struct qpnp_pwm_config {
236 int channel_id;
237 bool in_use;
238 const char *lable;
239 int pwm_value;
240 int pwm_period;
241 int pwm_duty;
242 struct pwm_period_config period;
243};
244
245/* Public facing structure */
246struct pwm_device {
247 struct qpnp_lpg_chip *chip;
248 struct qpnp_pwm_config pwm_config;
249};
250
251struct qpnp_lpg_chip {
252 struct spmi_device *spmi_dev;
253 struct pwm_device pwm_dev;
254 struct mutex lpg_mutex;
255 struct qpnp_lpg_config lpg_config;
256 u8 qpnp_lpg_registers[QPNP_TOTAL_LPG_SPMI_REGISTERS];
257};
258
259/* Internal functions */
260static inline void qpnp_set_pattern_config(u8 *val,
261 struct qpnp_lut_config *lut_config)
262{
263 *val = lut_config->enable_pause_lo & QPNP_EN_PAUSE_LO_MASK;
264 *val |= (lut_config->enable_pause_hi << QPNP_EN_PAUSE_HI_SHIFT) &
265 QPNP_EN_PAUSE_HI_MASK;
266 *val |= (lut_config->ramp_toggle << QPNP_RAMP_TOGGLE_SHIFT) &
267 QPNP_RAMP_TOGGLE_MASK;
268 *val |= (lut_config->pattern_repeat << QPNP_PATTERN_REPEAT_SHIFT) &
269 QPNP_PATTERN_REPEAT_MASK;
270 *val |= (lut_config->ramp_direction << QPNP_RAMP_DIRECTION_SHIFT) &
271 QPNP_RAMP_DIRECTION_MASK;
272}
273
274static inline void qpnp_set_pwm_type_config(u8 *val, bool glitch,
275 bool full_scale, bool en_phase, bool phase)
276{
277 *val = phase;
278 *val |= (en_phase << QPNP_EN_PHASE_STAGGER_SHIFT) &
279 QPNP_EN_PHASE_STAGGER_MASK;
280 *val |= (full_scale << QPNP_EN_FULL_SCALE_SHIFT) &
281 QPNP_EN_FULL_SCALE_MASK;
282 *val |= (glitch << QPNP_EN_GLITCH_REMOVAL_SHIFT) &
283 QPNP_EN_GLITCH_REMOVAL_MASK;
284}
285
286static inline void qpnp_set_control(u8 *val, bool pwm_hi, bool pwm_lo,
287 bool pwm_out, bool pwm_src, bool ramp_gen)
288{
289 *val = (ramp_gen << QPNP_PWM_EN_RAMP_GEN_SHIFT) &
290 QPNP_PWM_EN_RAMP_GEN_MASK;
291 *val |= (pwm_src << QPNP_PWM_SRC_SELECT_SHIFT) &
292 QPNP_PWM_SRC_SELECT_MASK;
293 *val |= (pwm_out << QPNP_EN_PWM_OUTPUT_SHIFT) &
294 QPNP_EN_PWM_OUTPUT_MASK;
295 *val |= (pwm_lo << QPNP_EN_PWM_LO_SHIFT) & QPNP_EN_PWM_LO_MASK;
296 *val |= (pwm_hi << QPNP_EN_PWM_HIGH_SHIFT) & QPNP_EN_PWM_HIGH_MASK;
297}
298
299#define QPNP_ENABLE_LUT_CONTROL(p_val) qpnp_set_control(p_val, 1, 1, 1, 0, 1)
300#define QPNP_ENABLE_PWM_CONTROL(p_val) qpnp_set_control(p_val, 1, 1, 0, 1, 0)
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700301#define QPNP_IS_PWM_CONFIG_SELECTED(val) (val & QPNP_PWM_SRC_SELECT_MASK)
302
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700303
304static inline void qpnp_convert_to_lut_flags(int *flags,
305 struct qpnp_lut_config *l_config)
306{
307 *flags = ((l_config->ramp_direction ? PM_PWM_LUT_RAMP_UP : 0) |
308 (l_config->pattern_repeat ? PM_PWM_LUT_LOOP : 0)|
309 (l_config->ramp_toggle ? PM_PWM_LUT_REVERSE : 0) |
310 (l_config->enable_pause_hi ? PM_PWM_LUT_PAUSE_HI_EN : 0) |
311 (l_config->enable_pause_lo ? PM_PWM_LUT_PAUSE_LO_EN : 0));
312}
313
314static inline void qpnp_set_lut_params(struct lut_params *l_params,
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700315 struct qpnp_lut_config *l_config, int s_idx, int size)
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700316{
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700317 l_params->start_idx = s_idx;
318 l_params->idx_len = size;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700319 l_params->lut_pause_hi = l_config->lut_pause_hi_cnt;
320 l_params->lut_pause_lo = l_config->lut_pause_lo_cnt;
321 l_params->ramp_step_ms = l_config->ramp_step_ms;
322 qpnp_convert_to_lut_flags(&l_params->flags, l_config);
323}
324
325static void qpnp_lpg_save(u8 *u8p, u8 mask, u8 val)
326{
327 *u8p &= ~mask;
328 *u8p |= val & mask;
329}
330
331static int qpnp_lpg_save_and_write(u8 value, u8 mask, u8 *reg, u16 base_addr,
332 u16 offset, u16 size, struct qpnp_lpg_chip *chip)
333{
334 qpnp_lpg_save(reg, mask, value);
335
336 return spmi_ext_register_writel(chip->spmi_dev->ctrl,
337 chip->spmi_dev->sid, SPMI_LPG_REG_ADDR(base_addr, offset), reg, size);
338}
339
340/*
341 * PWM Frequency = Clock Frequency / (N * T)
342 * or
343 * PWM Period = Clock Period * (N * T)
344 * where
345 * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
346 * T = Pre-divide * 2^m, where m = 0..7 (exponent)
347 *
348 * This is the formula to figure out m for the best pre-divide and clock:
349 * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
350 */
351static void qpnp_lpg_calc_period(unsigned int period_us,
352 struct pwm_period_config *period)
353{
354 int n, m, clk, div;
355 int best_m, best_div, best_clk;
356 unsigned int last_err, cur_err, min_err;
357 unsigned int tmp_p, period_n;
358
359 /* PWM Period / N */
360 if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
361 period_n = (period_us * NSEC_PER_USEC) >> 6;
362 n = 6;
363 } else {
364 period_n = (period_us >> 9) * NSEC_PER_USEC;
365 n = 9;
366 }
367
368 min_err = last_err = (unsigned)(-1);
369 best_m = 0;
370 best_clk = 0;
371 best_div = 0;
372 for (clk = 0; clk < NUM_CLOCKS; clk++) {
373 for (div = 0; div < NUM_LPG_PRE_DIVIDE; div++) {
374 /* period_n = (PWM Period / N) */
375 /* tmp_p = (Pre-divide * Clock Period) * 2^m */
376 tmp_p = pt_t[div][clk];
377 for (m = 0; m <= QPNP_PWM_M_MAX; m++) {
378 if (period_n > tmp_p)
379 cur_err = period_n - tmp_p;
380 else
381 cur_err = tmp_p - period_n;
382
383 if (cur_err < min_err) {
384 min_err = cur_err;
385 best_m = m;
386 best_clk = clk;
387 best_div = div;
388 }
389
390 if (m && cur_err > last_err)
391 /* Break for bigger cur_err */
392 break;
393
394 last_err = cur_err;
395 tmp_p <<= 1;
396 }
397 }
398 }
399
400 /* Use higher resolution */
401 if (best_m >= 3 && n == 6) {
402 n += 3;
403 best_m -= 3;
404 }
405
406 period->pwm_size = n;
407 period->clk = best_clk;
408 period->pre_div = best_div;
409 period->pre_div_exp = best_m;
410}
411
412static void qpnp_lpg_calc_pwm_value(struct pwm_device *pwm,
413 unsigned int period_us,
414 unsigned int duty_us)
415{
416 unsigned int max_pwm_value, tmp;
417 struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
418
419 /* Figure out pwm_value with overflow handling */
420 tmp = 1 << (sizeof(tmp) * 8 - pwm_config->period.pwm_size);
421 if (duty_us < tmp) {
422 tmp = duty_us << pwm_config->period.pwm_size;
423 pwm_config->pwm_value = tmp / period_us;
424 } else {
425 tmp = period_us >> pwm_config->period.pwm_size;
426 pwm_config->pwm_value = duty_us / tmp;
427 }
428 max_pwm_value = (1 << pwm_config->period.pwm_size) - 1;
429 if (pwm_config->pwm_value > max_pwm_value)
430 pwm_config->pwm_value = max_pwm_value;
431}
432
433static int qpnp_lpg_change_table(struct pwm_device *pwm,
434 int duty_pct[], int raw_value)
435{
436 unsigned int pwm_value, max_pwm_value;
437 struct qpnp_lpg_chip *chip = pwm->chip;
438 struct qpnp_lut_config *lut = &chip->lpg_config.lut_config;
Jay Chokshieef72ab2012-07-27 14:02:35 -0700439 int i, pwm_size, rc = 0;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700440 int burst_size = SPMI_MAX_BUF_LEN;
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700441 int list_len = lut->list_len << 1;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700442 int offset = lut->lo_index << 2;
443
444 pwm_size = QPNP_GET_PWM_SIZE(
445 chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
446 QPNP_PWM_SIZE_9_BIT ? 9 : 6;
447
448 max_pwm_value = (1 << pwm_size) - 1;
449
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700450 if (unlikely(lut->list_len != (lut->hi_index - lut->lo_index + 1))) {
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700451 pr_err("LUT internal Data structure corruption detected\n");
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700452 pr_err("LUT list size: %d\n", lut->list_len);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700453 pr_err("However, index size is: %d\n",
454 (lut->hi_index - lut->lo_index + 1));
455 return -EINVAL;
456 }
457
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700458 for (i = 0; i <= lut->list_len; i++) {
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700459 if (raw_value)
460 pwm_value = duty_pct[i];
461 else
462 pwm_value = (duty_pct[i] << pwm_size) / 100;
463
464 if (pwm_value > max_pwm_value)
465 pwm_value = max_pwm_value;
466
467 lut->duty_pct_list[i*2] = pwm_value;
468 lut->duty_pct_list[(i*2)+1] = (pwm_value >>
469 QPNP_PWM_VALUE_MSB_SHIFT) & QPNP_PWM_VALUE_MSB_MASK;
470 }
471
472 /* Write with max allowable burst mode, each entry is of two bytes */
473 for (i = 0; i < list_len;) {
474 if (i + burst_size >= list_len)
475 burst_size = list_len - i;
476 rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
477 chip->spmi_dev->sid,
478 chip->lpg_config.lut_base_addr + offset + i,
479 lut->duty_pct_list + i, burst_size);
480 i += burst_size;
481 }
482
483 return rc;
484}
485
486static void qpnp_lpg_save_period(struct pwm_device *pwm)
487{
488 u8 mask, val;
489 struct qpnp_lpg_chip *chip = pwm->chip;
490 struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
491
492 QPNP_SET_PWM_CLK(val, pwm_config->period.clk,
493 pwm_config->period.pwm_size);
494
495 mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
496
497 qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK],
498 mask, val);
499
500 QPNP_SET_PWM_FREQ_PREDIV(val, pwm_config->period.pre_div,
501 pwm_config->period.pre_div_exp);
502
503 mask = QPNP_PWM_FREQ_PRE_DIVIDE_MASK | QPNP_PWM_FREQ_EXP_MASK;
504
505 qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK],
506 mask, val);
507}
508
509static int qpnp_lpg_save_pwm_value(struct pwm_device *pwm)
510{
511 unsigned int max_pwm_value;
512 int pwm_size;
513 u8 mask, value;
514 struct qpnp_lpg_chip *chip = pwm->chip;
515 struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
516 struct qpnp_lpg_config *lpg_config = &chip->lpg_config;
517 int rc;
518
519 pwm_size = QPNP_GET_PWM_SIZE(
520 chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
521 QPNP_PWM_SIZE_9_BIT ? 9 : 6;
522
523 max_pwm_value = (1 << pwm_size) - 1;
524
525 if (pwm_config->pwm_value > max_pwm_value)
526 pwm_config->pwm_value = max_pwm_value;
527
528 value = pwm_config->pwm_value;
529 mask = QPNP_PWM_VALUE_LSB_MASK;
530
531 rc = qpnp_lpg_save_and_write(value, mask,
532 &pwm->chip->qpnp_lpg_registers[QPNP_PWM_VALUE_LSB],
533 lpg_config->base_addr, QPNP_PWM_VALUE_LSB, 1, chip);
534 if (rc)
535 return rc;
536
537 value = (pwm_config->pwm_value >> QPNP_PWM_VALUE_MSB_SHIFT) &
538 QPNP_PWM_VALUE_MSB_MASK;
539
540 mask = QPNP_PWM_VALUE_MSB_MASK;
541
542 return qpnp_lpg_save_and_write(value, mask,
543 &pwm->chip->qpnp_lpg_registers[QPNP_PWM_VALUE_MSB],
544 lpg_config->base_addr, QPNP_PWM_VALUE_MSB, 1, chip);
545}
546
547static int qpnp_lpg_configure_pattern(struct pwm_device *pwm)
548{
549 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
550 struct qpnp_lut_config *lut_config = &lpg_config->lut_config;
551 struct qpnp_lpg_chip *chip = pwm->chip;
552 u8 value, mask;
553
554 qpnp_set_pattern_config(&value, lut_config);
555
556 mask = QPNP_RAMP_DIRECTION_MASK | QPNP_PATTERN_REPEAT_MASK |
557 QPNP_RAMP_TOGGLE_MASK | QPNP_EN_PAUSE_HI_MASK |
558 QPNP_EN_PAUSE_LO_MASK;
559
560 return qpnp_lpg_save_and_write(value, mask,
561 &pwm->chip->qpnp_lpg_registers[QPNP_LPG_PATTERN_CONFIG],
562 lpg_config->base_addr, QPNP_LPG_PATTERN_CONFIG, 1, chip);
563}
564
565static int qpnp_lpg_configure_pwm(struct pwm_device *pwm)
566{
567 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
568 struct qpnp_lpg_chip *chip = pwm->chip;
569 int rc;
570 u8 value, mask;
571
572 rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
573 SPMI_LPG_REG_ADDR(lpg_config->base_addr, QPNP_LPG_PWM_SIZE_CLK),
574 &chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK], 1);
575
576 if (rc)
577 return rc;
578
579 rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
580 SPMI_LPG_REG_ADDR(lpg_config->base_addr,
581 QPNP_LPG_PWM_FREQ_PREDIV_CLK),
582 &chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK], 1);
583 if (rc)
584 return rc;
585
586 qpnp_set_pwm_type_config(&value, 1, 0, 0, 0);
587
588 mask = QPNP_EN_GLITCH_REMOVAL_MASK | QPNP_EN_FULL_SCALE_MASK |
589 QPNP_EN_PHASE_STAGGER_MASK | QPNP_PHASE_STAGGER_MASK;
590
591 return qpnp_lpg_save_and_write(value, mask,
592 &pwm->chip->qpnp_lpg_registers[QPNP_LPG_PWM_TYPE_CONFIG],
593 lpg_config->base_addr, QPNP_LPG_PWM_TYPE_CONFIG, 1, chip);
594}
595
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700596static int qpnp_configure_pwm_control(struct pwm_device *pwm)
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700597{
598 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
599 struct qpnp_lpg_chip *chip = pwm->chip;
600 u8 value, mask;
601
602 QPNP_ENABLE_PWM_CONTROL(&value);
603
604 mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
605 QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
606 QPNP_PWM_EN_RAMP_GEN_MASK;
607
608 return qpnp_lpg_save_and_write(value, mask,
609 &pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
610 lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
611
612}
613
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700614static int qpnp_configure_lpg_control(struct pwm_device *pwm)
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700615{
616 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
617 struct qpnp_lpg_chip *chip = pwm->chip;
618 u8 value, mask;
619
620 QPNP_ENABLE_LUT_CONTROL(&value);
621
622 mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
623 QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
624 QPNP_PWM_EN_RAMP_GEN_MASK;
625
626 return qpnp_lpg_save_and_write(value, mask,
627 &pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
628 lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
629
630}
631
632static int qpnp_lpg_configure_ramp_step_duration(struct pwm_device *pwm)
633{
634 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
635 struct qpnp_lut_config lut_config = lpg_config->lut_config;
636 struct qpnp_lpg_chip *chip = pwm->chip;
637 int rc, value;
638 u8 val, mask;
639
640 value = QPNP_GET_RAMP_STEP_DURATION(lut_config.ramp_step_ms);
641 val = value & QPNP_RAMP_STEP_DURATION_LSB_MASK;
642 mask = QPNP_RAMP_STEP_DURATION_LSB_MASK;
643
644 rc = qpnp_lpg_save_and_write(val, mask,
645 &pwm->chip->qpnp_lpg_registers[QPNP_RAMP_STEP_DURATION_LSB],
646 lpg_config->base_addr, QPNP_RAMP_STEP_DURATION_LSB, 1, chip);
647 if (rc)
648 return rc;
649
650 val = (value >> QPNP_RAMP_STEP_DURATION_MSB_SHIFT) &
651 QPNP_RAMP_STEP_DURATION_MSB_MASK;
652
653 mask = QPNP_RAMP_STEP_DURATION_MSB_MASK;
654
655 return qpnp_lpg_save_and_write(val, mask,
656 &pwm->chip->qpnp_lpg_registers[QPNP_RAMP_STEP_DURATION_MSB],
657 lpg_config->base_addr, QPNP_RAMP_STEP_DURATION_MSB, 1, chip);
658}
659
660static int qpnp_lpg_configure_pause(struct pwm_device *pwm)
661{
662 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
663 struct qpnp_lut_config lut_config = lpg_config->lut_config;
664 struct qpnp_lpg_chip *chip = pwm->chip;
665 u8 value, mask;
666 int rc = 0;
667
668 if (lut_config.enable_pause_hi) {
669 value = lut_config.lut_pause_hi_cnt;
670 mask = QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK;
671
672 rc = qpnp_lpg_save_and_write(value, mask,
673 &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_LSB],
674 lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_LSB, 1, chip);
675 if (rc)
676 return rc;
677
678 value = (lut_config.lut_pause_hi_cnt >>
679 QPNP_PAUSE_HI_MULTIPLIER_MSB_SHIFT) &
680 QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
681
682 mask = QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
683
684 rc = qpnp_lpg_save_and_write(value, mask,
685 &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_MSB],
686 lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_MSB, 1, chip);
687 } else {
688 value = 0;
689 mask = QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK;
690
691 rc = qpnp_lpg_save_and_write(value, mask,
692 &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_LSB],
693 lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_LSB, 1, chip);
694 if (rc)
695 return rc;
696
697 mask = QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
698
699 rc = qpnp_lpg_save_and_write(value, mask,
700 &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_MSB],
701 lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_MSB, 1, chip);
702 if (rc)
703 return rc;
704
705 }
706
707 if (lut_config.enable_pause_lo) {
708 value = lut_config.lut_pause_lo_cnt;
709 mask = QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK;
710
711 rc = qpnp_lpg_save_and_write(value, mask,
712 &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_LSB],
713 lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_LSB, 1, chip);
714 if (rc)
715 return rc;
716
717 value = (lut_config.lut_pause_lo_cnt >>
718 QPNP_PAUSE_LO_MULTIPLIER_MSB_SHIFT) &
719 QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
720
721 mask = QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
722
723 rc = qpnp_lpg_save_and_write(value, mask,
724 &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_MSB],
725 lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_MSB, 1, chip);
726 } else {
727 value = 0;
728 mask = QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK;
729
730 rc = qpnp_lpg_save_and_write(value, mask,
731 &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_LSB],
732 lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_LSB, 1, chip);
733 if (rc)
734 return rc;
735
736 mask = QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
737
738 rc = qpnp_lpg_save_and_write(value, mask,
739 &pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_MSB],
740 lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_MSB, 1, chip);
741 return rc;
742 }
743
744 return rc;
745}
746
747static int qpnp_lpg_configure_index(struct pwm_device *pwm)
748{
749 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
750 struct qpnp_lut_config lut_config = lpg_config->lut_config;
751 struct qpnp_lpg_chip *chip = pwm->chip;
752 u8 value, mask;
753 int rc = 0;
754
755 value = lut_config.hi_index;
756 mask = QPNP_HI_INDEX_MASK;
757
758 rc = qpnp_lpg_save_and_write(value, mask,
759 &pwm->chip->qpnp_lpg_registers[QPNP_HI_INDEX],
760 lpg_config->base_addr, QPNP_HI_INDEX, 1, chip);
761 if (rc)
762 return rc;
763
764 value = lut_config.lo_index;
765 mask = QPNP_LO_INDEX_MASK;
766
767 rc = qpnp_lpg_save_and_write(value, mask,
768 &pwm->chip->qpnp_lpg_registers[QPNP_LO_INDEX],
769 lpg_config->base_addr, QPNP_LO_INDEX, 1, chip);
770
771 return rc;
772}
773
774static int qpnp_lpg_change_lut(struct pwm_device *pwm)
775{
776 int rc;
777
778 rc = qpnp_lpg_configure_pattern(pwm);
779 if (rc) {
780 pr_err("Failed to configure LUT pattern");
781 return rc;
782 }
783 rc = qpnp_lpg_configure_pwm(pwm);
784 if (rc) {
785 pr_err("Failed to configure LUT pattern");
786 return rc;
787 }
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700788 rc = qpnp_configure_lpg_control(pwm);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700789 if (rc) {
790 pr_err("Failed to configure pause registers");
791 return rc;
792 }
793 rc = qpnp_lpg_configure_ramp_step_duration(pwm);
794 if (rc) {
795 pr_err("Failed to configure duty time");
796 return rc;
797 }
798 rc = qpnp_lpg_configure_pause(pwm);
799 if (rc) {
800 pr_err("Failed to configure pause registers");
801 return rc;
802 }
803 rc = qpnp_lpg_configure_index(pwm);
804 if (rc) {
805 pr_err("Failed to configure index registers");
806 return rc;
807 }
808 return rc;
809}
810
811static int qpnp_lpg_enable_lut(struct pwm_device *pwm)
812{
813 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
814 struct qpnp_lpg_chip *chip = pwm->chip;
815 u8 value, mask;
816
817 value = pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
818
819 QPNP_ENABLE_LUT(value);
820
821 mask = QPNP_RAMP_START_MASK;
822
823 return qpnp_lpg_save_and_write(value, mask,
824 &pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL],
825 lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
826}
827
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700828static int qpnp_disable_lut(struct pwm_device *pwm)
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700829{
830 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
831 struct qpnp_lpg_chip *chip = pwm->chip;
832 u8 value, mask;
833
834 value = pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
835
836 QPNP_DISABLE_LUT(value);
837
838 mask = QPNP_RAMP_START_MASK;
839
840 return qpnp_lpg_save_and_write(value, mask,
841 &pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL],
842 lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
843}
844
845static int qpnp_lpg_enable_pwm(struct pwm_device *pwm)
846{
847 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
848 struct qpnp_lpg_chip *chip = pwm->chip;
849 u8 value, mask;
850
851 value = pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL];
852
853 QPNP_ENABLE_PWM(value);
854
855 mask = QPNP_EN_PWM_OUTPUT_MASK;
856
857 return qpnp_lpg_save_and_write(value, mask,
858 &pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
859 lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
860}
861
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700862static int qpnp_disable_pwm(struct pwm_device *pwm)
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700863{
864 struct qpnp_lpg_config *lpg_config = &pwm->chip->lpg_config;
865 struct qpnp_lpg_chip *chip = pwm->chip;
866 u8 value, mask;
867
868 value = pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL];
869
870 QPNP_DISABLE_PWM(value);
871
872 mask = QPNP_EN_PWM_OUTPUT_MASK;
873
874 return qpnp_lpg_save_and_write(value, mask,
875 &pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
876 lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
877}
878
879static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
880{
881 struct qpnp_pwm_config *pwm_config;
882 struct qpnp_lpg_chip *chip;
883 struct pwm_period_config *period;
884 int rc;
885
886 chip = pwm->chip;
887 pwm_config = &pwm->pwm_config;
888 period = &pwm_config->period;
889
890 if (pwm_config->pwm_period != period_us) {
891 qpnp_lpg_calc_period(period_us, period);
892 qpnp_lpg_save_period(pwm);
893 pwm_config->pwm_period = period_us;
894 }
895
896 pwm_config->pwm_duty = duty_us;
897 qpnp_lpg_calc_pwm_value(pwm, period_us, duty_us);
898 rc = qpnp_lpg_save_pwm_value(pwm);
899
900 if (rc) {
901 pr_err("Could not update PWM value for channel %d rc=%d\n",
902 pwm_config->channel_id, rc);
903 return rc;
904 }
905
906 rc = qpnp_lpg_configure_pwm(pwm);
907 if (rc) {
908 pr_err("Could not configure PWM clock for\n");
909 pr_err("channel %d rc=%d\n", pwm_config->channel_id, rc);
910 return rc;
911 }
912
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700913 rc = qpnp_configure_pwm_control(pwm);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700914 if (rc) {
915 pr_err("Could not update PWM control for");
916 pr_err("channel %d rc=%d\n", pwm_config->channel_id, rc);
917 return rc;
918 }
919
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700920 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
921 (unsigned)duty_us, (unsigned)period_us,
922 pwm_config->pwm_value, 1 << period->pwm_size);
923
924 return 0;
925}
926
927static int _pwm_lut_config(struct pwm_device *pwm, int period_us,
928 int duty_pct[], struct lut_params lut_params)
929{
930 struct qpnp_lpg_config *lpg_config;
931 struct qpnp_lut_config *lut_config;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700932 struct pwm_period_config *period;
933 struct qpnp_pwm_config *pwm_config;
934 int start_idx = lut_params.start_idx;
935 int len = lut_params.idx_len;
936 int flags = lut_params.flags;
937 int raw_lut, ramp_step_ms;
938 int rc = 0;
939
940 pwm_config = &pwm->pwm_config;
941 lpg_config = &pwm->chip->lpg_config;
942 lut_config = &lpg_config->lut_config;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700943
944 period = &pwm_config->period;
945
946 if (pwm_config->pwm_period != period_us) {
947 qpnp_lpg_calc_period(period_us, period);
948 qpnp_lpg_save_period(pwm);
949 pwm_config->pwm_period = period_us;
950 }
951
952 if (flags & PM_PWM_LUT_NO_TABLE)
953 goto after_table_write;
954
955 raw_lut = 0;
956 if (flags & PM_PWM_LUT_USE_RAW_VALUE)
957 raw_lut = 1;
958
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700959 lut_config->list_len = len;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700960 lut_config->lo_index = start_idx;
961 lut_config->hi_index = start_idx + len - 1;
962
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700963 rc = qpnp_lpg_change_table(pwm, duty_pct, raw_lut);
964 if (rc) {
965 pr_err("qpnp_lpg_change_table: rc=%d\n", rc);
966 return -EINVAL;
967 }
968
969after_table_write:
970 ramp_step_ms = lut_params.ramp_step_ms;
971
972 if (ramp_step_ms > PM_PWM_LUT_RAMP_STEP_TIME_MAX)
973 ramp_step_ms = PM_PWM_LUT_RAMP_STEP_TIME_MAX;
974
975 QPNP_SET_PAUSE_CNT(lut_config->lut_pause_lo_cnt,
976 lut_params.lut_pause_lo, ramp_step_ms);
977 if (lut_config->lut_pause_lo_cnt > PM_PWM_LUT_PAUSE_MAX)
978 lut_config->lut_pause_lo_cnt = PM_PWM_LUT_PAUSE_MAX;
979
980 QPNP_SET_PAUSE_CNT(lut_config->lut_pause_hi_cnt,
981 lut_params.lut_pause_hi, ramp_step_ms);
982 if (lut_config->lut_pause_hi_cnt > PM_PWM_LUT_PAUSE_MAX)
983 lut_config->lut_pause_hi_cnt = PM_PWM_LUT_PAUSE_MAX;
984
985 lut_config->ramp_step_ms = ramp_step_ms;
986
987 lut_config->ramp_direction = !!(flags & PM_PWM_LUT_RAMP_UP);
988 lut_config->pattern_repeat = !!(flags & PM_PWM_LUT_LOOP);
989 lut_config->ramp_toggle = !!(flags & PM_PWM_LUT_REVERSE);
990 lut_config->enable_pause_hi = !!(flags & PM_PWM_LUT_PAUSE_HI_EN);
991 lut_config->enable_pause_lo = !!(flags & PM_PWM_LUT_PAUSE_LO_EN);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -0700992
993 rc = qpnp_lpg_change_lut(pwm);
994
Jay Chokshi219fcfc2012-07-27 17:39:15 -0700995 return rc;
996}
997
998static int _pwm_enable(struct pwm_device *pwm)
999{
1000 int rc;
1001 struct qpnp_lpg_chip *chip;
1002
1003 chip = pwm->chip;
1004
1005 mutex_lock(&pwm->chip->lpg_mutex);
1006
1007 if (QPNP_IS_PWM_CONFIG_SELECTED(
1008 chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]))
1009 rc = qpnp_lpg_enable_pwm(pwm);
1010 else
1011 rc = qpnp_lpg_enable_lut(pwm);
1012
1013 mutex_unlock(&pwm->chip->lpg_mutex);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001014
1015 return rc;
1016}
1017
1018/* APIs */
1019/**
1020 * pwm_request - request a PWM device
1021 * @channel_id: PWM id or channel
1022 * @lable: the label to identify the user
1023 */
1024struct pwm_device *pwm_request(int pwm_id, const char *lable)
1025{
1026 struct qpnp_lpg_chip *chip;
1027 struct pwm_device *pwm;
1028
1029 chip = radix_tree_lookup(&lpg_dev_tree, pwm_id);
1030
1031 if (!chip) {
1032 pr_err("Could not find PWM Device for the\n");
1033 pr_err("input pwm channel %d\n", pwm_id);
1034 return ERR_PTR(-EINVAL);
1035 }
1036
1037 mutex_lock(&chip->lpg_mutex);
1038
1039 pwm = &chip->pwm_dev;
1040
1041 if (pwm->pwm_config.in_use) {
1042 pr_err("PWM device associated with the");
1043 pr_err("input pwm id: %d is in use by %s",
1044 pwm_id, pwm->pwm_config.lable);
1045 pwm = ERR_PTR(-EBUSY);
1046 } else {
1047 pwm->pwm_config.in_use = 1;
1048 pwm->pwm_config.lable = lable;
1049 }
1050
1051 mutex_unlock(&chip->lpg_mutex);
1052
1053 return pwm;
1054}
1055EXPORT_SYMBOL_GPL(pwm_request);
1056
1057/**
1058 * pwm_free - free a PWM device
1059 * @pwm: the PWM device
1060 */
1061void pwm_free(struct pwm_device *pwm)
1062{
1063 struct qpnp_pwm_config *pwm_config;
1064
1065 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
1066 pr_err("Invalid pwm handle or no pwm_chip\n");
1067 return;
1068 }
1069
1070 mutex_lock(&pwm->chip->lpg_mutex);
1071
1072 pwm_config = &pwm->pwm_config;
1073
1074 if (pwm_config->in_use) {
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001075 qpnp_disable_pwm(pwm);
1076 qpnp_disable_lut(pwm);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001077 pwm_config->in_use = 0;
1078 pwm_config->lable = NULL;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001079 }
1080
1081 mutex_unlock(&pwm->chip->lpg_mutex);
1082}
1083EXPORT_SYMBOL_GPL(pwm_free);
1084
1085/**
1086 * pwm_config - change a PWM device configuration
1087 * @pwm: the PWM device
1088 * @period_us: period in microseconds
1089 * @duty_us: duty cycle in microseconds
1090 */
1091int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
1092{
1093 int rc;
1094
1095 if (pwm == NULL || IS_ERR(pwm) ||
1096 duty_us > period_us ||
1097 (unsigned)period_us > PM_PWM_PERIOD_MAX ||
1098 (unsigned)period_us < PM_PWM_PERIOD_MIN) {
1099 pr_err("Invalid pwm handle or parameters\n");
1100 return -EINVAL;
1101 }
1102
1103 if (!pwm->pwm_config.in_use)
1104 return -EINVAL;
1105
1106 mutex_lock(&pwm->chip->lpg_mutex);
1107 rc = _pwm_config(pwm, duty_us, period_us);
1108 mutex_unlock(&pwm->chip->lpg_mutex);
1109
1110 return rc;
1111}
1112EXPORT_SYMBOL_GPL(pwm_config);
1113
1114/**
1115 * pwm_enable - start a PWM output toggling
1116 * @pwm: the PWM device
1117 */
1118int pwm_enable(struct pwm_device *pwm)
1119{
1120 struct qpnp_pwm_config *p_config;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001121
1122 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
1123 pr_err("Invalid pwm handle or no pwm_chip\n");
1124 return -EINVAL;
1125 }
1126
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001127 p_config = &pwm->pwm_config;
1128
1129 if (!p_config->in_use) {
1130 pr_err("channel_id: %d: stale handle?\n", p_config->channel_id);
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001131 return -EINVAL;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001132 }
1133
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001134 return _pwm_enable(pwm);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001135}
1136EXPORT_SYMBOL_GPL(pwm_enable);
1137
1138/**
1139 * pwm_disable - stop a PWM output toggling
1140 * @pwm: the PWM device
1141 */
1142void pwm_disable(struct pwm_device *pwm)
1143{
1144 struct qpnp_pwm_config *pwm_config;
1145 struct qpnp_lpg_chip *chip;
1146
1147 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
1148 pr_err("Invalid pwm handle or no pwm_chip\n");
1149 return;
1150 }
1151
1152 mutex_lock(&pwm->chip->lpg_mutex);
1153
1154 chip = pwm->chip;
1155 pwm_config = &pwm->pwm_config;
1156
1157 if (pwm_config->in_use) {
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001158 if (QPNP_IS_PWM_CONFIG_SELECTED(
1159 chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]))
1160 qpnp_disable_pwm(pwm);
1161 else
1162 qpnp_disable_lut(pwm);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001163 }
1164
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001165 mutex_unlock(&pwm->chip->lpg_mutex);
1166}
1167EXPORT_SYMBOL_GPL(pwm_disable);
1168
1169/**
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001170 * pwm_change_mode - Change the PWM mode configuration
1171 * @pwm: the PWM device
1172 * @mode: Mode selection value
1173 */
1174int pwm_change_mode(struct pwm_device *pwm, enum pm_pwm_mode mode)
1175{
1176 int rc;
1177
1178 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
1179 pr_err("Invalid pwm handle or no pwm_chip\n");
1180 return -EINVAL;
1181 }
1182
1183 if (mode < PM_PWM_MODE_PWM || mode > PM_PWM_MODE_LPG) {
1184 pr_err("Invalid mode value\n");
1185 return -EINVAL;
1186 }
1187
1188 mutex_lock(&pwm->chip->lpg_mutex);
1189
1190 if (mode)
1191 rc = qpnp_configure_lpg_control(pwm);
1192 else
1193 rc = qpnp_configure_pwm_control(pwm);
1194
1195 mutex_unlock(&pwm->chip->lpg_mutex);
1196
1197 return rc;
1198}
1199EXPORT_SYMBOL_GPL(pwm_change_mode);
1200
1201/**
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001202 * pwm_config_period - change PWM period
1203 *
1204 * @pwm: the PWM device
1205 * @pwm_p: period in struct qpnp_lpg_period
1206 */
1207int pwm_config_period(struct pwm_device *pwm,
1208 struct pwm_period_config *period)
1209{
1210 struct qpnp_pwm_config *pwm_config;
1211 struct qpnp_lpg_config *lpg_config;
1212 struct qpnp_lpg_chip *chip;
1213 int rc = 0;
1214
1215 if (pwm == NULL || IS_ERR(pwm) || period == NULL)
1216 return -EINVAL;
1217 if (pwm->chip == NULL)
1218 return -ENODEV;
1219
1220 mutex_lock(&pwm->chip->lpg_mutex);
1221
1222 chip = pwm->chip;
1223 pwm_config = &pwm->pwm_config;
1224 lpg_config = &chip->lpg_config;
1225
1226 if (!pwm_config->in_use) {
1227 rc = -EINVAL;
1228 goto out_unlock;
1229 }
1230
1231 pwm_config->period.pwm_size = period->pwm_size;
1232 pwm_config->period.clk = period->clk;
1233 pwm_config->period.pre_div = period->pre_div;
1234 pwm_config->period.pre_div_exp = period->pre_div_exp;
1235
1236 qpnp_lpg_save_period(pwm);
1237
1238 rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
1239 SPMI_LPG_REG_ADDR(lpg_config->base_addr,
1240 QPNP_LPG_PWM_SIZE_CLK),
1241 &chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK], 1);
1242
1243 if (rc) {
1244 pr_err("Write failed: QPNP_LPG_PWM_SIZE_CLK register, rc: %d\n",
1245 rc);
1246 goto out_unlock;
1247 }
1248
1249 rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
1250 SPMI_LPG_REG_ADDR(lpg_config->base_addr,
1251 QPNP_LPG_PWM_FREQ_PREDIV_CLK),
1252 &chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK], 1);
1253 if (rc) {
1254 pr_err("Failed to write to QPNP_LPG_PWM_FREQ_PREDIV_CLK\n");
1255 pr_err("register, rc = %d\n", rc);
1256 }
1257
1258out_unlock:
1259 mutex_unlock(&pwm->chip->lpg_mutex);
1260 return rc;
1261}
1262EXPORT_SYMBOL(pwm_config_period);
1263
1264/**
1265 * pwm_config_pwm_value - change a PWM device configuration
1266 * @pwm: the PWM device
1267 * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
1268 */
1269int pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
1270{
1271 struct qpnp_lpg_config *lpg_config;
1272 struct qpnp_pwm_config *pwm_config;
1273 int rc = 0;
1274
1275 if (pwm == NULL || IS_ERR(pwm))
1276 return -EINVAL;
1277
1278 if (pwm->chip == NULL)
1279 return -ENODEV;
1280
1281 lpg_config = &pwm->chip->lpg_config;
1282 pwm_config = &pwm->pwm_config;
1283
1284 mutex_lock(&pwm->chip->lpg_mutex);
1285
1286 if (!pwm_config->in_use || !pwm_config->pwm_period) {
1287 rc = -EINVAL;
1288 goto out_unlock;
1289 }
1290
1291 if (pwm_config->pwm_value == pwm_value)
1292 goto out_unlock;
1293
1294 pwm_config->pwm_value = pwm_value;
1295
1296 rc = qpnp_lpg_save_pwm_value(pwm);
1297
1298 if (rc)
1299 pr_err("Could not update PWM value for channel %d rc=%d\n",
1300 pwm_config->channel_id, rc);
1301
1302out_unlock:
1303 mutex_unlock(&pwm->chip->lpg_mutex);
1304 return rc;
1305}
1306EXPORT_SYMBOL_GPL(pwm_config_pwm_value);
1307
1308/**
1309 * pwm_lut_config - change LPG LUT device configuration
1310 * @pwm: the PWM device
1311 * @period_us: period in micro second
1312 * @duty_pct: array of duty cycles in percent, like 20, 50.
1313 * @lut_params: Lookup table parameters
1314 */
1315int pwm_lut_config(struct pwm_device *pwm, int period_us,
1316 int duty_pct[], struct lut_params lut_params)
1317{
1318 int rc = 0;
1319
1320 if (pwm == NULL || IS_ERR(pwm) || !lut_params.idx_len) {
1321 pr_err("Invalid pwm handle or idx_len=0\n");
1322 return -EINVAL;
1323 }
1324
1325 if (pwm->chip == NULL)
1326 return -ENODEV;
1327
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001328 if (!pwm->pwm_config.in_use) {
1329 pr_err("channel_id: %d: stale handle?\n",
1330 pwm->pwm_config.channel_id);
1331 return -EINVAL;
1332 }
1333
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001334 if (duty_pct == NULL && !(lut_params.flags & PM_PWM_LUT_NO_TABLE)) {
1335 pr_err("Invalid duty_pct with flag\n");
1336 return -EINVAL;
1337 }
1338
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001339 if ((lut_params.start_idx + lut_params.idx_len) >
1340 pwm->chip->lpg_config.lut_size) {
1341 pr_err("Exceed LUT limit\n");
1342 return -EINVAL;
1343 }
1344
1345 if ((unsigned)period_us > PM_PWM_PERIOD_MAX ||
1346 (unsigned)period_us < PM_PWM_PERIOD_MIN) {
1347 pr_err("Period out of range\n");
1348 return -EINVAL;
1349 }
1350
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001351 mutex_lock(&pwm->chip->lpg_mutex);
1352
1353 rc = _pwm_lut_config(pwm, period_us, duty_pct, lut_params);
1354
1355 mutex_unlock(&pwm->chip->lpg_mutex);
1356
1357 return rc;
1358}
1359EXPORT_SYMBOL_GPL(pwm_lut_config);
1360
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001361static int qpnp_parse_pwm_dt_config(struct device_node *of_pwm_node,
1362 struct device_node *of_parent, struct qpnp_lpg_chip *chip)
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001363{
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001364 int rc, period;
1365 struct pwm_device *pwm_dev = &chip->pwm_dev;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001366
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001367 rc = of_property_read_u32(of_parent, "qcom,period", (u32 *)&period);
1368 if (rc) {
1369 pr_err("node is missing PWM Period prop");
1370 return rc;
1371 }
1372
1373 rc = of_property_read_u32(of_pwm_node, "qcom,duty",
1374 &pwm_dev->pwm_config.pwm_duty);
1375 if (rc) {
1376 pr_err("node is missing PWM Duty prop");
1377 return rc;
1378 }
1379
1380 rc = _pwm_config(pwm_dev, pwm_dev->pwm_config.pwm_duty, period);
1381
1382 return rc;
1383}
1384
1385#define qpnp_check_optional_dt_bindings(func) \
1386do { \
1387 rc = func; \
1388 if (rc && rc != -EINVAL) \
1389 goto out; \
1390 rc = 0; \
1391} while (0);
1392
1393static int qpnp_parse_lpg_dt_config(struct device_node *of_lpg_node,
1394 struct device_node *of_parent, struct qpnp_lpg_chip *chip)
1395{
1396 int rc, period, list_size, start_idx, *duty_pct_list;
1397 struct pwm_device *pwm_dev = &chip->pwm_dev;
1398 struct qpnp_lpg_config *lpg_config = &chip->lpg_config;
1399 struct qpnp_lut_config *lut_config = &lpg_config->lut_config;
1400 struct lut_params lut_params;
1401
1402 rc = of_property_read_u32(of_parent, "qcom,period", &period);
1403 if (rc) {
1404 pr_err("node is missing PWM Period prop");
1405 return rc;
1406 }
1407
1408 if (!of_get_property(of_lpg_node, "qcom,duty-percents", &list_size)) {
1409 pr_err("node is missing duty-pct list");
1410 return rc;
1411 }
1412
1413 rc = of_property_read_u32(of_lpg_node, "cell-index", &start_idx);
1414 if (rc) {
1415 pr_err("Missing start index");
1416 return rc;
1417 }
1418
1419 list_size /= sizeof(u32);
1420
1421 if (list_size + start_idx > lpg_config->lut_size) {
1422 pr_err("duty pct list size overflows\n");
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001423 return -EINVAL;
1424 }
1425
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001426 duty_pct_list = kzalloc(sizeof(u32) * list_size, GFP_KERNEL);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001427
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001428 if (!duty_pct_list) {
1429 pr_err("kzalloc failed on duty_pct_list\n");
1430 return -ENOMEM;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001431 }
1432
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001433 rc = of_property_read_u32_array(of_lpg_node, "qcom,duty-percents",
1434 duty_pct_list, list_size);
1435 if (rc) {
1436 pr_err("invalid or missing property:\n");
1437 pr_err("qcom,duty-pcts-list\n");
1438 kfree(duty_pct_list);
1439 return rc;
1440 }
1441
1442 /* Read optional properties */
1443 qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
1444 "qcom,ramp-step-duration", &lut_config->ramp_step_ms));
1445 qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
1446 "qcom,lpg-lut-pause-hi", &lut_config->lut_pause_hi_cnt));
1447 qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
1448 "qcom,lpg-lut-pause-lo", &lut_config->lut_pause_lo_cnt));
1449 qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
1450 "qcom,lpg-lut-ramp-direction",
1451 (u32 *)&lut_config->ramp_direction));
1452 qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
1453 "qcom,lpg-lut-pattern-repeat",
1454 (u32 *)&lut_config->pattern_repeat));
1455 qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
1456 "qcom,lpg-lut-ramp-toggle",
1457 (u32 *)&lut_config->ramp_toggle));
1458 qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
1459 "qcom,lpg-lut-enable-pause-hi",
1460 (u32 *)&lut_config->enable_pause_hi));
1461 qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
1462 "qcom,lpg-lut-enable-pause-lo",
1463 (u32 *)&lut_config->enable_pause_lo));
1464
1465 qpnp_set_lut_params(&lut_params, lut_config, start_idx, list_size);
1466
1467 _pwm_lut_config(pwm_dev, period, duty_pct_list, lut_params);
1468
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001469out:
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001470 kfree(duty_pct_list);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001471 return rc;
1472}
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001473
1474/* Fill in lpg device elements based on values found in device tree. */
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001475static int qpnp_parse_dt_config(struct spmi_device *spmi,
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001476 struct qpnp_lpg_chip *chip)
1477{
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001478 int rc, enable;
1479 const char *lable;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001480 struct resource *res;
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001481 struct device_node *node;
1482 int found_pwm_subnode = 0;
1483 int found_lpg_subnode = 0;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001484 struct device_node *of_node = spmi->dev.of_node;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001485 struct pwm_device *pwm_dev = &chip->pwm_dev;
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001486 struct qpnp_lpg_config *lpg_config = &chip->lpg_config;
1487 struct qpnp_lut_config *lut_config = &lpg_config->lut_config;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001488
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001489 res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
1490 QPNP_LPG_CHANNEL_BASE);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001491 if (!res) {
1492 dev_err(&spmi->dev, "%s: node is missing base address\n",
1493 __func__);
1494 return -EINVAL;
1495 }
1496
1497 lpg_config->base_addr = res->start;
1498
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001499 res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
1500 QPNP_LPG_LUT_BASE);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001501 if (!res) {
1502 dev_err(&spmi->dev, "%s: node is missing LUT base address\n",
1503 __func__);
1504 return -EINVAL;
1505 }
1506
1507 lpg_config->lut_base_addr = res->start;
1508 /* Each entry of LUT is of 2 bytes */
1509 lpg_config->lut_size = resource_size(res) >> 1;
1510
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001511 lut_config->duty_pct_list = kzalloc(lpg_config->lut_size *
1512 sizeof(u16), GFP_KERNEL);
1513 if (!lut_config->duty_pct_list) {
1514 pr_err("can not allocate duty pct list\n");
1515 return -ENOMEM;
1516 }
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001517
1518 rc = of_property_read_u32(of_node, "qcom,channel-id",
1519 &pwm_dev->pwm_config.channel_id);
1520 if (rc) {
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001521 dev_err(&spmi->dev, "%s: node is missing LPG channel id\n",
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001522 __func__);
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001523 goto out;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001524 }
1525
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001526 for_each_child_of_node(of_node, node) {
1527 rc = of_property_read_string(node, "label", &lable);
1528 if (rc) {
1529 dev_err(&spmi->dev, "%s: Missing lable property\n",
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001530 __func__);
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001531 goto out;
1532 }
1533 if (!strncmp(lable, "pwm", 3)) {
1534 rc = qpnp_parse_pwm_dt_config(node, of_node, chip);
1535 if (rc)
1536 goto out;
1537 found_pwm_subnode = 1;
1538 } else if (!strncmp(lable, "lpg", 3)) {
1539 qpnp_parse_lpg_dt_config(node, of_node, chip);
1540 if (rc)
1541 goto out;
1542 found_lpg_subnode = 1;
1543 } else {
1544 dev_err(&spmi->dev, "%s: Invalid value for lable prop",
1545 __func__);
1546 }
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001547 }
1548
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001549 rc = of_property_read_u32(of_node, "qcom,mode-select", &enable);
1550 if (rc)
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001551 goto read_opt_props;
1552
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001553 if ((enable == PM_PWM_MODE_PWM && found_pwm_subnode == 0) ||
1554 (enable == PM_PWM_MODE_LPG && found_lpg_subnode == 0)) {
1555 dev_err(&spmi->dev, "%s: Invalid mode select\n", __func__);
1556 rc = -EINVAL;
1557 goto out;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001558 }
1559
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001560 pwm_change_mode(pwm_dev, enable);
1561 _pwm_enable(pwm_dev);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001562
1563read_opt_props:
1564 /* Initialize optional config parameters from DT if provided */
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001565 of_property_read_string(node, "qcom,channel-owner",
1566 &pwm_dev->pwm_config.lable);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001567
1568 return 0;
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001569
1570out:
1571 kfree(lut_config->duty_pct_list);
1572 return rc;
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001573}
1574
1575static int __devinit qpnp_pwm_probe(struct spmi_device *spmi)
1576{
1577 struct qpnp_lpg_chip *chip;
1578 int rc, id;
1579
1580 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1581 if (chip == NULL) {
1582 pr_err("kzalloc() failed.\n");
1583 return -ENOMEM;
1584 }
1585
1586 mutex_init(&chip->lpg_mutex);
1587
1588 chip->spmi_dev = spmi;
1589 chip->pwm_dev.chip = chip;
1590 dev_set_drvdata(&spmi->dev, chip);
1591
Jay Chokshi219fcfc2012-07-27 17:39:15 -07001592 rc = qpnp_parse_dt_config(spmi, chip);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001593
1594 if (rc)
1595 goto failed_config;
1596
1597 id = chip->pwm_dev.pwm_config.channel_id;
1598
1599 rc = radix_tree_insert(&lpg_dev_tree, id, chip);
1600
1601 if (rc) {
1602 dev_err(&spmi->dev, "%s: Failed to register LPG Channel %d\n",
1603 __func__, id);
1604 goto failed_insert;
1605 }
1606
1607 return 0;
1608
1609failed_insert:
1610 kfree(chip->lpg_config.lut_config.duty_pct_list);
1611failed_config:
1612 dev_set_drvdata(&spmi->dev, NULL);
1613 mutex_destroy(&chip->lpg_mutex);
1614 kfree(chip);
1615 return rc;
1616}
1617
1618static int __devexit qpnp_pwm_remove(struct spmi_device *spmi)
1619{
1620 struct qpnp_lpg_chip *chip;
1621 struct qpnp_lpg_config *lpg_config;
1622
1623 chip = dev_get_drvdata(&spmi->dev);
1624
1625 dev_set_drvdata(&spmi->dev, NULL);
1626
1627 if (chip) {
1628 lpg_config = &chip->lpg_config;
1629 kfree(lpg_config->lut_config.duty_pct_list);
Jay Chokshi12cc1dd2012-04-30 17:07:35 -07001630 mutex_destroy(&chip->lpg_mutex);
1631 kfree(chip);
1632 }
1633
1634 return 0;
1635}
1636
1637static struct of_device_id spmi_match_table[] = {
1638 { .compatible = QPNP_LPG_DRIVER_NAME, },
1639 {}
1640};
1641
1642static const struct spmi_device_id qpnp_lpg_id[] = {
1643 { QPNP_LPG_DRIVER_NAME, 0 },
1644 { }
1645};
1646MODULE_DEVICE_TABLE(spmi, qpnp_lpg_id);
1647
1648static struct spmi_driver qpnp_lpg_driver = {
1649 .driver = {
1650 .name = QPNP_LPG_DRIVER_NAME,
1651 .of_match_table = spmi_match_table,
1652 .owner = THIS_MODULE,
1653 },
1654 .probe = qpnp_pwm_probe,
1655 .remove = __devexit_p(qpnp_pwm_remove),
1656 .id_table = qpnp_lpg_id,
1657};
1658
1659/**
1660 * qpnp_lpg_init() - register spmi driver for qpnp-lpg
1661 */
1662int __init qpnp_lpg_init(void)
1663{
1664 return spmi_driver_register(&qpnp_lpg_driver);
1665}
1666
1667static void __exit qpnp_lpg_exit(void)
1668{
1669 spmi_driver_unregister(&qpnp_lpg_driver);
1670}
1671
1672MODULE_DESCRIPTION("QPNP PMIC LPG driver");
1673MODULE_LICENSE("GPL v2");
1674MODULE_ALIAS("platform:" QPNP_LPG_DRIVER_NAME);
1675
1676subsys_initcall(qpnp_lpg_init);
1677module_exit(qpnp_lpg_exit);