blob: 70f4cd551064585bae4e80180ceb161503ab4ef0 [file] [log] [blame]
Willie Ruan70f989d2012-01-10 10:09:36 -08001/* Copyright (c) 2011-2012, 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 * 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
Jay Chokshi57656862011-09-07 12:02:22 -070028#define PM8XXX_PWM_CHANNELS 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
Jay Chokshi0c220cd2011-12-09 17:18:20 -080030/*
31 * For the lack of better term to distinguish functional
32 * differences, hereby, LPG version 0 (V0, v0) denotes
33 * PM8058/8921, and version 1 (V1, v1) denotes
34 * PM8922/8038.
35 */
36#define PM8XXX_LPG_V0_PWM_CHANNELS 8
37#define PM8XXX_LPG_V1_PWM_CHANNELS 6
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#define PM8XXX_LPG_CTL_REGS 7
39
40/* PM8XXX PWM */
Jay Chokshi57656862011-09-07 12:02:22 -070041#define SSBI_REG_ADDR_PWM1_CTRL1 0x88
42#define SSBI_REG_ADDR_PWM1_CTRL2 0x89
43#define SSBI_REG_ADDR_PWM_CTL(id, base) (id == 0 ? base : (base + (id << 1)))
44#define SSBI_REG_ADDR_PWM_CTL1(id) SSBI_REG_ADDR_PWM_CTL(id, \
45 SSBI_REG_ADDR_PWM1_CTRL1)
46#define SSBI_REG_ADDR_PWM_CTL2(id) SSBI_REG_ADDR_PWM_CTL(id, \
47 SSBI_REG_ADDR_PWM1_CTRL2)
48
49#define PM8XXX_PWM_CLK_SEL_SHIFT 6
50#define PM8XXX_PWM_CLK_SEL_MASK 0xC0
51#define PM8XXX_PWM_PREDIVIDE_SHIFT 5
52#define PM8XXX_PWM_PREDIVIDE_MASK 0x20
53#define PM8XXX_PWM_M_SHIFT 2
54#define PM8XXX_PWM_M_MASK 0x1C
55#define PM8XXX_PWM_SIZE_SHIFT 1
56#define PM8XXX_PWM_SIZE_MASK 0x02
57#define PM8XXX_PWM_VALUE_BIT0 0x01
58#define PM8XXX_PWM_DISABLE 0x3F
59
60/* PM8XXX LPG PWM */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#define SSBI_REG_ADDR_LPG_CTL_BASE 0x13C
62#define SSBI_REG_ADDR_LPG_CTL(n) (SSBI_REG_ADDR_LPG_CTL_BASE + (n))
63#define SSBI_REG_ADDR_LPG_BANK_SEL 0x143
64#define SSBI_REG_ADDR_LPG_BANK_EN 0x144
65#define SSBI_REG_ADDR_LPG_LUT_CFG0 0x145
66#define SSBI_REG_ADDR_LPG_LUT_CFG1 0x146
Jay Chokshib0a0fa52012-02-23 16:18:44 -080067#define SSBI_REG_ADDR_LPG_TEST 0x147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068
Jay Chokshi57656862011-09-07 12:02:22 -070069/* LPG Control 0 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070#define PM8XXX_PWM_1KHZ_COUNT_MASK 0xF0
71#define PM8XXX_PWM_1KHZ_COUNT_SHIFT 4
72
73#define PM8XXX_PWM_1KHZ_COUNT_MAX 15
74
75#define PM8XXX_PWM_OUTPUT_EN 0x08
76#define PM8XXX_PWM_PWM_EN 0x04
77#define PM8XXX_PWM_RAMP_GEN_EN 0x02
78#define PM8XXX_PWM_RAMP_START 0x01
79
80#define PM8XXX_PWM_PWM_START (PM8XXX_PWM_OUTPUT_EN \
81 | PM8XXX_PWM_PWM_EN)
82#define PM8XXX_PWM_RAMP_GEN_START (PM8XXX_PWM_RAMP_GEN_EN \
83 | PM8XXX_PWM_RAMP_START)
84
Jay Chokshi57656862011-09-07 12:02:22 -070085/* LPG Control 1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086#define PM8XXX_PWM_REVERSE_EN 0x80
87#define PM8XXX_PWM_BYPASS_LUT 0x40
88#define PM8XXX_PWM_HIGH_INDEX_MASK 0x3F
89
Jay Chokshi57656862011-09-07 12:02:22 -070090/* LPG Control 2 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091#define PM8XXX_PWM_LOOP_EN 0x80
92#define PM8XXX_PWM_RAMP_UP 0x40
93#define PM8XXX_PWM_LOW_INDEX_MASK 0x3F
94
Jay Chokshi57656862011-09-07 12:02:22 -070095/* LPG Control 3 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096#define PM8XXX_PWM_VALUE_BIT7_0 0xFF
97#define PM8XXX_PWM_VALUE_BIT5_0 0x3F
98
Jay Chokshi57656862011-09-07 12:02:22 -070099/* LPG Control 4 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100#define PM8XXX_PWM_VALUE_BIT8 0x80
101
Jay Chokshi57656862011-09-07 12:02:22 -0700102#define PM8XXX_LPG_PWM_CLK_SEL_MASK 0x60
103#define PM8XXX_LPG_PWM_CLK_SEL_SHIFT 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104
105#define PM8XXX_PWM_CLK_SEL_NO 0
106#define PM8XXX_PWM_CLK_SEL_1KHZ 1
107#define PM8XXX_PWM_CLK_SEL_32KHZ 2
108#define PM8XXX_PWM_CLK_SEL_19P2MHZ 3
109
Jay Chokshi57656862011-09-07 12:02:22 -0700110#define PM8XXX_LPG_PWM_PREDIVIDE_MASK 0x18
111#define PM8XXX_LPG_PWM_PREDIVIDE_SHIFT 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112
113#define PM8XXX_PWM_PREDIVIDE_2 0
114#define PM8XXX_PWM_PREDIVIDE_3 1
115#define PM8XXX_PWM_PREDIVIDE_5 2
116#define PM8XXX_PWM_PREDIVIDE_6 3
117
Jay Chokshi57656862011-09-07 12:02:22 -0700118#define PM8XXX_LPG_PWM_M_MASK 0x07
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119#define PM8XXX_PWM_M_MIN 0
120#define PM8XXX_PWM_M_MAX 7
121
Jay Chokshi57656862011-09-07 12:02:22 -0700122/* LPG Control 5 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123#define PM8XXX_PWM_PAUSE_COUNT_HI_MASK 0xFC
124#define PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT 2
125
126#define PM8XXX_PWM_PAUSE_ENABLE_HIGH 0x02
127#define PM8XXX_PWM_SIZE_9_BIT 0x01
128
Jay Chokshi57656862011-09-07 12:02:22 -0700129/* LPG Control 6 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130#define PM8XXX_PWM_PAUSE_COUNT_LO_MASK 0xFC
131#define PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT 2
132
133#define PM8XXX_PWM_PAUSE_ENABLE_LOW 0x02
134#define PM8XXX_PWM_RESERVED 0x01
135
136#define PM8XXX_PWM_PAUSE_COUNT_MAX 56 /* < 2^6 = 64 */
137
Jay Chokshi57656862011-09-07 12:02:22 -0700138/* LPG LUT_CFG1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139#define PM8XXX_PWM_LUT_READ 0x40
140
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800141/* TEST */
142#define PM8XXX_PWM_DTEST_MASK 0x38
143#define PM8XXX_PWM_DTEST_SHIFT 3
144#define PM8XXX_PWM_DTEST_BANK_MASK 0x07
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146/*
147 * PWM Frequency = Clock Frequency / (N * T)
148 * or
149 * PWM Period = Clock Period * (N * T)
150 * where
151 * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
152 * T = Pre-divide * 2^m, where m = 0..7 (exponent)
153 *
154 * This is the formula to figure out m for the best pre-divide and clock:
Willie Ruan4a0a7002012-01-10 15:39:44 -0800155 * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156 */
157#define NUM_CLOCKS 3
158
Willie Ruandb78e942012-01-10 15:00:28 -0800159#define NSEC_1024HZ (NSEC_PER_SEC / 1024)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
161#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
162
Willie Ruanb10be972012-01-12 11:30:11 -0800163#define NUM_LPG_PRE_DIVIDE 4
Jay Chokshi57656862011-09-07 12:02:22 -0700164#define NUM_PWM_PRE_DIVIDE 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165
Jay Chokshi0c220cd2011-12-09 17:18:20 -0800166#define PRE_DIVIDE_1 1 /* v1 */
Willie Ruanb10be972012-01-12 11:30:11 -0800167#define PRE_DIVIDE_2 2
168#define PRE_DIVIDE_3 3
169#define PRE_DIVIDE_5 5
170#define PRE_DIVIDE_6 6
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171
Jay Chokshi57656862011-09-07 12:02:22 -0700172static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
Willie Ruandb78e942012-01-10 15:00:28 -0800173 { PRE_DIVIDE_2 * NSEC_1024HZ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174 PRE_DIVIDE_2 * NSEC_32768HZ,
175 PRE_DIVIDE_2 * NSEC_19P2MHZ,
176 },
Willie Ruanb10be972012-01-12 11:30:11 -0800177 { PRE_DIVIDE_3 * NSEC_1024HZ,
178 PRE_DIVIDE_3 * NSEC_32768HZ,
179 PRE_DIVIDE_3 * NSEC_19P2MHZ,
180 },
181 { PRE_DIVIDE_5 * NSEC_1024HZ,
182 PRE_DIVIDE_5 * NSEC_32768HZ,
183 PRE_DIVIDE_5 * NSEC_19P2MHZ,
184 },
185 { PRE_DIVIDE_6 * NSEC_1024HZ,
186 PRE_DIVIDE_6 * NSEC_32768HZ,
187 PRE_DIVIDE_6 * NSEC_19P2MHZ,
188 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189};
190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191/* Private data */
192struct pm8xxx_pwm_chip;
193
194struct pwm_device {
195 int pwm_id; /* = bank/channel id */
196 int in_use;
197 const char *label;
Willie Ruan719c6762011-08-25 11:03:14 -0700198 struct pm8xxx_pwm_period period;
199 int pwm_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 int pwm_period;
201 int pwm_duty;
Jay Chokshi57656862011-09-07 12:02:22 -0700202 u8 pwm_lpg_ctl[PM8XXX_LPG_CTL_REGS];
203 u8 pwm_ctl1;
204 u8 pwm_ctl2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 int irq;
206 struct pm8xxx_pwm_chip *chip;
Willie Ruan719c6762011-08-25 11:03:14 -0700207 int bypass_lut;
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800208 int dtest_mode_supported;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209};
210
211struct pm8xxx_pwm_chip {
Jay Chokshi57656862011-09-07 12:02:22 -0700212 struct pwm_device *pwm_dev;
213 u8 pwm_channels;
214 u8 pwm_total_pre_divs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215 u8 bank_mask;
216 struct mutex pwm_mutex;
217 struct device *dev;
Jay Chokshi57656862011-09-07 12:02:22 -0700218 bool is_lpg_supported;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219};
220
221static struct pm8xxx_pwm_chip *pwm_chip;
222
Willie Ruan719c6762011-08-25 11:03:14 -0700223struct pm8xxx_pwm_lut {
224 /* LUT parameters */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 int lut_duty_ms;
226 int lut_lo_index;
227 int lut_hi_index;
228 int lut_pause_hi;
229 int lut_pause_lo;
230 int flags;
231};
232
233static const u16 duty_msec[PM8XXX_PWM_1KHZ_COUNT_MAX + 1] = {
234 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
235};
236
237static const u16 pause_count[PM8XXX_PWM_PAUSE_COUNT_MAX + 1] = {
238 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
239 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
240 375, 500, 667, 750, 800, 900, 1000, 1100,
241 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
242 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
243 7000
244};
245
246/* Internal functions */
Willie Ruan8de2f382011-08-25 11:04:50 -0700247static void pm8xxx_pwm_save(u8 *u8p, u8 mask, u8 val)
248{
249 *u8p &= ~mask;
250 *u8p |= val & mask;
251}
252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253static int pm8xxx_pwm_bank_enable(struct pwm_device *pwm, int enable)
254{
255 int rc;
256 u8 reg;
257 struct pm8xxx_pwm_chip *chip;
258
259 chip = pwm->chip;
260
261 if (enable)
262 reg = chip->bank_mask | (1 << pwm->pwm_id);
263 else
264 reg = chip->bank_mask & ~(1 << pwm->pwm_id);
265
266 rc = pm8xxx_writeb(chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
267 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700268 pr_err("pm8xxx_writeb(): rc=%d (Enable LPG Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 return rc;
270 }
271 chip->bank_mask = reg;
272
273 return 0;
274}
275
276static int pm8xxx_pwm_bank_sel(struct pwm_device *pwm)
277{
278 int rc;
279
280 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_SEL,
281 pwm->pwm_id);
282 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700283 pr_err("pm8xxx_writeb(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 return rc;
285}
286
287static int pm8xxx_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
288{
289 int rc;
290 u8 reg;
291
292 if (start) {
Jay Chokshi57656862011-09-07 12:02:22 -0700293 reg = pwm->pwm_lpg_ctl[0] | PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 if (ramp_start)
295 reg |= PM8XXX_PWM_RAMP_GEN_START;
296 else
297 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
298 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700299 reg = pwm->pwm_lpg_ctl[0] & ~PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
301 }
302
303 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
304 reg);
305 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700306 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307 else
Jay Chokshi57656862011-09-07 12:02:22 -0700308 pwm->pwm_lpg_ctl[0] = reg;
309 return rc;
310}
311
312static int pm8xxx_pwm_disable(struct pwm_device *pwm)
313{
314 int rc;
315 u8 reg;
316
317 reg = pwm->pwm_ctl1 & PM8XXX_PWM_DISABLE;
318
319 rc = pm8xxx_writeb(pwm->chip->dev->parent,
320 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), reg);
321
322 if (rc)
323 pr_err("pm8xxx_writeb(): rc=%d (Disable PWM Ctl %d)\n", rc,
324 pwm->pwm_id);
325 return rc;
326}
327
328static int pm8xxx_pwm_enable(struct pwm_device *pwm)
329{
330 /**
331 * A kind of best Effort: Just write the clock information that
332 * we have in the register.
333 */
334 int rc;
335
336 rc = pm8xxx_writeb(pwm->chip->dev->parent,
337 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), pwm->pwm_ctl1);
338
339 if (rc)
340 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl %d)\n", rc,
341 pwm->pwm_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 return rc;
343}
344
345static void pm8xxx_pwm_calc_period(unsigned int period_us,
Willie Ruan719c6762011-08-25 11:03:14 -0700346 struct pm8xxx_pwm_period *period)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347{
348 int n, m, clk, div;
349 int best_m, best_div, best_clk;
Willie Ruan4a0a7002012-01-10 15:39:44 -0800350 unsigned int last_err, cur_err, min_err;
351 unsigned int tmp_p, period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352
353 /* PWM Period / N */
Willie Ruan70f989d2012-01-10 10:09:36 -0800354 if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355 period_n = (period_us * NSEC_PER_USEC) >> 6;
356 n = 6;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357 } else {
358 period_n = (period_us >> 9) * NSEC_PER_USEC;
359 n = 9;
360 }
361
Willie Ruan4a0a7002012-01-10 15:39:44 -0800362 min_err = last_err = (unsigned)(-1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 best_m = 0;
364 best_clk = 0;
365 best_div = 0;
366 for (clk = 0; clk < NUM_CLOCKS; clk++) {
Jay Chokshi57656862011-09-07 12:02:22 -0700367 for (div = 0; div < pwm_chip->pwm_total_pre_divs; div++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800368 /* period_n = (PWM Period / N) */
369 /* tmp_p = (Pre-divide * Clock Period) * 2^m */
370 tmp_p = pt_t[div][clk];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 for (m = 0; m <= PM8XXX_PWM_M_MAX; m++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800372 if (period_n > tmp_p)
373 cur_err = period_n - tmp_p;
374 else
375 cur_err = tmp_p - period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376
Willie Ruan4a0a7002012-01-10 15:39:44 -0800377 if (cur_err < min_err) {
378 min_err = cur_err;
379 best_m = m;
380 best_clk = clk;
381 best_div = div;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 }
Willie Ruan4a0a7002012-01-10 15:39:44 -0800383
384 if (m && cur_err > last_err)
385 /* Break for bigger cur_err */
386 break;
387
388 last_err = cur_err;
389 tmp_p <<= 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 }
391 }
392 }
393
Willie Ruan75d9e5b2011-08-25 10:59:17 -0700394 /* Use higher resolution */
395 if (best_m >= 3 && n == 6) {
396 n += 3;
397 best_m -= 3;
398 }
399
Willie Ruan719c6762011-08-25 11:03:14 -0700400 period->pwm_size = n;
401 period->clk = best_clk;
402 period->pre_div = best_div;
403 period->pre_div_exp = best_m;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404}
405
Willie Ruan8de2f382011-08-25 11:04:50 -0700406static void pm8xxx_pwm_calc_pwm_value(struct pwm_device *pwm,
407 unsigned int period_us,
408 unsigned int duty_us)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409{
Willie Ruan8de2f382011-08-25 11:04:50 -0700410 unsigned int max_pwm_value, tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411
Willie Ruan8de2f382011-08-25 11:04:50 -0700412 /* Figure out pwm_value with overflow handling */
413 tmp = 1 << (sizeof(tmp) * 8 - pwm->period.pwm_size);
414 if (duty_us < tmp) {
415 tmp = duty_us << pwm->period.pwm_size;
416 pwm->pwm_value = tmp / period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 } else {
Willie Ruan8de2f382011-08-25 11:04:50 -0700418 tmp = period_us >> pwm->period.pwm_size;
419 pwm->pwm_value = duty_us / tmp;
420 }
421 max_pwm_value = (1 << pwm->period.pwm_size) - 1;
422 if (pwm->pwm_value > max_pwm_value)
423 pwm->pwm_value = max_pwm_value;
424}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425
Willie Ruan8de2f382011-08-25 11:04:50 -0700426static int pm8xxx_pwm_change_table(struct pwm_device *pwm, int duty_pct[],
427 int start_idx, int len, int raw_value)
428{
429 unsigned int pwm_value, max_pwm_value;
430 u8 cfg0, cfg1;
431 int i, pwm_size;
432 int rc = 0;
433
Jay Chokshi57656862011-09-07 12:02:22 -0700434 pwm_size = (pwm->pwm_lpg_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
Willie Ruan8de2f382011-08-25 11:04:50 -0700435 max_pwm_value = (1 << pwm_size) - 1;
436 for (i = 0; i < len; i++) {
437 if (raw_value)
438 pwm_value = duty_pct[i];
439 else
440 pwm_value = (duty_pct[i] << pwm_size) / 100;
441
442 if (pwm_value > max_pwm_value)
443 pwm_value = max_pwm_value;
444 cfg0 = pwm_value;
445 cfg1 = (pwm_value >> 1) & 0x80;
446 cfg1 |= start_idx + i;
447
448 rc = pm8xxx_writeb(pwm->chip->dev->parent,
449 SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
450 if (rc)
451 break;
452
453 rc = pm8xxx_writeb(pwm->chip->dev->parent,
454 SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
455 if (rc)
456 break;
457 }
458 return rc;
459}
460
461static void pm8xxx_pwm_save_index(struct pwm_device *pwm,
462 int low_idx, int high_idx, int flags)
463{
Jay Chokshi57656862011-09-07 12:02:22 -0700464 pwm->pwm_lpg_ctl[1] = high_idx & PM8XXX_PWM_HIGH_INDEX_MASK;
465 pwm->pwm_lpg_ctl[2] = low_idx & PM8XXX_PWM_LOW_INDEX_MASK;
Willie Ruan8de2f382011-08-25 11:04:50 -0700466
467 if (flags & PM_PWM_LUT_REVERSE)
Jay Chokshi57656862011-09-07 12:02:22 -0700468 pwm->pwm_lpg_ctl[1] |= PM8XXX_PWM_REVERSE_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700469 if (flags & PM_PWM_LUT_RAMP_UP)
Jay Chokshi57656862011-09-07 12:02:22 -0700470 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_RAMP_UP;
Willie Ruan8de2f382011-08-25 11:04:50 -0700471 if (flags & PM_PWM_LUT_LOOP)
Jay Chokshi57656862011-09-07 12:02:22 -0700472 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_LOOP_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700473}
474
475static void pm8xxx_pwm_save_period(struct pwm_device *pwm)
476{
477 u8 mask, val;
478
Jay Chokshi57656862011-09-07 12:02:22 -0700479 if (pwm_chip->is_lpg_supported) {
480 val = ((pwm->period.clk + 1) << PM8XXX_LPG_PWM_CLK_SEL_SHIFT)
481 & PM8XXX_LPG_PWM_CLK_SEL_MASK;
482 val |= (pwm->period.pre_div << PM8XXX_LPG_PWM_PREDIVIDE_SHIFT)
483 & PM8XXX_LPG_PWM_PREDIVIDE_MASK;
484 val |= pwm->period.pre_div_exp & PM8XXX_LPG_PWM_M_MASK;
485 mask = PM8XXX_LPG_PWM_CLK_SEL_MASK |
486 PM8XXX_LPG_PWM_PREDIVIDE_MASK | PM8XXX_LPG_PWM_M_MASK;
487 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700488
Jay Chokshi57656862011-09-07 12:02:22 -0700489 val = (pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0;
490 mask = PM8XXX_PWM_SIZE_9_BIT;
491 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
492 } else {
493 val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
494 & PM8XXX_PWM_CLK_SEL_MASK;
495 val |= (pwm->period.pre_div << PM8XXX_PWM_PREDIVIDE_SHIFT)
496 & PM8XXX_PWM_PREDIVIDE_MASK;
497 val |= (pwm->period.pre_div_exp << PM8XXX_PWM_M_SHIFT)
498 & PM8XXX_PWM_M_MASK;
499 val |= (((pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0)
500 << PM8XXX_PWM_SIZE_SHIFT) & PM8XXX_PWM_SIZE_MASK;
501
502 mask = PM8XXX_PWM_CLK_SEL_MASK | PM8XXX_PWM_PREDIVIDE_MASK |
503 PM8XXX_PWM_M_MASK | PM8XXX_PWM_SIZE_MASK;
504 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
505 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700506}
507
508static void pm8xxx_pwm_save_pwm_value(struct pwm_device *pwm)
509{
510 u8 mask, val;
511
Jay Chokshi57656862011-09-07 12:02:22 -0700512 if (pwm_chip->is_lpg_supported) {
513 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 1) : 0;
514 pwm->pwm_lpg_ctl[3] = pwm->pwm_value;
515 mask = PM8XXX_PWM_VALUE_BIT8;
516 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
517 } else {
518 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 8) : 0;
519 pwm->pwm_ctl2 = pwm->pwm_value;
520 mask = PM8XXX_PWM_VALUE_BIT0;
521 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
522 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700523}
524
525static void pm8xxx_pwm_save_duty_time(struct pwm_device *pwm,
526 struct pm8xxx_pwm_lut *lut)
527{
528 int i;
529 u8 mask, val;
530
531 /* Linear search for duty time */
532 for (i = 0; i < PM8XXX_PWM_1KHZ_COUNT_MAX; i++) {
533 if (duty_msec[i] >= lut->lut_duty_ms)
534 break;
535 }
536 val = i << PM8XXX_PWM_1KHZ_COUNT_SHIFT;
537
538 mask = PM8XXX_PWM_1KHZ_COUNT_MASK;
Jay Chokshi57656862011-09-07 12:02:22 -0700539 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[0], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700540}
541
542static void pm8xxx_pwm_save_pause(struct pwm_device *pwm,
543 struct pm8xxx_pwm_lut *lut)
544{
545 int i, pause_cnt, time_cnt;
546 u8 mask, val;
547
Jay Chokshi57656862011-09-07 12:02:22 -0700548 time_cnt = (pwm->pwm_lpg_ctl[0] & PM8XXX_PWM_1KHZ_COUNT_MASK)
Willie Ruan8de2f382011-08-25 11:04:50 -0700549 >> PM8XXX_PWM_1KHZ_COUNT_SHIFT;
550 if (lut->flags & PM_PWM_LUT_PAUSE_HI_EN) {
551 pause_cnt = (lut->lut_pause_hi + duty_msec[time_cnt] / 2)
552 / duty_msec[time_cnt];
553 /* Linear search for pause time */
554 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
555 if (pause_count[i] >= pause_cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556 break;
557 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700558 val = (i << PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT) &
559 PM8XXX_PWM_PAUSE_COUNT_HI_MASK;
560 val |= PM8XXX_PWM_PAUSE_ENABLE_HIGH;
561 } else {
562 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 }
564
Willie Ruan8de2f382011-08-25 11:04:50 -0700565 mask = PM8XXX_PWM_PAUSE_COUNT_HI_MASK | PM8XXX_PWM_PAUSE_ENABLE_HIGH;
Jay Chokshi57656862011-09-07 12:02:22 -0700566 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567
Willie Ruan8de2f382011-08-25 11:04:50 -0700568 if (lut->flags & PM_PWM_LUT_PAUSE_LO_EN) {
569 /* Linear search for pause time */
570 pause_cnt = (lut->lut_pause_lo + duty_msec[time_cnt] / 2)
571 / duty_msec[time_cnt];
572 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
573 if (pause_count[i] >= pause_cnt)
574 break;
575 }
576 val = (i << PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT) &
577 PM8XXX_PWM_PAUSE_COUNT_LO_MASK;
578 val |= PM8XXX_PWM_PAUSE_ENABLE_LOW;
579 } else {
580 val = 0;
581 }
582
583 mask = PM8XXX_PWM_PAUSE_COUNT_LO_MASK | PM8XXX_PWM_PAUSE_ENABLE_LOW;
Jay Chokshi57656862011-09-07 12:02:22 -0700584 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[6], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700585}
586
Jay Chokshi57656862011-09-07 12:02:22 -0700587static int pm8xxx_pwm_write(struct pwm_device *pwm)
588{
589 int rc = 0;
590
591 rc = pm8xxx_writeb(pwm->chip->dev->parent,
592 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id),
593 pwm->pwm_ctl1);
594 if (rc) {
595 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl1[%d])\n",
596 rc, pwm->pwm_id);
597 return rc;
598 }
599
600 rc = pm8xxx_writeb(pwm->chip->dev->parent,
601 SSBI_REG_ADDR_PWM_CTL2(pwm->pwm_id),
602 pwm->pwm_ctl2);
603 if (rc) {
604 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl2[%d])\n",
605 rc, pwm->pwm_id);
606 return rc;
607 }
608
609 return rc;
610}
611
612static int pm8xxx_lpg_pwm_write(struct pwm_device *pwm, int start, int end)
Willie Ruan8de2f382011-08-25 11:04:50 -0700613{
614 int i, rc;
615
616 /* Write in reverse way so 0 would be the last */
617 for (i = end - 1; i >= start; i--) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 rc = pm8xxx_writeb(pwm->chip->dev->parent,
619 SSBI_REG_ADDR_LPG_CTL(i),
Jay Chokshi57656862011-09-07 12:02:22 -0700620 pwm->pwm_lpg_ctl[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700622 pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[%d])\n", rc, i);
623 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 }
625 }
626
Willie Ruan8de2f382011-08-25 11:04:50 -0700627 return 0;
628}
629
630static int pm8xxx_pwm_change_lut(struct pwm_device *pwm,
631 struct pm8xxx_pwm_lut *lut)
632{
633 int rc;
634
635 pm8xxx_pwm_save_index(pwm, lut->lut_lo_index,
636 lut->lut_hi_index, lut->flags);
637 pm8xxx_pwm_save_duty_time(pwm, lut);
638 pm8xxx_pwm_save_pause(pwm, lut);
Jay Chokshi57656862011-09-07 12:02:22 -0700639 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1], PM8XXX_PWM_BYPASS_LUT, 0);
Willie Ruan8de2f382011-08-25 11:04:50 -0700640
641 pm8xxx_pwm_bank_sel(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700642 rc = pm8xxx_lpg_pwm_write(pwm, 0, 7);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643
644 return rc;
645}
646
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800647static int pm8xxx_pwm_set_dtest(struct pwm_device *pwm, int enable)
648{
649 int rc;
650 u8 reg;
651
652 reg = pwm->pwm_id & PM8XXX_PWM_DTEST_BANK_MASK;
653
654 if (enable) {
655 /* Observe LPG_OUT on DTEST1*/
656 reg |= (1 << PM8XXX_PWM_DTEST_SHIFT) &
657 PM8XXX_PWM_DTEST_MASK;
658 }
659
660 rc = pm8xxx_writeb(pwm->chip->dev->parent,
661 SSBI_REG_ADDR_LPG_TEST, reg);
662 if (rc)
663 pr_err("pm8xxx_write(DTEST=0x%x) failed: rc=%d\n",
664 reg, rc);
665
666 return rc;
667}
668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669/* APIs */
670/**
671 * pwm_request - request a PWM device
672 * @pwm_id: PWM id or channel
673 * @label: the label to identify the user
674 */
675struct pwm_device *pwm_request(int pwm_id, const char *label)
676{
677 struct pwm_device *pwm;
678
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 if (pwm_chip == NULL) {
680 pr_err("No pwm_chip\n");
681 return ERR_PTR(-ENODEV);
682 }
683
Jay Chokshi57656862011-09-07 12:02:22 -0700684 if (pwm_id >= pwm_chip->pwm_channels || pwm_id < 0) {
685 pr_err("Invalid pwm_id: %d with %s\n",
686 pwm_id, label ? label : ".");
687 return ERR_PTR(-EINVAL);
688 }
689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690 mutex_lock(&pwm_chip->pwm_mutex);
691 pwm = &pwm_chip->pwm_dev[pwm_id];
692 if (!pwm->in_use) {
693 pwm->in_use = 1;
694 pwm->label = label;
695 } else {
696 pwm = ERR_PTR(-EBUSY);
697 }
698 mutex_unlock(&pwm_chip->pwm_mutex);
699
700 return pwm;
701}
702EXPORT_SYMBOL_GPL(pwm_request);
703
704/**
705 * pwm_free - free a PWM device
706 * @pwm: the PWM device
707 */
708void pwm_free(struct pwm_device *pwm)
709{
710 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
711 pr_err("Invalid pwm handle\n");
712 return;
713 }
714
715 mutex_lock(&pwm->chip->pwm_mutex);
716 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700717 if (pwm_chip->is_lpg_supported) {
718 pm8xxx_pwm_bank_sel(pwm);
719 pm8xxx_pwm_start(pwm, 0, 0);
720 } else {
721 pm8xxx_pwm_disable(pwm);
722 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 pwm->in_use = 0;
724 pwm->label = NULL;
725 }
Jay Chokshi57656862011-09-07 12:02:22 -0700726 if (pwm_chip->is_lpg_supported)
727 pm8xxx_pwm_bank_enable(pwm, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728 mutex_unlock(&pwm->chip->pwm_mutex);
729}
730EXPORT_SYMBOL_GPL(pwm_free);
731
732/**
733 * pwm_config - change a PWM device configuration
734 * @pwm: the PWM device
735 * @period_us: period in microseconds
736 * @duty_us: duty cycle in microseconds
737 */
738int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
739{
Willie Ruan719c6762011-08-25 11:03:14 -0700740 struct pm8xxx_pwm_period *period;
Jay Chokshi57656862011-09-07 12:02:22 -0700741 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742
743 if (pwm == NULL || IS_ERR(pwm) ||
744 duty_us > period_us ||
745 (unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
746 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
747 pr_err("Invalid pwm handle or parameters\n");
748 return -EINVAL;
749 }
750 if (pwm->chip == NULL) {
751 pr_err("No pwm_chip\n");
752 return -ENODEV;
753 }
754
Willie Ruan719c6762011-08-25 11:03:14 -0700755 period = &pwm->period;
756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700757 mutex_lock(&pwm->chip->pwm_mutex);
758
759 if (!pwm->in_use) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700760 rc = -EINVAL;
761 goto out_unlock;
762 }
763
Willie Ruan8de2f382011-08-25 11:04:50 -0700764 if (pwm->pwm_period != period_us) {
765 pm8xxx_pwm_calc_period(period_us, period);
766 pm8xxx_pwm_save_period(pwm);
767 pwm->pwm_period = period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700769
Willie Ruan8de2f382011-08-25 11:04:50 -0700770 pm8xxx_pwm_calc_pwm_value(pwm, period_us, duty_us);
771 pm8xxx_pwm_save_pwm_value(pwm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772
Jay Chokshi57656862011-09-07 12:02:22 -0700773 if (pwm_chip->is_lpg_supported) {
774 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
775 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
776
777 pm8xxx_pwm_bank_sel(pwm);
778 rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
779 } else {
780 rc = pm8xxx_pwm_write(pwm);
781 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700782
783 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
784 (unsigned)duty_us, (unsigned)period_us,
785 pwm->pwm_value, 1 << period->pwm_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700786
787out_unlock:
788 mutex_unlock(&pwm->chip->pwm_mutex);
789 return rc;
790}
791EXPORT_SYMBOL_GPL(pwm_config);
792
793/**
794 * pwm_enable - start a PWM output toggling
795 * @pwm: the PWM device
796 */
797int pwm_enable(struct pwm_device *pwm)
798{
Jay Chokshi57656862011-09-07 12:02:22 -0700799 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800
801 if (pwm == NULL || IS_ERR(pwm)) {
802 pr_err("Invalid pwm handle\n");
803 return -EINVAL;
804 }
805 if (pwm->chip == NULL) {
806 pr_err("No pwm_chip\n");
807 return -ENODEV;
808 }
809
810 mutex_lock(&pwm->chip->pwm_mutex);
811 if (!pwm->in_use) {
812 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
813 rc = -EINVAL;
814 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700815 if (pwm_chip->is_lpg_supported) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800816 if (pwm->dtest_mode_supported)
817 pm8xxx_pwm_set_dtest(pwm, 1);
Jay Chokshi57656862011-09-07 12:02:22 -0700818 pm8xxx_pwm_bank_sel(pwm);
Jay Chokshif3db97a2012-08-08 19:32:15 -0700819 rc = pm8xxx_pwm_bank_enable(pwm, 1);
Jay Chokshi57656862011-09-07 12:02:22 -0700820 pm8xxx_pwm_start(pwm, 1, 0);
821 } else {
822 pm8xxx_pwm_enable(pwm);
823 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 }
825 mutex_unlock(&pwm->chip->pwm_mutex);
826 return rc;
827}
828EXPORT_SYMBOL_GPL(pwm_enable);
829
830/**
831 * pwm_disable - stop a PWM output toggling
832 * @pwm: the PWM device
833 */
834void pwm_disable(struct pwm_device *pwm)
835{
836 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
837 pr_err("Invalid pwm handle or no pwm_chip\n");
838 return;
839 }
840
841 mutex_lock(&pwm->chip->pwm_mutex);
842 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700843 if (pwm_chip->is_lpg_supported) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800844 if (pwm->dtest_mode_supported)
845 pm8xxx_pwm_set_dtest(pwm, 0);
Jay Chokshi57656862011-09-07 12:02:22 -0700846 pm8xxx_pwm_bank_sel(pwm);
847 pm8xxx_pwm_start(pwm, 0, 0);
848 pm8xxx_pwm_bank_enable(pwm, 0);
849 } else {
850 pm8xxx_pwm_disable(pwm);
851 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852 }
853 mutex_unlock(&pwm->chip->pwm_mutex);
854}
855EXPORT_SYMBOL_GPL(pwm_disable);
856
857/**
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700858 * pm8xxx_pwm_config_period - change PWM period
859 *
860 * @pwm: the PWM device
861 * @pwm_p: period in struct pm8xxx_pwm_period
862 */
863int pm8xxx_pwm_config_period(struct pwm_device *pwm,
864 struct pm8xxx_pwm_period *period)
865{
866 int rc;
867
868 if (pwm == NULL || IS_ERR(pwm) || period == NULL)
869 return -EINVAL;
870 if (pwm->chip == NULL)
871 return -ENODEV;
872
873 mutex_lock(&pwm->chip->pwm_mutex);
874
875 if (!pwm->in_use) {
876 rc = -EINVAL;
877 goto out_unlock;
878 }
879
880 pwm->period.pwm_size = period->pwm_size;
881 pwm->period.clk = period->clk;
882 pwm->period.pre_div = period->pre_div;
883 pwm->period.pre_div_exp = period->pre_div_exp;
884
885 pm8xxx_pwm_save_period(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700886
887 if (pwm_chip->is_lpg_supported) {
888 pm8xxx_pwm_bank_sel(pwm);
889 rc = pm8xxx_lpg_pwm_write(pwm, 4, 6);
890 } else {
891 rc = pm8xxx_pwm_write(pwm);
892 }
893
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700894
895out_unlock:
896 mutex_unlock(&pwm->chip->pwm_mutex);
897 return rc;
898}
899EXPORT_SYMBOL(pm8xxx_pwm_config_period);
900
901/**
902 * pm8xxx_pwm_config_pwm_value - change a PWM device configuration
903 * @pwm: the PWM device
904 * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
905 */
906int pm8xxx_pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
907{
908 int rc = 0;
909
910 if (pwm == NULL || IS_ERR(pwm))
911 return -EINVAL;
912 if (pwm->chip == NULL)
913 return -ENODEV;
914
915 mutex_lock(&pwm->chip->pwm_mutex);
916
917 if (!pwm->in_use || !pwm->pwm_period) {
918 rc = -EINVAL;
919 goto out_unlock;
920 }
921
922 if (pwm->pwm_value == pwm_value)
923 goto out_unlock;
924
925 pwm->pwm_value = pwm_value;
926
927 pm8xxx_pwm_save_pwm_value(pwm);
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700928
Jay Chokshi57656862011-09-07 12:02:22 -0700929 if (pwm_chip->is_lpg_supported) {
930 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
931 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
932 pm8xxx_pwm_bank_sel(pwm);
933 rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
934 } else {
935 rc = pm8xxx_pwm_write(pwm);
936 }
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700937
938 if (rc)
939 pr_err("[%d]: pm8xxx_pwm_write: rc=%d\n", pwm->pwm_id, rc);
940
941out_unlock:
942 mutex_unlock(&pwm->chip->pwm_mutex);
943 return rc;
944}
945EXPORT_SYMBOL_GPL(pm8xxx_pwm_config_pwm_value);
946
947/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700948 * pm8xxx_pwm_lut_config - change a PWM device configuration to use LUT
949 * @pwm: the PWM device
950 * @period_us: period in microseconds
951 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
952 * @duty_time_ms: time for each duty cycle in milliseconds
953 * @start_idx: start index in lookup table from 0 to MAX-1
954 * @idx_len: number of index
955 * @pause_lo: pause time in milliseconds at low index
956 * @pause_hi: pause time in milliseconds at high index
957 * @flags: control flags
958 */
959int pm8xxx_pwm_lut_config(struct pwm_device *pwm, int period_us,
960 int duty_pct[], int duty_time_ms, int start_idx,
961 int idx_len, int pause_lo, int pause_hi, int flags)
962{
Willie Ruan719c6762011-08-25 11:03:14 -0700963 struct pm8xxx_pwm_lut lut;
964 struct pm8xxx_pwm_period *period;
Willie Ruan8de2f382011-08-25 11:04:50 -0700965 int len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 int rc;
967
968 if (pwm == NULL || IS_ERR(pwm) || !idx_len) {
969 pr_err("Invalid pwm handle or idx_len=0\n");
970 return -EINVAL;
971 }
972 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE)) {
973 pr_err("Invalid duty_pct with flag\n");
974 return -EINVAL;
975 }
976 if (pwm->chip == NULL) {
977 pr_err("No pwm_chip\n");
978 return -ENODEV;
979 }
Jay Chokshi57656862011-09-07 12:02:22 -0700980
981 if (pwm->chip->is_lpg_supported == 0) {
982 pr_err("LPG module isn't supported\n");
983 return -EINVAL;
984 }
985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 if (idx_len >= PM_PWM_LUT_SIZE && start_idx) {
987 pr_err("Wrong LUT size or index\n");
988 return -EINVAL;
989 }
990 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE) {
991 pr_err("Exceed LUT limit\n");
992 return -EINVAL;
993 }
994 if ((unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
995 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
996 pr_err("Period out of range\n");
997 return -EINVAL;
998 }
999
Willie Ruan719c6762011-08-25 11:03:14 -07001000 period = &pwm->period;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001 mutex_lock(&pwm->chip->pwm_mutex);
1002
1003 if (!pwm->in_use) {
1004 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
1005 rc = -EINVAL;
1006 goto out_unlock;
1007 }
1008
Willie Ruan8de2f382011-08-25 11:04:50 -07001009 if (pwm->pwm_period != period_us) {
1010 pm8xxx_pwm_calc_period(period_us, period);
1011 pm8xxx_pwm_save_period(pwm);
1012 pwm->pwm_period = period_us;
1013 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014
1015 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
1016
1017 if (flags & PM_PWM_LUT_NO_TABLE)
1018 goto after_table_write;
1019
Willie Ruan8de2f382011-08-25 11:04:50 -07001020 rc = pm8xxx_pwm_change_table(pwm, duty_pct, start_idx, len, 0);
1021 if (rc) {
1022 pr_err("pm8xxx_pwm_change_table: rc=%d\n", rc);
1023 goto out_unlock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 }
1025
1026after_table_write:
Willie Ruan719c6762011-08-25 11:03:14 -07001027 lut.lut_duty_ms = duty_time_ms;
1028 lut.lut_lo_index = start_idx;
1029 lut.lut_hi_index = start_idx + len - 1;
1030 lut.lut_pause_lo = pause_lo;
1031 lut.lut_pause_hi = pause_hi;
1032 lut.flags = flags;
1033 pwm->bypass_lut = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034
Willie Ruan8de2f382011-08-25 11:04:50 -07001035 rc = pm8xxx_pwm_change_lut(pwm, &lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036
1037out_unlock:
1038 mutex_unlock(&pwm->chip->pwm_mutex);
1039 return rc;
1040}
1041EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_config);
1042
1043/**
1044 * pm8xxx_pwm_lut_enable - control a PWM device to start/stop LUT ramp
1045 * @pwm: the PWM device
1046 * @start: to start (1), or stop (0)
1047 */
1048int pm8xxx_pwm_lut_enable(struct pwm_device *pwm, int start)
1049{
1050 if (pwm == NULL || IS_ERR(pwm)) {
1051 pr_err("Invalid pwm handle\n");
1052 return -EINVAL;
1053 }
1054 if (pwm->chip == NULL) {
1055 pr_err("No pwm_chip\n");
1056 return -ENODEV;
1057 }
Jay Chokshi57656862011-09-07 12:02:22 -07001058 if (pwm->chip->is_lpg_supported == 0) {
1059 pr_err("LPG module isn't supported\n");
1060 return -EINVAL;
1061 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062
1063 mutex_lock(&pwm->chip->pwm_mutex);
1064 if (start) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001065 if (pwm->dtest_mode_supported)
1066 pm8xxx_pwm_set_dtest(pwm, 1);
1067
Jay Chokshif3db97a2012-08-08 19:32:15 -07001068 pm8xxx_pwm_bank_sel(pwm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069 pm8xxx_pwm_bank_enable(pwm, 1);
1070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 pm8xxx_pwm_start(pwm, 1, 1);
1072 } else {
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001073 if (pwm->dtest_mode_supported)
1074 pm8xxx_pwm_set_dtest(pwm, 0);
1075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 pm8xxx_pwm_bank_sel(pwm);
1077 pm8xxx_pwm_start(pwm, 0, 0);
1078
1079 pm8xxx_pwm_bank_enable(pwm, 0);
1080 }
1081 mutex_unlock(&pwm->chip->pwm_mutex);
1082 return 0;
1083}
1084EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_enable);
1085
1086#if defined(CONFIG_DEBUG_FS)
1087
1088struct pm8xxx_pwm_dbg_device;
1089
1090struct pm8xxx_pwm_user {
1091 int pwm_id;
1092 struct pwm_device *pwm;
1093 int period;
1094 int duty_cycle;
1095 int enable;
1096 struct pm8xxx_pwm_dbg_device *dbgdev;
1097};
1098
1099struct pm8xxx_pwm_dbg_device {
1100 struct mutex dbg_mutex;
1101 struct device *dev;
1102 struct dentry *dent;
1103
Jay Chokshi57656862011-09-07 12:02:22 -07001104 struct pm8xxx_pwm_user *user;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105};
1106
1107static struct pm8xxx_pwm_dbg_device *pmic_dbg_device;
1108
1109static int dbg_pwm_check_period(int period)
1110{
1111 if (period < PM8XXX_PWM_PERIOD_MIN || period > PM8XXX_PWM_PERIOD_MAX) {
1112 pr_err("period is invalid: %d\n", period);
1113 return -EINVAL;
1114 }
1115 return 0;
1116}
1117
1118static int dbg_pwm_check_duty_cycle(int duty_cycle, const char *func_name)
1119{
1120 if (duty_cycle <= 0 || duty_cycle > 100) {
1121 pr_err("%s: duty_cycle is invalid: %d\n",
1122 func_name, duty_cycle);
1123 return -EINVAL;
1124 }
1125 return 0;
1126}
1127
1128static void dbg_pwm_check_handle(struct pm8xxx_pwm_user *puser)
1129{
1130 struct pwm_device *tmp;
1131
1132 if (puser->pwm == NULL) {
1133 tmp = pwm_request(puser->pwm_id, "pwm-dbg");
1134 if (PTR_ERR(puser->pwm)) {
1135 pr_err("pwm_request: err=%ld\n", PTR_ERR(puser->pwm));
1136 puser->pwm = NULL;
Willie Ruan10976ea2011-08-25 11:01:15 -07001137 } else {
1138 pr_debug("[id=%d] pwm_request ok\n", puser->pwm_id);
1139 puser->pwm = tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 }
1141 }
1142}
1143
1144static int dbg_pwm_enable_set(void *data, u64 val)
1145{
1146 struct pm8xxx_pwm_user *puser = data;
1147 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1148 int rc;
1149
1150 mutex_lock(&dbgdev->dbg_mutex);
1151 rc = dbg_pwm_check_duty_cycle(puser->duty_cycle, __func__);
1152 if (!rc) {
1153 puser->enable = val;
1154 dbg_pwm_check_handle(puser);
1155 if (puser->pwm) {
1156 if (puser->enable)
1157 pwm_enable(puser->pwm);
1158 else
1159 pwm_disable(puser->pwm);
1160 }
1161 }
1162 mutex_unlock(&dbgdev->dbg_mutex);
1163 return 0;
1164}
1165
1166static int dbg_pwm_enable_get(void *data, u64 *val)
1167{
1168 struct pm8xxx_pwm_user *puser = data;
1169 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1170
1171 mutex_lock(&dbgdev->dbg_mutex);
1172 *val = puser->enable;
1173 mutex_unlock(&dbgdev->dbg_mutex);
1174 return 0;
1175}
1176
1177DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_enable_fops,
1178 dbg_pwm_enable_get, dbg_pwm_enable_set,
1179 "%lld\n");
1180
1181static int dbg_pwm_duty_cycle_set(void *data, u64 val)
1182{
1183 struct pm8xxx_pwm_user *puser = data;
1184 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1185 int rc;
1186
1187 mutex_lock(&dbgdev->dbg_mutex);
1188 rc = dbg_pwm_check_duty_cycle(val, __func__);
1189 if (!rc) {
1190 puser->duty_cycle = val;
1191 dbg_pwm_check_handle(puser);
1192 if (puser->pwm) {
1193 int duty_us;
1194
Willie Ruan10976ea2011-08-25 11:01:15 -07001195 duty_us = puser->duty_cycle * puser->period / 100;
1196 pwm_config(puser->pwm, duty_us, puser->period);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 }
1198 }
1199 mutex_unlock(&dbgdev->dbg_mutex);
1200 return 0;
1201}
1202
1203static int dbg_pwm_duty_cycle_get(void *data, u64 *val)
1204{
1205 struct pm8xxx_pwm_user *puser = data;
1206 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1207
1208 mutex_lock(&dbgdev->dbg_mutex);
1209 *val = puser->duty_cycle;
1210 mutex_unlock(&dbgdev->dbg_mutex);
1211 return 0;
1212}
1213
1214DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_duty_cycle_fops,
1215 dbg_pwm_duty_cycle_get, dbg_pwm_duty_cycle_set,
1216 "%lld\n");
1217
1218static int dbg_pwm_period_set(void *data, u64 val)
1219{
1220 struct pm8xxx_pwm_user *puser = data;
1221 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1222 int rc;
1223
1224 mutex_lock(&dbgdev->dbg_mutex);
1225 rc = dbg_pwm_check_period(val);
1226 if (!rc)
1227 puser->period = val;
1228 mutex_unlock(&dbgdev->dbg_mutex);
1229 return 0;
1230}
1231
1232static int dbg_pwm_period_get(void *data, u64 *val)
1233{
1234 struct pm8xxx_pwm_user *puser = data;
1235 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1236
1237 mutex_lock(&dbgdev->dbg_mutex);
1238 *val = puser->period;
1239 mutex_unlock(&dbgdev->dbg_mutex);
1240 return 0;
1241}
1242
1243DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_period_fops,
1244 dbg_pwm_period_get, dbg_pwm_period_set, "%lld\n");
1245
1246static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1247{
1248 struct pm8xxx_pwm_dbg_device *dbgdev;
1249 struct dentry *dent;
1250 struct dentry *temp;
1251 struct pm8xxx_pwm_user *puser;
1252 int i;
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001253 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254
1255 if (dev == NULL) {
1256 pr_err("no parent data passed in.\n");
1257 return -EINVAL;
1258 }
1259
1260 dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
1261 if (dbgdev == NULL) {
1262 pr_err("kzalloc() failed.\n");
1263 return -ENOMEM;
1264 }
1265
Jay Chokshi57656862011-09-07 12:02:22 -07001266 dbgdev->user = kcalloc(pwm_chip->pwm_channels,
1267 sizeof(struct pm8xxx_pwm_user), GFP_KERNEL);
1268 if (dbgdev->user == NULL) {
1269 pr_err("kcalloc() failed.\n");
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001270 rc = -ENOMEM;
1271 goto user_error;
Jay Chokshi57656862011-09-07 12:02:22 -07001272 }
1273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 mutex_init(&dbgdev->dbg_mutex);
1275
1276 dbgdev->dev = dev;
1277
1278 dent = debugfs_create_dir("pm8xxx-pwm-dbg", NULL);
1279 if (dent == NULL || IS_ERR(dent)) {
1280 pr_err("ERR debugfs_create_dir: dent=%p\n", dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001281 rc = -ENOMEM;
1282 goto dir_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 }
1284
1285 dbgdev->dent = dent;
1286
Jay Chokshi57656862011-09-07 12:02:22 -07001287 for (i = 0; i < pwm_chip->pwm_channels; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288 char pwm_ch[] = "0";
1289
1290 pwm_ch[0] = '0' + i;
1291 dent = debugfs_create_dir(pwm_ch, dbgdev->dent);
1292 if (dent == NULL || IS_ERR(dent)) {
1293 pr_err("ERR: pwm=%d: dir: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001294 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 goto debug_error;
1296 }
1297
1298 puser = &dbgdev->user[i];
1299 puser->dbgdev = dbgdev;
1300 puser->pwm_id = i;
1301 temp = debugfs_create_file("period", S_IRUGO | S_IWUSR,
1302 dent, puser, &dbg_pwm_period_fops);
1303 if (temp == NULL || IS_ERR(temp)) {
1304 pr_err("ERR: pwm=%d: period: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001305 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 goto debug_error;
1307 }
1308
1309 temp = debugfs_create_file("duty-cycle", S_IRUGO | S_IWUSR,
1310 dent, puser, &dbg_pwm_duty_cycle_fops);
1311 if (temp == NULL || IS_ERR(temp)) {
1312 pr_err("ERR: pwm=%d: duty-cycle: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001313 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 goto debug_error;
1315 }
1316
1317 temp = debugfs_create_file("enable", S_IRUGO | S_IWUSR,
1318 dent, puser, &dbg_pwm_enable_fops);
1319 if (temp == NULL || IS_ERR(temp)) {
1320 pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001321 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 goto debug_error;
1323 }
1324 }
1325
1326 pmic_dbg_device = dbgdev;
1327
1328 return 0;
1329
1330debug_error:
1331 debugfs_remove_recursive(dbgdev->dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001332dir_error:
1333 kfree(dbgdev->user);
1334user_error:
1335 kfree(dbgdev);
1336 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337}
1338
1339static int __devexit pm8xxx_pwm_dbg_remove(void)
1340{
1341 if (pmic_dbg_device) {
Jay Chokshi57656862011-09-07 12:02:22 -07001342 kfree(pmic_dbg_device->user);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 debugfs_remove_recursive(pmic_dbg_device->dent);
1344 kfree(pmic_dbg_device);
1345 }
1346 return 0;
1347}
1348
1349#else
1350
1351static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1352{
1353 return 0;
1354}
1355
1356static int __devexit pm8xxx_pwm_dbg_remove(void)
1357{
1358 return 0;
1359}
1360
1361#endif
1362
1363static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
1364{
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001365 const struct pm8xxx_pwm_platform_data *pdata = pdev->dev.platform_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 struct pm8xxx_pwm_chip *chip;
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001367 int i, dtest_channel;
Jay Chokshi57656862011-09-07 12:02:22 -07001368 enum pm8xxx_version version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369
1370 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1371 if (chip == NULL) {
1372 pr_err("kzalloc() failed.\n");
1373 return -ENOMEM;
1374 }
1375
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001376 if (pdata != NULL)
1377 dtest_channel = pdata->dtest_channel;
1378 else
1379 dtest_channel = -1;
1380
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 mutex_init(&chip->pwm_mutex);
1382
1383 chip->dev = &pdev->dev;
1384 pwm_chip = chip;
Jay Chokshi57656862011-09-07 12:02:22 -07001385
1386 version = pm8xxx_get_version(chip->dev->parent);
1387
1388 if (version == PM8XXX_VERSION_8921 ||
David Collins999480d2011-11-16 08:52:30 -08001389 version == PM8XXX_VERSION_8058 ||
Jay Chokshi0c220cd2011-12-09 17:18:20 -08001390 version == PM8XXX_VERSION_8922 ||
1391 version == PM8XXX_VERSION_8038) {
Jay Chokshi57656862011-09-07 12:02:22 -07001392 chip->is_lpg_supported = 1;
1393 }
1394 if (chip->is_lpg_supported) {
Jay Chokshi0c220cd2011-12-09 17:18:20 -08001395 if (version == PM8XXX_VERSION_8922 ||
1396 version == PM8XXX_VERSION_8038) {
1397 for (i = 0; i < NUM_CLOCKS; i++)
1398 pt_t[0][i] /= PRE_DIVIDE_2;
1399 chip->pwm_channels = PM8XXX_LPG_V1_PWM_CHANNELS;
1400 } else {
1401 chip->pwm_channels = PM8XXX_LPG_V0_PWM_CHANNELS;
1402 }
Jay Chokshi57656862011-09-07 12:02:22 -07001403 chip->pwm_total_pre_divs = NUM_LPG_PRE_DIVIDE;
1404 } else {
1405 chip->pwm_channels = PM8XXX_PWM_CHANNELS;
1406 chip->pwm_total_pre_divs = NUM_PWM_PRE_DIVIDE;
1407 }
1408
1409 chip->pwm_dev = kcalloc(chip->pwm_channels, sizeof(struct pwm_device),
1410 GFP_KERNEL);
1411 if (chip->pwm_dev == NULL) {
1412 pr_err("kcalloc() failed.\n");
1413 mutex_destroy(&chip->pwm_mutex);
1414 kfree(chip);
1415 return -ENOMEM;
1416 }
1417
1418 for (i = 0; i < chip->pwm_channels; i++) {
1419 chip->pwm_dev[i].pwm_id = i;
1420 chip->pwm_dev[i].chip = chip;
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001421 if (i == dtest_channel)
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001422 chip->pwm_dev[i].dtest_mode_supported = 1;
Jay Chokshi57656862011-09-07 12:02:22 -07001423 }
1424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 platform_set_drvdata(pdev, chip);
1426
1427 if (pm8xxx_pwm_dbg_probe(&pdev->dev) < 0)
1428 pr_err("could not set up debugfs\n");
1429
1430 pr_notice("OK\n");
1431 return 0;
1432}
1433
1434static int __devexit pm8xxx_pwm_remove(struct platform_device *pdev)
1435{
1436 struct pm8xxx_pwm_chip *chip = dev_get_drvdata(pdev->dev.parent);
1437
1438 pm8xxx_pwm_dbg_remove();
Jay Chokshi57656862011-09-07 12:02:22 -07001439 kfree(chip->pwm_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 mutex_destroy(&chip->pwm_mutex);
1441 platform_set_drvdata(pdev, NULL);
1442 kfree(chip);
1443 return 0;
1444}
1445
1446static struct platform_driver pm8xxx_pwm_driver = {
1447 .probe = pm8xxx_pwm_probe,
1448 .remove = __devexit_p(pm8xxx_pwm_remove),
1449 .driver = {
1450 .name = PM8XXX_PWM_DEV_NAME,
1451 .owner = THIS_MODULE,
1452 },
1453};
1454
1455static int __init pm8xxx_pwm_init(void)
1456{
1457 return platform_driver_register(&pm8xxx_pwm_driver);
1458}
1459
1460static void __exit pm8xxx_pwm_exit(void)
1461{
1462 platform_driver_unregister(&pm8xxx_pwm_driver);
1463}
1464
1465subsys_initcall(pm8xxx_pwm_init);
1466module_exit(pm8xxx_pwm_exit);
1467
1468MODULE_LICENSE("GPL v2");
1469MODULE_DESCRIPTION("PM8XXX PWM driver");
1470MODULE_VERSION("1.0");
1471MODULE_ALIAS("platform:" PM8XXX_PWM_DEV_NAME);