blob: b5e209254861250101078f785129804d85dffdbc [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 Chokshi57656862011-09-07 12:02:22 -070030#define PM8XXX_LPG_BANKS 8
31#define PM8XXX_LPG_PWM_CHANNELS PM8XXX_LPG_BANKS
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#define PM8XXX_LPG_CTL_REGS 7
33
34/* PM8XXX PWM */
Jay Chokshi57656862011-09-07 12:02:22 -070035#define SSBI_REG_ADDR_PWM1_CTRL1 0x88
36#define SSBI_REG_ADDR_PWM1_CTRL2 0x89
37#define SSBI_REG_ADDR_PWM_CTL(id, base) (id == 0 ? base : (base + (id << 1)))
38#define SSBI_REG_ADDR_PWM_CTL1(id) SSBI_REG_ADDR_PWM_CTL(id, \
39 SSBI_REG_ADDR_PWM1_CTRL1)
40#define SSBI_REG_ADDR_PWM_CTL2(id) SSBI_REG_ADDR_PWM_CTL(id, \
41 SSBI_REG_ADDR_PWM1_CTRL2)
42
43#define PM8XXX_PWM_CLK_SEL_SHIFT 6
44#define PM8XXX_PWM_CLK_SEL_MASK 0xC0
45#define PM8XXX_PWM_PREDIVIDE_SHIFT 5
46#define PM8XXX_PWM_PREDIVIDE_MASK 0x20
47#define PM8XXX_PWM_M_SHIFT 2
48#define PM8XXX_PWM_M_MASK 0x1C
49#define PM8XXX_PWM_SIZE_SHIFT 1
50#define PM8XXX_PWM_SIZE_MASK 0x02
51#define PM8XXX_PWM_VALUE_BIT0 0x01
52#define PM8XXX_PWM_DISABLE 0x3F
53
54/* PM8XXX LPG PWM */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#define SSBI_REG_ADDR_LPG_CTL_BASE 0x13C
56#define SSBI_REG_ADDR_LPG_CTL(n) (SSBI_REG_ADDR_LPG_CTL_BASE + (n))
57#define SSBI_REG_ADDR_LPG_BANK_SEL 0x143
58#define SSBI_REG_ADDR_LPG_BANK_EN 0x144
59#define SSBI_REG_ADDR_LPG_LUT_CFG0 0x145
60#define SSBI_REG_ADDR_LPG_LUT_CFG1 0x146
61
Jay Chokshi57656862011-09-07 12:02:22 -070062/* LPG Control 0 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063#define PM8XXX_PWM_1KHZ_COUNT_MASK 0xF0
64#define PM8XXX_PWM_1KHZ_COUNT_SHIFT 4
65
66#define PM8XXX_PWM_1KHZ_COUNT_MAX 15
67
68#define PM8XXX_PWM_OUTPUT_EN 0x08
69#define PM8XXX_PWM_PWM_EN 0x04
70#define PM8XXX_PWM_RAMP_GEN_EN 0x02
71#define PM8XXX_PWM_RAMP_START 0x01
72
73#define PM8XXX_PWM_PWM_START (PM8XXX_PWM_OUTPUT_EN \
74 | PM8XXX_PWM_PWM_EN)
75#define PM8XXX_PWM_RAMP_GEN_START (PM8XXX_PWM_RAMP_GEN_EN \
76 | PM8XXX_PWM_RAMP_START)
77
Jay Chokshi57656862011-09-07 12:02:22 -070078/* LPG Control 1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079#define PM8XXX_PWM_REVERSE_EN 0x80
80#define PM8XXX_PWM_BYPASS_LUT 0x40
81#define PM8XXX_PWM_HIGH_INDEX_MASK 0x3F
82
Jay Chokshi57656862011-09-07 12:02:22 -070083/* LPG Control 2 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084#define PM8XXX_PWM_LOOP_EN 0x80
85#define PM8XXX_PWM_RAMP_UP 0x40
86#define PM8XXX_PWM_LOW_INDEX_MASK 0x3F
87
Jay Chokshi57656862011-09-07 12:02:22 -070088/* LPG Control 3 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089#define PM8XXX_PWM_VALUE_BIT7_0 0xFF
90#define PM8XXX_PWM_VALUE_BIT5_0 0x3F
91
Jay Chokshi57656862011-09-07 12:02:22 -070092/* LPG Control 4 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093#define PM8XXX_PWM_VALUE_BIT8 0x80
94
Jay Chokshi57656862011-09-07 12:02:22 -070095#define PM8XXX_LPG_PWM_CLK_SEL_MASK 0x60
96#define PM8XXX_LPG_PWM_CLK_SEL_SHIFT 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097
98#define PM8XXX_PWM_CLK_SEL_NO 0
99#define PM8XXX_PWM_CLK_SEL_1KHZ 1
100#define PM8XXX_PWM_CLK_SEL_32KHZ 2
101#define PM8XXX_PWM_CLK_SEL_19P2MHZ 3
102
Jay Chokshi57656862011-09-07 12:02:22 -0700103#define PM8XXX_LPG_PWM_PREDIVIDE_MASK 0x18
104#define PM8XXX_LPG_PWM_PREDIVIDE_SHIFT 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105
106#define PM8XXX_PWM_PREDIVIDE_2 0
107#define PM8XXX_PWM_PREDIVIDE_3 1
108#define PM8XXX_PWM_PREDIVIDE_5 2
109#define PM8XXX_PWM_PREDIVIDE_6 3
110
Jay Chokshi57656862011-09-07 12:02:22 -0700111#define PM8XXX_LPG_PWM_M_MASK 0x07
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112#define PM8XXX_PWM_M_MIN 0
113#define PM8XXX_PWM_M_MAX 7
114
Jay Chokshi57656862011-09-07 12:02:22 -0700115/* LPG Control 5 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116#define PM8XXX_PWM_PAUSE_COUNT_HI_MASK 0xFC
117#define PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT 2
118
119#define PM8XXX_PWM_PAUSE_ENABLE_HIGH 0x02
120#define PM8XXX_PWM_SIZE_9_BIT 0x01
121
Jay Chokshi57656862011-09-07 12:02:22 -0700122/* LPG Control 6 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123#define PM8XXX_PWM_PAUSE_COUNT_LO_MASK 0xFC
124#define PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT 2
125
126#define PM8XXX_PWM_PAUSE_ENABLE_LOW 0x02
127#define PM8XXX_PWM_RESERVED 0x01
128
129#define PM8XXX_PWM_PAUSE_COUNT_MAX 56 /* < 2^6 = 64 */
130
Jay Chokshi57656862011-09-07 12:02:22 -0700131/* LPG LUT_CFG1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132#define PM8XXX_PWM_LUT_READ 0x40
133
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135/*
136 * PWM Frequency = Clock Frequency / (N * T)
137 * or
138 * PWM Period = Clock Period * (N * T)
139 * where
140 * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
141 * T = Pre-divide * 2^m, where m = 0..7 (exponent)
142 *
143 * This is the formula to figure out m for the best pre-divide and clock:
Willie Ruan4a0a7002012-01-10 15:39:44 -0800144 * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 */
146#define NUM_CLOCKS 3
147
Willie Ruandb78e942012-01-10 15:00:28 -0800148#define NSEC_1024HZ (NSEC_PER_SEC / 1024)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
150#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
151
152#define CLK_PERIOD_MIN NSEC_19P2MHZ
Willie Ruandb78e942012-01-10 15:00:28 -0800153#define CLK_PERIOD_MAX NSEC_1024HZ
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154
Willie Ruanb10be972012-01-12 11:30:11 -0800155#define NUM_LPG_PRE_DIVIDE 4
Jay Chokshi57656862011-09-07 12:02:22 -0700156#define NUM_PWM_PRE_DIVIDE 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157
Willie Ruanb10be972012-01-12 11:30:11 -0800158#define PRE_DIVIDE_2 2
159#define PRE_DIVIDE_3 3
160#define PRE_DIVIDE_5 5
161#define PRE_DIVIDE_6 6
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162
Jay Chokshi57656862011-09-07 12:02:22 -0700163static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
Willie Ruandb78e942012-01-10 15:00:28 -0800164 { PRE_DIVIDE_2 * NSEC_1024HZ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 PRE_DIVIDE_2 * NSEC_32768HZ,
166 PRE_DIVIDE_2 * NSEC_19P2MHZ,
167 },
Willie Ruanb10be972012-01-12 11:30:11 -0800168 { PRE_DIVIDE_3 * NSEC_1024HZ,
169 PRE_DIVIDE_3 * NSEC_32768HZ,
170 PRE_DIVIDE_3 * NSEC_19P2MHZ,
171 },
172 { PRE_DIVIDE_5 * NSEC_1024HZ,
173 PRE_DIVIDE_5 * NSEC_32768HZ,
174 PRE_DIVIDE_5 * NSEC_19P2MHZ,
175 },
176 { PRE_DIVIDE_6 * NSEC_1024HZ,
177 PRE_DIVIDE_6 * NSEC_32768HZ,
178 PRE_DIVIDE_6 * NSEC_19P2MHZ,
179 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180};
181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182/* Private data */
183struct pm8xxx_pwm_chip;
184
185struct pwm_device {
186 int pwm_id; /* = bank/channel id */
187 int in_use;
188 const char *label;
Willie Ruan719c6762011-08-25 11:03:14 -0700189 struct pm8xxx_pwm_period period;
190 int pwm_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191 int pwm_period;
192 int pwm_duty;
Jay Chokshi57656862011-09-07 12:02:22 -0700193 u8 pwm_lpg_ctl[PM8XXX_LPG_CTL_REGS];
194 u8 pwm_ctl1;
195 u8 pwm_ctl2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 int irq;
197 struct pm8xxx_pwm_chip *chip;
Willie Ruan719c6762011-08-25 11:03:14 -0700198 int bypass_lut;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199};
200
201struct pm8xxx_pwm_chip {
Jay Chokshi57656862011-09-07 12:02:22 -0700202 struct pwm_device *pwm_dev;
203 u8 pwm_channels;
204 u8 pwm_total_pre_divs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 u8 bank_mask;
206 struct mutex pwm_mutex;
207 struct device *dev;
Jay Chokshi57656862011-09-07 12:02:22 -0700208 bool is_lpg_supported;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209};
210
211static struct pm8xxx_pwm_chip *pwm_chip;
212
Willie Ruan719c6762011-08-25 11:03:14 -0700213struct pm8xxx_pwm_lut {
214 /* LUT parameters */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215 int lut_duty_ms;
216 int lut_lo_index;
217 int lut_hi_index;
218 int lut_pause_hi;
219 int lut_pause_lo;
220 int flags;
221};
222
223static const u16 duty_msec[PM8XXX_PWM_1KHZ_COUNT_MAX + 1] = {
224 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
225};
226
227static const u16 pause_count[PM8XXX_PWM_PAUSE_COUNT_MAX + 1] = {
228 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
229 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
230 375, 500, 667, 750, 800, 900, 1000, 1100,
231 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
232 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
233 7000
234};
235
236/* Internal functions */
Willie Ruan8de2f382011-08-25 11:04:50 -0700237static void pm8xxx_pwm_save(u8 *u8p, u8 mask, u8 val)
238{
239 *u8p &= ~mask;
240 *u8p |= val & mask;
241}
242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243static int pm8xxx_pwm_bank_enable(struct pwm_device *pwm, int enable)
244{
245 int rc;
246 u8 reg;
247 struct pm8xxx_pwm_chip *chip;
248
249 chip = pwm->chip;
250
251 if (enable)
252 reg = chip->bank_mask | (1 << pwm->pwm_id);
253 else
254 reg = chip->bank_mask & ~(1 << pwm->pwm_id);
255
256 rc = pm8xxx_writeb(chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
257 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700258 pr_err("pm8xxx_writeb(): rc=%d (Enable LPG Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 return rc;
260 }
261 chip->bank_mask = reg;
262
263 return 0;
264}
265
266static int pm8xxx_pwm_bank_sel(struct pwm_device *pwm)
267{
268 int rc;
269
270 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_SEL,
271 pwm->pwm_id);
272 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700273 pr_err("pm8xxx_writeb(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 return rc;
275}
276
277static int pm8xxx_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
278{
279 int rc;
280 u8 reg;
281
282 if (start) {
Jay Chokshi57656862011-09-07 12:02:22 -0700283 reg = pwm->pwm_lpg_ctl[0] | PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 if (ramp_start)
285 reg |= PM8XXX_PWM_RAMP_GEN_START;
286 else
287 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
288 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700289 reg = pwm->pwm_lpg_ctl[0] & ~PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
291 }
292
293 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
294 reg);
295 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700296 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 else
Jay Chokshi57656862011-09-07 12:02:22 -0700298 pwm->pwm_lpg_ctl[0] = reg;
299 return rc;
300}
301
302static int pm8xxx_pwm_disable(struct pwm_device *pwm)
303{
304 int rc;
305 u8 reg;
306
307 reg = pwm->pwm_ctl1 & PM8XXX_PWM_DISABLE;
308
309 rc = pm8xxx_writeb(pwm->chip->dev->parent,
310 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), reg);
311
312 if (rc)
313 pr_err("pm8xxx_writeb(): rc=%d (Disable PWM Ctl %d)\n", rc,
314 pwm->pwm_id);
315 return rc;
316}
317
318static int pm8xxx_pwm_enable(struct pwm_device *pwm)
319{
320 /**
321 * A kind of best Effort: Just write the clock information that
322 * we have in the register.
323 */
324 int rc;
325
326 rc = pm8xxx_writeb(pwm->chip->dev->parent,
327 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), pwm->pwm_ctl1);
328
329 if (rc)
330 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl %d)\n", rc,
331 pwm->pwm_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 return rc;
333}
334
335static void pm8xxx_pwm_calc_period(unsigned int period_us,
Willie Ruan719c6762011-08-25 11:03:14 -0700336 struct pm8xxx_pwm_period *period)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337{
338 int n, m, clk, div;
339 int best_m, best_div, best_clk;
Willie Ruan4a0a7002012-01-10 15:39:44 -0800340 unsigned int last_err, cur_err, min_err;
341 unsigned int tmp_p, period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342
343 /* PWM Period / N */
Willie Ruan70f989d2012-01-10 10:09:36 -0800344 if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 period_n = (period_us * NSEC_PER_USEC) >> 6;
346 n = 6;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 } else {
348 period_n = (period_us >> 9) * NSEC_PER_USEC;
349 n = 9;
350 }
351
Willie Ruan4a0a7002012-01-10 15:39:44 -0800352 min_err = last_err = (unsigned)(-1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 best_m = 0;
354 best_clk = 0;
355 best_div = 0;
356 for (clk = 0; clk < NUM_CLOCKS; clk++) {
Jay Chokshi57656862011-09-07 12:02:22 -0700357 for (div = 0; div < pwm_chip->pwm_total_pre_divs; div++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800358 /* period_n = (PWM Period / N) */
359 /* tmp_p = (Pre-divide * Clock Period) * 2^m */
360 tmp_p = pt_t[div][clk];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361 for (m = 0; m <= PM8XXX_PWM_M_MAX; m++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800362 if (period_n > tmp_p)
363 cur_err = period_n - tmp_p;
364 else
365 cur_err = tmp_p - period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366
Willie Ruan4a0a7002012-01-10 15:39:44 -0800367 if (cur_err < min_err) {
368 min_err = cur_err;
369 best_m = m;
370 best_clk = clk;
371 best_div = div;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372 }
Willie Ruan4a0a7002012-01-10 15:39:44 -0800373
374 if (m && cur_err > last_err)
375 /* Break for bigger cur_err */
376 break;
377
378 last_err = cur_err;
379 tmp_p <<= 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 }
381 }
382 }
383
Willie Ruan75d9e5b2011-08-25 10:59:17 -0700384 /* Use higher resolution */
385 if (best_m >= 3 && n == 6) {
386 n += 3;
387 best_m -= 3;
388 }
389
Willie Ruan719c6762011-08-25 11:03:14 -0700390 period->pwm_size = n;
391 period->clk = best_clk;
392 period->pre_div = best_div;
393 period->pre_div_exp = best_m;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394}
395
Willie Ruan8de2f382011-08-25 11:04:50 -0700396static void pm8xxx_pwm_calc_pwm_value(struct pwm_device *pwm,
397 unsigned int period_us,
398 unsigned int duty_us)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399{
Willie Ruan8de2f382011-08-25 11:04:50 -0700400 unsigned int max_pwm_value, tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401
Willie Ruan8de2f382011-08-25 11:04:50 -0700402 /* Figure out pwm_value with overflow handling */
403 tmp = 1 << (sizeof(tmp) * 8 - pwm->period.pwm_size);
404 if (duty_us < tmp) {
405 tmp = duty_us << pwm->period.pwm_size;
406 pwm->pwm_value = tmp / period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 } else {
Willie Ruan8de2f382011-08-25 11:04:50 -0700408 tmp = period_us >> pwm->period.pwm_size;
409 pwm->pwm_value = duty_us / tmp;
410 }
411 max_pwm_value = (1 << pwm->period.pwm_size) - 1;
412 if (pwm->pwm_value > max_pwm_value)
413 pwm->pwm_value = max_pwm_value;
414}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415
Willie Ruan8de2f382011-08-25 11:04:50 -0700416static int pm8xxx_pwm_change_table(struct pwm_device *pwm, int duty_pct[],
417 int start_idx, int len, int raw_value)
418{
419 unsigned int pwm_value, max_pwm_value;
420 u8 cfg0, cfg1;
421 int i, pwm_size;
422 int rc = 0;
423
Jay Chokshi57656862011-09-07 12:02:22 -0700424 pwm_size = (pwm->pwm_lpg_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
Willie Ruan8de2f382011-08-25 11:04:50 -0700425 max_pwm_value = (1 << pwm_size) - 1;
426 for (i = 0; i < len; i++) {
427 if (raw_value)
428 pwm_value = duty_pct[i];
429 else
430 pwm_value = (duty_pct[i] << pwm_size) / 100;
431
432 if (pwm_value > max_pwm_value)
433 pwm_value = max_pwm_value;
434 cfg0 = pwm_value;
435 cfg1 = (pwm_value >> 1) & 0x80;
436 cfg1 |= start_idx + i;
437
438 rc = pm8xxx_writeb(pwm->chip->dev->parent,
439 SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
440 if (rc)
441 break;
442
443 rc = pm8xxx_writeb(pwm->chip->dev->parent,
444 SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
445 if (rc)
446 break;
447 }
448 return rc;
449}
450
451static void pm8xxx_pwm_save_index(struct pwm_device *pwm,
452 int low_idx, int high_idx, int flags)
453{
Jay Chokshi57656862011-09-07 12:02:22 -0700454 pwm->pwm_lpg_ctl[1] = high_idx & PM8XXX_PWM_HIGH_INDEX_MASK;
455 pwm->pwm_lpg_ctl[2] = low_idx & PM8XXX_PWM_LOW_INDEX_MASK;
Willie Ruan8de2f382011-08-25 11:04:50 -0700456
457 if (flags & PM_PWM_LUT_REVERSE)
Jay Chokshi57656862011-09-07 12:02:22 -0700458 pwm->pwm_lpg_ctl[1] |= PM8XXX_PWM_REVERSE_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700459 if (flags & PM_PWM_LUT_RAMP_UP)
Jay Chokshi57656862011-09-07 12:02:22 -0700460 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_RAMP_UP;
Willie Ruan8de2f382011-08-25 11:04:50 -0700461 if (flags & PM_PWM_LUT_LOOP)
Jay Chokshi57656862011-09-07 12:02:22 -0700462 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_LOOP_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700463}
464
465static void pm8xxx_pwm_save_period(struct pwm_device *pwm)
466{
467 u8 mask, val;
468
Jay Chokshi57656862011-09-07 12:02:22 -0700469 if (pwm_chip->is_lpg_supported) {
470 val = ((pwm->period.clk + 1) << PM8XXX_LPG_PWM_CLK_SEL_SHIFT)
471 & PM8XXX_LPG_PWM_CLK_SEL_MASK;
472 val |= (pwm->period.pre_div << PM8XXX_LPG_PWM_PREDIVIDE_SHIFT)
473 & PM8XXX_LPG_PWM_PREDIVIDE_MASK;
474 val |= pwm->period.pre_div_exp & PM8XXX_LPG_PWM_M_MASK;
475 mask = PM8XXX_LPG_PWM_CLK_SEL_MASK |
476 PM8XXX_LPG_PWM_PREDIVIDE_MASK | PM8XXX_LPG_PWM_M_MASK;
477 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700478
Jay Chokshi57656862011-09-07 12:02:22 -0700479 val = (pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0;
480 mask = PM8XXX_PWM_SIZE_9_BIT;
481 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
482 } else {
483 val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
484 & PM8XXX_PWM_CLK_SEL_MASK;
485 val |= (pwm->period.pre_div << PM8XXX_PWM_PREDIVIDE_SHIFT)
486 & PM8XXX_PWM_PREDIVIDE_MASK;
487 val |= (pwm->period.pre_div_exp << PM8XXX_PWM_M_SHIFT)
488 & PM8XXX_PWM_M_MASK;
489 val |= (((pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0)
490 << PM8XXX_PWM_SIZE_SHIFT) & PM8XXX_PWM_SIZE_MASK;
491
492 mask = PM8XXX_PWM_CLK_SEL_MASK | PM8XXX_PWM_PREDIVIDE_MASK |
493 PM8XXX_PWM_M_MASK | PM8XXX_PWM_SIZE_MASK;
494 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
495 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700496}
497
498static void pm8xxx_pwm_save_pwm_value(struct pwm_device *pwm)
499{
500 u8 mask, val;
501
Jay Chokshi57656862011-09-07 12:02:22 -0700502 if (pwm_chip->is_lpg_supported) {
503 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 1) : 0;
504 pwm->pwm_lpg_ctl[3] = pwm->pwm_value;
505 mask = PM8XXX_PWM_VALUE_BIT8;
506 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
507 } else {
508 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 8) : 0;
509 pwm->pwm_ctl2 = pwm->pwm_value;
510 mask = PM8XXX_PWM_VALUE_BIT0;
511 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
512 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700513}
514
515static void pm8xxx_pwm_save_duty_time(struct pwm_device *pwm,
516 struct pm8xxx_pwm_lut *lut)
517{
518 int i;
519 u8 mask, val;
520
521 /* Linear search for duty time */
522 for (i = 0; i < PM8XXX_PWM_1KHZ_COUNT_MAX; i++) {
523 if (duty_msec[i] >= lut->lut_duty_ms)
524 break;
525 }
526 val = i << PM8XXX_PWM_1KHZ_COUNT_SHIFT;
527
528 mask = PM8XXX_PWM_1KHZ_COUNT_MASK;
Jay Chokshi57656862011-09-07 12:02:22 -0700529 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[0], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700530}
531
532static void pm8xxx_pwm_save_pause(struct pwm_device *pwm,
533 struct pm8xxx_pwm_lut *lut)
534{
535 int i, pause_cnt, time_cnt;
536 u8 mask, val;
537
Jay Chokshi57656862011-09-07 12:02:22 -0700538 time_cnt = (pwm->pwm_lpg_ctl[0] & PM8XXX_PWM_1KHZ_COUNT_MASK)
Willie Ruan8de2f382011-08-25 11:04:50 -0700539 >> PM8XXX_PWM_1KHZ_COUNT_SHIFT;
540 if (lut->flags & PM_PWM_LUT_PAUSE_HI_EN) {
541 pause_cnt = (lut->lut_pause_hi + duty_msec[time_cnt] / 2)
542 / duty_msec[time_cnt];
543 /* Linear search for pause time */
544 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
545 if (pause_count[i] >= pause_cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546 break;
547 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700548 val = (i << PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT) &
549 PM8XXX_PWM_PAUSE_COUNT_HI_MASK;
550 val |= PM8XXX_PWM_PAUSE_ENABLE_HIGH;
551 } else {
552 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 }
554
Willie Ruan8de2f382011-08-25 11:04:50 -0700555 mask = PM8XXX_PWM_PAUSE_COUNT_HI_MASK | PM8XXX_PWM_PAUSE_ENABLE_HIGH;
Jay Chokshi57656862011-09-07 12:02:22 -0700556 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557
Willie Ruan8de2f382011-08-25 11:04:50 -0700558 if (lut->flags & PM_PWM_LUT_PAUSE_LO_EN) {
559 /* Linear search for pause time */
560 pause_cnt = (lut->lut_pause_lo + duty_msec[time_cnt] / 2)
561 / duty_msec[time_cnt];
562 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
563 if (pause_count[i] >= pause_cnt)
564 break;
565 }
566 val = (i << PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT) &
567 PM8XXX_PWM_PAUSE_COUNT_LO_MASK;
568 val |= PM8XXX_PWM_PAUSE_ENABLE_LOW;
569 } else {
570 val = 0;
571 }
572
573 mask = PM8XXX_PWM_PAUSE_COUNT_LO_MASK | PM8XXX_PWM_PAUSE_ENABLE_LOW;
Jay Chokshi57656862011-09-07 12:02:22 -0700574 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[6], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700575}
576
Jay Chokshi57656862011-09-07 12:02:22 -0700577static int pm8xxx_pwm_write(struct pwm_device *pwm)
578{
579 int rc = 0;
580
581 rc = pm8xxx_writeb(pwm->chip->dev->parent,
582 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id),
583 pwm->pwm_ctl1);
584 if (rc) {
585 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl1[%d])\n",
586 rc, pwm->pwm_id);
587 return rc;
588 }
589
590 rc = pm8xxx_writeb(pwm->chip->dev->parent,
591 SSBI_REG_ADDR_PWM_CTL2(pwm->pwm_id),
592 pwm->pwm_ctl2);
593 if (rc) {
594 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl2[%d])\n",
595 rc, pwm->pwm_id);
596 return rc;
597 }
598
599 return rc;
600}
601
602static int pm8xxx_lpg_pwm_write(struct pwm_device *pwm, int start, int end)
Willie Ruan8de2f382011-08-25 11:04:50 -0700603{
604 int i, rc;
605
606 /* Write in reverse way so 0 would be the last */
607 for (i = end - 1; i >= start; i--) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 rc = pm8xxx_writeb(pwm->chip->dev->parent,
609 SSBI_REG_ADDR_LPG_CTL(i),
Jay Chokshi57656862011-09-07 12:02:22 -0700610 pwm->pwm_lpg_ctl[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700612 pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[%d])\n", rc, i);
613 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614 }
615 }
616
Willie Ruan8de2f382011-08-25 11:04:50 -0700617 return 0;
618}
619
620static int pm8xxx_pwm_change_lut(struct pwm_device *pwm,
621 struct pm8xxx_pwm_lut *lut)
622{
623 int rc;
624
625 pm8xxx_pwm_save_index(pwm, lut->lut_lo_index,
626 lut->lut_hi_index, lut->flags);
627 pm8xxx_pwm_save_duty_time(pwm, lut);
628 pm8xxx_pwm_save_pause(pwm, lut);
Jay Chokshi57656862011-09-07 12:02:22 -0700629 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1], PM8XXX_PWM_BYPASS_LUT, 0);
Willie Ruan8de2f382011-08-25 11:04:50 -0700630
631 pm8xxx_pwm_bank_sel(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700632 rc = pm8xxx_lpg_pwm_write(pwm, 0, 7);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633
634 return rc;
635}
636
637/* APIs */
638/**
639 * pwm_request - request a PWM device
640 * @pwm_id: PWM id or channel
641 * @label: the label to identify the user
642 */
643struct pwm_device *pwm_request(int pwm_id, const char *label)
644{
645 struct pwm_device *pwm;
646
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647 if (pwm_chip == NULL) {
648 pr_err("No pwm_chip\n");
649 return ERR_PTR(-ENODEV);
650 }
651
Jay Chokshi57656862011-09-07 12:02:22 -0700652 if (pwm_id >= pwm_chip->pwm_channels || pwm_id < 0) {
653 pr_err("Invalid pwm_id: %d with %s\n",
654 pwm_id, label ? label : ".");
655 return ERR_PTR(-EINVAL);
656 }
657
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658 mutex_lock(&pwm_chip->pwm_mutex);
659 pwm = &pwm_chip->pwm_dev[pwm_id];
660 if (!pwm->in_use) {
661 pwm->in_use = 1;
662 pwm->label = label;
663 } else {
664 pwm = ERR_PTR(-EBUSY);
665 }
666 mutex_unlock(&pwm_chip->pwm_mutex);
667
668 return pwm;
669}
670EXPORT_SYMBOL_GPL(pwm_request);
671
672/**
673 * pwm_free - free a PWM device
674 * @pwm: the PWM device
675 */
676void pwm_free(struct pwm_device *pwm)
677{
678 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
679 pr_err("Invalid pwm handle\n");
680 return;
681 }
682
683 mutex_lock(&pwm->chip->pwm_mutex);
684 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700685 if (pwm_chip->is_lpg_supported) {
686 pm8xxx_pwm_bank_sel(pwm);
687 pm8xxx_pwm_start(pwm, 0, 0);
688 } else {
689 pm8xxx_pwm_disable(pwm);
690 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691 pwm->in_use = 0;
692 pwm->label = NULL;
693 }
Jay Chokshi57656862011-09-07 12:02:22 -0700694 if (pwm_chip->is_lpg_supported)
695 pm8xxx_pwm_bank_enable(pwm, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696 mutex_unlock(&pwm->chip->pwm_mutex);
697}
698EXPORT_SYMBOL_GPL(pwm_free);
699
700/**
701 * pwm_config - change a PWM device configuration
702 * @pwm: the PWM device
703 * @period_us: period in microseconds
704 * @duty_us: duty cycle in microseconds
705 */
706int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
707{
Willie Ruan719c6762011-08-25 11:03:14 -0700708 struct pm8xxx_pwm_period *period;
Jay Chokshi57656862011-09-07 12:02:22 -0700709 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710
711 if (pwm == NULL || IS_ERR(pwm) ||
712 duty_us > period_us ||
713 (unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
714 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
715 pr_err("Invalid pwm handle or parameters\n");
716 return -EINVAL;
717 }
718 if (pwm->chip == NULL) {
719 pr_err("No pwm_chip\n");
720 return -ENODEV;
721 }
722
Willie Ruan719c6762011-08-25 11:03:14 -0700723 period = &pwm->period;
724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725 mutex_lock(&pwm->chip->pwm_mutex);
726
727 if (!pwm->in_use) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728 rc = -EINVAL;
729 goto out_unlock;
730 }
731
Willie Ruan8de2f382011-08-25 11:04:50 -0700732 if (pwm->pwm_period != period_us) {
733 pm8xxx_pwm_calc_period(period_us, period);
734 pm8xxx_pwm_save_period(pwm);
735 pwm->pwm_period = period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737
Willie Ruan8de2f382011-08-25 11:04:50 -0700738 pm8xxx_pwm_calc_pwm_value(pwm, period_us, duty_us);
739 pm8xxx_pwm_save_pwm_value(pwm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740
Jay Chokshi57656862011-09-07 12:02:22 -0700741 if (pwm_chip->is_lpg_supported) {
742 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
743 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
744
745 pm8xxx_pwm_bank_sel(pwm);
746 rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
747 } else {
748 rc = pm8xxx_pwm_write(pwm);
749 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700750
751 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
752 (unsigned)duty_us, (unsigned)period_us,
753 pwm->pwm_value, 1 << period->pwm_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754
755out_unlock:
756 mutex_unlock(&pwm->chip->pwm_mutex);
757 return rc;
758}
759EXPORT_SYMBOL_GPL(pwm_config);
760
761/**
762 * pwm_enable - start a PWM output toggling
763 * @pwm: the PWM device
764 */
765int pwm_enable(struct pwm_device *pwm)
766{
Jay Chokshi57656862011-09-07 12:02:22 -0700767 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768
769 if (pwm == NULL || IS_ERR(pwm)) {
770 pr_err("Invalid pwm handle\n");
771 return -EINVAL;
772 }
773 if (pwm->chip == NULL) {
774 pr_err("No pwm_chip\n");
775 return -ENODEV;
776 }
777
778 mutex_lock(&pwm->chip->pwm_mutex);
779 if (!pwm->in_use) {
780 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
781 rc = -EINVAL;
782 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700783 if (pwm_chip->is_lpg_supported) {
784 rc = pm8xxx_pwm_bank_enable(pwm, 1);
785 pm8xxx_pwm_bank_sel(pwm);
786 pm8xxx_pwm_start(pwm, 1, 0);
787 } else {
788 pm8xxx_pwm_enable(pwm);
789 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790 }
791 mutex_unlock(&pwm->chip->pwm_mutex);
792 return rc;
793}
794EXPORT_SYMBOL_GPL(pwm_enable);
795
796/**
797 * pwm_disable - stop a PWM output toggling
798 * @pwm: the PWM device
799 */
800void pwm_disable(struct pwm_device *pwm)
801{
802 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
803 pr_err("Invalid pwm handle or no pwm_chip\n");
804 return;
805 }
806
807 mutex_lock(&pwm->chip->pwm_mutex);
808 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700809 if (pwm_chip->is_lpg_supported) {
810 pm8xxx_pwm_bank_sel(pwm);
811 pm8xxx_pwm_start(pwm, 0, 0);
812 pm8xxx_pwm_bank_enable(pwm, 0);
813 } else {
814 pm8xxx_pwm_disable(pwm);
815 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816 }
817 mutex_unlock(&pwm->chip->pwm_mutex);
818}
819EXPORT_SYMBOL_GPL(pwm_disable);
820
821/**
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700822 * pm8xxx_pwm_config_period - change PWM period
823 *
824 * @pwm: the PWM device
825 * @pwm_p: period in struct pm8xxx_pwm_period
826 */
827int pm8xxx_pwm_config_period(struct pwm_device *pwm,
828 struct pm8xxx_pwm_period *period)
829{
830 int rc;
831
832 if (pwm == NULL || IS_ERR(pwm) || period == NULL)
833 return -EINVAL;
834 if (pwm->chip == NULL)
835 return -ENODEV;
836
837 mutex_lock(&pwm->chip->pwm_mutex);
838
839 if (!pwm->in_use) {
840 rc = -EINVAL;
841 goto out_unlock;
842 }
843
844 pwm->period.pwm_size = period->pwm_size;
845 pwm->period.clk = period->clk;
846 pwm->period.pre_div = period->pre_div;
847 pwm->period.pre_div_exp = period->pre_div_exp;
848
849 pm8xxx_pwm_save_period(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700850
851 if (pwm_chip->is_lpg_supported) {
852 pm8xxx_pwm_bank_sel(pwm);
853 rc = pm8xxx_lpg_pwm_write(pwm, 4, 6);
854 } else {
855 rc = pm8xxx_pwm_write(pwm);
856 }
857
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700858
859out_unlock:
860 mutex_unlock(&pwm->chip->pwm_mutex);
861 return rc;
862}
863EXPORT_SYMBOL(pm8xxx_pwm_config_period);
864
865/**
866 * pm8xxx_pwm_config_pwm_value - change a PWM device configuration
867 * @pwm: the PWM device
868 * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
869 */
870int pm8xxx_pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
871{
872 int rc = 0;
873
874 if (pwm == NULL || IS_ERR(pwm))
875 return -EINVAL;
876 if (pwm->chip == NULL)
877 return -ENODEV;
878
879 mutex_lock(&pwm->chip->pwm_mutex);
880
881 if (!pwm->in_use || !pwm->pwm_period) {
882 rc = -EINVAL;
883 goto out_unlock;
884 }
885
886 if (pwm->pwm_value == pwm_value)
887 goto out_unlock;
888
889 pwm->pwm_value = pwm_value;
890
891 pm8xxx_pwm_save_pwm_value(pwm);
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700892
Jay Chokshi57656862011-09-07 12:02:22 -0700893 if (pwm_chip->is_lpg_supported) {
894 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
895 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
896 pm8xxx_pwm_bank_sel(pwm);
897 rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
898 } else {
899 rc = pm8xxx_pwm_write(pwm);
900 }
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700901
902 if (rc)
903 pr_err("[%d]: pm8xxx_pwm_write: rc=%d\n", pwm->pwm_id, rc);
904
905out_unlock:
906 mutex_unlock(&pwm->chip->pwm_mutex);
907 return rc;
908}
909EXPORT_SYMBOL_GPL(pm8xxx_pwm_config_pwm_value);
910
911/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 * pm8xxx_pwm_lut_config - change a PWM device configuration to use LUT
913 * @pwm: the PWM device
914 * @period_us: period in microseconds
915 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
916 * @duty_time_ms: time for each duty cycle in milliseconds
917 * @start_idx: start index in lookup table from 0 to MAX-1
918 * @idx_len: number of index
919 * @pause_lo: pause time in milliseconds at low index
920 * @pause_hi: pause time in milliseconds at high index
921 * @flags: control flags
922 */
923int pm8xxx_pwm_lut_config(struct pwm_device *pwm, int period_us,
924 int duty_pct[], int duty_time_ms, int start_idx,
925 int idx_len, int pause_lo, int pause_hi, int flags)
926{
Willie Ruan719c6762011-08-25 11:03:14 -0700927 struct pm8xxx_pwm_lut lut;
928 struct pm8xxx_pwm_period *period;
Willie Ruan8de2f382011-08-25 11:04:50 -0700929 int len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 int rc;
931
932 if (pwm == NULL || IS_ERR(pwm) || !idx_len) {
933 pr_err("Invalid pwm handle or idx_len=0\n");
934 return -EINVAL;
935 }
936 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE)) {
937 pr_err("Invalid duty_pct with flag\n");
938 return -EINVAL;
939 }
940 if (pwm->chip == NULL) {
941 pr_err("No pwm_chip\n");
942 return -ENODEV;
943 }
Jay Chokshi57656862011-09-07 12:02:22 -0700944
945 if (pwm->chip->is_lpg_supported == 0) {
946 pr_err("LPG module isn't supported\n");
947 return -EINVAL;
948 }
949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950 if (idx_len >= PM_PWM_LUT_SIZE && start_idx) {
951 pr_err("Wrong LUT size or index\n");
952 return -EINVAL;
953 }
954 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE) {
955 pr_err("Exceed LUT limit\n");
956 return -EINVAL;
957 }
958 if ((unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
959 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
960 pr_err("Period out of range\n");
961 return -EINVAL;
962 }
963
Willie Ruan719c6762011-08-25 11:03:14 -0700964 period = &pwm->period;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 mutex_lock(&pwm->chip->pwm_mutex);
966
967 if (!pwm->in_use) {
968 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
969 rc = -EINVAL;
970 goto out_unlock;
971 }
972
Willie Ruan8de2f382011-08-25 11:04:50 -0700973 if (pwm->pwm_period != period_us) {
974 pm8xxx_pwm_calc_period(period_us, period);
975 pm8xxx_pwm_save_period(pwm);
976 pwm->pwm_period = period_us;
977 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978
979 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
980
981 if (flags & PM_PWM_LUT_NO_TABLE)
982 goto after_table_write;
983
Willie Ruan8de2f382011-08-25 11:04:50 -0700984 rc = pm8xxx_pwm_change_table(pwm, duty_pct, start_idx, len, 0);
985 if (rc) {
986 pr_err("pm8xxx_pwm_change_table: rc=%d\n", rc);
987 goto out_unlock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 }
989
990after_table_write:
Willie Ruan719c6762011-08-25 11:03:14 -0700991 lut.lut_duty_ms = duty_time_ms;
992 lut.lut_lo_index = start_idx;
993 lut.lut_hi_index = start_idx + len - 1;
994 lut.lut_pause_lo = pause_lo;
995 lut.lut_pause_hi = pause_hi;
996 lut.flags = flags;
997 pwm->bypass_lut = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998
Willie Ruan8de2f382011-08-25 11:04:50 -0700999 rc = pm8xxx_pwm_change_lut(pwm, &lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000
1001out_unlock:
1002 mutex_unlock(&pwm->chip->pwm_mutex);
1003 return rc;
1004}
1005EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_config);
1006
1007/**
1008 * pm8xxx_pwm_lut_enable - control a PWM device to start/stop LUT ramp
1009 * @pwm: the PWM device
1010 * @start: to start (1), or stop (0)
1011 */
1012int pm8xxx_pwm_lut_enable(struct pwm_device *pwm, int start)
1013{
1014 if (pwm == NULL || IS_ERR(pwm)) {
1015 pr_err("Invalid pwm handle\n");
1016 return -EINVAL;
1017 }
1018 if (pwm->chip == NULL) {
1019 pr_err("No pwm_chip\n");
1020 return -ENODEV;
1021 }
Jay Chokshi57656862011-09-07 12:02:22 -07001022 if (pwm->chip->is_lpg_supported == 0) {
1023 pr_err("LPG module isn't supported\n");
1024 return -EINVAL;
1025 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026
1027 mutex_lock(&pwm->chip->pwm_mutex);
1028 if (start) {
1029 pm8xxx_pwm_bank_enable(pwm, 1);
1030
1031 pm8xxx_pwm_bank_sel(pwm);
1032 pm8xxx_pwm_start(pwm, 1, 1);
1033 } else {
1034 pm8xxx_pwm_bank_sel(pwm);
1035 pm8xxx_pwm_start(pwm, 0, 0);
1036
1037 pm8xxx_pwm_bank_enable(pwm, 0);
1038 }
1039 mutex_unlock(&pwm->chip->pwm_mutex);
1040 return 0;
1041}
1042EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_enable);
1043
1044#if defined(CONFIG_DEBUG_FS)
1045
1046struct pm8xxx_pwm_dbg_device;
1047
1048struct pm8xxx_pwm_user {
1049 int pwm_id;
1050 struct pwm_device *pwm;
1051 int period;
1052 int duty_cycle;
1053 int enable;
1054 struct pm8xxx_pwm_dbg_device *dbgdev;
1055};
1056
1057struct pm8xxx_pwm_dbg_device {
1058 struct mutex dbg_mutex;
1059 struct device *dev;
1060 struct dentry *dent;
1061
Jay Chokshi57656862011-09-07 12:02:22 -07001062 struct pm8xxx_pwm_user *user;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063};
1064
1065static struct pm8xxx_pwm_dbg_device *pmic_dbg_device;
1066
1067static int dbg_pwm_check_period(int period)
1068{
1069 if (period < PM8XXX_PWM_PERIOD_MIN || period > PM8XXX_PWM_PERIOD_MAX) {
1070 pr_err("period is invalid: %d\n", period);
1071 return -EINVAL;
1072 }
1073 return 0;
1074}
1075
1076static int dbg_pwm_check_duty_cycle(int duty_cycle, const char *func_name)
1077{
1078 if (duty_cycle <= 0 || duty_cycle > 100) {
1079 pr_err("%s: duty_cycle is invalid: %d\n",
1080 func_name, duty_cycle);
1081 return -EINVAL;
1082 }
1083 return 0;
1084}
1085
1086static void dbg_pwm_check_handle(struct pm8xxx_pwm_user *puser)
1087{
1088 struct pwm_device *tmp;
1089
1090 if (puser->pwm == NULL) {
1091 tmp = pwm_request(puser->pwm_id, "pwm-dbg");
1092 if (PTR_ERR(puser->pwm)) {
1093 pr_err("pwm_request: err=%ld\n", PTR_ERR(puser->pwm));
1094 puser->pwm = NULL;
Willie Ruan10976ea2011-08-25 11:01:15 -07001095 } else {
1096 pr_debug("[id=%d] pwm_request ok\n", puser->pwm_id);
1097 puser->pwm = tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 }
1099 }
1100}
1101
1102static int dbg_pwm_enable_set(void *data, u64 val)
1103{
1104 struct pm8xxx_pwm_user *puser = data;
1105 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1106 int rc;
1107
1108 mutex_lock(&dbgdev->dbg_mutex);
1109 rc = dbg_pwm_check_duty_cycle(puser->duty_cycle, __func__);
1110 if (!rc) {
1111 puser->enable = val;
1112 dbg_pwm_check_handle(puser);
1113 if (puser->pwm) {
1114 if (puser->enable)
1115 pwm_enable(puser->pwm);
1116 else
1117 pwm_disable(puser->pwm);
1118 }
1119 }
1120 mutex_unlock(&dbgdev->dbg_mutex);
1121 return 0;
1122}
1123
1124static int dbg_pwm_enable_get(void *data, u64 *val)
1125{
1126 struct pm8xxx_pwm_user *puser = data;
1127 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1128
1129 mutex_lock(&dbgdev->dbg_mutex);
1130 *val = puser->enable;
1131 mutex_unlock(&dbgdev->dbg_mutex);
1132 return 0;
1133}
1134
1135DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_enable_fops,
1136 dbg_pwm_enable_get, dbg_pwm_enable_set,
1137 "%lld\n");
1138
1139static int dbg_pwm_duty_cycle_set(void *data, u64 val)
1140{
1141 struct pm8xxx_pwm_user *puser = data;
1142 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1143 int rc;
1144
1145 mutex_lock(&dbgdev->dbg_mutex);
1146 rc = dbg_pwm_check_duty_cycle(val, __func__);
1147 if (!rc) {
1148 puser->duty_cycle = val;
1149 dbg_pwm_check_handle(puser);
1150 if (puser->pwm) {
1151 int duty_us;
1152
Willie Ruan10976ea2011-08-25 11:01:15 -07001153 duty_us = puser->duty_cycle * puser->period / 100;
1154 pwm_config(puser->pwm, duty_us, puser->period);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 }
1156 }
1157 mutex_unlock(&dbgdev->dbg_mutex);
1158 return 0;
1159}
1160
1161static int dbg_pwm_duty_cycle_get(void *data, u64 *val)
1162{
1163 struct pm8xxx_pwm_user *puser = data;
1164 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1165
1166 mutex_lock(&dbgdev->dbg_mutex);
1167 *val = puser->duty_cycle;
1168 mutex_unlock(&dbgdev->dbg_mutex);
1169 return 0;
1170}
1171
1172DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_duty_cycle_fops,
1173 dbg_pwm_duty_cycle_get, dbg_pwm_duty_cycle_set,
1174 "%lld\n");
1175
1176static int dbg_pwm_period_set(void *data, u64 val)
1177{
1178 struct pm8xxx_pwm_user *puser = data;
1179 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1180 int rc;
1181
1182 mutex_lock(&dbgdev->dbg_mutex);
1183 rc = dbg_pwm_check_period(val);
1184 if (!rc)
1185 puser->period = val;
1186 mutex_unlock(&dbgdev->dbg_mutex);
1187 return 0;
1188}
1189
1190static int dbg_pwm_period_get(void *data, u64 *val)
1191{
1192 struct pm8xxx_pwm_user *puser = data;
1193 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1194
1195 mutex_lock(&dbgdev->dbg_mutex);
1196 *val = puser->period;
1197 mutex_unlock(&dbgdev->dbg_mutex);
1198 return 0;
1199}
1200
1201DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_period_fops,
1202 dbg_pwm_period_get, dbg_pwm_period_set, "%lld\n");
1203
1204static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1205{
1206 struct pm8xxx_pwm_dbg_device *dbgdev;
1207 struct dentry *dent;
1208 struct dentry *temp;
1209 struct pm8xxx_pwm_user *puser;
1210 int i;
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001211 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212
1213 if (dev == NULL) {
1214 pr_err("no parent data passed in.\n");
1215 return -EINVAL;
1216 }
1217
1218 dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
1219 if (dbgdev == NULL) {
1220 pr_err("kzalloc() failed.\n");
1221 return -ENOMEM;
1222 }
1223
Jay Chokshi57656862011-09-07 12:02:22 -07001224 dbgdev->user = kcalloc(pwm_chip->pwm_channels,
1225 sizeof(struct pm8xxx_pwm_user), GFP_KERNEL);
1226 if (dbgdev->user == NULL) {
1227 pr_err("kcalloc() failed.\n");
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001228 rc = -ENOMEM;
1229 goto user_error;
Jay Chokshi57656862011-09-07 12:02:22 -07001230 }
1231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 mutex_init(&dbgdev->dbg_mutex);
1233
1234 dbgdev->dev = dev;
1235
1236 dent = debugfs_create_dir("pm8xxx-pwm-dbg", NULL);
1237 if (dent == NULL || IS_ERR(dent)) {
1238 pr_err("ERR debugfs_create_dir: dent=%p\n", dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001239 rc = -ENOMEM;
1240 goto dir_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 }
1242
1243 dbgdev->dent = dent;
1244
Jay Chokshi57656862011-09-07 12:02:22 -07001245 for (i = 0; i < pwm_chip->pwm_channels; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 char pwm_ch[] = "0";
1247
1248 pwm_ch[0] = '0' + i;
1249 dent = debugfs_create_dir(pwm_ch, dbgdev->dent);
1250 if (dent == NULL || IS_ERR(dent)) {
1251 pr_err("ERR: pwm=%d: dir: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001252 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253 goto debug_error;
1254 }
1255
1256 puser = &dbgdev->user[i];
1257 puser->dbgdev = dbgdev;
1258 puser->pwm_id = i;
1259 temp = debugfs_create_file("period", S_IRUGO | S_IWUSR,
1260 dent, puser, &dbg_pwm_period_fops);
1261 if (temp == NULL || IS_ERR(temp)) {
1262 pr_err("ERR: pwm=%d: period: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001263 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 goto debug_error;
1265 }
1266
1267 temp = debugfs_create_file("duty-cycle", S_IRUGO | S_IWUSR,
1268 dent, puser, &dbg_pwm_duty_cycle_fops);
1269 if (temp == NULL || IS_ERR(temp)) {
1270 pr_err("ERR: pwm=%d: duty-cycle: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001271 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 goto debug_error;
1273 }
1274
1275 temp = debugfs_create_file("enable", S_IRUGO | S_IWUSR,
1276 dent, puser, &dbg_pwm_enable_fops);
1277 if (temp == NULL || IS_ERR(temp)) {
1278 pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001279 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280 goto debug_error;
1281 }
1282 }
1283
1284 pmic_dbg_device = dbgdev;
1285
1286 return 0;
1287
1288debug_error:
1289 debugfs_remove_recursive(dbgdev->dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001290dir_error:
1291 kfree(dbgdev->user);
1292user_error:
1293 kfree(dbgdev);
1294 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295}
1296
1297static int __devexit pm8xxx_pwm_dbg_remove(void)
1298{
1299 if (pmic_dbg_device) {
Jay Chokshi57656862011-09-07 12:02:22 -07001300 kfree(pmic_dbg_device->user);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 debugfs_remove_recursive(pmic_dbg_device->dent);
1302 kfree(pmic_dbg_device);
1303 }
1304 return 0;
1305}
1306
1307#else
1308
1309static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1310{
1311 return 0;
1312}
1313
1314static int __devexit pm8xxx_pwm_dbg_remove(void)
1315{
1316 return 0;
1317}
1318
1319#endif
1320
1321static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
1322{
1323 struct pm8xxx_pwm_chip *chip;
1324 int i;
Jay Chokshi57656862011-09-07 12:02:22 -07001325 enum pm8xxx_version version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326
1327 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1328 if (chip == NULL) {
1329 pr_err("kzalloc() failed.\n");
1330 return -ENOMEM;
1331 }
1332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 mutex_init(&chip->pwm_mutex);
1334
1335 chip->dev = &pdev->dev;
1336 pwm_chip = chip;
Jay Chokshi57656862011-09-07 12:02:22 -07001337
1338 version = pm8xxx_get_version(chip->dev->parent);
1339
1340 if (version == PM8XXX_VERSION_8921 ||
David Collins999480d2011-11-16 08:52:30 -08001341 version == PM8XXX_VERSION_8058 ||
1342 version == PM8XXX_VERSION_8922) {
Jay Chokshi57656862011-09-07 12:02:22 -07001343 chip->is_lpg_supported = 1;
1344 }
1345 if (chip->is_lpg_supported) {
1346 chip->pwm_channels = PM8XXX_LPG_PWM_CHANNELS;
1347 chip->pwm_total_pre_divs = NUM_LPG_PRE_DIVIDE;
1348 } else {
1349 chip->pwm_channels = PM8XXX_PWM_CHANNELS;
1350 chip->pwm_total_pre_divs = NUM_PWM_PRE_DIVIDE;
1351 }
1352
1353 chip->pwm_dev = kcalloc(chip->pwm_channels, sizeof(struct pwm_device),
1354 GFP_KERNEL);
1355 if (chip->pwm_dev == NULL) {
1356 pr_err("kcalloc() failed.\n");
1357 mutex_destroy(&chip->pwm_mutex);
1358 kfree(chip);
1359 return -ENOMEM;
1360 }
1361
1362 for (i = 0; i < chip->pwm_channels; i++) {
1363 chip->pwm_dev[i].pwm_id = i;
1364 chip->pwm_dev[i].chip = chip;
1365 }
1366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 platform_set_drvdata(pdev, chip);
1368
1369 if (pm8xxx_pwm_dbg_probe(&pdev->dev) < 0)
1370 pr_err("could not set up debugfs\n");
1371
1372 pr_notice("OK\n");
1373 return 0;
1374}
1375
1376static int __devexit pm8xxx_pwm_remove(struct platform_device *pdev)
1377{
1378 struct pm8xxx_pwm_chip *chip = dev_get_drvdata(pdev->dev.parent);
1379
1380 pm8xxx_pwm_dbg_remove();
Jay Chokshi57656862011-09-07 12:02:22 -07001381 kfree(chip->pwm_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 mutex_destroy(&chip->pwm_mutex);
1383 platform_set_drvdata(pdev, NULL);
1384 kfree(chip);
1385 return 0;
1386}
1387
1388static struct platform_driver pm8xxx_pwm_driver = {
1389 .probe = pm8xxx_pwm_probe,
1390 .remove = __devexit_p(pm8xxx_pwm_remove),
1391 .driver = {
1392 .name = PM8XXX_PWM_DEV_NAME,
1393 .owner = THIS_MODULE,
1394 },
1395};
1396
1397static int __init pm8xxx_pwm_init(void)
1398{
1399 return platform_driver_register(&pm8xxx_pwm_driver);
1400}
1401
1402static void __exit pm8xxx_pwm_exit(void)
1403{
1404 platform_driver_unregister(&pm8xxx_pwm_driver);
1405}
1406
1407subsys_initcall(pm8xxx_pwm_init);
1408module_exit(pm8xxx_pwm_exit);
1409
1410MODULE_LICENSE("GPL v2");
1411MODULE_DESCRIPTION("PM8XXX PWM driver");
1412MODULE_VERSION("1.0");
1413MODULE_ALIAS("platform:" PM8XXX_PWM_DEV_NAME);