blob: 523d3b6faaba769583eda7995c9e0e0e13452bd7 [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
Jay Chokshi57656862011-09-07 12:02:22 -0700155#define NUM_LPG_PRE_DIVIDE 3 /* No default support for pre-divide = 6 */
156#define NUM_PWM_PRE_DIVIDE 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157
158#define PRE_DIVIDE_0 2
159#define PRE_DIVIDE_1 3
160#define PRE_DIVIDE_2 5
161
162#define PRE_DIVIDE_MIN PRE_DIVIDE_0
163#define PRE_DIVIDE_MAX PRE_DIVIDE_2
164
Jay Chokshi57656862011-09-07 12:02:22 -0700165static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
Willie Ruandb78e942012-01-10 15:00:28 -0800166 { PRE_DIVIDE_0 * NSEC_1024HZ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167 PRE_DIVIDE_0 * NSEC_32768HZ,
168 PRE_DIVIDE_0 * NSEC_19P2MHZ,
169 },
Willie Ruandb78e942012-01-10 15:00:28 -0800170 { PRE_DIVIDE_1 * NSEC_1024HZ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 PRE_DIVIDE_1 * NSEC_32768HZ,
172 PRE_DIVIDE_1 * NSEC_19P2MHZ,
173 },
Willie Ruandb78e942012-01-10 15:00:28 -0800174 { PRE_DIVIDE_2 * NSEC_1024HZ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175 PRE_DIVIDE_2 * NSEC_32768HZ,
176 PRE_DIVIDE_2 * NSEC_19P2MHZ,
177 },
178};
179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180/* Private data */
181struct pm8xxx_pwm_chip;
182
183struct pwm_device {
184 int pwm_id; /* = bank/channel id */
185 int in_use;
186 const char *label;
Willie Ruan719c6762011-08-25 11:03:14 -0700187 struct pm8xxx_pwm_period period;
188 int pwm_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189 int pwm_period;
190 int pwm_duty;
Jay Chokshi57656862011-09-07 12:02:22 -0700191 u8 pwm_lpg_ctl[PM8XXX_LPG_CTL_REGS];
192 u8 pwm_ctl1;
193 u8 pwm_ctl2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 int irq;
195 struct pm8xxx_pwm_chip *chip;
Willie Ruan719c6762011-08-25 11:03:14 -0700196 int bypass_lut;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197};
198
199struct pm8xxx_pwm_chip {
Jay Chokshi57656862011-09-07 12:02:22 -0700200 struct pwm_device *pwm_dev;
201 u8 pwm_channels;
202 u8 pwm_total_pre_divs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 u8 bank_mask;
204 struct mutex pwm_mutex;
205 struct device *dev;
Jay Chokshi57656862011-09-07 12:02:22 -0700206 bool is_lpg_supported;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207};
208
209static struct pm8xxx_pwm_chip *pwm_chip;
210
Willie Ruan719c6762011-08-25 11:03:14 -0700211struct pm8xxx_pwm_lut {
212 /* LUT parameters */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 int lut_duty_ms;
214 int lut_lo_index;
215 int lut_hi_index;
216 int lut_pause_hi;
217 int lut_pause_lo;
218 int flags;
219};
220
221static const u16 duty_msec[PM8XXX_PWM_1KHZ_COUNT_MAX + 1] = {
222 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
223};
224
225static const u16 pause_count[PM8XXX_PWM_PAUSE_COUNT_MAX + 1] = {
226 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
227 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
228 375, 500, 667, 750, 800, 900, 1000, 1100,
229 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
230 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
231 7000
232};
233
234/* Internal functions */
Willie Ruan8de2f382011-08-25 11:04:50 -0700235static void pm8xxx_pwm_save(u8 *u8p, u8 mask, u8 val)
236{
237 *u8p &= ~mask;
238 *u8p |= val & mask;
239}
240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241static int pm8xxx_pwm_bank_enable(struct pwm_device *pwm, int enable)
242{
243 int rc;
244 u8 reg;
245 struct pm8xxx_pwm_chip *chip;
246
247 chip = pwm->chip;
248
249 if (enable)
250 reg = chip->bank_mask | (1 << pwm->pwm_id);
251 else
252 reg = chip->bank_mask & ~(1 << pwm->pwm_id);
253
254 rc = pm8xxx_writeb(chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
255 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700256 pr_err("pm8xxx_writeb(): rc=%d (Enable LPG Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257 return rc;
258 }
259 chip->bank_mask = reg;
260
261 return 0;
262}
263
264static int pm8xxx_pwm_bank_sel(struct pwm_device *pwm)
265{
266 int rc;
267
268 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_SEL,
269 pwm->pwm_id);
270 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700271 pr_err("pm8xxx_writeb(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 return rc;
273}
274
275static int pm8xxx_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
276{
277 int rc;
278 u8 reg;
279
280 if (start) {
Jay Chokshi57656862011-09-07 12:02:22 -0700281 reg = pwm->pwm_lpg_ctl[0] | PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 if (ramp_start)
283 reg |= PM8XXX_PWM_RAMP_GEN_START;
284 else
285 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
286 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700287 reg = pwm->pwm_lpg_ctl[0] & ~PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
289 }
290
291 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
292 reg);
293 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700294 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 else
Jay Chokshi57656862011-09-07 12:02:22 -0700296 pwm->pwm_lpg_ctl[0] = reg;
297 return rc;
298}
299
300static int pm8xxx_pwm_disable(struct pwm_device *pwm)
301{
302 int rc;
303 u8 reg;
304
305 reg = pwm->pwm_ctl1 & PM8XXX_PWM_DISABLE;
306
307 rc = pm8xxx_writeb(pwm->chip->dev->parent,
308 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), reg);
309
310 if (rc)
311 pr_err("pm8xxx_writeb(): rc=%d (Disable PWM Ctl %d)\n", rc,
312 pwm->pwm_id);
313 return rc;
314}
315
316static int pm8xxx_pwm_enable(struct pwm_device *pwm)
317{
318 /**
319 * A kind of best Effort: Just write the clock information that
320 * we have in the register.
321 */
322 int rc;
323
324 rc = pm8xxx_writeb(pwm->chip->dev->parent,
325 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), pwm->pwm_ctl1);
326
327 if (rc)
328 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl %d)\n", rc,
329 pwm->pwm_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 return rc;
331}
332
333static void pm8xxx_pwm_calc_period(unsigned int period_us,
Willie Ruan719c6762011-08-25 11:03:14 -0700334 struct pm8xxx_pwm_period *period)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335{
336 int n, m, clk, div;
337 int best_m, best_div, best_clk;
Willie Ruan4a0a7002012-01-10 15:39:44 -0800338 unsigned int last_err, cur_err, min_err;
339 unsigned int tmp_p, period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340
341 /* PWM Period / N */
Willie Ruan70f989d2012-01-10 10:09:36 -0800342 if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 period_n = (period_us * NSEC_PER_USEC) >> 6;
344 n = 6;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 } else {
346 period_n = (period_us >> 9) * NSEC_PER_USEC;
347 n = 9;
348 }
349
Willie Ruan4a0a7002012-01-10 15:39:44 -0800350 min_err = last_err = (unsigned)(-1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 best_m = 0;
352 best_clk = 0;
353 best_div = 0;
354 for (clk = 0; clk < NUM_CLOCKS; clk++) {
Jay Chokshi57656862011-09-07 12:02:22 -0700355 for (div = 0; div < pwm_chip->pwm_total_pre_divs; div++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800356 /* period_n = (PWM Period / N) */
357 /* tmp_p = (Pre-divide * Clock Period) * 2^m */
358 tmp_p = pt_t[div][clk];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700359 for (m = 0; m <= PM8XXX_PWM_M_MAX; m++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800360 if (period_n > tmp_p)
361 cur_err = period_n - tmp_p;
362 else
363 cur_err = tmp_p - period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364
Willie Ruan4a0a7002012-01-10 15:39:44 -0800365 if (cur_err < min_err) {
366 min_err = cur_err;
367 best_m = m;
368 best_clk = clk;
369 best_div = div;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 }
Willie Ruan4a0a7002012-01-10 15:39:44 -0800371
372 if (m && cur_err > last_err)
373 /* Break for bigger cur_err */
374 break;
375
376 last_err = cur_err;
377 tmp_p <<= 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 }
379 }
380 }
381
Willie Ruan75d9e5b2011-08-25 10:59:17 -0700382 /* Use higher resolution */
383 if (best_m >= 3 && n == 6) {
384 n += 3;
385 best_m -= 3;
386 }
387
Willie Ruan719c6762011-08-25 11:03:14 -0700388 period->pwm_size = n;
389 period->clk = best_clk;
390 period->pre_div = best_div;
391 period->pre_div_exp = best_m;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392}
393
Willie Ruan8de2f382011-08-25 11:04:50 -0700394static void pm8xxx_pwm_calc_pwm_value(struct pwm_device *pwm,
395 unsigned int period_us,
396 unsigned int duty_us)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397{
Willie Ruan8de2f382011-08-25 11:04:50 -0700398 unsigned int max_pwm_value, tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399
Willie Ruan8de2f382011-08-25 11:04:50 -0700400 /* Figure out pwm_value with overflow handling */
401 tmp = 1 << (sizeof(tmp) * 8 - pwm->period.pwm_size);
402 if (duty_us < tmp) {
403 tmp = duty_us << pwm->period.pwm_size;
404 pwm->pwm_value = tmp / period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 } else {
Willie Ruan8de2f382011-08-25 11:04:50 -0700406 tmp = period_us >> pwm->period.pwm_size;
407 pwm->pwm_value = duty_us / tmp;
408 }
409 max_pwm_value = (1 << pwm->period.pwm_size) - 1;
410 if (pwm->pwm_value > max_pwm_value)
411 pwm->pwm_value = max_pwm_value;
412}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413
Willie Ruan8de2f382011-08-25 11:04:50 -0700414static int pm8xxx_pwm_change_table(struct pwm_device *pwm, int duty_pct[],
415 int start_idx, int len, int raw_value)
416{
417 unsigned int pwm_value, max_pwm_value;
418 u8 cfg0, cfg1;
419 int i, pwm_size;
420 int rc = 0;
421
Jay Chokshi57656862011-09-07 12:02:22 -0700422 pwm_size = (pwm->pwm_lpg_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
Willie Ruan8de2f382011-08-25 11:04:50 -0700423 max_pwm_value = (1 << pwm_size) - 1;
424 for (i = 0; i < len; i++) {
425 if (raw_value)
426 pwm_value = duty_pct[i];
427 else
428 pwm_value = (duty_pct[i] << pwm_size) / 100;
429
430 if (pwm_value > max_pwm_value)
431 pwm_value = max_pwm_value;
432 cfg0 = pwm_value;
433 cfg1 = (pwm_value >> 1) & 0x80;
434 cfg1 |= start_idx + i;
435
436 rc = pm8xxx_writeb(pwm->chip->dev->parent,
437 SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
438 if (rc)
439 break;
440
441 rc = pm8xxx_writeb(pwm->chip->dev->parent,
442 SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
443 if (rc)
444 break;
445 }
446 return rc;
447}
448
449static void pm8xxx_pwm_save_index(struct pwm_device *pwm,
450 int low_idx, int high_idx, int flags)
451{
Jay Chokshi57656862011-09-07 12:02:22 -0700452 pwm->pwm_lpg_ctl[1] = high_idx & PM8XXX_PWM_HIGH_INDEX_MASK;
453 pwm->pwm_lpg_ctl[2] = low_idx & PM8XXX_PWM_LOW_INDEX_MASK;
Willie Ruan8de2f382011-08-25 11:04:50 -0700454
455 if (flags & PM_PWM_LUT_REVERSE)
Jay Chokshi57656862011-09-07 12:02:22 -0700456 pwm->pwm_lpg_ctl[1] |= PM8XXX_PWM_REVERSE_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700457 if (flags & PM_PWM_LUT_RAMP_UP)
Jay Chokshi57656862011-09-07 12:02:22 -0700458 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_RAMP_UP;
Willie Ruan8de2f382011-08-25 11:04:50 -0700459 if (flags & PM_PWM_LUT_LOOP)
Jay Chokshi57656862011-09-07 12:02:22 -0700460 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_LOOP_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700461}
462
463static void pm8xxx_pwm_save_period(struct pwm_device *pwm)
464{
465 u8 mask, val;
466
Jay Chokshi57656862011-09-07 12:02:22 -0700467 if (pwm_chip->is_lpg_supported) {
468 val = ((pwm->period.clk + 1) << PM8XXX_LPG_PWM_CLK_SEL_SHIFT)
469 & PM8XXX_LPG_PWM_CLK_SEL_MASK;
470 val |= (pwm->period.pre_div << PM8XXX_LPG_PWM_PREDIVIDE_SHIFT)
471 & PM8XXX_LPG_PWM_PREDIVIDE_MASK;
472 val |= pwm->period.pre_div_exp & PM8XXX_LPG_PWM_M_MASK;
473 mask = PM8XXX_LPG_PWM_CLK_SEL_MASK |
474 PM8XXX_LPG_PWM_PREDIVIDE_MASK | PM8XXX_LPG_PWM_M_MASK;
475 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700476
Jay Chokshi57656862011-09-07 12:02:22 -0700477 val = (pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0;
478 mask = PM8XXX_PWM_SIZE_9_BIT;
479 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
480 } else {
481 val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
482 & PM8XXX_PWM_CLK_SEL_MASK;
483 val |= (pwm->period.pre_div << PM8XXX_PWM_PREDIVIDE_SHIFT)
484 & PM8XXX_PWM_PREDIVIDE_MASK;
485 val |= (pwm->period.pre_div_exp << PM8XXX_PWM_M_SHIFT)
486 & PM8XXX_PWM_M_MASK;
487 val |= (((pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0)
488 << PM8XXX_PWM_SIZE_SHIFT) & PM8XXX_PWM_SIZE_MASK;
489
490 mask = PM8XXX_PWM_CLK_SEL_MASK | PM8XXX_PWM_PREDIVIDE_MASK |
491 PM8XXX_PWM_M_MASK | PM8XXX_PWM_SIZE_MASK;
492 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
493 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700494}
495
496static void pm8xxx_pwm_save_pwm_value(struct pwm_device *pwm)
497{
498 u8 mask, val;
499
Jay Chokshi57656862011-09-07 12:02:22 -0700500 if (pwm_chip->is_lpg_supported) {
501 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 1) : 0;
502 pwm->pwm_lpg_ctl[3] = pwm->pwm_value;
503 mask = PM8XXX_PWM_VALUE_BIT8;
504 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
505 } else {
506 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 8) : 0;
507 pwm->pwm_ctl2 = pwm->pwm_value;
508 mask = PM8XXX_PWM_VALUE_BIT0;
509 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
510 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700511}
512
513static void pm8xxx_pwm_save_duty_time(struct pwm_device *pwm,
514 struct pm8xxx_pwm_lut *lut)
515{
516 int i;
517 u8 mask, val;
518
519 /* Linear search for duty time */
520 for (i = 0; i < PM8XXX_PWM_1KHZ_COUNT_MAX; i++) {
521 if (duty_msec[i] >= lut->lut_duty_ms)
522 break;
523 }
524 val = i << PM8XXX_PWM_1KHZ_COUNT_SHIFT;
525
526 mask = PM8XXX_PWM_1KHZ_COUNT_MASK;
Jay Chokshi57656862011-09-07 12:02:22 -0700527 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[0], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700528}
529
530static void pm8xxx_pwm_save_pause(struct pwm_device *pwm,
531 struct pm8xxx_pwm_lut *lut)
532{
533 int i, pause_cnt, time_cnt;
534 u8 mask, val;
535
Jay Chokshi57656862011-09-07 12:02:22 -0700536 time_cnt = (pwm->pwm_lpg_ctl[0] & PM8XXX_PWM_1KHZ_COUNT_MASK)
Willie Ruan8de2f382011-08-25 11:04:50 -0700537 >> PM8XXX_PWM_1KHZ_COUNT_SHIFT;
538 if (lut->flags & PM_PWM_LUT_PAUSE_HI_EN) {
539 pause_cnt = (lut->lut_pause_hi + duty_msec[time_cnt] / 2)
540 / duty_msec[time_cnt];
541 /* Linear search for pause time */
542 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
543 if (pause_count[i] >= pause_cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544 break;
545 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700546 val = (i << PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT) &
547 PM8XXX_PWM_PAUSE_COUNT_HI_MASK;
548 val |= PM8XXX_PWM_PAUSE_ENABLE_HIGH;
549 } else {
550 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 }
552
Willie Ruan8de2f382011-08-25 11:04:50 -0700553 mask = PM8XXX_PWM_PAUSE_COUNT_HI_MASK | PM8XXX_PWM_PAUSE_ENABLE_HIGH;
Jay Chokshi57656862011-09-07 12:02:22 -0700554 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555
Willie Ruan8de2f382011-08-25 11:04:50 -0700556 if (lut->flags & PM_PWM_LUT_PAUSE_LO_EN) {
557 /* Linear search for pause time */
558 pause_cnt = (lut->lut_pause_lo + duty_msec[time_cnt] / 2)
559 / duty_msec[time_cnt];
560 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
561 if (pause_count[i] >= pause_cnt)
562 break;
563 }
564 val = (i << PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT) &
565 PM8XXX_PWM_PAUSE_COUNT_LO_MASK;
566 val |= PM8XXX_PWM_PAUSE_ENABLE_LOW;
567 } else {
568 val = 0;
569 }
570
571 mask = PM8XXX_PWM_PAUSE_COUNT_LO_MASK | PM8XXX_PWM_PAUSE_ENABLE_LOW;
Jay Chokshi57656862011-09-07 12:02:22 -0700572 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[6], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700573}
574
Jay Chokshi57656862011-09-07 12:02:22 -0700575static int pm8xxx_pwm_write(struct pwm_device *pwm)
576{
577 int rc = 0;
578
579 rc = pm8xxx_writeb(pwm->chip->dev->parent,
580 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id),
581 pwm->pwm_ctl1);
582 if (rc) {
583 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl1[%d])\n",
584 rc, pwm->pwm_id);
585 return rc;
586 }
587
588 rc = pm8xxx_writeb(pwm->chip->dev->parent,
589 SSBI_REG_ADDR_PWM_CTL2(pwm->pwm_id),
590 pwm->pwm_ctl2);
591 if (rc) {
592 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl2[%d])\n",
593 rc, pwm->pwm_id);
594 return rc;
595 }
596
597 return rc;
598}
599
600static int pm8xxx_lpg_pwm_write(struct pwm_device *pwm, int start, int end)
Willie Ruan8de2f382011-08-25 11:04:50 -0700601{
602 int i, rc;
603
604 /* Write in reverse way so 0 would be the last */
605 for (i = end - 1; i >= start; i--) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 rc = pm8xxx_writeb(pwm->chip->dev->parent,
607 SSBI_REG_ADDR_LPG_CTL(i),
Jay Chokshi57656862011-09-07 12:02:22 -0700608 pwm->pwm_lpg_ctl[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700610 pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[%d])\n", rc, i);
611 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 }
613 }
614
Willie Ruan8de2f382011-08-25 11:04:50 -0700615 return 0;
616}
617
618static int pm8xxx_pwm_change_lut(struct pwm_device *pwm,
619 struct pm8xxx_pwm_lut *lut)
620{
621 int rc;
622
623 pm8xxx_pwm_save_index(pwm, lut->lut_lo_index,
624 lut->lut_hi_index, lut->flags);
625 pm8xxx_pwm_save_duty_time(pwm, lut);
626 pm8xxx_pwm_save_pause(pwm, lut);
Jay Chokshi57656862011-09-07 12:02:22 -0700627 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1], PM8XXX_PWM_BYPASS_LUT, 0);
Willie Ruan8de2f382011-08-25 11:04:50 -0700628
629 pm8xxx_pwm_bank_sel(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700630 rc = pm8xxx_lpg_pwm_write(pwm, 0, 7);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700631
632 return rc;
633}
634
635/* APIs */
636/**
637 * pwm_request - request a PWM device
638 * @pwm_id: PWM id or channel
639 * @label: the label to identify the user
640 */
641struct pwm_device *pwm_request(int pwm_id, const char *label)
642{
643 struct pwm_device *pwm;
644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 if (pwm_chip == NULL) {
646 pr_err("No pwm_chip\n");
647 return ERR_PTR(-ENODEV);
648 }
649
Jay Chokshi57656862011-09-07 12:02:22 -0700650 if (pwm_id >= pwm_chip->pwm_channels || pwm_id < 0) {
651 pr_err("Invalid pwm_id: %d with %s\n",
652 pwm_id, label ? label : ".");
653 return ERR_PTR(-EINVAL);
654 }
655
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656 mutex_lock(&pwm_chip->pwm_mutex);
657 pwm = &pwm_chip->pwm_dev[pwm_id];
658 if (!pwm->in_use) {
659 pwm->in_use = 1;
660 pwm->label = label;
661 } else {
662 pwm = ERR_PTR(-EBUSY);
663 }
664 mutex_unlock(&pwm_chip->pwm_mutex);
665
666 return pwm;
667}
668EXPORT_SYMBOL_GPL(pwm_request);
669
670/**
671 * pwm_free - free a PWM device
672 * @pwm: the PWM device
673 */
674void pwm_free(struct pwm_device *pwm)
675{
676 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
677 pr_err("Invalid pwm handle\n");
678 return;
679 }
680
681 mutex_lock(&pwm->chip->pwm_mutex);
682 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700683 if (pwm_chip->is_lpg_supported) {
684 pm8xxx_pwm_bank_sel(pwm);
685 pm8xxx_pwm_start(pwm, 0, 0);
686 } else {
687 pm8xxx_pwm_disable(pwm);
688 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 pwm->in_use = 0;
690 pwm->label = NULL;
691 }
Jay Chokshi57656862011-09-07 12:02:22 -0700692 if (pwm_chip->is_lpg_supported)
693 pm8xxx_pwm_bank_enable(pwm, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694 mutex_unlock(&pwm->chip->pwm_mutex);
695}
696EXPORT_SYMBOL_GPL(pwm_free);
697
698/**
699 * pwm_config - change a PWM device configuration
700 * @pwm: the PWM device
701 * @period_us: period in microseconds
702 * @duty_us: duty cycle in microseconds
703 */
704int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
705{
Willie Ruan719c6762011-08-25 11:03:14 -0700706 struct pm8xxx_pwm_period *period;
Jay Chokshi57656862011-09-07 12:02:22 -0700707 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708
709 if (pwm == NULL || IS_ERR(pwm) ||
710 duty_us > period_us ||
711 (unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
712 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
713 pr_err("Invalid pwm handle or parameters\n");
714 return -EINVAL;
715 }
716 if (pwm->chip == NULL) {
717 pr_err("No pwm_chip\n");
718 return -ENODEV;
719 }
720
Willie Ruan719c6762011-08-25 11:03:14 -0700721 period = &pwm->period;
722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 mutex_lock(&pwm->chip->pwm_mutex);
724
725 if (!pwm->in_use) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 rc = -EINVAL;
727 goto out_unlock;
728 }
729
Willie Ruan8de2f382011-08-25 11:04:50 -0700730 if (pwm->pwm_period != period_us) {
731 pm8xxx_pwm_calc_period(period_us, period);
732 pm8xxx_pwm_save_period(pwm);
733 pwm->pwm_period = period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700734 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735
Willie Ruan8de2f382011-08-25 11:04:50 -0700736 pm8xxx_pwm_calc_pwm_value(pwm, period_us, duty_us);
737 pm8xxx_pwm_save_pwm_value(pwm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738
Jay Chokshi57656862011-09-07 12:02:22 -0700739 if (pwm_chip->is_lpg_supported) {
740 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
741 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
742
743 pm8xxx_pwm_bank_sel(pwm);
744 rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
745 } else {
746 rc = pm8xxx_pwm_write(pwm);
747 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700748
749 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
750 (unsigned)duty_us, (unsigned)period_us,
751 pwm->pwm_value, 1 << period->pwm_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700752
753out_unlock:
754 mutex_unlock(&pwm->chip->pwm_mutex);
755 return rc;
756}
757EXPORT_SYMBOL_GPL(pwm_config);
758
759/**
760 * pwm_enable - start a PWM output toggling
761 * @pwm: the PWM device
762 */
763int pwm_enable(struct pwm_device *pwm)
764{
Jay Chokshi57656862011-09-07 12:02:22 -0700765 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700766
767 if (pwm == NULL || IS_ERR(pwm)) {
768 pr_err("Invalid pwm handle\n");
769 return -EINVAL;
770 }
771 if (pwm->chip == NULL) {
772 pr_err("No pwm_chip\n");
773 return -ENODEV;
774 }
775
776 mutex_lock(&pwm->chip->pwm_mutex);
777 if (!pwm->in_use) {
778 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
779 rc = -EINVAL;
780 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700781 if (pwm_chip->is_lpg_supported) {
782 rc = pm8xxx_pwm_bank_enable(pwm, 1);
783 pm8xxx_pwm_bank_sel(pwm);
784 pm8xxx_pwm_start(pwm, 1, 0);
785 } else {
786 pm8xxx_pwm_enable(pwm);
787 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788 }
789 mutex_unlock(&pwm->chip->pwm_mutex);
790 return rc;
791}
792EXPORT_SYMBOL_GPL(pwm_enable);
793
794/**
795 * pwm_disable - stop a PWM output toggling
796 * @pwm: the PWM device
797 */
798void pwm_disable(struct pwm_device *pwm)
799{
800 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
801 pr_err("Invalid pwm handle or no pwm_chip\n");
802 return;
803 }
804
805 mutex_lock(&pwm->chip->pwm_mutex);
806 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700807 if (pwm_chip->is_lpg_supported) {
808 pm8xxx_pwm_bank_sel(pwm);
809 pm8xxx_pwm_start(pwm, 0, 0);
810 pm8xxx_pwm_bank_enable(pwm, 0);
811 } else {
812 pm8xxx_pwm_disable(pwm);
813 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814 }
815 mutex_unlock(&pwm->chip->pwm_mutex);
816}
817EXPORT_SYMBOL_GPL(pwm_disable);
818
819/**
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700820 * pm8xxx_pwm_config_period - change PWM period
821 *
822 * @pwm: the PWM device
823 * @pwm_p: period in struct pm8xxx_pwm_period
824 */
825int pm8xxx_pwm_config_period(struct pwm_device *pwm,
826 struct pm8xxx_pwm_period *period)
827{
828 int rc;
829
830 if (pwm == NULL || IS_ERR(pwm) || period == NULL)
831 return -EINVAL;
832 if (pwm->chip == NULL)
833 return -ENODEV;
834
835 mutex_lock(&pwm->chip->pwm_mutex);
836
837 if (!pwm->in_use) {
838 rc = -EINVAL;
839 goto out_unlock;
840 }
841
842 pwm->period.pwm_size = period->pwm_size;
843 pwm->period.clk = period->clk;
844 pwm->period.pre_div = period->pre_div;
845 pwm->period.pre_div_exp = period->pre_div_exp;
846
847 pm8xxx_pwm_save_period(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700848
849 if (pwm_chip->is_lpg_supported) {
850 pm8xxx_pwm_bank_sel(pwm);
851 rc = pm8xxx_lpg_pwm_write(pwm, 4, 6);
852 } else {
853 rc = pm8xxx_pwm_write(pwm);
854 }
855
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700856
857out_unlock:
858 mutex_unlock(&pwm->chip->pwm_mutex);
859 return rc;
860}
861EXPORT_SYMBOL(pm8xxx_pwm_config_period);
862
863/**
864 * pm8xxx_pwm_config_pwm_value - change a PWM device configuration
865 * @pwm: the PWM device
866 * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
867 */
868int pm8xxx_pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
869{
870 int rc = 0;
871
872 if (pwm == NULL || IS_ERR(pwm))
873 return -EINVAL;
874 if (pwm->chip == NULL)
875 return -ENODEV;
876
877 mutex_lock(&pwm->chip->pwm_mutex);
878
879 if (!pwm->in_use || !pwm->pwm_period) {
880 rc = -EINVAL;
881 goto out_unlock;
882 }
883
884 if (pwm->pwm_value == pwm_value)
885 goto out_unlock;
886
887 pwm->pwm_value = pwm_value;
888
889 pm8xxx_pwm_save_pwm_value(pwm);
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700890
Jay Chokshi57656862011-09-07 12:02:22 -0700891 if (pwm_chip->is_lpg_supported) {
892 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
893 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
894 pm8xxx_pwm_bank_sel(pwm);
895 rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
896 } else {
897 rc = pm8xxx_pwm_write(pwm);
898 }
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700899
900 if (rc)
901 pr_err("[%d]: pm8xxx_pwm_write: rc=%d\n", pwm->pwm_id, rc);
902
903out_unlock:
904 mutex_unlock(&pwm->chip->pwm_mutex);
905 return rc;
906}
907EXPORT_SYMBOL_GPL(pm8xxx_pwm_config_pwm_value);
908
909/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 * pm8xxx_pwm_lut_config - change a PWM device configuration to use LUT
911 * @pwm: the PWM device
912 * @period_us: period in microseconds
913 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
914 * @duty_time_ms: time for each duty cycle in milliseconds
915 * @start_idx: start index in lookup table from 0 to MAX-1
916 * @idx_len: number of index
917 * @pause_lo: pause time in milliseconds at low index
918 * @pause_hi: pause time in milliseconds at high index
919 * @flags: control flags
920 */
921int pm8xxx_pwm_lut_config(struct pwm_device *pwm, int period_us,
922 int duty_pct[], int duty_time_ms, int start_idx,
923 int idx_len, int pause_lo, int pause_hi, int flags)
924{
Willie Ruan719c6762011-08-25 11:03:14 -0700925 struct pm8xxx_pwm_lut lut;
926 struct pm8xxx_pwm_period *period;
Willie Ruan8de2f382011-08-25 11:04:50 -0700927 int len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 int rc;
929
930 if (pwm == NULL || IS_ERR(pwm) || !idx_len) {
931 pr_err("Invalid pwm handle or idx_len=0\n");
932 return -EINVAL;
933 }
934 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE)) {
935 pr_err("Invalid duty_pct with flag\n");
936 return -EINVAL;
937 }
938 if (pwm->chip == NULL) {
939 pr_err("No pwm_chip\n");
940 return -ENODEV;
941 }
Jay Chokshi57656862011-09-07 12:02:22 -0700942
943 if (pwm->chip->is_lpg_supported == 0) {
944 pr_err("LPG module isn't supported\n");
945 return -EINVAL;
946 }
947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700948 if (idx_len >= PM_PWM_LUT_SIZE && start_idx) {
949 pr_err("Wrong LUT size or index\n");
950 return -EINVAL;
951 }
952 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE) {
953 pr_err("Exceed LUT limit\n");
954 return -EINVAL;
955 }
956 if ((unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
957 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
958 pr_err("Period out of range\n");
959 return -EINVAL;
960 }
961
Willie Ruan719c6762011-08-25 11:03:14 -0700962 period = &pwm->period;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963 mutex_lock(&pwm->chip->pwm_mutex);
964
965 if (!pwm->in_use) {
966 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
967 rc = -EINVAL;
968 goto out_unlock;
969 }
970
Willie Ruan8de2f382011-08-25 11:04:50 -0700971 if (pwm->pwm_period != period_us) {
972 pm8xxx_pwm_calc_period(period_us, period);
973 pm8xxx_pwm_save_period(pwm);
974 pwm->pwm_period = period_us;
975 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976
977 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
978
979 if (flags & PM_PWM_LUT_NO_TABLE)
980 goto after_table_write;
981
Willie Ruan8de2f382011-08-25 11:04:50 -0700982 rc = pm8xxx_pwm_change_table(pwm, duty_pct, start_idx, len, 0);
983 if (rc) {
984 pr_err("pm8xxx_pwm_change_table: rc=%d\n", rc);
985 goto out_unlock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 }
987
988after_table_write:
Willie Ruan719c6762011-08-25 11:03:14 -0700989 lut.lut_duty_ms = duty_time_ms;
990 lut.lut_lo_index = start_idx;
991 lut.lut_hi_index = start_idx + len - 1;
992 lut.lut_pause_lo = pause_lo;
993 lut.lut_pause_hi = pause_hi;
994 lut.flags = flags;
995 pwm->bypass_lut = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996
Willie Ruan8de2f382011-08-25 11:04:50 -0700997 rc = pm8xxx_pwm_change_lut(pwm, &lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998
999out_unlock:
1000 mutex_unlock(&pwm->chip->pwm_mutex);
1001 return rc;
1002}
1003EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_config);
1004
1005/**
1006 * pm8xxx_pwm_lut_enable - control a PWM device to start/stop LUT ramp
1007 * @pwm: the PWM device
1008 * @start: to start (1), or stop (0)
1009 */
1010int pm8xxx_pwm_lut_enable(struct pwm_device *pwm, int start)
1011{
1012 if (pwm == NULL || IS_ERR(pwm)) {
1013 pr_err("Invalid pwm handle\n");
1014 return -EINVAL;
1015 }
1016 if (pwm->chip == NULL) {
1017 pr_err("No pwm_chip\n");
1018 return -ENODEV;
1019 }
Jay Chokshi57656862011-09-07 12:02:22 -07001020 if (pwm->chip->is_lpg_supported == 0) {
1021 pr_err("LPG module isn't supported\n");
1022 return -EINVAL;
1023 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024
1025 mutex_lock(&pwm->chip->pwm_mutex);
1026 if (start) {
1027 pm8xxx_pwm_bank_enable(pwm, 1);
1028
1029 pm8xxx_pwm_bank_sel(pwm);
1030 pm8xxx_pwm_start(pwm, 1, 1);
1031 } else {
1032 pm8xxx_pwm_bank_sel(pwm);
1033 pm8xxx_pwm_start(pwm, 0, 0);
1034
1035 pm8xxx_pwm_bank_enable(pwm, 0);
1036 }
1037 mutex_unlock(&pwm->chip->pwm_mutex);
1038 return 0;
1039}
1040EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_enable);
1041
1042#if defined(CONFIG_DEBUG_FS)
1043
1044struct pm8xxx_pwm_dbg_device;
1045
1046struct pm8xxx_pwm_user {
1047 int pwm_id;
1048 struct pwm_device *pwm;
1049 int period;
1050 int duty_cycle;
1051 int enable;
1052 struct pm8xxx_pwm_dbg_device *dbgdev;
1053};
1054
1055struct pm8xxx_pwm_dbg_device {
1056 struct mutex dbg_mutex;
1057 struct device *dev;
1058 struct dentry *dent;
1059
Jay Chokshi57656862011-09-07 12:02:22 -07001060 struct pm8xxx_pwm_user *user;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061};
1062
1063static struct pm8xxx_pwm_dbg_device *pmic_dbg_device;
1064
1065static int dbg_pwm_check_period(int period)
1066{
1067 if (period < PM8XXX_PWM_PERIOD_MIN || period > PM8XXX_PWM_PERIOD_MAX) {
1068 pr_err("period is invalid: %d\n", period);
1069 return -EINVAL;
1070 }
1071 return 0;
1072}
1073
1074static int dbg_pwm_check_duty_cycle(int duty_cycle, const char *func_name)
1075{
1076 if (duty_cycle <= 0 || duty_cycle > 100) {
1077 pr_err("%s: duty_cycle is invalid: %d\n",
1078 func_name, duty_cycle);
1079 return -EINVAL;
1080 }
1081 return 0;
1082}
1083
1084static void dbg_pwm_check_handle(struct pm8xxx_pwm_user *puser)
1085{
1086 struct pwm_device *tmp;
1087
1088 if (puser->pwm == NULL) {
1089 tmp = pwm_request(puser->pwm_id, "pwm-dbg");
1090 if (PTR_ERR(puser->pwm)) {
1091 pr_err("pwm_request: err=%ld\n", PTR_ERR(puser->pwm));
1092 puser->pwm = NULL;
Willie Ruan10976ea2011-08-25 11:01:15 -07001093 } else {
1094 pr_debug("[id=%d] pwm_request ok\n", puser->pwm_id);
1095 puser->pwm = tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096 }
1097 }
1098}
1099
1100static int dbg_pwm_enable_set(void *data, u64 val)
1101{
1102 struct pm8xxx_pwm_user *puser = data;
1103 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1104 int rc;
1105
1106 mutex_lock(&dbgdev->dbg_mutex);
1107 rc = dbg_pwm_check_duty_cycle(puser->duty_cycle, __func__);
1108 if (!rc) {
1109 puser->enable = val;
1110 dbg_pwm_check_handle(puser);
1111 if (puser->pwm) {
1112 if (puser->enable)
1113 pwm_enable(puser->pwm);
1114 else
1115 pwm_disable(puser->pwm);
1116 }
1117 }
1118 mutex_unlock(&dbgdev->dbg_mutex);
1119 return 0;
1120}
1121
1122static int dbg_pwm_enable_get(void *data, u64 *val)
1123{
1124 struct pm8xxx_pwm_user *puser = data;
1125 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1126
1127 mutex_lock(&dbgdev->dbg_mutex);
1128 *val = puser->enable;
1129 mutex_unlock(&dbgdev->dbg_mutex);
1130 return 0;
1131}
1132
1133DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_enable_fops,
1134 dbg_pwm_enable_get, dbg_pwm_enable_set,
1135 "%lld\n");
1136
1137static int dbg_pwm_duty_cycle_set(void *data, u64 val)
1138{
1139 struct pm8xxx_pwm_user *puser = data;
1140 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1141 int rc;
1142
1143 mutex_lock(&dbgdev->dbg_mutex);
1144 rc = dbg_pwm_check_duty_cycle(val, __func__);
1145 if (!rc) {
1146 puser->duty_cycle = val;
1147 dbg_pwm_check_handle(puser);
1148 if (puser->pwm) {
1149 int duty_us;
1150
Willie Ruan10976ea2011-08-25 11:01:15 -07001151 duty_us = puser->duty_cycle * puser->period / 100;
1152 pwm_config(puser->pwm, duty_us, puser->period);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153 }
1154 }
1155 mutex_unlock(&dbgdev->dbg_mutex);
1156 return 0;
1157}
1158
1159static int dbg_pwm_duty_cycle_get(void *data, u64 *val)
1160{
1161 struct pm8xxx_pwm_user *puser = data;
1162 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1163
1164 mutex_lock(&dbgdev->dbg_mutex);
1165 *val = puser->duty_cycle;
1166 mutex_unlock(&dbgdev->dbg_mutex);
1167 return 0;
1168}
1169
1170DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_duty_cycle_fops,
1171 dbg_pwm_duty_cycle_get, dbg_pwm_duty_cycle_set,
1172 "%lld\n");
1173
1174static int dbg_pwm_period_set(void *data, u64 val)
1175{
1176 struct pm8xxx_pwm_user *puser = data;
1177 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1178 int rc;
1179
1180 mutex_lock(&dbgdev->dbg_mutex);
1181 rc = dbg_pwm_check_period(val);
1182 if (!rc)
1183 puser->period = val;
1184 mutex_unlock(&dbgdev->dbg_mutex);
1185 return 0;
1186}
1187
1188static int dbg_pwm_period_get(void *data, u64 *val)
1189{
1190 struct pm8xxx_pwm_user *puser = data;
1191 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1192
1193 mutex_lock(&dbgdev->dbg_mutex);
1194 *val = puser->period;
1195 mutex_unlock(&dbgdev->dbg_mutex);
1196 return 0;
1197}
1198
1199DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_period_fops,
1200 dbg_pwm_period_get, dbg_pwm_period_set, "%lld\n");
1201
1202static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1203{
1204 struct pm8xxx_pwm_dbg_device *dbgdev;
1205 struct dentry *dent;
1206 struct dentry *temp;
1207 struct pm8xxx_pwm_user *puser;
1208 int i;
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001209 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210
1211 if (dev == NULL) {
1212 pr_err("no parent data passed in.\n");
1213 return -EINVAL;
1214 }
1215
1216 dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
1217 if (dbgdev == NULL) {
1218 pr_err("kzalloc() failed.\n");
1219 return -ENOMEM;
1220 }
1221
Jay Chokshi57656862011-09-07 12:02:22 -07001222 dbgdev->user = kcalloc(pwm_chip->pwm_channels,
1223 sizeof(struct pm8xxx_pwm_user), GFP_KERNEL);
1224 if (dbgdev->user == NULL) {
1225 pr_err("kcalloc() failed.\n");
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001226 rc = -ENOMEM;
1227 goto user_error;
Jay Chokshi57656862011-09-07 12:02:22 -07001228 }
1229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 mutex_init(&dbgdev->dbg_mutex);
1231
1232 dbgdev->dev = dev;
1233
1234 dent = debugfs_create_dir("pm8xxx-pwm-dbg", NULL);
1235 if (dent == NULL || IS_ERR(dent)) {
1236 pr_err("ERR debugfs_create_dir: dent=%p\n", dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001237 rc = -ENOMEM;
1238 goto dir_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 }
1240
1241 dbgdev->dent = dent;
1242
Jay Chokshi57656862011-09-07 12:02:22 -07001243 for (i = 0; i < pwm_chip->pwm_channels; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 char pwm_ch[] = "0";
1245
1246 pwm_ch[0] = '0' + i;
1247 dent = debugfs_create_dir(pwm_ch, dbgdev->dent);
1248 if (dent == NULL || IS_ERR(dent)) {
1249 pr_err("ERR: pwm=%d: dir: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001250 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 goto debug_error;
1252 }
1253
1254 puser = &dbgdev->user[i];
1255 puser->dbgdev = dbgdev;
1256 puser->pwm_id = i;
1257 temp = debugfs_create_file("period", S_IRUGO | S_IWUSR,
1258 dent, puser, &dbg_pwm_period_fops);
1259 if (temp == NULL || IS_ERR(temp)) {
1260 pr_err("ERR: pwm=%d: period: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001261 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 goto debug_error;
1263 }
1264
1265 temp = debugfs_create_file("duty-cycle", S_IRUGO | S_IWUSR,
1266 dent, puser, &dbg_pwm_duty_cycle_fops);
1267 if (temp == NULL || IS_ERR(temp)) {
1268 pr_err("ERR: pwm=%d: duty-cycle: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001269 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 goto debug_error;
1271 }
1272
1273 temp = debugfs_create_file("enable", S_IRUGO | S_IWUSR,
1274 dent, puser, &dbg_pwm_enable_fops);
1275 if (temp == NULL || IS_ERR(temp)) {
1276 pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001277 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 goto debug_error;
1279 }
1280 }
1281
1282 pmic_dbg_device = dbgdev;
1283
1284 return 0;
1285
1286debug_error:
1287 debugfs_remove_recursive(dbgdev->dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001288dir_error:
1289 kfree(dbgdev->user);
1290user_error:
1291 kfree(dbgdev);
1292 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293}
1294
1295static int __devexit pm8xxx_pwm_dbg_remove(void)
1296{
1297 if (pmic_dbg_device) {
Jay Chokshi57656862011-09-07 12:02:22 -07001298 kfree(pmic_dbg_device->user);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 debugfs_remove_recursive(pmic_dbg_device->dent);
1300 kfree(pmic_dbg_device);
1301 }
1302 return 0;
1303}
1304
1305#else
1306
1307static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1308{
1309 return 0;
1310}
1311
1312static int __devexit pm8xxx_pwm_dbg_remove(void)
1313{
1314 return 0;
1315}
1316
1317#endif
1318
1319static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
1320{
1321 struct pm8xxx_pwm_chip *chip;
1322 int i;
Jay Chokshi57656862011-09-07 12:02:22 -07001323 enum pm8xxx_version version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324
1325 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1326 if (chip == NULL) {
1327 pr_err("kzalloc() failed.\n");
1328 return -ENOMEM;
1329 }
1330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 mutex_init(&chip->pwm_mutex);
1332
1333 chip->dev = &pdev->dev;
1334 pwm_chip = chip;
Jay Chokshi57656862011-09-07 12:02:22 -07001335
1336 version = pm8xxx_get_version(chip->dev->parent);
1337
1338 if (version == PM8XXX_VERSION_8921 ||
David Collins999480d2011-11-16 08:52:30 -08001339 version == PM8XXX_VERSION_8058 ||
1340 version == PM8XXX_VERSION_8922) {
Jay Chokshi57656862011-09-07 12:02:22 -07001341 chip->is_lpg_supported = 1;
1342 }
1343 if (chip->is_lpg_supported) {
1344 chip->pwm_channels = PM8XXX_LPG_PWM_CHANNELS;
1345 chip->pwm_total_pre_divs = NUM_LPG_PRE_DIVIDE;
1346 } else {
1347 chip->pwm_channels = PM8XXX_PWM_CHANNELS;
1348 chip->pwm_total_pre_divs = NUM_PWM_PRE_DIVIDE;
1349 }
1350
1351 chip->pwm_dev = kcalloc(chip->pwm_channels, sizeof(struct pwm_device),
1352 GFP_KERNEL);
1353 if (chip->pwm_dev == NULL) {
1354 pr_err("kcalloc() failed.\n");
1355 mutex_destroy(&chip->pwm_mutex);
1356 kfree(chip);
1357 return -ENOMEM;
1358 }
1359
1360 for (i = 0; i < chip->pwm_channels; i++) {
1361 chip->pwm_dev[i].pwm_id = i;
1362 chip->pwm_dev[i].chip = chip;
1363 }
1364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 platform_set_drvdata(pdev, chip);
1366
1367 if (pm8xxx_pwm_dbg_probe(&pdev->dev) < 0)
1368 pr_err("could not set up debugfs\n");
1369
1370 pr_notice("OK\n");
1371 return 0;
1372}
1373
1374static int __devexit pm8xxx_pwm_remove(struct platform_device *pdev)
1375{
1376 struct pm8xxx_pwm_chip *chip = dev_get_drvdata(pdev->dev.parent);
1377
1378 pm8xxx_pwm_dbg_remove();
Jay Chokshi57656862011-09-07 12:02:22 -07001379 kfree(chip->pwm_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 mutex_destroy(&chip->pwm_mutex);
1381 platform_set_drvdata(pdev, NULL);
1382 kfree(chip);
1383 return 0;
1384}
1385
1386static struct platform_driver pm8xxx_pwm_driver = {
1387 .probe = pm8xxx_pwm_probe,
1388 .remove = __devexit_p(pm8xxx_pwm_remove),
1389 .driver = {
1390 .name = PM8XXX_PWM_DEV_NAME,
1391 .owner = THIS_MODULE,
1392 },
1393};
1394
1395static int __init pm8xxx_pwm_init(void)
1396{
1397 return platform_driver_register(&pm8xxx_pwm_driver);
1398}
1399
1400static void __exit pm8xxx_pwm_exit(void)
1401{
1402 platform_driver_unregister(&pm8xxx_pwm_driver);
1403}
1404
1405subsys_initcall(pm8xxx_pwm_init);
1406module_exit(pm8xxx_pwm_exit);
1407
1408MODULE_LICENSE("GPL v2");
1409MODULE_DESCRIPTION("PM8XXX PWM driver");
1410MODULE_VERSION("1.0");
1411MODULE_ALIAS("platform:" PM8XXX_PWM_DEV_NAME);