blob: ca9eebb24a73856d0842f2ff21c4021626cc64a2 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12/*
13 * Qualcomm PM8XXX Pulse Width Modulation (PWM) driver
14 *
15 * The HW module is also called LPG (Light Pulse Generator).
16 */
17
18#define pr_fmt(fmt) "%s: " fmt, __func__
19
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <linux/err.h>
24#include <linux/debugfs.h>
25#include <linux/mfd/pm8xxx/core.h>
26#include <linux/mfd/pm8xxx/pwm.h>
27
28#define PM8XXX_LPG_BANKS 8
29#define PM8XXX_PWM_CHANNELS PM8XXX_LPG_BANKS
30
31#define PM8XXX_LPG_CTL_REGS 7
32
33/* PM8XXX PWM */
34#define SSBI_REG_ADDR_LPG_CTL_BASE 0x13C
35#define SSBI_REG_ADDR_LPG_CTL(n) (SSBI_REG_ADDR_LPG_CTL_BASE + (n))
36#define SSBI_REG_ADDR_LPG_BANK_SEL 0x143
37#define SSBI_REG_ADDR_LPG_BANK_EN 0x144
38#define SSBI_REG_ADDR_LPG_LUT_CFG0 0x145
39#define SSBI_REG_ADDR_LPG_LUT_CFG1 0x146
40
41/* Control 0 */
42#define PM8XXX_PWM_1KHZ_COUNT_MASK 0xF0
43#define PM8XXX_PWM_1KHZ_COUNT_SHIFT 4
44
45#define PM8XXX_PWM_1KHZ_COUNT_MAX 15
46
47#define PM8XXX_PWM_OUTPUT_EN 0x08
48#define PM8XXX_PWM_PWM_EN 0x04
49#define PM8XXX_PWM_RAMP_GEN_EN 0x02
50#define PM8XXX_PWM_RAMP_START 0x01
51
52#define PM8XXX_PWM_PWM_START (PM8XXX_PWM_OUTPUT_EN \
53 | PM8XXX_PWM_PWM_EN)
54#define PM8XXX_PWM_RAMP_GEN_START (PM8XXX_PWM_RAMP_GEN_EN \
55 | PM8XXX_PWM_RAMP_START)
56
57/* Control 1 */
58#define PM8XXX_PWM_REVERSE_EN 0x80
59#define PM8XXX_PWM_BYPASS_LUT 0x40
60#define PM8XXX_PWM_HIGH_INDEX_MASK 0x3F
61
62/* Control 2 */
63#define PM8XXX_PWM_LOOP_EN 0x80
64#define PM8XXX_PWM_RAMP_UP 0x40
65#define PM8XXX_PWM_LOW_INDEX_MASK 0x3F
66
67/* Control 3 */
68#define PM8XXX_PWM_VALUE_BIT7_0 0xFF
69#define PM8XXX_PWM_VALUE_BIT5_0 0x3F
70
71/* Control 4 */
72#define PM8XXX_PWM_VALUE_BIT8 0x80
73
74#define PM8XXX_PWM_CLK_SEL_MASK 0x60
75#define PM8XXX_PWM_CLK_SEL_SHIFT 5
76
77#define PM8XXX_PWM_CLK_SEL_NO 0
78#define PM8XXX_PWM_CLK_SEL_1KHZ 1
79#define PM8XXX_PWM_CLK_SEL_32KHZ 2
80#define PM8XXX_PWM_CLK_SEL_19P2MHZ 3
81
82#define PM8XXX_PWM_PREDIVIDE_MASK 0x18
83#define PM8XXX_PWM_PREDIVIDE_SHIFT 3
84
85#define PM8XXX_PWM_PREDIVIDE_2 0
86#define PM8XXX_PWM_PREDIVIDE_3 1
87#define PM8XXX_PWM_PREDIVIDE_5 2
88#define PM8XXX_PWM_PREDIVIDE_6 3
89
90#define PM8XXX_PWM_M_MASK 0x07
91#define PM8XXX_PWM_M_MIN 0
92#define PM8XXX_PWM_M_MAX 7
93
94/* Control 5 */
95#define PM8XXX_PWM_PAUSE_COUNT_HI_MASK 0xFC
96#define PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT 2
97
98#define PM8XXX_PWM_PAUSE_ENABLE_HIGH 0x02
99#define PM8XXX_PWM_SIZE_9_BIT 0x01
100
101/* Control 6 */
102#define PM8XXX_PWM_PAUSE_COUNT_LO_MASK 0xFC
103#define PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT 2
104
105#define PM8XXX_PWM_PAUSE_ENABLE_LOW 0x02
106#define PM8XXX_PWM_RESERVED 0x01
107
108#define PM8XXX_PWM_PAUSE_COUNT_MAX 56 /* < 2^6 = 64 */
109
110/* LUT_CFG1 */
111#define PM8XXX_PWM_LUT_READ 0x40
112
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700113
114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115/*
116 * PWM Frequency = Clock Frequency / (N * T)
117 * or
118 * PWM Period = Clock Period * (N * T)
119 * where
120 * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
121 * T = Pre-divide * 2^m, where m = 0..7 (exponent)
122 *
123 * This is the formula to figure out m for the best pre-divide and clock:
124 * (PWM Period / N) / 2^m = (Pre-divide * Clock Period)
125 */
126#define NUM_CLOCKS 3
127
128#define NSEC_1000HZ (NSEC_PER_SEC / 1000)
129#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
130#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
131
132#define CLK_PERIOD_MIN NSEC_19P2MHZ
133#define CLK_PERIOD_MAX NSEC_1000HZ
134
135#define NUM_PRE_DIVIDE 3 /* No default support for pre-divide = 6 */
136
137#define PRE_DIVIDE_0 2
138#define PRE_DIVIDE_1 3
139#define PRE_DIVIDE_2 5
140
141#define PRE_DIVIDE_MIN PRE_DIVIDE_0
142#define PRE_DIVIDE_MAX PRE_DIVIDE_2
143
144static unsigned int pt_t[NUM_PRE_DIVIDE][NUM_CLOCKS] = {
145 { PRE_DIVIDE_0 * NSEC_1000HZ,
146 PRE_DIVIDE_0 * NSEC_32768HZ,
147 PRE_DIVIDE_0 * NSEC_19P2MHZ,
148 },
149 { PRE_DIVIDE_1 * NSEC_1000HZ,
150 PRE_DIVIDE_1 * NSEC_32768HZ,
151 PRE_DIVIDE_1 * NSEC_19P2MHZ,
152 },
153 { PRE_DIVIDE_2 * NSEC_1000HZ,
154 PRE_DIVIDE_2 * NSEC_32768HZ,
155 PRE_DIVIDE_2 * NSEC_19P2MHZ,
156 },
157};
158
159#define MIN_MPT ((PRE_DIVIDE_MIN * CLK_PERIOD_MIN) << PM8XXX_PWM_M_MIN)
160#define MAX_MPT ((PRE_DIVIDE_MAX * CLK_PERIOD_MAX) << PM8XXX_PWM_M_MAX)
161
162/* Private data */
163struct pm8xxx_pwm_chip;
164
165struct pwm_device {
166 int pwm_id; /* = bank/channel id */
167 int in_use;
168 const char *label;
Willie Ruan719c6762011-08-25 11:03:14 -0700169 struct pm8xxx_pwm_period period;
170 int pwm_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 int pwm_period;
172 int pwm_duty;
173 u8 pwm_ctl[PM8XXX_LPG_CTL_REGS];
174 int irq;
175 struct pm8xxx_pwm_chip *chip;
Willie Ruan719c6762011-08-25 11:03:14 -0700176 int bypass_lut;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177};
178
179struct pm8xxx_pwm_chip {
180 struct pwm_device pwm_dev[PM8XXX_PWM_CHANNELS];
181 u8 bank_mask;
182 struct mutex pwm_mutex;
183 struct device *dev;
184};
185
186static struct pm8xxx_pwm_chip *pwm_chip;
187
Willie Ruan719c6762011-08-25 11:03:14 -0700188struct pm8xxx_pwm_lut {
189 /* LUT parameters */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 int lut_duty_ms;
191 int lut_lo_index;
192 int lut_hi_index;
193 int lut_pause_hi;
194 int lut_pause_lo;
195 int flags;
196};
197
198static const u16 duty_msec[PM8XXX_PWM_1KHZ_COUNT_MAX + 1] = {
199 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
200};
201
202static const u16 pause_count[PM8XXX_PWM_PAUSE_COUNT_MAX + 1] = {
203 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
204 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
205 375, 500, 667, 750, 800, 900, 1000, 1100,
206 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
207 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
208 7000
209};
210
211/* Internal functions */
Willie Ruan8de2f382011-08-25 11:04:50 -0700212static void pm8xxx_pwm_save(u8 *u8p, u8 mask, u8 val)
213{
214 *u8p &= ~mask;
215 *u8p |= val & mask;
216}
217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218static int pm8xxx_pwm_bank_enable(struct pwm_device *pwm, int enable)
219{
220 int rc;
221 u8 reg;
222 struct pm8xxx_pwm_chip *chip;
223
224 chip = pwm->chip;
225
226 if (enable)
227 reg = chip->bank_mask | (1 << pwm->pwm_id);
228 else
229 reg = chip->bank_mask & ~(1 << pwm->pwm_id);
230
231 rc = pm8xxx_writeb(chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
232 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700233 pr_err("pm8xxx_writeb(): rc=%d (Enable LPG Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 return rc;
235 }
236 chip->bank_mask = reg;
237
238 return 0;
239}
240
241static int pm8xxx_pwm_bank_sel(struct pwm_device *pwm)
242{
243 int rc;
244
245 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_SEL,
246 pwm->pwm_id);
247 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700248 pr_err("pm8xxx_writeb(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 return rc;
250}
251
252static int pm8xxx_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
253{
254 int rc;
255 u8 reg;
256
257 if (start) {
258 reg = pwm->pwm_ctl[0] | PM8XXX_PWM_PWM_START;
259 if (ramp_start)
260 reg |= PM8XXX_PWM_RAMP_GEN_START;
261 else
262 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
263 } else {
264 reg = pwm->pwm_ctl[0] & ~PM8XXX_PWM_PWM_START;
265 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
266 }
267
268 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
269 reg);
270 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700271 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 else
273 pwm->pwm_ctl[0] = reg;
274 return rc;
275}
276
277static void pm8xxx_pwm_calc_period(unsigned int period_us,
Willie Ruan719c6762011-08-25 11:03:14 -0700278 struct pm8xxx_pwm_period *period)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279{
280 int n, m, clk, div;
281 int best_m, best_div, best_clk;
282 int last_err, cur_err, better_err, better_m;
283 unsigned int tmp_p, last_p, min_err, period_n;
284
285 /* PWM Period / N */
286 if (period_us < (40 * USEC_PER_SEC)) { /* ~6-bit max */
287 period_n = (period_us * NSEC_PER_USEC) >> 6;
288 n = 6;
289 } else if (period_us < (274 * USEC_PER_SEC)) { /* overflow threshold */
290 period_n = (period_us >> 6) * NSEC_PER_USEC;
291 if (period_n >= MAX_MPT) {
292 n = 9;
293 period_n >>= 3;
294 } else {
295 n = 6;
296 }
297 } else {
298 period_n = (period_us >> 9) * NSEC_PER_USEC;
299 n = 9;
300 }
301
302 min_err = MAX_MPT;
303 best_m = 0;
304 best_clk = 0;
305 best_div = 0;
306 for (clk = 0; clk < NUM_CLOCKS; clk++) {
307 for (div = 0; div < NUM_PRE_DIVIDE; div++) {
308 tmp_p = period_n;
309 last_p = tmp_p;
310 for (m = 0; m <= PM8XXX_PWM_M_MAX; m++) {
311 if (tmp_p <= pt_t[div][clk]) {
312 /* Found local best */
313 if (!m) {
314 better_err = pt_t[div][clk] -
315 tmp_p;
316 better_m = m;
317 } else {
318 last_err = last_p -
319 pt_t[div][clk];
320 cur_err = pt_t[div][clk] -
321 tmp_p;
322
323 if (cur_err < last_err) {
324 better_err = cur_err;
325 better_m = m;
326 } else {
327 better_err = last_err;
328 better_m = m - 1;
329 }
330 }
331
332 if (better_err < min_err) {
333 min_err = better_err;
334 best_m = better_m;
335 best_clk = clk;
336 best_div = div;
337 }
338 break;
339 } else {
340 last_p = tmp_p;
341 tmp_p >>= 1;
342 }
343 }
344 }
345 }
346
Willie Ruan75d9e5b2011-08-25 10:59:17 -0700347 /* Use higher resolution */
348 if (best_m >= 3 && n == 6) {
349 n += 3;
350 best_m -= 3;
351 }
352
Willie Ruan719c6762011-08-25 11:03:14 -0700353 period->pwm_size = n;
354 period->clk = best_clk;
355 period->pre_div = best_div;
356 period->pre_div_exp = best_m;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357}
358
Willie Ruan8de2f382011-08-25 11:04:50 -0700359static void pm8xxx_pwm_calc_pwm_value(struct pwm_device *pwm,
360 unsigned int period_us,
361 unsigned int duty_us)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362{
Willie Ruan8de2f382011-08-25 11:04:50 -0700363 unsigned int max_pwm_value, tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364
Willie Ruan8de2f382011-08-25 11:04:50 -0700365 /* Figure out pwm_value with overflow handling */
366 tmp = 1 << (sizeof(tmp) * 8 - pwm->period.pwm_size);
367 if (duty_us < tmp) {
368 tmp = duty_us << pwm->period.pwm_size;
369 pwm->pwm_value = tmp / period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 } else {
Willie Ruan8de2f382011-08-25 11:04:50 -0700371 tmp = period_us >> pwm->period.pwm_size;
372 pwm->pwm_value = duty_us / tmp;
373 }
374 max_pwm_value = (1 << pwm->period.pwm_size) - 1;
375 if (pwm->pwm_value > max_pwm_value)
376 pwm->pwm_value = max_pwm_value;
377}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378
Willie Ruan8de2f382011-08-25 11:04:50 -0700379static int pm8xxx_pwm_change_table(struct pwm_device *pwm, int duty_pct[],
380 int start_idx, int len, int raw_value)
381{
382 unsigned int pwm_value, max_pwm_value;
383 u8 cfg0, cfg1;
384 int i, pwm_size;
385 int rc = 0;
386
387 pwm_size = (pwm->pwm_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
388 max_pwm_value = (1 << pwm_size) - 1;
389 for (i = 0; i < len; i++) {
390 if (raw_value)
391 pwm_value = duty_pct[i];
392 else
393 pwm_value = (duty_pct[i] << pwm_size) / 100;
394
395 if (pwm_value > max_pwm_value)
396 pwm_value = max_pwm_value;
397 cfg0 = pwm_value;
398 cfg1 = (pwm_value >> 1) & 0x80;
399 cfg1 |= start_idx + i;
400
401 rc = pm8xxx_writeb(pwm->chip->dev->parent,
402 SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
403 if (rc)
404 break;
405
406 rc = pm8xxx_writeb(pwm->chip->dev->parent,
407 SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
408 if (rc)
409 break;
410 }
411 return rc;
412}
413
414static void pm8xxx_pwm_save_index(struct pwm_device *pwm,
415 int low_idx, int high_idx, int flags)
416{
417 pwm->pwm_ctl[1] = high_idx & PM8XXX_PWM_HIGH_INDEX_MASK;
418 pwm->pwm_ctl[2] = low_idx & PM8XXX_PWM_LOW_INDEX_MASK;
419
420 if (flags & PM_PWM_LUT_REVERSE)
421 pwm->pwm_ctl[1] |= PM8XXX_PWM_REVERSE_EN;
422 if (flags & PM_PWM_LUT_RAMP_UP)
423 pwm->pwm_ctl[2] |= PM8XXX_PWM_RAMP_UP;
424 if (flags & PM_PWM_LUT_LOOP)
425 pwm->pwm_ctl[2] |= PM8XXX_PWM_LOOP_EN;
426}
427
428static void pm8xxx_pwm_save_period(struct pwm_device *pwm)
429{
430 u8 mask, val;
431
432 val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
433 & PM8XXX_PWM_CLK_SEL_MASK;
434 val |= (pwm->period.pre_div << PM8XXX_PWM_PREDIVIDE_SHIFT)
435 & PM8XXX_PWM_PREDIVIDE_MASK;
436 val |= pwm->period.pre_div_exp & PM8XXX_PWM_M_MASK;
437 mask = PM8XXX_PWM_CLK_SEL_MASK | PM8XXX_PWM_PREDIVIDE_MASK |
438 PM8XXX_PWM_M_MASK;
439 pm8xxx_pwm_save(&pwm->pwm_ctl[4], mask, val);
440
441 val = (pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0;
442 mask = PM8XXX_PWM_SIZE_9_BIT;
443 pm8xxx_pwm_save(&pwm->pwm_ctl[5], mask, val);
444}
445
446static void pm8xxx_pwm_save_pwm_value(struct pwm_device *pwm)
447{
448 u8 mask, val;
449
450 pwm->pwm_ctl[3] = pwm->pwm_value;
451
452 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 1) : 0;
453 mask = PM8XXX_PWM_VALUE_BIT8;
454 pm8xxx_pwm_save(&pwm->pwm_ctl[4], mask, val);
455}
456
457static void pm8xxx_pwm_save_duty_time(struct pwm_device *pwm,
458 struct pm8xxx_pwm_lut *lut)
459{
460 int i;
461 u8 mask, val;
462
463 /* Linear search for duty time */
464 for (i = 0; i < PM8XXX_PWM_1KHZ_COUNT_MAX; i++) {
465 if (duty_msec[i] >= lut->lut_duty_ms)
466 break;
467 }
468 val = i << PM8XXX_PWM_1KHZ_COUNT_SHIFT;
469
470 mask = PM8XXX_PWM_1KHZ_COUNT_MASK;
471 pm8xxx_pwm_save(&pwm->pwm_ctl[0], mask, val);
472}
473
474static void pm8xxx_pwm_save_pause(struct pwm_device *pwm,
475 struct pm8xxx_pwm_lut *lut)
476{
477 int i, pause_cnt, time_cnt;
478 u8 mask, val;
479
480 time_cnt = (pwm->pwm_ctl[0] & PM8XXX_PWM_1KHZ_COUNT_MASK)
481 >> PM8XXX_PWM_1KHZ_COUNT_SHIFT;
482 if (lut->flags & PM_PWM_LUT_PAUSE_HI_EN) {
483 pause_cnt = (lut->lut_pause_hi + duty_msec[time_cnt] / 2)
484 / duty_msec[time_cnt];
485 /* Linear search for pause time */
486 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
487 if (pause_count[i] >= pause_cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 break;
489 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700490 val = (i << PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT) &
491 PM8XXX_PWM_PAUSE_COUNT_HI_MASK;
492 val |= PM8XXX_PWM_PAUSE_ENABLE_HIGH;
493 } else {
494 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 }
496
Willie Ruan8de2f382011-08-25 11:04:50 -0700497 mask = PM8XXX_PWM_PAUSE_COUNT_HI_MASK | PM8XXX_PWM_PAUSE_ENABLE_HIGH;
498 pm8xxx_pwm_save(&pwm->pwm_ctl[5], mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499
Willie Ruan8de2f382011-08-25 11:04:50 -0700500 if (lut->flags & PM_PWM_LUT_PAUSE_LO_EN) {
501 /* Linear search for pause time */
502 pause_cnt = (lut->lut_pause_lo + duty_msec[time_cnt] / 2)
503 / duty_msec[time_cnt];
504 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
505 if (pause_count[i] >= pause_cnt)
506 break;
507 }
508 val = (i << PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT) &
509 PM8XXX_PWM_PAUSE_COUNT_LO_MASK;
510 val |= PM8XXX_PWM_PAUSE_ENABLE_LOW;
511 } else {
512 val = 0;
513 }
514
515 mask = PM8XXX_PWM_PAUSE_COUNT_LO_MASK | PM8XXX_PWM_PAUSE_ENABLE_LOW;
516 pm8xxx_pwm_save(&pwm->pwm_ctl[6], mask, val);
517}
518
519static int pm8xxx_pwm_write(struct pwm_device *pwm, int start, int end)
520{
521 int i, rc;
522
523 /* Write in reverse way so 0 would be the last */
524 for (i = end - 1; i >= start; i--) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525 rc = pm8xxx_writeb(pwm->chip->dev->parent,
526 SSBI_REG_ADDR_LPG_CTL(i),
527 pwm->pwm_ctl[i]);
528 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700529 pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[%d])\n", rc, i);
530 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531 }
532 }
533
Willie Ruan8de2f382011-08-25 11:04:50 -0700534 return 0;
535}
536
537static int pm8xxx_pwm_change_lut(struct pwm_device *pwm,
538 struct pm8xxx_pwm_lut *lut)
539{
540 int rc;
541
542 pm8xxx_pwm_save_index(pwm, lut->lut_lo_index,
543 lut->lut_hi_index, lut->flags);
544 pm8xxx_pwm_save_duty_time(pwm, lut);
545 pm8xxx_pwm_save_pause(pwm, lut);
546 pm8xxx_pwm_save(&pwm->pwm_ctl[1], PM8XXX_PWM_BYPASS_LUT, 0);
547
548 pm8xxx_pwm_bank_sel(pwm);
549 rc = pm8xxx_pwm_write(pwm, 0, 7);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550
551 return rc;
552}
553
554/* APIs */
555/**
556 * pwm_request - request a PWM device
557 * @pwm_id: PWM id or channel
558 * @label: the label to identify the user
559 */
560struct pwm_device *pwm_request(int pwm_id, const char *label)
561{
562 struct pwm_device *pwm;
563
564 if (pwm_id > PM8XXX_PWM_CHANNELS || pwm_id < 0) {
565 pr_err("Invalid pwm_id: %d with %s\n",
566 pwm_id, label ? label : ".");
567 return ERR_PTR(-EINVAL);
568 }
569 if (pwm_chip == NULL) {
570 pr_err("No pwm_chip\n");
571 return ERR_PTR(-ENODEV);
572 }
573
574 mutex_lock(&pwm_chip->pwm_mutex);
575 pwm = &pwm_chip->pwm_dev[pwm_id];
576 if (!pwm->in_use) {
577 pwm->in_use = 1;
578 pwm->label = label;
579 } else {
580 pwm = ERR_PTR(-EBUSY);
581 }
582 mutex_unlock(&pwm_chip->pwm_mutex);
583
584 return pwm;
585}
586EXPORT_SYMBOL_GPL(pwm_request);
587
588/**
589 * pwm_free - free a PWM device
590 * @pwm: the PWM device
591 */
592void pwm_free(struct pwm_device *pwm)
593{
594 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
595 pr_err("Invalid pwm handle\n");
596 return;
597 }
598
599 mutex_lock(&pwm->chip->pwm_mutex);
600 if (pwm->in_use) {
601 pm8xxx_pwm_bank_sel(pwm);
602 pm8xxx_pwm_start(pwm, 0, 0);
603
604 pwm->in_use = 0;
605 pwm->label = NULL;
606 }
607 pm8xxx_pwm_bank_enable(pwm, 0);
608 mutex_unlock(&pwm->chip->pwm_mutex);
609}
610EXPORT_SYMBOL_GPL(pwm_free);
611
612/**
613 * pwm_config - change a PWM device configuration
614 * @pwm: the PWM device
615 * @period_us: period in microseconds
616 * @duty_us: duty cycle in microseconds
617 */
618int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
619{
Willie Ruan719c6762011-08-25 11:03:14 -0700620 struct pm8xxx_pwm_period *period;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 int rc;
622
623 if (pwm == NULL || IS_ERR(pwm) ||
624 duty_us > period_us ||
625 (unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
626 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
627 pr_err("Invalid pwm handle or parameters\n");
628 return -EINVAL;
629 }
630 if (pwm->chip == NULL) {
631 pr_err("No pwm_chip\n");
632 return -ENODEV;
633 }
634
Willie Ruan719c6762011-08-25 11:03:14 -0700635 period = &pwm->period;
636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 mutex_lock(&pwm->chip->pwm_mutex);
638
639 if (!pwm->in_use) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 rc = -EINVAL;
641 goto out_unlock;
642 }
643
Willie Ruan8de2f382011-08-25 11:04:50 -0700644 if (pwm->pwm_period != period_us) {
645 pm8xxx_pwm_calc_period(period_us, period);
646 pm8xxx_pwm_save_period(pwm);
647 pwm->pwm_period = period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700648 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649
Willie Ruan8de2f382011-08-25 11:04:50 -0700650 pm8xxx_pwm_calc_pwm_value(pwm, period_us, duty_us);
651 pm8xxx_pwm_save_pwm_value(pwm);
652 pm8xxx_pwm_save(&pwm->pwm_ctl[1],
653 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654
Willie Ruan8de2f382011-08-25 11:04:50 -0700655 pm8xxx_pwm_bank_sel(pwm);
656 rc = pm8xxx_pwm_write(pwm, 1, 6);
657
658 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
659 (unsigned)duty_us, (unsigned)period_us,
660 pwm->pwm_value, 1 << period->pwm_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661
662out_unlock:
663 mutex_unlock(&pwm->chip->pwm_mutex);
664 return rc;
665}
666EXPORT_SYMBOL_GPL(pwm_config);
667
668/**
669 * pwm_enable - start a PWM output toggling
670 * @pwm: the PWM device
671 */
672int pwm_enable(struct pwm_device *pwm)
673{
674 int rc;
675
676 if (pwm == NULL || IS_ERR(pwm)) {
677 pr_err("Invalid pwm handle\n");
678 return -EINVAL;
679 }
680 if (pwm->chip == NULL) {
681 pr_err("No pwm_chip\n");
682 return -ENODEV;
683 }
684
685 mutex_lock(&pwm->chip->pwm_mutex);
686 if (!pwm->in_use) {
687 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
688 rc = -EINVAL;
689 } else {
690 rc = pm8xxx_pwm_bank_enable(pwm, 1);
691
692 pm8xxx_pwm_bank_sel(pwm);
693 pm8xxx_pwm_start(pwm, 1, 0);
694 }
695 mutex_unlock(&pwm->chip->pwm_mutex);
696 return rc;
697}
698EXPORT_SYMBOL_GPL(pwm_enable);
699
700/**
701 * pwm_disable - stop a PWM output toggling
702 * @pwm: the PWM device
703 */
704void pwm_disable(struct pwm_device *pwm)
705{
706 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
707 pr_err("Invalid pwm handle or no pwm_chip\n");
708 return;
709 }
710
711 mutex_lock(&pwm->chip->pwm_mutex);
712 if (pwm->in_use) {
713 pm8xxx_pwm_bank_sel(pwm);
714 pm8xxx_pwm_start(pwm, 0, 0);
715
716 pm8xxx_pwm_bank_enable(pwm, 0);
717 }
718 mutex_unlock(&pwm->chip->pwm_mutex);
719}
720EXPORT_SYMBOL_GPL(pwm_disable);
721
722/**
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700723 * pm8xxx_pwm_config_period - change PWM period
724 *
725 * @pwm: the PWM device
726 * @pwm_p: period in struct pm8xxx_pwm_period
727 */
728int pm8xxx_pwm_config_period(struct pwm_device *pwm,
729 struct pm8xxx_pwm_period *period)
730{
731 int rc;
732
733 if (pwm == NULL || IS_ERR(pwm) || period == NULL)
734 return -EINVAL;
735 if (pwm->chip == NULL)
736 return -ENODEV;
737
738 mutex_lock(&pwm->chip->pwm_mutex);
739
740 if (!pwm->in_use) {
741 rc = -EINVAL;
742 goto out_unlock;
743 }
744
745 pwm->period.pwm_size = period->pwm_size;
746 pwm->period.clk = period->clk;
747 pwm->period.pre_div = period->pre_div;
748 pwm->period.pre_div_exp = period->pre_div_exp;
749
750 pm8xxx_pwm_save_period(pwm);
751 pm8xxx_pwm_bank_sel(pwm);
752 rc = pm8xxx_pwm_write(pwm, 4, 6);
753
754out_unlock:
755 mutex_unlock(&pwm->chip->pwm_mutex);
756 return rc;
757}
758EXPORT_SYMBOL(pm8xxx_pwm_config_period);
759
760/**
761 * pm8xxx_pwm_config_pwm_value - change a PWM device configuration
762 * @pwm: the PWM device
763 * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
764 */
765int pm8xxx_pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
766{
767 int rc = 0;
768
769 if (pwm == NULL || IS_ERR(pwm))
770 return -EINVAL;
771 if (pwm->chip == NULL)
772 return -ENODEV;
773
774 mutex_lock(&pwm->chip->pwm_mutex);
775
776 if (!pwm->in_use || !pwm->pwm_period) {
777 rc = -EINVAL;
778 goto out_unlock;
779 }
780
781 if (pwm->pwm_value == pwm_value)
782 goto out_unlock;
783
784 pwm->pwm_value = pwm_value;
785
786 pm8xxx_pwm_save_pwm_value(pwm);
787 pm8xxx_pwm_save(&pwm->pwm_ctl[1],
788 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
789
790 pm8xxx_pwm_bank_sel(pwm);
791 rc = pm8xxx_pwm_write(pwm, 1, 6);
792
793 if (rc)
794 pr_err("[%d]: pm8xxx_pwm_write: rc=%d\n", pwm->pwm_id, rc);
795
796out_unlock:
797 mutex_unlock(&pwm->chip->pwm_mutex);
798 return rc;
799}
800EXPORT_SYMBOL_GPL(pm8xxx_pwm_config_pwm_value);
801
802/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803 * pm8xxx_pwm_lut_config - change a PWM device configuration to use LUT
804 * @pwm: the PWM device
805 * @period_us: period in microseconds
806 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
807 * @duty_time_ms: time for each duty cycle in milliseconds
808 * @start_idx: start index in lookup table from 0 to MAX-1
809 * @idx_len: number of index
810 * @pause_lo: pause time in milliseconds at low index
811 * @pause_hi: pause time in milliseconds at high index
812 * @flags: control flags
813 */
814int pm8xxx_pwm_lut_config(struct pwm_device *pwm, int period_us,
815 int duty_pct[], int duty_time_ms, int start_idx,
816 int idx_len, int pause_lo, int pause_hi, int flags)
817{
Willie Ruan719c6762011-08-25 11:03:14 -0700818 struct pm8xxx_pwm_lut lut;
819 struct pm8xxx_pwm_period *period;
Willie Ruan8de2f382011-08-25 11:04:50 -0700820 int len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 int rc;
822
823 if (pwm == NULL || IS_ERR(pwm) || !idx_len) {
824 pr_err("Invalid pwm handle or idx_len=0\n");
825 return -EINVAL;
826 }
827 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE)) {
828 pr_err("Invalid duty_pct with flag\n");
829 return -EINVAL;
830 }
831 if (pwm->chip == NULL) {
832 pr_err("No pwm_chip\n");
833 return -ENODEV;
834 }
835 if (idx_len >= PM_PWM_LUT_SIZE && start_idx) {
836 pr_err("Wrong LUT size or index\n");
837 return -EINVAL;
838 }
839 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE) {
840 pr_err("Exceed LUT limit\n");
841 return -EINVAL;
842 }
843 if ((unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
844 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
845 pr_err("Period out of range\n");
846 return -EINVAL;
847 }
848
Willie Ruan719c6762011-08-25 11:03:14 -0700849 period = &pwm->period;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 mutex_lock(&pwm->chip->pwm_mutex);
851
852 if (!pwm->in_use) {
853 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
854 rc = -EINVAL;
855 goto out_unlock;
856 }
857
Willie Ruan8de2f382011-08-25 11:04:50 -0700858 if (pwm->pwm_period != period_us) {
859 pm8xxx_pwm_calc_period(period_us, period);
860 pm8xxx_pwm_save_period(pwm);
861 pwm->pwm_period = period_us;
862 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863
864 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
865
866 if (flags & PM_PWM_LUT_NO_TABLE)
867 goto after_table_write;
868
Willie Ruan8de2f382011-08-25 11:04:50 -0700869 rc = pm8xxx_pwm_change_table(pwm, duty_pct, start_idx, len, 0);
870 if (rc) {
871 pr_err("pm8xxx_pwm_change_table: rc=%d\n", rc);
872 goto out_unlock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700873 }
874
875after_table_write:
Willie Ruan719c6762011-08-25 11:03:14 -0700876 lut.lut_duty_ms = duty_time_ms;
877 lut.lut_lo_index = start_idx;
878 lut.lut_hi_index = start_idx + len - 1;
879 lut.lut_pause_lo = pause_lo;
880 lut.lut_pause_hi = pause_hi;
881 lut.flags = flags;
882 pwm->bypass_lut = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883
Willie Ruan8de2f382011-08-25 11:04:50 -0700884 rc = pm8xxx_pwm_change_lut(pwm, &lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885
886out_unlock:
887 mutex_unlock(&pwm->chip->pwm_mutex);
888 return rc;
889}
890EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_config);
891
892/**
893 * pm8xxx_pwm_lut_enable - control a PWM device to start/stop LUT ramp
894 * @pwm: the PWM device
895 * @start: to start (1), or stop (0)
896 */
897int pm8xxx_pwm_lut_enable(struct pwm_device *pwm, int start)
898{
899 if (pwm == NULL || IS_ERR(pwm)) {
900 pr_err("Invalid pwm handle\n");
901 return -EINVAL;
902 }
903 if (pwm->chip == NULL) {
904 pr_err("No pwm_chip\n");
905 return -ENODEV;
906 }
907
908 mutex_lock(&pwm->chip->pwm_mutex);
909 if (start) {
910 pm8xxx_pwm_bank_enable(pwm, 1);
911
912 pm8xxx_pwm_bank_sel(pwm);
913 pm8xxx_pwm_start(pwm, 1, 1);
914 } else {
915 pm8xxx_pwm_bank_sel(pwm);
916 pm8xxx_pwm_start(pwm, 0, 0);
917
918 pm8xxx_pwm_bank_enable(pwm, 0);
919 }
920 mutex_unlock(&pwm->chip->pwm_mutex);
921 return 0;
922}
923EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_enable);
924
925#if defined(CONFIG_DEBUG_FS)
926
927struct pm8xxx_pwm_dbg_device;
928
929struct pm8xxx_pwm_user {
930 int pwm_id;
931 struct pwm_device *pwm;
932 int period;
933 int duty_cycle;
934 int enable;
935 struct pm8xxx_pwm_dbg_device *dbgdev;
936};
937
938struct pm8xxx_pwm_dbg_device {
939 struct mutex dbg_mutex;
940 struct device *dev;
941 struct dentry *dent;
942
943 struct pm8xxx_pwm_user user[PM8XXX_PWM_CHANNELS];
944};
945
946static struct pm8xxx_pwm_dbg_device *pmic_dbg_device;
947
948static int dbg_pwm_check_period(int period)
949{
950 if (period < PM8XXX_PWM_PERIOD_MIN || period > PM8XXX_PWM_PERIOD_MAX) {
951 pr_err("period is invalid: %d\n", period);
952 return -EINVAL;
953 }
954 return 0;
955}
956
957static int dbg_pwm_check_duty_cycle(int duty_cycle, const char *func_name)
958{
959 if (duty_cycle <= 0 || duty_cycle > 100) {
960 pr_err("%s: duty_cycle is invalid: %d\n",
961 func_name, duty_cycle);
962 return -EINVAL;
963 }
964 return 0;
965}
966
967static void dbg_pwm_check_handle(struct pm8xxx_pwm_user *puser)
968{
969 struct pwm_device *tmp;
970
971 if (puser->pwm == NULL) {
972 tmp = pwm_request(puser->pwm_id, "pwm-dbg");
973 if (PTR_ERR(puser->pwm)) {
974 pr_err("pwm_request: err=%ld\n", PTR_ERR(puser->pwm));
975 puser->pwm = NULL;
Willie Ruan10976ea2011-08-25 11:01:15 -0700976 } else {
977 pr_debug("[id=%d] pwm_request ok\n", puser->pwm_id);
978 puser->pwm = tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979 }
980 }
981}
982
983static int dbg_pwm_enable_set(void *data, u64 val)
984{
985 struct pm8xxx_pwm_user *puser = data;
986 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
987 int rc;
988
989 mutex_lock(&dbgdev->dbg_mutex);
990 rc = dbg_pwm_check_duty_cycle(puser->duty_cycle, __func__);
991 if (!rc) {
992 puser->enable = val;
993 dbg_pwm_check_handle(puser);
994 if (puser->pwm) {
995 if (puser->enable)
996 pwm_enable(puser->pwm);
997 else
998 pwm_disable(puser->pwm);
999 }
1000 }
1001 mutex_unlock(&dbgdev->dbg_mutex);
1002 return 0;
1003}
1004
1005static int dbg_pwm_enable_get(void *data, u64 *val)
1006{
1007 struct pm8xxx_pwm_user *puser = data;
1008 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1009
1010 mutex_lock(&dbgdev->dbg_mutex);
1011 *val = puser->enable;
1012 mutex_unlock(&dbgdev->dbg_mutex);
1013 return 0;
1014}
1015
1016DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_enable_fops,
1017 dbg_pwm_enable_get, dbg_pwm_enable_set,
1018 "%lld\n");
1019
1020static int dbg_pwm_duty_cycle_set(void *data, u64 val)
1021{
1022 struct pm8xxx_pwm_user *puser = data;
1023 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1024 int rc;
1025
1026 mutex_lock(&dbgdev->dbg_mutex);
1027 rc = dbg_pwm_check_duty_cycle(val, __func__);
1028 if (!rc) {
1029 puser->duty_cycle = val;
1030 dbg_pwm_check_handle(puser);
1031 if (puser->pwm) {
1032 int duty_us;
1033
Willie Ruan10976ea2011-08-25 11:01:15 -07001034 duty_us = puser->duty_cycle * puser->period / 100;
1035 pwm_config(puser->pwm, duty_us, puser->period);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036 }
1037 }
1038 mutex_unlock(&dbgdev->dbg_mutex);
1039 return 0;
1040}
1041
1042static int dbg_pwm_duty_cycle_get(void *data, u64 *val)
1043{
1044 struct pm8xxx_pwm_user *puser = data;
1045 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1046
1047 mutex_lock(&dbgdev->dbg_mutex);
1048 *val = puser->duty_cycle;
1049 mutex_unlock(&dbgdev->dbg_mutex);
1050 return 0;
1051}
1052
1053DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_duty_cycle_fops,
1054 dbg_pwm_duty_cycle_get, dbg_pwm_duty_cycle_set,
1055 "%lld\n");
1056
1057static int dbg_pwm_period_set(void *data, u64 val)
1058{
1059 struct pm8xxx_pwm_user *puser = data;
1060 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1061 int rc;
1062
1063 mutex_lock(&dbgdev->dbg_mutex);
1064 rc = dbg_pwm_check_period(val);
1065 if (!rc)
1066 puser->period = val;
1067 mutex_unlock(&dbgdev->dbg_mutex);
1068 return 0;
1069}
1070
1071static int dbg_pwm_period_get(void *data, u64 *val)
1072{
1073 struct pm8xxx_pwm_user *puser = data;
1074 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1075
1076 mutex_lock(&dbgdev->dbg_mutex);
1077 *val = puser->period;
1078 mutex_unlock(&dbgdev->dbg_mutex);
1079 return 0;
1080}
1081
1082DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_period_fops,
1083 dbg_pwm_period_get, dbg_pwm_period_set, "%lld\n");
1084
1085static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1086{
1087 struct pm8xxx_pwm_dbg_device *dbgdev;
1088 struct dentry *dent;
1089 struct dentry *temp;
1090 struct pm8xxx_pwm_user *puser;
1091 int i;
1092
1093 if (dev == NULL) {
1094 pr_err("no parent data passed in.\n");
1095 return -EINVAL;
1096 }
1097
1098 dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
1099 if (dbgdev == NULL) {
1100 pr_err("kzalloc() failed.\n");
1101 return -ENOMEM;
1102 }
1103
1104 mutex_init(&dbgdev->dbg_mutex);
1105
1106 dbgdev->dev = dev;
1107
1108 dent = debugfs_create_dir("pm8xxx-pwm-dbg", NULL);
1109 if (dent == NULL || IS_ERR(dent)) {
1110 pr_err("ERR debugfs_create_dir: dent=%p\n", dent);
1111 return -ENOMEM;
1112 }
1113
1114 dbgdev->dent = dent;
1115
1116 for (i = 0; i < PM8XXX_PWM_CHANNELS; i++) {
1117 char pwm_ch[] = "0";
1118
1119 pwm_ch[0] = '0' + i;
1120 dent = debugfs_create_dir(pwm_ch, dbgdev->dent);
1121 if (dent == NULL || IS_ERR(dent)) {
1122 pr_err("ERR: pwm=%d: dir: dent=%p\n", i, dent);
1123 goto debug_error;
1124 }
1125
1126 puser = &dbgdev->user[i];
1127 puser->dbgdev = dbgdev;
1128 puser->pwm_id = i;
1129 temp = debugfs_create_file("period", S_IRUGO | S_IWUSR,
1130 dent, puser, &dbg_pwm_period_fops);
1131 if (temp == NULL || IS_ERR(temp)) {
1132 pr_err("ERR: pwm=%d: period: dent=%p\n", i, dent);
1133 goto debug_error;
1134 }
1135
1136 temp = debugfs_create_file("duty-cycle", S_IRUGO | S_IWUSR,
1137 dent, puser, &dbg_pwm_duty_cycle_fops);
1138 if (temp == NULL || IS_ERR(temp)) {
1139 pr_err("ERR: pwm=%d: duty-cycle: dent=%p\n", i, dent);
1140 goto debug_error;
1141 }
1142
1143 temp = debugfs_create_file("enable", S_IRUGO | S_IWUSR,
1144 dent, puser, &dbg_pwm_enable_fops);
1145 if (temp == NULL || IS_ERR(temp)) {
1146 pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);
1147 goto debug_error;
1148 }
1149 }
1150
1151 pmic_dbg_device = dbgdev;
1152
1153 return 0;
1154
1155debug_error:
1156 debugfs_remove_recursive(dbgdev->dent);
1157 return -ENOMEM;
1158}
1159
1160static int __devexit pm8xxx_pwm_dbg_remove(void)
1161{
1162 if (pmic_dbg_device) {
1163 debugfs_remove_recursive(pmic_dbg_device->dent);
1164 kfree(pmic_dbg_device);
1165 }
1166 return 0;
1167}
1168
1169#else
1170
1171static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1172{
1173 return 0;
1174}
1175
1176static int __devexit pm8xxx_pwm_dbg_remove(void)
1177{
1178 return 0;
1179}
1180
1181#endif
1182
1183static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
1184{
1185 struct pm8xxx_pwm_chip *chip;
1186 int i;
1187
1188 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1189 if (chip == NULL) {
1190 pr_err("kzalloc() failed.\n");
1191 return -ENOMEM;
1192 }
1193
1194 for (i = 0; i < PM8XXX_PWM_CHANNELS; i++) {
1195 chip->pwm_dev[i].pwm_id = i;
1196 chip->pwm_dev[i].chip = chip;
1197 }
1198
1199 mutex_init(&chip->pwm_mutex);
1200
1201 chip->dev = &pdev->dev;
1202 pwm_chip = chip;
1203 platform_set_drvdata(pdev, chip);
1204
1205 if (pm8xxx_pwm_dbg_probe(&pdev->dev) < 0)
1206 pr_err("could not set up debugfs\n");
1207
1208 pr_notice("OK\n");
1209 return 0;
1210}
1211
1212static int __devexit pm8xxx_pwm_remove(struct platform_device *pdev)
1213{
1214 struct pm8xxx_pwm_chip *chip = dev_get_drvdata(pdev->dev.parent);
1215
1216 pm8xxx_pwm_dbg_remove();
1217 mutex_destroy(&chip->pwm_mutex);
1218 platform_set_drvdata(pdev, NULL);
1219 kfree(chip);
1220 return 0;
1221}
1222
1223static struct platform_driver pm8xxx_pwm_driver = {
1224 .probe = pm8xxx_pwm_probe,
1225 .remove = __devexit_p(pm8xxx_pwm_remove),
1226 .driver = {
1227 .name = PM8XXX_PWM_DEV_NAME,
1228 .owner = THIS_MODULE,
1229 },
1230};
1231
1232static int __init pm8xxx_pwm_init(void)
1233{
1234 return platform_driver_register(&pm8xxx_pwm_driver);
1235}
1236
1237static void __exit pm8xxx_pwm_exit(void)
1238{
1239 platform_driver_unregister(&pm8xxx_pwm_driver);
1240}
1241
1242subsys_initcall(pm8xxx_pwm_init);
1243module_exit(pm8xxx_pwm_exit);
1244
1245MODULE_LICENSE("GPL v2");
1246MODULE_DESCRIPTION("PM8XXX PWM driver");
1247MODULE_VERSION("1.0");
1248MODULE_ALIAS("platform:" PM8XXX_PWM_DEV_NAME);