blob: 1a7507ed179c2e9516db0d250dcf7eb4d664c038 [file] [log] [blame]
Willie Ruan0d9acd92011-07-04 21:31:30 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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/*
14 * Qualcomm PMIC8058 PWM driver
15 *
16 */
17
Willie Ruan0d9acd92011-07-04 21:31:30 -070018#define pr_fmt(fmt) "%s: " fmt, __func__
19
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/err.h>
23#include <linux/pwm.h>
24#include <linux/mfd/pmic8058.h>
25#include <linux/pmic8058-pwm.h>
26#include <linux/slab.h>
27
28#define PM8058_LPG_BANKS 8
29#define PM8058_PWM_CHANNELS PM8058_LPG_BANKS /* MAX=8 */
30
31#define PM8058_LPG_CTL_REGS 7
32
33/* PMIC8058 LPG/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#define SSBI_REG_ADDR_LPG_TEST 0x147
41
42/* Control 0 */
43#define PM8058_PWM_1KHZ_COUNT_MASK 0xF0
44#define PM8058_PWM_1KHZ_COUNT_SHIFT 4
45
46#define PM8058_PWM_1KHZ_COUNT_MAX 15
47
48#define PM8058_PWM_OUTPUT_EN 0x08
49#define PM8058_PWM_PWM_EN 0x04
50#define PM8058_PWM_RAMP_GEN_EN 0x02
51#define PM8058_PWM_RAMP_START 0x01
52
53#define PM8058_PWM_PWM_START (PM8058_PWM_OUTPUT_EN \
54 | PM8058_PWM_PWM_EN)
55#define PM8058_PWM_RAMP_GEN_START (PM8058_PWM_RAMP_GEN_EN \
56 | PM8058_PWM_RAMP_START)
57
58/* Control 1 */
59#define PM8058_PWM_REVERSE_EN 0x80
60#define PM8058_PWM_BYPASS_LUT 0x40
61#define PM8058_PWM_HIGH_INDEX_MASK 0x3F
62
63/* Control 2 */
64#define PM8058_PWM_LOOP_EN 0x80
65#define PM8058_PWM_RAMP_UP 0x40
66#define PM8058_PWM_LOW_INDEX_MASK 0x3F
67
68/* Control 3 */
69#define PM8058_PWM_VALUE_BIT7_0 0xFF
70#define PM8058_PWM_VALUE_BIT5_0 0x3F
71
72/* Control 4 */
73#define PM8058_PWM_VALUE_BIT8 0x80
74
75#define PM8058_PWM_CLK_SEL_MASK 0x60
76#define PM8058_PWM_CLK_SEL_SHIFT 5
77
78#define PM8058_PWM_CLK_SEL_NO 0
79#define PM8058_PWM_CLK_SEL_1KHZ 1
80#define PM8058_PWM_CLK_SEL_32KHZ 2
81#define PM8058_PWM_CLK_SEL_19P2MHZ 3
82
83#define PM8058_PWM_PREDIVIDE_MASK 0x18
84#define PM8058_PWM_PREDIVIDE_SHIFT 3
85
86#define PM8058_PWM_PREDIVIDE_2 0
87#define PM8058_PWM_PREDIVIDE_3 1
88#define PM8058_PWM_PREDIVIDE_5 2
89#define PM8058_PWM_PREDIVIDE_6 3
90
91#define PM8058_PWM_M_MASK 0x07
92#define PM8058_PWM_M_MIN 0
93#define PM8058_PWM_M_MAX 7
94
95/* Control 5 */
96#define PM8058_PWM_PAUSE_COUNT_HI_MASK 0xFC
97#define PM8058_PWM_PAUSE_COUNT_HI_SHIFT 2
98
99#define PM8058_PWM_PAUSE_ENABLE_HIGH 0x02
100#define PM8058_PWM_SIZE_9_BIT 0x01
101
102/* Control 6 */
103#define PM8058_PWM_PAUSE_COUNT_LO_MASK 0xFC
104#define PM8058_PWM_PAUSE_COUNT_LO_SHIFT 2
105
106#define PM8058_PWM_PAUSE_ENABLE_LOW 0x02
107#define PM8058_PWM_RESERVED 0x01
108
109#define PM8058_PWM_PAUSE_COUNT_MAX 56 /* < 2^6 = 64*/
110
111/* LUT_CFG1 */
112#define PM8058_PWM_LUT_READ 0x40
113
114/* TEST */
115#define PM8058_PWM_DTEST_MASK 0x38
116#define PM8058_PWM_DTEST_SHIFT 3
117
118#define PM8058_PWM_DTEST_BANK_MASK 0x07
119
120/* PWM frequency support
121 *
122 * PWM Frequency = Clock Frequency / (N * T)
123 * or
124 * PWM Period = Clock Period * (N * T)
125 * where
126 * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
127 * T = Pre-divide * 2^m, m = 0..7 (exponent)
128 *
129 * We use this formula to figure out m for the best pre-divide and clock:
130 * (PWM Period / N) / 2^m = (Pre-divide * Clock Period)
131*/
132#define NUM_CLOCKS 3
133
134#define NSEC_1000HZ (NSEC_PER_SEC / 1000)
135#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
136#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
137
138#define CLK_PERIOD_MIN NSEC_19P2MHZ
139#define CLK_PERIOD_MAX NSEC_1000HZ
140
141#define NUM_PRE_DIVIDE 3 /* No default support for pre-divide = 6 */
142
143#define PRE_DIVIDE_0 2
144#define PRE_DIVIDE_1 3
145#define PRE_DIVIDE_2 5
146
147#define PRE_DIVIDE_MIN PRE_DIVIDE_0
148#define PRE_DIVIDE_MAX PRE_DIVIDE_2
149
150static char *clks[NUM_CLOCKS] = {
151 "1K", "32768", "19.2M"
152};
153
154static unsigned pre_div[NUM_PRE_DIVIDE] = {
155 PRE_DIVIDE_0, PRE_DIVIDE_1, PRE_DIVIDE_2
156};
157
158static unsigned int pt_t[NUM_PRE_DIVIDE][NUM_CLOCKS] = {
159 { PRE_DIVIDE_0 * NSEC_1000HZ,
160 PRE_DIVIDE_0 * NSEC_32768HZ,
161 PRE_DIVIDE_0 * NSEC_19P2MHZ,
162 },
163 { PRE_DIVIDE_1 * NSEC_1000HZ,
164 PRE_DIVIDE_1 * NSEC_32768HZ,
165 PRE_DIVIDE_1 * NSEC_19P2MHZ,
166 },
167 { PRE_DIVIDE_2 * NSEC_1000HZ,
168 PRE_DIVIDE_2 * NSEC_32768HZ,
169 PRE_DIVIDE_2 * NSEC_19P2MHZ,
170 },
171};
172
173#define MIN_MPT ((PRE_DIVIDE_MIN * CLK_PERIOD_MIN) << PM8058_PWM_M_MIN)
174#define MAX_MPT ((PRE_DIVIDE_MAX * CLK_PERIOD_MAX) << PM8058_PWM_M_MAX)
175
176/* Private data */
177struct pm8058_pwm_chip;
178
179struct pwm_device {
180 int pwm_id; /* = bank/channel id */
181 int in_use;
182 const char *label;
183 int pwm_period;
184 int pwm_duty;
185 u8 pwm_ctl[PM8058_LPG_CTL_REGS];
186 int irq;
187 struct pm8058_pwm_chip *chip;
188};
189
190struct pm8058_pwm_chip {
191 struct pwm_device pwm_dev[PM8058_PWM_CHANNELS];
192 u8 bank_mask;
193 struct mutex pwm_mutex;
194 struct pm8058_chip *pm_chip;
195 struct pm8058_pwm_pdata *pdata;
196};
197
198static struct pm8058_pwm_chip *pwm_chip;
199
200struct pw8058_pwm_config {
201 int pwm_size; /* round up to 6 or 9 for 6/9-bit PWM SIZE */
202 int clk;
203 int pre_div;
204 int pre_div_exp;
205 int pwm_value;
206 int bypass_lut;
207
208 /* LUT parameters when bypass_lut is 0 */
209 int lut_duty_ms;
210 int lut_lo_index;
211 int lut_hi_index;
212 int lut_pause_hi;
213 int lut_pause_lo;
214 int flags;
215};
216
217static u16 duty_msec[PM8058_PWM_1KHZ_COUNT_MAX + 1] = {
218 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
219};
220
221static u16 pause_count[PM8058_PWM_PAUSE_COUNT_MAX + 1] = {
222 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
223 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
224 375, 500, 667, 750, 800, 900, 1000, 1100,
225 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
226 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
227 7000
228};
229
230/* Internal functions */
231static int pm8058_pwm_bank_enable(struct pwm_device *pwm, int enable)
232{
233 int rc;
234 u8 reg;
235 struct pm8058_pwm_chip *chip;
236
237 chip = pwm->chip;
238
239 if (enable)
240 reg = chip->bank_mask | (1 << pwm->pwm_id);
241 else
242 reg = chip->bank_mask & ~(1 << pwm->pwm_id);
243
244 rc = pm8058_write(chip->pm_chip, SSBI_REG_ADDR_LPG_BANK_EN, &reg, 1);
245 if (rc) {
Willie Ruan0d9acd92011-07-04 21:31:30 -0700246 pr_err("pm8058_write(): rc=%d (Enable LPG Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 goto bail_out;
248 }
249 chip->bank_mask = reg;
250
251bail_out:
252 return rc;
253}
254
255static int pm8058_pwm_bank_sel(struct pwm_device *pwm)
256{
257 int rc;
258 u8 reg;
259
260 reg = pwm->pwm_id;
261 rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_BANK_SEL,
262 &reg, 1);
263 if (rc)
Willie Ruan0d9acd92011-07-04 21:31:30 -0700264 pr_err("pm8058_write(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 return rc;
266}
267
268static int pm8058_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
269{
270 int rc;
271 u8 reg;
272
273 if (start) {
274 reg = pwm->pwm_ctl[0] | PM8058_PWM_PWM_START;
275 if (ramp_start)
276 reg |= PM8058_PWM_RAMP_GEN_START;
277 else
278 reg &= ~PM8058_PWM_RAMP_GEN_START;
279 } else {
280 reg = pwm->pwm_ctl[0] & ~PM8058_PWM_PWM_START;
281 reg &= ~PM8058_PWM_RAMP_GEN_START;
282 }
283
284 rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_CTL(0),
285 &reg, 1);
286 if (rc)
Willie Ruan0d9acd92011-07-04 21:31:30 -0700287 pr_err("pm8058_write(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 else
289 pwm->pwm_ctl[0] = reg;
290 return rc;
291}
292
293static void pm8058_pwm_calc_period(unsigned int period_us,
294 struct pw8058_pwm_config *pwm_conf)
295{
296 int n, m, clk, div;
297 int best_m, best_div, best_clk;
298 int last_err, cur_err, better_err, better_m;
299 unsigned int tmp_p, last_p, min_err, period_n;
300
301 /* PWM Period / N : handle underflow or overflow */
302 if (period_us < (PM_PWM_PERIOD_MAX / NSEC_PER_USEC))
303 period_n = (period_us * NSEC_PER_USEC) >> 6;
304 else
305 period_n = (period_us >> 6) * NSEC_PER_USEC;
306 if (period_n >= MAX_MPT) {
307 n = 9;
308 period_n >>= 3;
309 } else
310 n = 6;
311
312 min_err = MAX_MPT;
313 best_m = 0;
314 best_clk = 0;
315 best_div = 0;
316 for (clk = 0; clk < NUM_CLOCKS; clk++) {
317 for (div = 0; div < NUM_PRE_DIVIDE; div++) {
318 tmp_p = period_n;
319 last_p = tmp_p;
320 for (m = 0; m <= PM8058_PWM_M_MAX; m++) {
321 if (tmp_p <= pt_t[div][clk]) {
322 /* Found local best */
323 if (!m) {
324 better_err = pt_t[div][clk] -
325 tmp_p;
326 better_m = m;
327 } else {
328 last_err = last_p -
329 pt_t[div][clk];
330 cur_err = pt_t[div][clk] -
331 tmp_p;
332
333 if (cur_err < last_err) {
334 better_err = cur_err;
335 better_m = m;
336 } else {
337 better_err = last_err;
338 better_m = m - 1;
339 }
340 }
341
342 if (better_err < min_err) {
343 min_err = better_err;
344 best_m = better_m;
345 best_clk = clk;
346 best_div = div;
347 }
348 break;
349 } else {
350 last_p = tmp_p;
351 tmp_p >>= 1;
352 }
353 }
354 }
355 }
356
357 pwm_conf->pwm_size = n;
358 pwm_conf->clk = best_clk;
359 pwm_conf->pre_div = best_div;
360 pwm_conf->pre_div_exp = best_m;
361
Willie Ruan0d9acd92011-07-04 21:31:30 -0700362 pr_debug("period=%u: n=%d, m=%d, clk[%d]=%s, div[%d]=%d\n",
363 (unsigned)period_us, n, best_m,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 best_clk, clks[best_clk], best_div, pre_div[best_div]);
365}
366
367static int pm8058_pwm_configure(struct pwm_device *pwm,
368 struct pw8058_pwm_config *pwm_conf)
369{
370 int i, rc, len;
371 u8 reg, ramp_enabled = 0;
372
373 reg = (pwm_conf->pwm_size > 6) ? PM8058_PWM_SIZE_9_BIT : 0;
374 pwm->pwm_ctl[5] = reg;
375
376 reg = ((pwm_conf->clk + 1) << PM8058_PWM_CLK_SEL_SHIFT)
377 & PM8058_PWM_CLK_SEL_MASK;
378 reg |= (pwm_conf->pre_div << PM8058_PWM_PREDIVIDE_SHIFT)
379 & PM8058_PWM_PREDIVIDE_MASK;
380 reg |= pwm_conf->pre_div_exp & PM8058_PWM_M_MASK;
381 pwm->pwm_ctl[4] = reg;
382
383 if (pwm_conf->bypass_lut) {
384 pwm->pwm_ctl[0] &= PM8058_PWM_PWM_START; /* keep enabled */
385 pwm->pwm_ctl[1] = PM8058_PWM_BYPASS_LUT;
386 pwm->pwm_ctl[2] = 0;
387
388 if (pwm_conf->pwm_size > 6) {
389 pwm->pwm_ctl[3] = pwm_conf->pwm_value
390 & PM8058_PWM_VALUE_BIT7_0;
391 pwm->pwm_ctl[4] |= (pwm_conf->pwm_value >> 1)
392 & PM8058_PWM_VALUE_BIT8;
393 } else {
394 pwm->pwm_ctl[3] = pwm_conf->pwm_value
395 & PM8058_PWM_VALUE_BIT5_0;
396 }
397
398 len = 6;
399 } else {
400 int pause_cnt, j;
401
402 /* Linear search for duty time */
403 for (i = 0; i < PM8058_PWM_1KHZ_COUNT_MAX; i++) {
404 if (duty_msec[i] >= pwm_conf->lut_duty_ms)
405 break;
406 }
407
408 ramp_enabled = pwm->pwm_ctl[0] & PM8058_PWM_RAMP_GEN_START;
409 pwm->pwm_ctl[0] &= PM8058_PWM_PWM_START; /* keep enabled */
410 pwm->pwm_ctl[0] |= (i << PM8058_PWM_1KHZ_COUNT_SHIFT) &
411 PM8058_PWM_1KHZ_COUNT_MASK;
412 pwm->pwm_ctl[1] = pwm_conf->lut_hi_index &
413 PM8058_PWM_HIGH_INDEX_MASK;
414 pwm->pwm_ctl[2] = pwm_conf->lut_lo_index &
415 PM8058_PWM_LOW_INDEX_MASK;
416
417 if (pwm_conf->flags & PM_PWM_LUT_REVERSE)
418 pwm->pwm_ctl[1] |= PM8058_PWM_REVERSE_EN;
419 if (pwm_conf->flags & PM_PWM_LUT_RAMP_UP)
420 pwm->pwm_ctl[2] |= PM8058_PWM_RAMP_UP;
421 if (pwm_conf->flags & PM_PWM_LUT_LOOP)
422 pwm->pwm_ctl[2] |= PM8058_PWM_LOOP_EN;
423
424 /* Pause time */
425 if (pwm_conf->flags & PM_PWM_LUT_PAUSE_HI_EN) {
426 /* Linear search for pause time */
427 pause_cnt = (pwm_conf->lut_pause_hi + duty_msec[i] / 2)
428 / duty_msec[i];
429 for (j = 0; j < PM8058_PWM_PAUSE_COUNT_MAX; j++) {
430 if (pause_count[j] >= pause_cnt)
431 break;
432 }
433 pwm->pwm_ctl[5] = (j <<
434 PM8058_PWM_PAUSE_COUNT_HI_SHIFT) &
435 PM8058_PWM_PAUSE_COUNT_HI_MASK;
436 pwm->pwm_ctl[5] |= PM8058_PWM_PAUSE_ENABLE_HIGH;
437 } else
438 pwm->pwm_ctl[5] = 0;
439
440 if (pwm_conf->flags & PM_PWM_LUT_PAUSE_LO_EN) {
441 /* Linear search for pause time */
442 pause_cnt = (pwm_conf->lut_pause_lo + duty_msec[i] / 2)
443 / duty_msec[i];
444 for (j = 0; j < PM8058_PWM_PAUSE_COUNT_MAX; j++) {
445 if (pause_count[j] >= pause_cnt)
446 break;
447 }
448 pwm->pwm_ctl[6] = (j <<
449 PM8058_PWM_PAUSE_COUNT_LO_SHIFT) &
450 PM8058_PWM_PAUSE_COUNT_LO_MASK;
451 pwm->pwm_ctl[6] |= PM8058_PWM_PAUSE_ENABLE_LOW;
452 } else
453 pwm->pwm_ctl[6] = 0;
454
455 len = 7;
456 }
457
458 pm8058_pwm_bank_sel(pwm);
459
460 for (i = 0; i < len; i++) {
461 rc = pm8058_write(pwm->chip->pm_chip,
462 SSBI_REG_ADDR_LPG_CTL(i),
463 &pwm->pwm_ctl[i], 1);
464 if (rc) {
Willie Ruan0d9acd92011-07-04 21:31:30 -0700465 pr_err("pm8058_write(): rc=%d (PWM Ctl[%d])\n", rc, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 break;
467 }
468 }
469
470 if (ramp_enabled) {
471 pwm->pwm_ctl[0] |= ramp_enabled;
472 pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_CTL(0),
473 &pwm->pwm_ctl[0], 1);
474 }
475
476 return rc;
477}
478
479/* APIs */
480/*
481 * pwm_request - request a PWM device
482 */
483struct pwm_device *pwm_request(int pwm_id, const char *label)
484{
485 struct pwm_device *pwm;
486
487 if (pwm_id > PM8058_PWM_CHANNELS || pwm_id < 0)
488 return ERR_PTR(-EINVAL);
489 if (pwm_chip == NULL)
490 return ERR_PTR(-ENODEV);
491
492 mutex_lock(&pwm_chip->pwm_mutex);
493 pwm = &pwm_chip->pwm_dev[pwm_id];
494 if (!pwm->in_use) {
495 pwm->in_use = 1;
496 pwm->label = label;
497
498 if (pwm_chip->pdata && pwm_chip->pdata->config)
499 pwm_chip->pdata->config(pwm, pwm_id, 1);
500 } else
501 pwm = ERR_PTR(-EBUSY);
502 mutex_unlock(&pwm_chip->pwm_mutex);
503
504 return pwm;
505}
506EXPORT_SYMBOL(pwm_request);
507
508/*
509 * pwm_free - free a PWM device
510 */
511void pwm_free(struct pwm_device *pwm)
512{
513 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL)
514 return;
515
516 mutex_lock(&pwm->chip->pwm_mutex);
517 if (pwm->in_use) {
518 pm8058_pwm_bank_sel(pwm);
519 pm8058_pwm_start(pwm, 0, 0);
520
521 if (pwm->chip->pdata && pwm->chip->pdata->config)
522 pwm->chip->pdata->config(pwm, pwm->pwm_id, 0);
523
524 pwm->in_use = 0;
525 pwm->label = NULL;
526 }
527 pm8058_pwm_bank_enable(pwm, 0);
528 mutex_unlock(&pwm->chip->pwm_mutex);
529}
530EXPORT_SYMBOL(pwm_free);
531
532/*
533 * pwm_config - change a PWM device configuration
534 *
535 * @pwm: the PWM device
536 * @period_us: period in micro second
537 * @duty_us: duty cycle in micro second
538 */
539int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
540{
541 struct pw8058_pwm_config pwm_conf;
542 unsigned int max_pwm_value, tmp;
543 int rc;
544
545 if (pwm == NULL || IS_ERR(pwm) ||
546 (unsigned)duty_us > (unsigned)period_us ||
547 (unsigned)period_us > PM_PWM_PERIOD_MAX ||
548 (unsigned)period_us < PM_PWM_PERIOD_MIN)
549 return -EINVAL;
550 if (pwm->chip == NULL)
551 return -ENODEV;
552
553 mutex_lock(&pwm->chip->pwm_mutex);
554
555 if (!pwm->in_use) {
556 rc = -EINVAL;
557 goto out_unlock;
558 }
559
560 pm8058_pwm_calc_period(period_us, &pwm_conf);
561
562 /* Figure out pwm_value with overflow handling */
563 if ((unsigned)period_us > (1 << pwm_conf.pwm_size)) {
564 tmp = period_us;
565 tmp >>= pwm_conf.pwm_size;
566 pwm_conf.pwm_value = (unsigned)duty_us / tmp;
567 } else {
568 tmp = duty_us;
569 tmp <<= pwm_conf.pwm_size;
570 pwm_conf.pwm_value = tmp / (unsigned)period_us;
571 }
572 max_pwm_value = (1 << pwm_conf.pwm_size) - 1;
573 if (pwm_conf.pwm_value > max_pwm_value)
574 pwm_conf.pwm_value = max_pwm_value;
575
576 pwm_conf.bypass_lut = 1;
577
Willie Ruan0d9acd92011-07-04 21:31:30 -0700578 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
579 (unsigned)duty_us, (unsigned)period_us,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700580 pwm_conf.pwm_value, 1 << pwm_conf.pwm_size);
581
582 rc = pm8058_pwm_configure(pwm, &pwm_conf);
583
584out_unlock:
585 mutex_unlock(&pwm->chip->pwm_mutex);
586 return rc;
587}
588EXPORT_SYMBOL(pwm_config);
589
590/*
591 * pwm_enable - start a PWM output toggling
592 */
593int pwm_enable(struct pwm_device *pwm)
594{
595 int rc;
596
597 if (pwm == NULL || IS_ERR(pwm))
598 return -EINVAL;
599 if (pwm->chip == NULL)
600 return -ENODEV;
601
602 mutex_lock(&pwm->chip->pwm_mutex);
603 if (!pwm->in_use)
604 rc = -EINVAL;
605 else {
606 if (pwm->chip->pdata && pwm->chip->pdata->enable)
607 pwm->chip->pdata->enable(pwm, pwm->pwm_id, 1);
608
609 rc = pm8058_pwm_bank_enable(pwm, 1);
610
611 pm8058_pwm_bank_sel(pwm);
612 pm8058_pwm_start(pwm, 1, 0);
613 }
614 mutex_unlock(&pwm->chip->pwm_mutex);
615 return rc;
616}
617EXPORT_SYMBOL(pwm_enable);
618
619/*
620 * pwm_disable - stop a PWM output toggling
621 */
622void pwm_disable(struct pwm_device *pwm)
623{
624 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL)
625 return;
626
627 mutex_lock(&pwm->chip->pwm_mutex);
628 if (pwm->in_use) {
629 pm8058_pwm_bank_sel(pwm);
630 pm8058_pwm_start(pwm, 0, 0);
631
632 pm8058_pwm_bank_enable(pwm, 0);
633
634 if (pwm->chip->pdata && pwm->chip->pdata->enable)
635 pwm->chip->pdata->enable(pwm, pwm->pwm_id, 0);
636 }
637 mutex_unlock(&pwm->chip->pwm_mutex);
638}
639EXPORT_SYMBOL(pwm_disable);
640
641/*
642 * pm8058_pwm_lut_config - change a PWM device configuration to use LUT
643 *
644 * @pwm: the PWM device
645 * @period_us: period in micro second
646 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
647 * @duty_time_ms: time for each duty cycle in millisecond
648 * @start_idx: start index in lookup table from 0 to MAX-1
649 * @idx_len: number of index
650 * @pause_lo: pause time in millisecond at low index
651 * @pause_hi: pause time in millisecond at high index
652 * @flags: control flags
653 *
654 */
655int pm8058_pwm_lut_config(struct pwm_device *pwm, int period_us,
656 int duty_pct[], int duty_time_ms, int start_idx,
657 int idx_len, int pause_lo, int pause_hi, int flags)
658{
659 struct pw8058_pwm_config pwm_conf;
660 unsigned int pwm_value, max_pwm_value;
661 u8 cfg0, cfg1;
662 int i, len;
663 int rc;
664
665 if (pwm == NULL || IS_ERR(pwm) || !idx_len)
666 return -EINVAL;
667 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE))
668 return -EINVAL;
669 if (pwm->chip == NULL)
670 return -ENODEV;
671 if (idx_len >= PM_PWM_LUT_SIZE && start_idx)
672 return -EINVAL;
673 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE)
674 return -EINVAL;
675 if ((unsigned)period_us > PM_PWM_PERIOD_MAX ||
676 (unsigned)period_us < PM_PWM_PERIOD_MIN)
677 return -EINVAL;
678
679 mutex_lock(&pwm->chip->pwm_mutex);
680
681 if (!pwm->in_use) {
682 rc = -EINVAL;
683 goto out_unlock;
684 }
685
686 pm8058_pwm_calc_period(period_us, &pwm_conf);
687
688 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
689
690 if (flags & PM_PWM_LUT_NO_TABLE)
691 goto after_table_write;
692
693 max_pwm_value = (1 << pwm_conf.pwm_size) - 1;
694 for (i = 0; i < len; i++) {
695 pwm_value = (duty_pct[i] << pwm_conf.pwm_size) / 100;
696 /* Avoid overflow */
697 if (pwm_value > max_pwm_value)
698 pwm_value = max_pwm_value;
699 cfg0 = pwm_value & 0xff;
700 cfg1 = (pwm_value >> 1) & 0x80;
701 cfg1 |= start_idx + i;
702
Willie Ruan0d9acd92011-07-04 21:31:30 -0700703 pr_debug("%d: pwm=%d\n", i, pwm_value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704
705 pm8058_write(pwm->chip->pm_chip,
706 SSBI_REG_ADDR_LPG_LUT_CFG0,
707 &cfg0, 1);
708 pm8058_write(pwm->chip->pm_chip,
709 SSBI_REG_ADDR_LPG_LUT_CFG1,
710 &cfg1, 1);
711 }
712
713after_table_write:
714 pwm_conf.lut_duty_ms = duty_time_ms;
715 pwm_conf.lut_lo_index = start_idx;
716 pwm_conf.lut_hi_index = start_idx + len - 1;
717 pwm_conf.lut_pause_lo = pause_lo;
718 pwm_conf.lut_pause_hi = pause_hi;
719 pwm_conf.flags = flags;
720 pwm_conf.bypass_lut = 0;
721
722 rc = pm8058_pwm_configure(pwm, &pwm_conf);
723
724out_unlock:
725 mutex_unlock(&pwm->chip->pwm_mutex);
726 return rc;
727}
728EXPORT_SYMBOL(pm8058_pwm_lut_config);
729
730/*
731 * pm8058_pwm_lut_enable - control a PWM device to start/stop LUT ramp
732 *
733 * @pwm: the PWM device
734 * @start: to start (1), or stop (0)
735 */
736int pm8058_pwm_lut_enable(struct pwm_device *pwm, int start)
737{
738 if (pwm == NULL || IS_ERR(pwm))
739 return -EINVAL;
740 if (pwm->chip == NULL)
741 return -ENODEV;
742
743 mutex_lock(&pwm->chip->pwm_mutex);
744 if (start) {
745 pm8058_pwm_bank_enable(pwm, 1);
746
747 pm8058_pwm_bank_sel(pwm);
748 pm8058_pwm_start(pwm, 1, 1);
749 } else {
750 pm8058_pwm_bank_sel(pwm);
751 pm8058_pwm_start(pwm, 0, 0);
752
753 pm8058_pwm_bank_enable(pwm, 0);
754 }
755 mutex_unlock(&pwm->chip->pwm_mutex);
756 return 0;
757}
758EXPORT_SYMBOL(pm8058_pwm_lut_enable);
759
760#define SSBI_REG_ADDR_LED_BASE 0x131
761#define SSBI_REG_ADDR_LED(n) (SSBI_REG_ADDR_LED_BASE + (n))
762#define SSBI_REG_ADDR_FLASH_BASE 0x48
763#define SSBI_REG_ADDR_FLASH_DRV_1 0xFB
764#define SSBI_REG_ADDR_FLASH(n) (((n) < 2 ? \
765 SSBI_REG_ADDR_FLASH_BASE + (n) : \
766 SSBI_REG_ADDR_FLASH_DRV_1))
767
768#define PM8058_LED_CURRENT_SHIFT 3
769#define PM8058_LED_MODE_MASK 0x07
770
771#define PM8058_FLASH_CURRENT_SHIFT 4
772#define PM8058_FLASH_MODE_MASK 0x03
773#define PM8058_FLASH_MODE_NONE 0
774#define PM8058_FLASH_MODE_DTEST1 1
775#define PM8058_FLASH_MODE_DTEST2 2
776#define PM8058_FLASH_MODE_PWM 3
777
778int pm8058_pwm_config_led(struct pwm_device *pwm, int id,
779 int mode, int max_current)
780{
781 int rc;
782 u8 conf;
783
784 switch (id) {
785 case PM_PWM_LED_0:
786 case PM_PWM_LED_1:
787 case PM_PWM_LED_2:
788 conf = mode & PM8058_LED_MODE_MASK;
789 conf |= (max_current / 2) << PM8058_LED_CURRENT_SHIFT;
790 rc = pm8058_write(pwm->chip->pm_chip,
791 SSBI_REG_ADDR_LED(id), &conf, 1);
792 break;
793
794 case PM_PWM_LED_KPD:
795 case PM_PWM_LED_FLASH:
796 case PM_PWM_LED_FLASH1:
797 switch (mode) {
798 case PM_PWM_CONF_PWM1:
799 case PM_PWM_CONF_PWM2:
800 case PM_PWM_CONF_PWM3:
801 conf = PM8058_FLASH_MODE_PWM;
802 break;
803 case PM_PWM_CONF_DTEST1:
804 conf = PM8058_FLASH_MODE_DTEST1;
805 break;
806 case PM_PWM_CONF_DTEST2:
807 conf = PM8058_FLASH_MODE_DTEST2;
808 break;
809 default:
810 conf = PM8058_FLASH_MODE_NONE;
811 break;
812 }
813 conf |= (max_current / 20) << PM8058_FLASH_CURRENT_SHIFT;
814 id -= PM_PWM_LED_KPD;
815 rc = pm8058_write(pwm->chip->pm_chip,
816 SSBI_REG_ADDR_FLASH(id), &conf, 1);
817 break;
818 default:
819 rc = -EINVAL;
820 break;
821 }
822
823 return rc;
824}
825EXPORT_SYMBOL(pm8058_pwm_config_led);
826
827int pm8058_pwm_set_dtest(struct pwm_device *pwm, int enable)
828{
829 int rc;
830 u8 reg;
831
832 if (pwm == NULL || IS_ERR(pwm))
833 return -EINVAL;
834 if (pwm->chip == NULL)
835 return -ENODEV;
836
837 if (!pwm->in_use)
838 rc = -EINVAL;
839 else {
840 reg = pwm->pwm_id & PM8058_PWM_DTEST_BANK_MASK;
841 if (enable)
842 /* Only Test 1 available */
843 reg |= (1 << PM8058_PWM_DTEST_SHIFT) &
844 PM8058_PWM_DTEST_MASK;
845 rc = pm8058_write(pwm->chip->pm_chip, SSBI_REG_ADDR_LPG_TEST,
846 &reg, 1);
847 if (rc)
Willie Ruan0d9acd92011-07-04 21:31:30 -0700848 pr_err("pm8058_write(DTEST=0x%x): rc=%d\n", reg, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700849
850 }
851 return rc;
852}
853EXPORT_SYMBOL(pm8058_pwm_set_dtest);
854
855static int __devinit pmic8058_pwm_probe(struct platform_device *pdev)
856{
857 struct pm8058_chip *pm_chip;
858 struct pm8058_pwm_chip *chip;
859 int i;
860
861 pm_chip = dev_get_drvdata(pdev->dev.parent);
862 if (pm_chip == NULL) {
Willie Ruan0d9acd92011-07-04 21:31:30 -0700863 pr_err("no parent data passed in.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864 return -EFAULT;
865 }
866
867 chip = kzalloc(sizeof *chip, GFP_KERNEL);
868 if (chip == NULL) {
Willie Ruan0d9acd92011-07-04 21:31:30 -0700869 pr_err("kzalloc() failed.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870 return -ENOMEM;
871 }
872
873 for (i = 0; i < PM8058_PWM_CHANNELS; i++) {
874 chip->pwm_dev[i].pwm_id = i;
875 chip->pwm_dev[i].chip = chip;
876 }
877
878 mutex_init(&chip->pwm_mutex);
879
880 chip->pdata = pdev->dev.platform_data;
881 chip->pm_chip = pm_chip;
882 pwm_chip = chip;
883 platform_set_drvdata(pdev, chip);
884
Willie Ruan0d9acd92011-07-04 21:31:30 -0700885 pr_notice("OK\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 return 0;
887}
888
889static int __devexit pmic8058_pwm_remove(struct platform_device *pdev)
890{
891 struct pm8058_pwm_chip *chip = platform_get_drvdata(pdev);
892
893 platform_set_drvdata(pdev, NULL);
894 kfree(chip);
895 return 0;
896}
897
898static struct platform_driver pmic8058_pwm_driver = {
899 .probe = pmic8058_pwm_probe,
900 .remove = __devexit_p(pmic8058_pwm_remove),
901 .driver = {
902 .name = "pm8058-pwm",
903 .owner = THIS_MODULE,
904 },
905};
906
907static int __init pm8058_pwm_init(void)
908{
909 return platform_driver_register(&pmic8058_pwm_driver);
910}
911
912static void __exit pm8058_pwm_exit(void)
913{
914 platform_driver_unregister(&pmic8058_pwm_driver);
915}
916
917subsys_initcall(pm8058_pwm_init);
918module_exit(pm8058_pwm_exit);
919
920MODULE_LICENSE("GPL v2");
921MODULE_DESCRIPTION("PMIC8058 PWM driver");
922MODULE_VERSION("1.0");
923MODULE_ALIAS("platform:pmic8058_pwm");