blob: 996a81ed0addb5789da488561a292b45f7f4a3c2 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010-2011, The Linux Foundation. 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>
Anirudh Ghayalc2019332011-11-12 06:29:10 +053022#include <linux/slab.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/err.h>
24#include <linux/pwm.h>
Anirudh Ghayalc2019332011-11-12 06:29:10 +053025#include <linux/mfd/pm8xxx/core.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/pmic8058-pwm.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027
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
Willie Ruan368db792011-07-05 08:09:58 -0700176#define CHAN_LUT_SIZE (PM_PWM_LUT_SIZE / PM8058_PWM_CHANNELS)
177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178/* Private data */
179struct pm8058_pwm_chip;
180
181struct pwm_device {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530182 struct device *dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183 int pwm_id; /* = bank/channel id */
184 int in_use;
185 const char *label;
Willie Ruand3337ed2011-07-04 23:16:22 -0700186 struct pm8058_pwm_period period;
187 int pwm_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188 int pwm_period;
Willie Ruan368db792011-07-05 08:09:58 -0700189 int use_lut; /* Use LUT to output PWM */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 u8 pwm_ctl[PM8058_LPG_CTL_REGS];
191 int irq;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530192 struct pm8058_pwm_chip *chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193};
194
195struct pm8058_pwm_chip {
196 struct pwm_device pwm_dev[PM8058_PWM_CHANNELS];
197 u8 bank_mask;
198 struct mutex pwm_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199 struct pm8058_pwm_pdata *pdata;
200};
201
202static struct pm8058_pwm_chip *pwm_chip;
203
Willie Ruand3337ed2011-07-04 23:16:22 -0700204struct pm8058_pwm_lut {
205 /* LUT parameters */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206 int lut_duty_ms;
207 int lut_lo_index;
208 int lut_hi_index;
209 int lut_pause_hi;
210 int lut_pause_lo;
211 int flags;
212};
213
214static u16 duty_msec[PM8058_PWM_1KHZ_COUNT_MAX + 1] = {
215 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
216};
217
218static u16 pause_count[PM8058_PWM_PAUSE_COUNT_MAX + 1] = {
219 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
220 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
221 375, 500, 667, 750, 800, 900, 1000, 1100,
222 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
223 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
224 7000
225};
226
227/* Internal functions */
Willie Ruanefc2fa42011-07-05 00:12:41 -0700228static void pm8058_pwm_save(u8 *u8p, u8 mask, u8 val)
229{
230 *u8p &= ~mask;
231 *u8p |= val & mask;
232}
233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234static int pm8058_pwm_bank_enable(struct pwm_device *pwm, int enable)
235{
236 int rc;
237 u8 reg;
238 struct pm8058_pwm_chip *chip;
239
240 chip = pwm->chip;
241
242 if (enable)
243 reg = chip->bank_mask | (1 << pwm->pwm_id);
244 else
245 reg = chip->bank_mask & ~(1 << pwm->pwm_id);
246
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530247 rc = pm8xxx_writeb(pwm->dev->parent,
248 SSBI_REG_ADDR_LPG_BANK_EN, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 if (rc) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530250 pr_err("pm8xxx_write(): rc=%d (Enable LPG Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 goto bail_out;
252 }
253 chip->bank_mask = reg;
254
255bail_out:
256 return rc;
257}
258
259static int pm8058_pwm_bank_sel(struct pwm_device *pwm)
260{
261 int rc;
262 u8 reg;
263
264 reg = pwm->pwm_id;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530265 rc = pm8xxx_writeb(pwm->dev->parent,
266 SSBI_REG_ADDR_LPG_BANK_SEL, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 if (rc)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530268 pr_err("pm8xxx_write(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 return rc;
270}
271
272static int pm8058_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
273{
274 int rc;
275 u8 reg;
276
277 if (start) {
278 reg = pwm->pwm_ctl[0] | PM8058_PWM_PWM_START;
279 if (ramp_start)
280 reg |= PM8058_PWM_RAMP_GEN_START;
281 else
282 reg &= ~PM8058_PWM_RAMP_GEN_START;
283 } else {
284 reg = pwm->pwm_ctl[0] & ~PM8058_PWM_PWM_START;
285 reg &= ~PM8058_PWM_RAMP_GEN_START;
286 }
287
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530288 rc = pm8xxx_writeb(pwm->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
289 reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 if (rc)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530291 pr_err("pm8xxx_write(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292 else
293 pwm->pwm_ctl[0] = reg;
294 return rc;
295}
296
297static void pm8058_pwm_calc_period(unsigned int period_us,
Willie Ruand3337ed2011-07-04 23:16:22 -0700298 struct pm8058_pwm_period *period)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299{
300 int n, m, clk, div;
301 int best_m, best_div, best_clk;
302 int last_err, cur_err, better_err, better_m;
303 unsigned int tmp_p, last_p, min_err, period_n;
304
305 /* PWM Period / N : handle underflow or overflow */
306 if (period_us < (PM_PWM_PERIOD_MAX / NSEC_PER_USEC))
307 period_n = (period_us * NSEC_PER_USEC) >> 6;
308 else
309 period_n = (period_us >> 6) * NSEC_PER_USEC;
310 if (period_n >= MAX_MPT) {
311 n = 9;
312 period_n >>= 3;
313 } else
314 n = 6;
315
316 min_err = MAX_MPT;
317 best_m = 0;
318 best_clk = 0;
319 best_div = 0;
320 for (clk = 0; clk < NUM_CLOCKS; clk++) {
321 for (div = 0; div < NUM_PRE_DIVIDE; div++) {
322 tmp_p = period_n;
323 last_p = tmp_p;
324 for (m = 0; m <= PM8058_PWM_M_MAX; m++) {
325 if (tmp_p <= pt_t[div][clk]) {
326 /* Found local best */
327 if (!m) {
328 better_err = pt_t[div][clk] -
329 tmp_p;
330 better_m = m;
331 } else {
332 last_err = last_p -
333 pt_t[div][clk];
334 cur_err = pt_t[div][clk] -
335 tmp_p;
336
337 if (cur_err < last_err) {
338 better_err = cur_err;
339 better_m = m;
340 } else {
341 better_err = last_err;
342 better_m = m - 1;
343 }
344 }
345
346 if (better_err < min_err) {
347 min_err = better_err;
348 best_m = better_m;
349 best_clk = clk;
350 best_div = div;
351 }
352 break;
353 } else {
354 last_p = tmp_p;
355 tmp_p >>= 1;
356 }
357 }
358 }
359 }
360
Willie Ruan7bd18192011-07-05 14:11:17 -0700361 /* Use higher resolution */
362 if (best_m >= 3 && n == 6) {
363 n += 3;
364 best_m -= 3;
365 }
366
Willie Ruand3337ed2011-07-04 23:16:22 -0700367 period->pwm_size = n;
368 period->clk = best_clk;
369 period->pre_div = best_div;
370 period->pre_div_exp = best_m;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371
Willie Ruan0d9acd92011-07-04 21:31:30 -0700372 pr_debug("period=%u: n=%d, m=%d, clk[%d]=%s, div[%d]=%d\n",
373 (unsigned)period_us, n, best_m,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374 best_clk, clks[best_clk], best_div, pre_div[best_div]);
375}
376
Willie Ruanefc2fa42011-07-05 00:12:41 -0700377static void pm8058_pwm_calc_pwm_value(struct pwm_device *pwm,
378 unsigned int period_us,
379 unsigned int duty_us)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380{
Willie Ruanefc2fa42011-07-05 00:12:41 -0700381 unsigned int max_pwm_value, tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382
Willie Ruanefc2fa42011-07-05 00:12:41 -0700383 /* Figure out pwm_value with overflow handling */
384 tmp = 1 << (sizeof(tmp) * 8 - pwm->period.pwm_size);
385 if (duty_us < tmp) {
386 tmp = duty_us << pwm->period.pwm_size;
387 pwm->pwm_value = tmp / period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 } else {
Willie Ruanefc2fa42011-07-05 00:12:41 -0700389 tmp = period_us >> pwm->period.pwm_size;
390 pwm->pwm_value = duty_us / tmp;
391 }
392 max_pwm_value = (1 << pwm->period.pwm_size) - 1;
393 if (pwm->pwm_value > max_pwm_value)
394 pwm->pwm_value = max_pwm_value;
395}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396
Willie Ruanefc2fa42011-07-05 00:12:41 -0700397static int pm8058_pwm_change_table(struct pwm_device *pwm, int duty_pct[],
398 int start_idx, int len, int raw_value)
399{
400 unsigned int pwm_value, max_pwm_value;
401 u8 cfg0, cfg1;
402 int i, pwm_size;
403 int rc = 0;
404
405 pwm_size = (pwm->pwm_ctl[5] & PM8058_PWM_SIZE_9_BIT) ? 9 : 6;
406 max_pwm_value = (1 << pwm_size) - 1;
407 for (i = 0; i < len; i++) {
408 if (raw_value)
409 pwm_value = duty_pct[i];
410 else
411 pwm_value = (duty_pct[i] << pwm_size) / 100;
412
413 if (pwm_value > max_pwm_value)
414 pwm_value = max_pwm_value;
415 cfg0 = pwm_value;
416 cfg1 = (pwm_value >> 1) & 0x80;
417 cfg1 |= start_idx + i;
418
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530419 rc = pm8xxx_writeb(pwm->dev->parent,
420 SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
Willie Ruanefc2fa42011-07-05 00:12:41 -0700421 if (rc)
422 break;
423
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530424 rc = pm8xxx_writeb(pwm->dev->parent,
425 SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
Willie Ruanefc2fa42011-07-05 00:12:41 -0700426 if (rc)
427 break;
428 }
429 return rc;
430}
431
432static void pm8058_pwm_save_index(struct pwm_device *pwm,
433 int low_idx, int high_idx, int flags)
434{
435 pwm->pwm_ctl[1] = high_idx & PM8058_PWM_HIGH_INDEX_MASK;
436 pwm->pwm_ctl[2] = low_idx & PM8058_PWM_LOW_INDEX_MASK;
437
438 if (flags & PM_PWM_LUT_REVERSE)
439 pwm->pwm_ctl[1] |= PM8058_PWM_REVERSE_EN;
440 if (flags & PM_PWM_LUT_RAMP_UP)
441 pwm->pwm_ctl[2] |= PM8058_PWM_RAMP_UP;
442 if (flags & PM_PWM_LUT_LOOP)
443 pwm->pwm_ctl[2] |= PM8058_PWM_LOOP_EN;
444}
445
446static void pm8058_pwm_save_period(struct pwm_device *pwm)
447{
448 u8 mask, val;
449
450 val = ((pwm->period.clk + 1) << PM8058_PWM_CLK_SEL_SHIFT)
451 & PM8058_PWM_CLK_SEL_MASK;
452 val |= (pwm->period.pre_div << PM8058_PWM_PREDIVIDE_SHIFT)
453 & PM8058_PWM_PREDIVIDE_MASK;
454 val |= pwm->period.pre_div_exp & PM8058_PWM_M_MASK;
455 mask = PM8058_PWM_CLK_SEL_MASK | PM8058_PWM_PREDIVIDE_MASK |
456 PM8058_PWM_M_MASK;
457 pm8058_pwm_save(&pwm->pwm_ctl[4], mask, val);
458
459 val = (pwm->period.pwm_size > 6) ? PM8058_PWM_SIZE_9_BIT : 0;
460 mask = PM8058_PWM_SIZE_9_BIT;
461 pm8058_pwm_save(&pwm->pwm_ctl[5], mask, val);
462}
463
464static void pm8058_pwm_save_pwm_value(struct pwm_device *pwm)
465{
466 u8 mask, val;
467
468 pwm->pwm_ctl[3] = pwm->pwm_value;
469
470 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 1) : 0;
471 mask = PM8058_PWM_VALUE_BIT8;
472 pm8058_pwm_save(&pwm->pwm_ctl[4], mask, val);
473}
474
475static void pm8058_pwm_save_duty_time(struct pwm_device *pwm,
476 struct pm8058_pwm_lut *lut)
477{
478 int i;
479 u8 mask, val;
480
481 /* Linear search for duty time */
482 for (i = 0; i < PM8058_PWM_1KHZ_COUNT_MAX; i++) {
483 if (duty_msec[i] >= lut->lut_duty_ms)
484 break;
485 }
486 val = i << PM8058_PWM_1KHZ_COUNT_SHIFT;
487
488 mask = PM8058_PWM_1KHZ_COUNT_MASK;
489 pm8058_pwm_save(&pwm->pwm_ctl[0], mask, val);
490}
491
492static void pm8058_pwm_save_pause(struct pwm_device *pwm,
493 struct pm8058_pwm_lut *lut)
494{
495 int i, pause_cnt, time_cnt;
496 u8 mask, val;
497
498 time_cnt = (pwm->pwm_ctl[0] & PM8058_PWM_1KHZ_COUNT_MASK)
499 >> PM8058_PWM_1KHZ_COUNT_SHIFT;
500 if (lut->flags & PM_PWM_LUT_PAUSE_HI_EN) {
501 pause_cnt = (lut->lut_pause_hi + duty_msec[time_cnt] / 2)
502 / duty_msec[time_cnt];
503 /* Linear search for pause time */
504 for (i = 0; i < PM8058_PWM_PAUSE_COUNT_MAX; i++) {
505 if (pause_count[i] >= pause_cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 break;
507 }
Willie Ruanefc2fa42011-07-05 00:12:41 -0700508 val = (i << PM8058_PWM_PAUSE_COUNT_HI_SHIFT) &
509 PM8058_PWM_PAUSE_COUNT_HI_MASK;
510 val |= PM8058_PWM_PAUSE_ENABLE_HIGH;
511 } else
512 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513
Willie Ruanefc2fa42011-07-05 00:12:41 -0700514 mask = PM8058_PWM_PAUSE_COUNT_HI_MASK | PM8058_PWM_PAUSE_ENABLE_HIGH;
515 pm8058_pwm_save(&pwm->pwm_ctl[5], mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700516
Willie Ruanefc2fa42011-07-05 00:12:41 -0700517 if (lut->flags & PM_PWM_LUT_PAUSE_LO_EN) {
518 /* Linear search for pause time */
519 pause_cnt = (lut->lut_pause_lo + duty_msec[time_cnt] / 2)
520 / duty_msec[time_cnt];
521 for (i = 0; i < PM8058_PWM_PAUSE_COUNT_MAX; i++) {
522 if (pause_count[i] >= pause_cnt)
523 break;
524 }
525 val = (i << PM8058_PWM_PAUSE_COUNT_LO_SHIFT) &
526 PM8058_PWM_PAUSE_COUNT_LO_MASK;
527 val |= PM8058_PWM_PAUSE_ENABLE_LOW;
528 } else
529 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530
Willie Ruanefc2fa42011-07-05 00:12:41 -0700531 mask = PM8058_PWM_PAUSE_COUNT_LO_MASK | PM8058_PWM_PAUSE_ENABLE_LOW;
532 pm8058_pwm_save(&pwm->pwm_ctl[6], mask, val);
533}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534
Willie Ruanefc2fa42011-07-05 00:12:41 -0700535static int pm8058_pwm_write(struct pwm_device *pwm, int start, int end)
536{
537 int i, rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700538
Willie Ruanefc2fa42011-07-05 00:12:41 -0700539 /* Write in reverse way so 0 would be the last */
540 for (i = end - 1; i >= start; i--) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530541 rc = pm8xxx_writeb(pwm->dev->parent,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542 SSBI_REG_ADDR_LPG_CTL(i),
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530543 pwm->pwm_ctl[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544 if (rc) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530545 pr_err("pm8xxx_write(): rc=%d (PWM Ctl[%d])\n", rc, i);
Willie Ruanefc2fa42011-07-05 00:12:41 -0700546 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547 }
548 }
549
Willie Ruanefc2fa42011-07-05 00:12:41 -0700550 return 0;
551}
552
553static int pm8058_pwm_change_lut(struct pwm_device *pwm,
554 struct pm8058_pwm_lut *lut)
555{
556 int rc;
557
558 pm8058_pwm_save_index(pwm, lut->lut_lo_index,
559 lut->lut_hi_index, lut->flags);
560 pm8058_pwm_save_duty_time(pwm, lut);
561 pm8058_pwm_save_pause(pwm, lut);
562 pm8058_pwm_save(&pwm->pwm_ctl[1], PM8058_PWM_BYPASS_LUT, 0);
563
564 pm8058_pwm_bank_sel(pwm);
565 rc = pm8058_pwm_write(pwm, 0, 7);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700566
567 return rc;
568}
569
570/* APIs */
571/*
572 * pwm_request - request a PWM device
573 */
574struct pwm_device *pwm_request(int pwm_id, const char *label)
575{
576 struct pwm_device *pwm;
577
578 if (pwm_id > PM8058_PWM_CHANNELS || pwm_id < 0)
579 return ERR_PTR(-EINVAL);
580 if (pwm_chip == NULL)
581 return ERR_PTR(-ENODEV);
582
583 mutex_lock(&pwm_chip->pwm_mutex);
584 pwm = &pwm_chip->pwm_dev[pwm_id];
585 if (!pwm->in_use) {
586 pwm->in_use = 1;
587 pwm->label = label;
Willie Ruan368db792011-07-05 08:09:58 -0700588 pwm->use_lut = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589
590 if (pwm_chip->pdata && pwm_chip->pdata->config)
591 pwm_chip->pdata->config(pwm, pwm_id, 1);
592 } else
593 pwm = ERR_PTR(-EBUSY);
594 mutex_unlock(&pwm_chip->pwm_mutex);
595
596 return pwm;
597}
598EXPORT_SYMBOL(pwm_request);
599
600/*
601 * pwm_free - free a PWM device
602 */
603void pwm_free(struct pwm_device *pwm)
604{
605 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL)
606 return;
607
608 mutex_lock(&pwm->chip->pwm_mutex);
609 if (pwm->in_use) {
610 pm8058_pwm_bank_sel(pwm);
611 pm8058_pwm_start(pwm, 0, 0);
612
613 if (pwm->chip->pdata && pwm->chip->pdata->config)
614 pwm->chip->pdata->config(pwm, pwm->pwm_id, 0);
615
616 pwm->in_use = 0;
617 pwm->label = NULL;
618 }
619 pm8058_pwm_bank_enable(pwm, 0);
620 mutex_unlock(&pwm->chip->pwm_mutex);
621}
622EXPORT_SYMBOL(pwm_free);
623
624/*
625 * pwm_config - change a PWM device configuration
626 *
627 * @pwm: the PWM device
628 * @period_us: period in micro second
629 * @duty_us: duty cycle in micro second
630 */
631int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
632{
Willie Ruand3337ed2011-07-04 23:16:22 -0700633 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634
635 if (pwm == NULL || IS_ERR(pwm) ||
Willie Ruan8a08b962011-07-05 00:43:37 -0700636 duty_us > period_us ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 (unsigned)period_us > PM_PWM_PERIOD_MAX ||
638 (unsigned)period_us < PM_PWM_PERIOD_MIN)
639 return -EINVAL;
640 if (pwm->chip == NULL)
641 return -ENODEV;
642
643 mutex_lock(&pwm->chip->pwm_mutex);
644
645 if (!pwm->in_use) {
646 rc = -EINVAL;
647 goto out_unlock;
648 }
649
Willie Ruan8a08b962011-07-05 00:43:37 -0700650 if (pwm->pwm_period != period_us) {
651 pm8058_pwm_calc_period(period_us, &pwm->period);
652 pm8058_pwm_save_period(pwm);
653 pwm->pwm_period = period_us;
654 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655
Willie Ruanefc2fa42011-07-05 00:12:41 -0700656 pm8058_pwm_calc_pwm_value(pwm, period_us, duty_us);
657 pm8058_pwm_save_pwm_value(pwm);
658 pm8058_pwm_save(&pwm->pwm_ctl[1],
659 PM8058_PWM_BYPASS_LUT, PM8058_PWM_BYPASS_LUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660
Willie Ruanefc2fa42011-07-05 00:12:41 -0700661 pm8058_pwm_bank_sel(pwm);
662 rc = pm8058_pwm_write(pwm, 1, 6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663
Willie Ruan0d9acd92011-07-04 21:31:30 -0700664 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
665 (unsigned)duty_us, (unsigned)period_us,
Willie Ruand3337ed2011-07-04 23:16:22 -0700666 pwm->pwm_value, 1 << pwm->period.pwm_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700668out_unlock:
669 mutex_unlock(&pwm->chip->pwm_mutex);
670 return rc;
671}
672EXPORT_SYMBOL(pwm_config);
673
674/*
675 * pwm_enable - start a PWM output toggling
676 */
677int pwm_enable(struct pwm_device *pwm)
678{
679 int rc;
680
681 if (pwm == NULL || IS_ERR(pwm))
682 return -EINVAL;
683 if (pwm->chip == NULL)
684 return -ENODEV;
685
686 mutex_lock(&pwm->chip->pwm_mutex);
687 if (!pwm->in_use)
688 rc = -EINVAL;
689 else {
690 if (pwm->chip->pdata && pwm->chip->pdata->enable)
691 pwm->chip->pdata->enable(pwm, pwm->pwm_id, 1);
692
693 rc = pm8058_pwm_bank_enable(pwm, 1);
694
695 pm8058_pwm_bank_sel(pwm);
696 pm8058_pwm_start(pwm, 1, 0);
697 }
698 mutex_unlock(&pwm->chip->pwm_mutex);
699 return rc;
700}
701EXPORT_SYMBOL(pwm_enable);
702
703/*
704 * pwm_disable - stop a PWM output toggling
705 */
706void pwm_disable(struct pwm_device *pwm)
707{
708 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL)
709 return;
710
711 mutex_lock(&pwm->chip->pwm_mutex);
712 if (pwm->in_use) {
713 pm8058_pwm_bank_sel(pwm);
714 pm8058_pwm_start(pwm, 0, 0);
715
716 pm8058_pwm_bank_enable(pwm, 0);
717
718 if (pwm->chip->pdata && pwm->chip->pdata->enable)
719 pwm->chip->pdata->enable(pwm, pwm->pwm_id, 0);
720 }
721 mutex_unlock(&pwm->chip->pwm_mutex);
722}
723EXPORT_SYMBOL(pwm_disable);
724
Willie Ruan368db792011-07-05 08:09:58 -0700725/**
726 * pm8058_pwm_config_period - change PWM period
727 *
728 * @pwm: the PWM device
729 * @pwm_p: period in struct pm8058_pwm_period
730 */
731int pm8058_pwm_config_period(struct pwm_device *pwm,
732 struct pm8058_pwm_period *period)
733{
734 int rc;
735
736 if (pwm == NULL || IS_ERR(pwm) || period == NULL)
737 return -EINVAL;
738 if (pwm->chip == NULL)
739 return -ENODEV;
740
741 mutex_lock(&pwm->chip->pwm_mutex);
742
743 if (!pwm->in_use) {
744 rc = -EINVAL;
745 goto out_unlock;
746 }
747
748 pwm->period.pwm_size = period->pwm_size;
749 pwm->period.clk = period->clk;
750 pwm->period.pre_div = period->pre_div;
751 pwm->period.pre_div_exp = period->pre_div_exp;
752
753 pm8058_pwm_save_period(pwm);
754 pm8058_pwm_bank_sel(pwm);
755 rc = pm8058_pwm_write(pwm, 4, 6);
756
757out_unlock:
758 mutex_unlock(&pwm->chip->pwm_mutex);
759 return rc;
760}
761EXPORT_SYMBOL(pm8058_pwm_config_period);
762
763/**
764 * pm8058_pwm_config_duty_cycle - change PWM duty cycle
765 *
766 * @pwm: the PWM device
767 * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
768 */
769int pm8058_pwm_config_duty_cycle(struct pwm_device *pwm, int pwm_value)
770{
771 struct pm8058_pwm_lut lut;
772 int flags, start_idx;
773 int rc = 0;
774
775 if (pwm == NULL || IS_ERR(pwm))
776 return -EINVAL;
777 if (pwm->chip == NULL)
778 return -ENODEV;
779
780 mutex_lock(&pwm->chip->pwm_mutex);
781
782 if (!pwm->in_use || !pwm->pwm_period) {
783 rc = -EINVAL;
784 goto out_unlock;
785 }
786
787 if (pwm->pwm_value == pwm_value)
788 goto out_unlock;
789
790 pwm->pwm_value = pwm_value;
791 flags = PM_PWM_LUT_RAMP_UP;
792
793 start_idx = pwm->pwm_id * CHAN_LUT_SIZE;
794 pm8058_pwm_change_table(pwm, &pwm_value, start_idx, 1, 1);
795
796 if (!pwm->use_lut) {
797 pwm->use_lut = 1;
798
799 lut.lut_duty_ms = 1;
800 lut.lut_lo_index = start_idx;
801 lut.lut_hi_index = start_idx;
802 lut.lut_pause_lo = 0;
803 lut.lut_pause_hi = 0;
804 lut.flags = flags;
805
806 rc = pm8058_pwm_change_lut(pwm, &lut);
807 } else {
808 pm8058_pwm_save_index(pwm, start_idx, start_idx, flags);
809 pm8058_pwm_save(&pwm->pwm_ctl[1], PM8058_PWM_BYPASS_LUT, 0);
810
811 pm8058_pwm_bank_sel(pwm);
812 rc = pm8058_pwm_write(pwm, 0, 3);
813 }
814
815 if (rc)
816 pr_err("[%d]: pm8058_pwm_write: rc=%d\n", pwm->pwm_id, rc);
817
818out_unlock:
819 mutex_unlock(&pwm->chip->pwm_mutex);
820 return rc;
821}
822EXPORT_SYMBOL(pm8058_pwm_config_duty_cycle);
823
824/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825 * pm8058_pwm_lut_config - change a PWM device configuration to use LUT
826 *
827 * @pwm: the PWM device
828 * @period_us: period in micro second
829 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
830 * @duty_time_ms: time for each duty cycle in millisecond
831 * @start_idx: start index in lookup table from 0 to MAX-1
832 * @idx_len: number of index
833 * @pause_lo: pause time in millisecond at low index
834 * @pause_hi: pause time in millisecond at high index
835 * @flags: control flags
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836 */
837int pm8058_pwm_lut_config(struct pwm_device *pwm, int period_us,
838 int duty_pct[], int duty_time_ms, int start_idx,
839 int idx_len, int pause_lo, int pause_hi, int flags)
840{
Willie Ruan965072e2011-07-05 14:03:55 -0700841 struct pm8058_pwm_lut lut;
Willie Ruanefc2fa42011-07-05 00:12:41 -0700842 int len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843 int rc;
844
845 if (pwm == NULL || IS_ERR(pwm) || !idx_len)
846 return -EINVAL;
847 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE))
848 return -EINVAL;
849 if (pwm->chip == NULL)
850 return -ENODEV;
851 if (idx_len >= PM_PWM_LUT_SIZE && start_idx)
852 return -EINVAL;
853 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE)
854 return -EINVAL;
855 if ((unsigned)period_us > PM_PWM_PERIOD_MAX ||
856 (unsigned)period_us < PM_PWM_PERIOD_MIN)
857 return -EINVAL;
858
859 mutex_lock(&pwm->chip->pwm_mutex);
860
861 if (!pwm->in_use) {
862 rc = -EINVAL;
863 goto out_unlock;
864 }
865
Willie Ruan8a08b962011-07-05 00:43:37 -0700866 if (pwm->pwm_period != period_us) {
867 pm8058_pwm_calc_period(period_us, &pwm->period);
868 pm8058_pwm_save_period(pwm);
869 pwm->pwm_period = period_us;
870 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871
872 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
873
874 if (flags & PM_PWM_LUT_NO_TABLE)
875 goto after_table_write;
876
Willie Ruanefc2fa42011-07-05 00:12:41 -0700877 rc = pm8058_pwm_change_table(pwm, duty_pct, start_idx, len, 0);
878 if (rc) {
879 pr_err("pm8058_pwm_change_table: rc=%d\n", rc);
880 goto out_unlock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700881 }
882
883after_table_write:
Willie Ruan965072e2011-07-05 14:03:55 -0700884 lut.lut_duty_ms = duty_time_ms;
885 lut.lut_lo_index = start_idx;
886 lut.lut_hi_index = start_idx + len - 1;
887 lut.lut_pause_lo = pause_lo;
888 lut.lut_pause_hi = pause_hi;
889 lut.flags = flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890
Willie Ruan965072e2011-07-05 14:03:55 -0700891 rc = pm8058_pwm_change_lut(pwm, &lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892
893out_unlock:
894 mutex_unlock(&pwm->chip->pwm_mutex);
895 return rc;
896}
897EXPORT_SYMBOL(pm8058_pwm_lut_config);
898
Willie Ruan368db792011-07-05 08:09:58 -0700899/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 * pm8058_pwm_lut_enable - control a PWM device to start/stop LUT ramp
901 *
902 * @pwm: the PWM device
903 * @start: to start (1), or stop (0)
904 */
905int pm8058_pwm_lut_enable(struct pwm_device *pwm, int start)
906{
907 if (pwm == NULL || IS_ERR(pwm))
908 return -EINVAL;
909 if (pwm->chip == NULL)
910 return -ENODEV;
911
912 mutex_lock(&pwm->chip->pwm_mutex);
913 if (start) {
914 pm8058_pwm_bank_enable(pwm, 1);
915
916 pm8058_pwm_bank_sel(pwm);
917 pm8058_pwm_start(pwm, 1, 1);
918 } else {
919 pm8058_pwm_bank_sel(pwm);
920 pm8058_pwm_start(pwm, 0, 0);
921
922 pm8058_pwm_bank_enable(pwm, 0);
923 }
924 mutex_unlock(&pwm->chip->pwm_mutex);
925 return 0;
926}
927EXPORT_SYMBOL(pm8058_pwm_lut_enable);
928
929#define SSBI_REG_ADDR_LED_BASE 0x131
930#define SSBI_REG_ADDR_LED(n) (SSBI_REG_ADDR_LED_BASE + (n))
931#define SSBI_REG_ADDR_FLASH_BASE 0x48
932#define SSBI_REG_ADDR_FLASH_DRV_1 0xFB
933#define SSBI_REG_ADDR_FLASH(n) (((n) < 2 ? \
934 SSBI_REG_ADDR_FLASH_BASE + (n) : \
935 SSBI_REG_ADDR_FLASH_DRV_1))
936
937#define PM8058_LED_CURRENT_SHIFT 3
938#define PM8058_LED_MODE_MASK 0x07
939
940#define PM8058_FLASH_CURRENT_SHIFT 4
941#define PM8058_FLASH_MODE_MASK 0x03
942#define PM8058_FLASH_MODE_NONE 0
943#define PM8058_FLASH_MODE_DTEST1 1
944#define PM8058_FLASH_MODE_DTEST2 2
945#define PM8058_FLASH_MODE_PWM 3
946
947int pm8058_pwm_config_led(struct pwm_device *pwm, int id,
948 int mode, int max_current)
949{
950 int rc;
951 u8 conf;
952
953 switch (id) {
954 case PM_PWM_LED_0:
955 case PM_PWM_LED_1:
956 case PM_PWM_LED_2:
957 conf = mode & PM8058_LED_MODE_MASK;
958 conf |= (max_current / 2) << PM8058_LED_CURRENT_SHIFT;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530959 rc = pm8xxx_writeb(pwm->dev->parent,
960 SSBI_REG_ADDR_LED(id), conf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961 break;
962
963 case PM_PWM_LED_KPD:
964 case PM_PWM_LED_FLASH:
965 case PM_PWM_LED_FLASH1:
966 switch (mode) {
967 case PM_PWM_CONF_PWM1:
968 case PM_PWM_CONF_PWM2:
969 case PM_PWM_CONF_PWM3:
970 conf = PM8058_FLASH_MODE_PWM;
971 break;
972 case PM_PWM_CONF_DTEST1:
973 conf = PM8058_FLASH_MODE_DTEST1;
974 break;
975 case PM_PWM_CONF_DTEST2:
976 conf = PM8058_FLASH_MODE_DTEST2;
977 break;
978 default:
979 conf = PM8058_FLASH_MODE_NONE;
980 break;
981 }
982 conf |= (max_current / 20) << PM8058_FLASH_CURRENT_SHIFT;
983 id -= PM_PWM_LED_KPD;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530984 rc = pm8xxx_writeb(pwm->dev->parent,
985 SSBI_REG_ADDR_FLASH(id), conf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 break;
987 default:
988 rc = -EINVAL;
989 break;
990 }
991
992 return rc;
993}
994EXPORT_SYMBOL(pm8058_pwm_config_led);
995
996int pm8058_pwm_set_dtest(struct pwm_device *pwm, int enable)
997{
998 int rc;
999 u8 reg;
1000
1001 if (pwm == NULL || IS_ERR(pwm))
1002 return -EINVAL;
1003 if (pwm->chip == NULL)
1004 return -ENODEV;
1005
1006 if (!pwm->in_use)
1007 rc = -EINVAL;
1008 else {
1009 reg = pwm->pwm_id & PM8058_PWM_DTEST_BANK_MASK;
1010 if (enable)
1011 /* Only Test 1 available */
1012 reg |= (1 << PM8058_PWM_DTEST_SHIFT) &
1013 PM8058_PWM_DTEST_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301014 rc = pm8xxx_writeb(pwm->dev->parent,
1015 SSBI_REG_ADDR_LPG_TEST, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 if (rc)
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301017 pr_err("pm8xxx_write(DTEST=0x%x): rc=%d\n", reg, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018
1019 }
1020 return rc;
1021}
1022EXPORT_SYMBOL(pm8058_pwm_set_dtest);
1023
1024static int __devinit pmic8058_pwm_probe(struct platform_device *pdev)
1025{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 struct pm8058_pwm_chip *chip;
1027 int i;
1028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1030 if (chip == NULL) {
Willie Ruan0d9acd92011-07-04 21:31:30 -07001031 pr_err("kzalloc() failed.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032 return -ENOMEM;
1033 }
1034
1035 for (i = 0; i < PM8058_PWM_CHANNELS; i++) {
1036 chip->pwm_dev[i].pwm_id = i;
1037 chip->pwm_dev[i].chip = chip;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301038 chip->pwm_dev[i].dev = &pdev->dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 }
1040
1041 mutex_init(&chip->pwm_mutex);
1042
1043 chip->pdata = pdev->dev.platform_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 pwm_chip = chip;
1045 platform_set_drvdata(pdev, chip);
1046
Willie Ruan0d9acd92011-07-04 21:31:30 -07001047 pr_notice("OK\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 return 0;
1049}
1050
1051static int __devexit pmic8058_pwm_remove(struct platform_device *pdev)
1052{
1053 struct pm8058_pwm_chip *chip = platform_get_drvdata(pdev);
1054
1055 platform_set_drvdata(pdev, NULL);
1056 kfree(chip);
1057 return 0;
1058}
1059
1060static struct platform_driver pmic8058_pwm_driver = {
1061 .probe = pmic8058_pwm_probe,
1062 .remove = __devexit_p(pmic8058_pwm_remove),
1063 .driver = {
1064 .name = "pm8058-pwm",
1065 .owner = THIS_MODULE,
1066 },
1067};
1068
1069static int __init pm8058_pwm_init(void)
1070{
1071 return platform_driver_register(&pmic8058_pwm_driver);
1072}
1073
1074static void __exit pm8058_pwm_exit(void)
1075{
1076 platform_driver_unregister(&pmic8058_pwm_driver);
1077}
1078
1079subsys_initcall(pm8058_pwm_init);
1080module_exit(pm8058_pwm_exit);
1081
1082MODULE_LICENSE("GPL v2");
1083MODULE_DESCRIPTION("PMIC8058 PWM driver");
1084MODULE_VERSION("1.0");
1085MODULE_ALIAS("platform:pmic8058_pwm");