blob: da3d12487386429db934b465fe8428ccc8179d76 [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
113/*
114 * PWM Frequency = Clock Frequency / (N * T)
115 * or
116 * PWM Period = Clock Period * (N * T)
117 * where
118 * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
119 * T = Pre-divide * 2^m, where m = 0..7 (exponent)
120 *
121 * This is the formula to figure out m for the best pre-divide and clock:
122 * (PWM Period / N) / 2^m = (Pre-divide * Clock Period)
123 */
124#define NUM_CLOCKS 3
125
126#define NSEC_1000HZ (NSEC_PER_SEC / 1000)
127#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
128#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
129
130#define CLK_PERIOD_MIN NSEC_19P2MHZ
131#define CLK_PERIOD_MAX NSEC_1000HZ
132
133#define NUM_PRE_DIVIDE 3 /* No default support for pre-divide = 6 */
134
135#define PRE_DIVIDE_0 2
136#define PRE_DIVIDE_1 3
137#define PRE_DIVIDE_2 5
138
139#define PRE_DIVIDE_MIN PRE_DIVIDE_0
140#define PRE_DIVIDE_MAX PRE_DIVIDE_2
141
142static unsigned int pt_t[NUM_PRE_DIVIDE][NUM_CLOCKS] = {
143 { PRE_DIVIDE_0 * NSEC_1000HZ,
144 PRE_DIVIDE_0 * NSEC_32768HZ,
145 PRE_DIVIDE_0 * NSEC_19P2MHZ,
146 },
147 { PRE_DIVIDE_1 * NSEC_1000HZ,
148 PRE_DIVIDE_1 * NSEC_32768HZ,
149 PRE_DIVIDE_1 * NSEC_19P2MHZ,
150 },
151 { PRE_DIVIDE_2 * NSEC_1000HZ,
152 PRE_DIVIDE_2 * NSEC_32768HZ,
153 PRE_DIVIDE_2 * NSEC_19P2MHZ,
154 },
155};
156
157#define MIN_MPT ((PRE_DIVIDE_MIN * CLK_PERIOD_MIN) << PM8XXX_PWM_M_MIN)
158#define MAX_MPT ((PRE_DIVIDE_MAX * CLK_PERIOD_MAX) << PM8XXX_PWM_M_MAX)
159
160/* Private data */
161struct pm8xxx_pwm_chip;
162
163struct pwm_device {
164 int pwm_id; /* = bank/channel id */
165 int in_use;
166 const char *label;
Willie Ruan719c6762011-08-25 11:03:14 -0700167 struct pm8xxx_pwm_period period;
168 int pwm_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169 int pwm_period;
170 int pwm_duty;
171 u8 pwm_ctl[PM8XXX_LPG_CTL_REGS];
172 int irq;
173 struct pm8xxx_pwm_chip *chip;
Willie Ruan719c6762011-08-25 11:03:14 -0700174 int bypass_lut;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175};
176
177struct pm8xxx_pwm_chip {
178 struct pwm_device pwm_dev[PM8XXX_PWM_CHANNELS];
179 u8 bank_mask;
180 struct mutex pwm_mutex;
181 struct device *dev;
182};
183
184static struct pm8xxx_pwm_chip *pwm_chip;
185
Willie Ruan719c6762011-08-25 11:03:14 -0700186struct pm8xxx_pwm_lut {
187 /* LUT parameters */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188 int lut_duty_ms;
189 int lut_lo_index;
190 int lut_hi_index;
191 int lut_pause_hi;
192 int lut_pause_lo;
193 int flags;
194};
195
196static const u16 duty_msec[PM8XXX_PWM_1KHZ_COUNT_MAX + 1] = {
197 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
198};
199
200static const u16 pause_count[PM8XXX_PWM_PAUSE_COUNT_MAX + 1] = {
201 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
202 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
203 375, 500, 667, 750, 800, 900, 1000, 1100,
204 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
205 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
206 7000
207};
208
209/* Internal functions */
Willie Ruan8de2f382011-08-25 11:04:50 -0700210static void pm8xxx_pwm_save(u8 *u8p, u8 mask, u8 val)
211{
212 *u8p &= ~mask;
213 *u8p |= val & mask;
214}
215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216static int pm8xxx_pwm_bank_enable(struct pwm_device *pwm, int enable)
217{
218 int rc;
219 u8 reg;
220 struct pm8xxx_pwm_chip *chip;
221
222 chip = pwm->chip;
223
224 if (enable)
225 reg = chip->bank_mask | (1 << pwm->pwm_id);
226 else
227 reg = chip->bank_mask & ~(1 << pwm->pwm_id);
228
229 rc = pm8xxx_writeb(chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
230 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700231 pr_err("pm8xxx_writeb(): rc=%d (Enable LPG Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232 return rc;
233 }
234 chip->bank_mask = reg;
235
236 return 0;
237}
238
239static int pm8xxx_pwm_bank_sel(struct pwm_device *pwm)
240{
241 int rc;
242
243 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_SEL,
244 pwm->pwm_id);
245 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700246 pr_err("pm8xxx_writeb(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 return rc;
248}
249
250static int pm8xxx_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
251{
252 int rc;
253 u8 reg;
254
255 if (start) {
256 reg = pwm->pwm_ctl[0] | PM8XXX_PWM_PWM_START;
257 if (ramp_start)
258 reg |= PM8XXX_PWM_RAMP_GEN_START;
259 else
260 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
261 } else {
262 reg = pwm->pwm_ctl[0] & ~PM8XXX_PWM_PWM_START;
263 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
264 }
265
266 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
267 reg);
268 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700269 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270 else
271 pwm->pwm_ctl[0] = reg;
272 return rc;
273}
274
275static void pm8xxx_pwm_calc_period(unsigned int period_us,
Willie Ruan719c6762011-08-25 11:03:14 -0700276 struct pm8xxx_pwm_period *period)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277{
278 int n, m, clk, div;
279 int best_m, best_div, best_clk;
280 int last_err, cur_err, better_err, better_m;
281 unsigned int tmp_p, last_p, min_err, period_n;
282
283 /* PWM Period / N */
284 if (period_us < (40 * USEC_PER_SEC)) { /* ~6-bit max */
285 period_n = (period_us * NSEC_PER_USEC) >> 6;
286 n = 6;
287 } else if (period_us < (274 * USEC_PER_SEC)) { /* overflow threshold */
288 period_n = (period_us >> 6) * NSEC_PER_USEC;
289 if (period_n >= MAX_MPT) {
290 n = 9;
291 period_n >>= 3;
292 } else {
293 n = 6;
294 }
295 } else {
296 period_n = (period_us >> 9) * NSEC_PER_USEC;
297 n = 9;
298 }
299
300 min_err = MAX_MPT;
301 best_m = 0;
302 best_clk = 0;
303 best_div = 0;
304 for (clk = 0; clk < NUM_CLOCKS; clk++) {
305 for (div = 0; div < NUM_PRE_DIVIDE; div++) {
306 tmp_p = period_n;
307 last_p = tmp_p;
308 for (m = 0; m <= PM8XXX_PWM_M_MAX; m++) {
309 if (tmp_p <= pt_t[div][clk]) {
310 /* Found local best */
311 if (!m) {
312 better_err = pt_t[div][clk] -
313 tmp_p;
314 better_m = m;
315 } else {
316 last_err = last_p -
317 pt_t[div][clk];
318 cur_err = pt_t[div][clk] -
319 tmp_p;
320
321 if (cur_err < last_err) {
322 better_err = cur_err;
323 better_m = m;
324 } else {
325 better_err = last_err;
326 better_m = m - 1;
327 }
328 }
329
330 if (better_err < min_err) {
331 min_err = better_err;
332 best_m = better_m;
333 best_clk = clk;
334 best_div = div;
335 }
336 break;
337 } else {
338 last_p = tmp_p;
339 tmp_p >>= 1;
340 }
341 }
342 }
343 }
344
Willie Ruan75d9e5b2011-08-25 10:59:17 -0700345 /* Use higher resolution */
346 if (best_m >= 3 && n == 6) {
347 n += 3;
348 best_m -= 3;
349 }
350
Willie Ruan719c6762011-08-25 11:03:14 -0700351 period->pwm_size = n;
352 period->clk = best_clk;
353 period->pre_div = best_div;
354 period->pre_div_exp = best_m;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355}
356
Willie Ruan8de2f382011-08-25 11:04:50 -0700357static void pm8xxx_pwm_calc_pwm_value(struct pwm_device *pwm,
358 unsigned int period_us,
359 unsigned int duty_us)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360{
Willie Ruan8de2f382011-08-25 11:04:50 -0700361 unsigned int max_pwm_value, tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362
Willie Ruan8de2f382011-08-25 11:04:50 -0700363 /* Figure out pwm_value with overflow handling */
364 tmp = 1 << (sizeof(tmp) * 8 - pwm->period.pwm_size);
365 if (duty_us < tmp) {
366 tmp = duty_us << pwm->period.pwm_size;
367 pwm->pwm_value = tmp / period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368 } else {
Willie Ruan8de2f382011-08-25 11:04:50 -0700369 tmp = period_us >> pwm->period.pwm_size;
370 pwm->pwm_value = duty_us / tmp;
371 }
372 max_pwm_value = (1 << pwm->period.pwm_size) - 1;
373 if (pwm->pwm_value > max_pwm_value)
374 pwm->pwm_value = max_pwm_value;
375}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376
Willie Ruan8de2f382011-08-25 11:04:50 -0700377static int pm8xxx_pwm_change_table(struct pwm_device *pwm, int duty_pct[],
378 int start_idx, int len, int raw_value)
379{
380 unsigned int pwm_value, max_pwm_value;
381 u8 cfg0, cfg1;
382 int i, pwm_size;
383 int rc = 0;
384
385 pwm_size = (pwm->pwm_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
386 max_pwm_value = (1 << pwm_size) - 1;
387 for (i = 0; i < len; i++) {
388 if (raw_value)
389 pwm_value = duty_pct[i];
390 else
391 pwm_value = (duty_pct[i] << pwm_size) / 100;
392
393 if (pwm_value > max_pwm_value)
394 pwm_value = max_pwm_value;
395 cfg0 = pwm_value;
396 cfg1 = (pwm_value >> 1) & 0x80;
397 cfg1 |= start_idx + i;
398
399 rc = pm8xxx_writeb(pwm->chip->dev->parent,
400 SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
401 if (rc)
402 break;
403
404 rc = pm8xxx_writeb(pwm->chip->dev->parent,
405 SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
406 if (rc)
407 break;
408 }
409 return rc;
410}
411
412static void pm8xxx_pwm_save_index(struct pwm_device *pwm,
413 int low_idx, int high_idx, int flags)
414{
415 pwm->pwm_ctl[1] = high_idx & PM8XXX_PWM_HIGH_INDEX_MASK;
416 pwm->pwm_ctl[2] = low_idx & PM8XXX_PWM_LOW_INDEX_MASK;
417
418 if (flags & PM_PWM_LUT_REVERSE)
419 pwm->pwm_ctl[1] |= PM8XXX_PWM_REVERSE_EN;
420 if (flags & PM_PWM_LUT_RAMP_UP)
421 pwm->pwm_ctl[2] |= PM8XXX_PWM_RAMP_UP;
422 if (flags & PM_PWM_LUT_LOOP)
423 pwm->pwm_ctl[2] |= PM8XXX_PWM_LOOP_EN;
424}
425
426static void pm8xxx_pwm_save_period(struct pwm_device *pwm)
427{
428 u8 mask, val;
429
430 val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
431 & PM8XXX_PWM_CLK_SEL_MASK;
432 val |= (pwm->period.pre_div << PM8XXX_PWM_PREDIVIDE_SHIFT)
433 & PM8XXX_PWM_PREDIVIDE_MASK;
434 val |= pwm->period.pre_div_exp & PM8XXX_PWM_M_MASK;
435 mask = PM8XXX_PWM_CLK_SEL_MASK | PM8XXX_PWM_PREDIVIDE_MASK |
436 PM8XXX_PWM_M_MASK;
437 pm8xxx_pwm_save(&pwm->pwm_ctl[4], mask, val);
438
439 val = (pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0;
440 mask = PM8XXX_PWM_SIZE_9_BIT;
441 pm8xxx_pwm_save(&pwm->pwm_ctl[5], mask, val);
442}
443
444static void pm8xxx_pwm_save_pwm_value(struct pwm_device *pwm)
445{
446 u8 mask, val;
447
448 pwm->pwm_ctl[3] = pwm->pwm_value;
449
450 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 1) : 0;
451 mask = PM8XXX_PWM_VALUE_BIT8;
452 pm8xxx_pwm_save(&pwm->pwm_ctl[4], mask, val);
453}
454
455static void pm8xxx_pwm_save_duty_time(struct pwm_device *pwm,
456 struct pm8xxx_pwm_lut *lut)
457{
458 int i;
459 u8 mask, val;
460
461 /* Linear search for duty time */
462 for (i = 0; i < PM8XXX_PWM_1KHZ_COUNT_MAX; i++) {
463 if (duty_msec[i] >= lut->lut_duty_ms)
464 break;
465 }
466 val = i << PM8XXX_PWM_1KHZ_COUNT_SHIFT;
467
468 mask = PM8XXX_PWM_1KHZ_COUNT_MASK;
469 pm8xxx_pwm_save(&pwm->pwm_ctl[0], mask, val);
470}
471
472static void pm8xxx_pwm_save_pause(struct pwm_device *pwm,
473 struct pm8xxx_pwm_lut *lut)
474{
475 int i, pause_cnt, time_cnt;
476 u8 mask, val;
477
478 time_cnt = (pwm->pwm_ctl[0] & PM8XXX_PWM_1KHZ_COUNT_MASK)
479 >> PM8XXX_PWM_1KHZ_COUNT_SHIFT;
480 if (lut->flags & PM_PWM_LUT_PAUSE_HI_EN) {
481 pause_cnt = (lut->lut_pause_hi + duty_msec[time_cnt] / 2)
482 / duty_msec[time_cnt];
483 /* Linear search for pause time */
484 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
485 if (pause_count[i] >= pause_cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486 break;
487 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700488 val = (i << PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT) &
489 PM8XXX_PWM_PAUSE_COUNT_HI_MASK;
490 val |= PM8XXX_PWM_PAUSE_ENABLE_HIGH;
491 } else {
492 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493 }
494
Willie Ruan8de2f382011-08-25 11:04:50 -0700495 mask = PM8XXX_PWM_PAUSE_COUNT_HI_MASK | PM8XXX_PWM_PAUSE_ENABLE_HIGH;
496 pm8xxx_pwm_save(&pwm->pwm_ctl[5], mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497
Willie Ruan8de2f382011-08-25 11:04:50 -0700498 if (lut->flags & PM_PWM_LUT_PAUSE_LO_EN) {
499 /* Linear search for pause time */
500 pause_cnt = (lut->lut_pause_lo + duty_msec[time_cnt] / 2)
501 / duty_msec[time_cnt];
502 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
503 if (pause_count[i] >= pause_cnt)
504 break;
505 }
506 val = (i << PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT) &
507 PM8XXX_PWM_PAUSE_COUNT_LO_MASK;
508 val |= PM8XXX_PWM_PAUSE_ENABLE_LOW;
509 } else {
510 val = 0;
511 }
512
513 mask = PM8XXX_PWM_PAUSE_COUNT_LO_MASK | PM8XXX_PWM_PAUSE_ENABLE_LOW;
514 pm8xxx_pwm_save(&pwm->pwm_ctl[6], mask, val);
515}
516
517static int pm8xxx_pwm_write(struct pwm_device *pwm, int start, int end)
518{
519 int i, rc;
520
521 /* Write in reverse way so 0 would be the last */
522 for (i = end - 1; i >= start; i--) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523 rc = pm8xxx_writeb(pwm->chip->dev->parent,
524 SSBI_REG_ADDR_LPG_CTL(i),
525 pwm->pwm_ctl[i]);
526 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700527 pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[%d])\n", rc, i);
528 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 }
530 }
531
Willie Ruan8de2f382011-08-25 11:04:50 -0700532 return 0;
533}
534
535static int pm8xxx_pwm_change_lut(struct pwm_device *pwm,
536 struct pm8xxx_pwm_lut *lut)
537{
538 int rc;
539
540 pm8xxx_pwm_save_index(pwm, lut->lut_lo_index,
541 lut->lut_hi_index, lut->flags);
542 pm8xxx_pwm_save_duty_time(pwm, lut);
543 pm8xxx_pwm_save_pause(pwm, lut);
544 pm8xxx_pwm_save(&pwm->pwm_ctl[1], PM8XXX_PWM_BYPASS_LUT, 0);
545
546 pm8xxx_pwm_bank_sel(pwm);
547 rc = pm8xxx_pwm_write(pwm, 0, 7);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548
549 return rc;
550}
551
552/* APIs */
553/**
554 * pwm_request - request a PWM device
555 * @pwm_id: PWM id or channel
556 * @label: the label to identify the user
557 */
558struct pwm_device *pwm_request(int pwm_id, const char *label)
559{
560 struct pwm_device *pwm;
561
562 if (pwm_id > PM8XXX_PWM_CHANNELS || pwm_id < 0) {
563 pr_err("Invalid pwm_id: %d with %s\n",
564 pwm_id, label ? label : ".");
565 return ERR_PTR(-EINVAL);
566 }
567 if (pwm_chip == NULL) {
568 pr_err("No pwm_chip\n");
569 return ERR_PTR(-ENODEV);
570 }
571
572 mutex_lock(&pwm_chip->pwm_mutex);
573 pwm = &pwm_chip->pwm_dev[pwm_id];
574 if (!pwm->in_use) {
575 pwm->in_use = 1;
576 pwm->label = label;
577 } else {
578 pwm = ERR_PTR(-EBUSY);
579 }
580 mutex_unlock(&pwm_chip->pwm_mutex);
581
582 return pwm;
583}
584EXPORT_SYMBOL_GPL(pwm_request);
585
586/**
587 * pwm_free - free a PWM device
588 * @pwm: the PWM device
589 */
590void pwm_free(struct pwm_device *pwm)
591{
592 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
593 pr_err("Invalid pwm handle\n");
594 return;
595 }
596
597 mutex_lock(&pwm->chip->pwm_mutex);
598 if (pwm->in_use) {
599 pm8xxx_pwm_bank_sel(pwm);
600 pm8xxx_pwm_start(pwm, 0, 0);
601
602 pwm->in_use = 0;
603 pwm->label = NULL;
604 }
605 pm8xxx_pwm_bank_enable(pwm, 0);
606 mutex_unlock(&pwm->chip->pwm_mutex);
607}
608EXPORT_SYMBOL_GPL(pwm_free);
609
610/**
611 * pwm_config - change a PWM device configuration
612 * @pwm: the PWM device
613 * @period_us: period in microseconds
614 * @duty_us: duty cycle in microseconds
615 */
616int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
617{
Willie Ruan719c6762011-08-25 11:03:14 -0700618 struct pm8xxx_pwm_period *period;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 int rc;
620
621 if (pwm == NULL || IS_ERR(pwm) ||
622 duty_us > period_us ||
623 (unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
624 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
625 pr_err("Invalid pwm handle or parameters\n");
626 return -EINVAL;
627 }
628 if (pwm->chip == NULL) {
629 pr_err("No pwm_chip\n");
630 return -ENODEV;
631 }
632
Willie Ruan719c6762011-08-25 11:03:14 -0700633 period = &pwm->period;
634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 mutex_lock(&pwm->chip->pwm_mutex);
636
637 if (!pwm->in_use) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700638 rc = -EINVAL;
639 goto out_unlock;
640 }
641
Willie Ruan8de2f382011-08-25 11:04:50 -0700642 if (pwm->pwm_period != period_us) {
643 pm8xxx_pwm_calc_period(period_us, period);
644 pm8xxx_pwm_save_period(pwm);
645 pwm->pwm_period = period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647
Willie Ruan8de2f382011-08-25 11:04:50 -0700648 pm8xxx_pwm_calc_pwm_value(pwm, period_us, duty_us);
649 pm8xxx_pwm_save_pwm_value(pwm);
650 pm8xxx_pwm_save(&pwm->pwm_ctl[1],
651 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652
Willie Ruan8de2f382011-08-25 11:04:50 -0700653 pm8xxx_pwm_bank_sel(pwm);
654 rc = pm8xxx_pwm_write(pwm, 1, 6);
655
656 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
657 (unsigned)duty_us, (unsigned)period_us,
658 pwm->pwm_value, 1 << period->pwm_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659
660out_unlock:
661 mutex_unlock(&pwm->chip->pwm_mutex);
662 return rc;
663}
664EXPORT_SYMBOL_GPL(pwm_config);
665
666/**
667 * pwm_enable - start a PWM output toggling
668 * @pwm: the PWM device
669 */
670int pwm_enable(struct pwm_device *pwm)
671{
672 int rc;
673
674 if (pwm == NULL || IS_ERR(pwm)) {
675 pr_err("Invalid pwm handle\n");
676 return -EINVAL;
677 }
678 if (pwm->chip == NULL) {
679 pr_err("No pwm_chip\n");
680 return -ENODEV;
681 }
682
683 mutex_lock(&pwm->chip->pwm_mutex);
684 if (!pwm->in_use) {
685 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
686 rc = -EINVAL;
687 } else {
688 rc = pm8xxx_pwm_bank_enable(pwm, 1);
689
690 pm8xxx_pwm_bank_sel(pwm);
691 pm8xxx_pwm_start(pwm, 1, 0);
692 }
693 mutex_unlock(&pwm->chip->pwm_mutex);
694 return rc;
695}
696EXPORT_SYMBOL_GPL(pwm_enable);
697
698/**
699 * pwm_disable - stop a PWM output toggling
700 * @pwm: the PWM device
701 */
702void pwm_disable(struct pwm_device *pwm)
703{
704 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
705 pr_err("Invalid pwm handle or no pwm_chip\n");
706 return;
707 }
708
709 mutex_lock(&pwm->chip->pwm_mutex);
710 if (pwm->in_use) {
711 pm8xxx_pwm_bank_sel(pwm);
712 pm8xxx_pwm_start(pwm, 0, 0);
713
714 pm8xxx_pwm_bank_enable(pwm, 0);
715 }
716 mutex_unlock(&pwm->chip->pwm_mutex);
717}
718EXPORT_SYMBOL_GPL(pwm_disable);
719
720/**
721 * pm8xxx_pwm_lut_config - change a PWM device configuration to use LUT
722 * @pwm: the PWM device
723 * @period_us: period in microseconds
724 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
725 * @duty_time_ms: time for each duty cycle in milliseconds
726 * @start_idx: start index in lookup table from 0 to MAX-1
727 * @idx_len: number of index
728 * @pause_lo: pause time in milliseconds at low index
729 * @pause_hi: pause time in milliseconds at high index
730 * @flags: control flags
731 */
732int pm8xxx_pwm_lut_config(struct pwm_device *pwm, int period_us,
733 int duty_pct[], int duty_time_ms, int start_idx,
734 int idx_len, int pause_lo, int pause_hi, int flags)
735{
Willie Ruan719c6762011-08-25 11:03:14 -0700736 struct pm8xxx_pwm_lut lut;
737 struct pm8xxx_pwm_period *period;
Willie Ruan8de2f382011-08-25 11:04:50 -0700738 int len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739 int rc;
740
741 if (pwm == NULL || IS_ERR(pwm) || !idx_len) {
742 pr_err("Invalid pwm handle or idx_len=0\n");
743 return -EINVAL;
744 }
745 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE)) {
746 pr_err("Invalid duty_pct with flag\n");
747 return -EINVAL;
748 }
749 if (pwm->chip == NULL) {
750 pr_err("No pwm_chip\n");
751 return -ENODEV;
752 }
753 if (idx_len >= PM_PWM_LUT_SIZE && start_idx) {
754 pr_err("Wrong LUT size or index\n");
755 return -EINVAL;
756 }
757 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE) {
758 pr_err("Exceed LUT limit\n");
759 return -EINVAL;
760 }
761 if ((unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
762 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
763 pr_err("Period out of range\n");
764 return -EINVAL;
765 }
766
Willie Ruan719c6762011-08-25 11:03:14 -0700767 period = &pwm->period;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768 mutex_lock(&pwm->chip->pwm_mutex);
769
770 if (!pwm->in_use) {
771 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
772 rc = -EINVAL;
773 goto out_unlock;
774 }
775
Willie Ruan8de2f382011-08-25 11:04:50 -0700776 if (pwm->pwm_period != period_us) {
777 pm8xxx_pwm_calc_period(period_us, period);
778 pm8xxx_pwm_save_period(pwm);
779 pwm->pwm_period = period_us;
780 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781
782 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
783
784 if (flags & PM_PWM_LUT_NO_TABLE)
785 goto after_table_write;
786
Willie Ruan8de2f382011-08-25 11:04:50 -0700787 rc = pm8xxx_pwm_change_table(pwm, duty_pct, start_idx, len, 0);
788 if (rc) {
789 pr_err("pm8xxx_pwm_change_table: rc=%d\n", rc);
790 goto out_unlock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 }
792
793after_table_write:
Willie Ruan719c6762011-08-25 11:03:14 -0700794 lut.lut_duty_ms = duty_time_ms;
795 lut.lut_lo_index = start_idx;
796 lut.lut_hi_index = start_idx + len - 1;
797 lut.lut_pause_lo = pause_lo;
798 lut.lut_pause_hi = pause_hi;
799 lut.flags = flags;
800 pwm->bypass_lut = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801
Willie Ruan8de2f382011-08-25 11:04:50 -0700802 rc = pm8xxx_pwm_change_lut(pwm, &lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803
804out_unlock:
805 mutex_unlock(&pwm->chip->pwm_mutex);
806 return rc;
807}
808EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_config);
809
810/**
811 * pm8xxx_pwm_lut_enable - control a PWM device to start/stop LUT ramp
812 * @pwm: the PWM device
813 * @start: to start (1), or stop (0)
814 */
815int pm8xxx_pwm_lut_enable(struct pwm_device *pwm, int start)
816{
817 if (pwm == NULL || IS_ERR(pwm)) {
818 pr_err("Invalid pwm handle\n");
819 return -EINVAL;
820 }
821 if (pwm->chip == NULL) {
822 pr_err("No pwm_chip\n");
823 return -ENODEV;
824 }
825
826 mutex_lock(&pwm->chip->pwm_mutex);
827 if (start) {
828 pm8xxx_pwm_bank_enable(pwm, 1);
829
830 pm8xxx_pwm_bank_sel(pwm);
831 pm8xxx_pwm_start(pwm, 1, 1);
832 } else {
833 pm8xxx_pwm_bank_sel(pwm);
834 pm8xxx_pwm_start(pwm, 0, 0);
835
836 pm8xxx_pwm_bank_enable(pwm, 0);
837 }
838 mutex_unlock(&pwm->chip->pwm_mutex);
839 return 0;
840}
841EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_enable);
842
843#if defined(CONFIG_DEBUG_FS)
844
845struct pm8xxx_pwm_dbg_device;
846
847struct pm8xxx_pwm_user {
848 int pwm_id;
849 struct pwm_device *pwm;
850 int period;
851 int duty_cycle;
852 int enable;
853 struct pm8xxx_pwm_dbg_device *dbgdev;
854};
855
856struct pm8xxx_pwm_dbg_device {
857 struct mutex dbg_mutex;
858 struct device *dev;
859 struct dentry *dent;
860
861 struct pm8xxx_pwm_user user[PM8XXX_PWM_CHANNELS];
862};
863
864static struct pm8xxx_pwm_dbg_device *pmic_dbg_device;
865
866static int dbg_pwm_check_period(int period)
867{
868 if (period < PM8XXX_PWM_PERIOD_MIN || period > PM8XXX_PWM_PERIOD_MAX) {
869 pr_err("period is invalid: %d\n", period);
870 return -EINVAL;
871 }
872 return 0;
873}
874
875static int dbg_pwm_check_duty_cycle(int duty_cycle, const char *func_name)
876{
877 if (duty_cycle <= 0 || duty_cycle > 100) {
878 pr_err("%s: duty_cycle is invalid: %d\n",
879 func_name, duty_cycle);
880 return -EINVAL;
881 }
882 return 0;
883}
884
885static void dbg_pwm_check_handle(struct pm8xxx_pwm_user *puser)
886{
887 struct pwm_device *tmp;
888
889 if (puser->pwm == NULL) {
890 tmp = pwm_request(puser->pwm_id, "pwm-dbg");
891 if (PTR_ERR(puser->pwm)) {
892 pr_err("pwm_request: err=%ld\n", PTR_ERR(puser->pwm));
893 puser->pwm = NULL;
Willie Ruan10976ea2011-08-25 11:01:15 -0700894 } else {
895 pr_debug("[id=%d] pwm_request ok\n", puser->pwm_id);
896 puser->pwm = tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 }
898 }
899}
900
901static int dbg_pwm_enable_set(void *data, u64 val)
902{
903 struct pm8xxx_pwm_user *puser = data;
904 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
905 int rc;
906
907 mutex_lock(&dbgdev->dbg_mutex);
908 rc = dbg_pwm_check_duty_cycle(puser->duty_cycle, __func__);
909 if (!rc) {
910 puser->enable = val;
911 dbg_pwm_check_handle(puser);
912 if (puser->pwm) {
913 if (puser->enable)
914 pwm_enable(puser->pwm);
915 else
916 pwm_disable(puser->pwm);
917 }
918 }
919 mutex_unlock(&dbgdev->dbg_mutex);
920 return 0;
921}
922
923static int dbg_pwm_enable_get(void *data, u64 *val)
924{
925 struct pm8xxx_pwm_user *puser = data;
926 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
927
928 mutex_lock(&dbgdev->dbg_mutex);
929 *val = puser->enable;
930 mutex_unlock(&dbgdev->dbg_mutex);
931 return 0;
932}
933
934DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_enable_fops,
935 dbg_pwm_enable_get, dbg_pwm_enable_set,
936 "%lld\n");
937
938static int dbg_pwm_duty_cycle_set(void *data, u64 val)
939{
940 struct pm8xxx_pwm_user *puser = data;
941 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
942 int rc;
943
944 mutex_lock(&dbgdev->dbg_mutex);
945 rc = dbg_pwm_check_duty_cycle(val, __func__);
946 if (!rc) {
947 puser->duty_cycle = val;
948 dbg_pwm_check_handle(puser);
949 if (puser->pwm) {
950 int duty_us;
951
Willie Ruan10976ea2011-08-25 11:01:15 -0700952 duty_us = puser->duty_cycle * puser->period / 100;
953 pwm_config(puser->pwm, duty_us, puser->period);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954 }
955 }
956 mutex_unlock(&dbgdev->dbg_mutex);
957 return 0;
958}
959
960static int dbg_pwm_duty_cycle_get(void *data, u64 *val)
961{
962 struct pm8xxx_pwm_user *puser = data;
963 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
964
965 mutex_lock(&dbgdev->dbg_mutex);
966 *val = puser->duty_cycle;
967 mutex_unlock(&dbgdev->dbg_mutex);
968 return 0;
969}
970
971DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_duty_cycle_fops,
972 dbg_pwm_duty_cycle_get, dbg_pwm_duty_cycle_set,
973 "%lld\n");
974
975static int dbg_pwm_period_set(void *data, u64 val)
976{
977 struct pm8xxx_pwm_user *puser = data;
978 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
979 int rc;
980
981 mutex_lock(&dbgdev->dbg_mutex);
982 rc = dbg_pwm_check_period(val);
983 if (!rc)
984 puser->period = val;
985 mutex_unlock(&dbgdev->dbg_mutex);
986 return 0;
987}
988
989static int dbg_pwm_period_get(void *data, u64 *val)
990{
991 struct pm8xxx_pwm_user *puser = data;
992 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
993
994 mutex_lock(&dbgdev->dbg_mutex);
995 *val = puser->period;
996 mutex_unlock(&dbgdev->dbg_mutex);
997 return 0;
998}
999
1000DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_period_fops,
1001 dbg_pwm_period_get, dbg_pwm_period_set, "%lld\n");
1002
1003static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1004{
1005 struct pm8xxx_pwm_dbg_device *dbgdev;
1006 struct dentry *dent;
1007 struct dentry *temp;
1008 struct pm8xxx_pwm_user *puser;
1009 int i;
1010
1011 if (dev == NULL) {
1012 pr_err("no parent data passed in.\n");
1013 return -EINVAL;
1014 }
1015
1016 dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
1017 if (dbgdev == NULL) {
1018 pr_err("kzalloc() failed.\n");
1019 return -ENOMEM;
1020 }
1021
1022 mutex_init(&dbgdev->dbg_mutex);
1023
1024 dbgdev->dev = dev;
1025
1026 dent = debugfs_create_dir("pm8xxx-pwm-dbg", NULL);
1027 if (dent == NULL || IS_ERR(dent)) {
1028 pr_err("ERR debugfs_create_dir: dent=%p\n", dent);
1029 return -ENOMEM;
1030 }
1031
1032 dbgdev->dent = dent;
1033
1034 for (i = 0; i < PM8XXX_PWM_CHANNELS; i++) {
1035 char pwm_ch[] = "0";
1036
1037 pwm_ch[0] = '0' + i;
1038 dent = debugfs_create_dir(pwm_ch, dbgdev->dent);
1039 if (dent == NULL || IS_ERR(dent)) {
1040 pr_err("ERR: pwm=%d: dir: dent=%p\n", i, dent);
1041 goto debug_error;
1042 }
1043
1044 puser = &dbgdev->user[i];
1045 puser->dbgdev = dbgdev;
1046 puser->pwm_id = i;
1047 temp = debugfs_create_file("period", S_IRUGO | S_IWUSR,
1048 dent, puser, &dbg_pwm_period_fops);
1049 if (temp == NULL || IS_ERR(temp)) {
1050 pr_err("ERR: pwm=%d: period: dent=%p\n", i, dent);
1051 goto debug_error;
1052 }
1053
1054 temp = debugfs_create_file("duty-cycle", S_IRUGO | S_IWUSR,
1055 dent, puser, &dbg_pwm_duty_cycle_fops);
1056 if (temp == NULL || IS_ERR(temp)) {
1057 pr_err("ERR: pwm=%d: duty-cycle: dent=%p\n", i, dent);
1058 goto debug_error;
1059 }
1060
1061 temp = debugfs_create_file("enable", S_IRUGO | S_IWUSR,
1062 dent, puser, &dbg_pwm_enable_fops);
1063 if (temp == NULL || IS_ERR(temp)) {
1064 pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);
1065 goto debug_error;
1066 }
1067 }
1068
1069 pmic_dbg_device = dbgdev;
1070
1071 return 0;
1072
1073debug_error:
1074 debugfs_remove_recursive(dbgdev->dent);
1075 return -ENOMEM;
1076}
1077
1078static int __devexit pm8xxx_pwm_dbg_remove(void)
1079{
1080 if (pmic_dbg_device) {
1081 debugfs_remove_recursive(pmic_dbg_device->dent);
1082 kfree(pmic_dbg_device);
1083 }
1084 return 0;
1085}
1086
1087#else
1088
1089static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1090{
1091 return 0;
1092}
1093
1094static int __devexit pm8xxx_pwm_dbg_remove(void)
1095{
1096 return 0;
1097}
1098
1099#endif
1100
1101static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
1102{
1103 struct pm8xxx_pwm_chip *chip;
1104 int i;
1105
1106 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1107 if (chip == NULL) {
1108 pr_err("kzalloc() failed.\n");
1109 return -ENOMEM;
1110 }
1111
1112 for (i = 0; i < PM8XXX_PWM_CHANNELS; i++) {
1113 chip->pwm_dev[i].pwm_id = i;
1114 chip->pwm_dev[i].chip = chip;
1115 }
1116
1117 mutex_init(&chip->pwm_mutex);
1118
1119 chip->dev = &pdev->dev;
1120 pwm_chip = chip;
1121 platform_set_drvdata(pdev, chip);
1122
1123 if (pm8xxx_pwm_dbg_probe(&pdev->dev) < 0)
1124 pr_err("could not set up debugfs\n");
1125
1126 pr_notice("OK\n");
1127 return 0;
1128}
1129
1130static int __devexit pm8xxx_pwm_remove(struct platform_device *pdev)
1131{
1132 struct pm8xxx_pwm_chip *chip = dev_get_drvdata(pdev->dev.parent);
1133
1134 pm8xxx_pwm_dbg_remove();
1135 mutex_destroy(&chip->pwm_mutex);
1136 platform_set_drvdata(pdev, NULL);
1137 kfree(chip);
1138 return 0;
1139}
1140
1141static struct platform_driver pm8xxx_pwm_driver = {
1142 .probe = pm8xxx_pwm_probe,
1143 .remove = __devexit_p(pm8xxx_pwm_remove),
1144 .driver = {
1145 .name = PM8XXX_PWM_DEV_NAME,
1146 .owner = THIS_MODULE,
1147 },
1148};
1149
1150static int __init pm8xxx_pwm_init(void)
1151{
1152 return platform_driver_register(&pm8xxx_pwm_driver);
1153}
1154
1155static void __exit pm8xxx_pwm_exit(void)
1156{
1157 platform_driver_unregister(&pm8xxx_pwm_driver);
1158}
1159
1160subsys_initcall(pm8xxx_pwm_init);
1161module_exit(pm8xxx_pwm_exit);
1162
1163MODULE_LICENSE("GPL v2");
1164MODULE_DESCRIPTION("PM8XXX PWM driver");
1165MODULE_VERSION("1.0");
1166MODULE_ALIAS("platform:" PM8XXX_PWM_DEV_NAME);