blob: 24fd5c1d1b067c9263e219d28fafc2836c40301f [file] [log] [blame]
Prasad Sodagudi5af87922013-06-05 17:33:52 +05301/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12/*
13 * Qualcomm PM8XXX Pulse Width Modulation (PWM) driver
14 *
15 * The HW module is also called LPG (Light Pulse Generator).
16 */
17
18#define pr_fmt(fmt) "%s: " fmt, __func__
19
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <linux/err.h>
24#include <linux/debugfs.h>
25#include <linux/mfd/pm8xxx/core.h>
26#include <linux/mfd/pm8xxx/pwm.h>
27
Jay Chokshi57656862011-09-07 12:02:22 -070028#define PM8XXX_PWM_CHANNELS 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
Jay Chokshi0c220cd2011-12-09 17:18:20 -080030/*
31 * For the lack of better term to distinguish functional
32 * differences, hereby, LPG version 0 (V0, v0) denotes
33 * PM8058/8921, and version 1 (V1, v1) denotes
34 * PM8922/8038.
35 */
36#define PM8XXX_LPG_V0_PWM_CHANNELS 8
37#define PM8XXX_LPG_V1_PWM_CHANNELS 6
Prasad Sodagudidefd6422013-06-24 22:23:29 +053038#define PM8XXX_LPG_CTL_REGS 8
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40/* PM8XXX PWM */
Jay Chokshi57656862011-09-07 12:02:22 -070041#define SSBI_REG_ADDR_PWM1_CTRL1 0x88
42#define SSBI_REG_ADDR_PWM1_CTRL2 0x89
43#define SSBI_REG_ADDR_PWM_CTL(id, base) (id == 0 ? base : (base + (id << 1)))
44#define SSBI_REG_ADDR_PWM_CTL1(id) SSBI_REG_ADDR_PWM_CTL(id, \
45 SSBI_REG_ADDR_PWM1_CTRL1)
46#define SSBI_REG_ADDR_PWM_CTL2(id) SSBI_REG_ADDR_PWM_CTL(id, \
47 SSBI_REG_ADDR_PWM1_CTRL2)
48
49#define PM8XXX_PWM_CLK_SEL_SHIFT 6
50#define PM8XXX_PWM_CLK_SEL_MASK 0xC0
51#define PM8XXX_PWM_PREDIVIDE_SHIFT 5
52#define PM8XXX_PWM_PREDIVIDE_MASK 0x20
53#define PM8XXX_PWM_M_SHIFT 2
54#define PM8XXX_PWM_M_MASK 0x1C
55#define PM8XXX_PWM_SIZE_SHIFT 1
56#define PM8XXX_PWM_SIZE_MASK 0x02
57#define PM8XXX_PWM_VALUE_BIT0 0x01
58#define PM8XXX_PWM_DISABLE 0x3F
59
60/* PM8XXX LPG PWM */
Prasad Sodagudi5af87922013-06-05 17:33:52 +053061#define SSBI_REG_ADDR_LPG_BANK_LOW_EN 0x130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062#define SSBI_REG_ADDR_LPG_CTL_BASE 0x13C
63#define SSBI_REG_ADDR_LPG_CTL(n) (SSBI_REG_ADDR_LPG_CTL_BASE + (n))
64#define SSBI_REG_ADDR_LPG_BANK_SEL 0x143
Prasad Sodagudi5af87922013-06-05 17:33:52 +053065#define SSBI_REG_ADDR_LPG_BANK_HIGH_EN 0x144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066#define SSBI_REG_ADDR_LPG_LUT_CFG0 0x145
67#define SSBI_REG_ADDR_LPG_LUT_CFG1 0x146
Jay Chokshib0a0fa52012-02-23 16:18:44 -080068#define SSBI_REG_ADDR_LPG_TEST 0x147
Prasad Sodagudidefd6422013-06-24 22:23:29 +053069#define SSBI_REG_ADDR_LPG_CTL_7 0x14D
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070
Jay Chokshi57656862011-09-07 12:02:22 -070071/* LPG Control 0 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072#define PM8XXX_PWM_1KHZ_COUNT_MASK 0xF0
73#define PM8XXX_PWM_1KHZ_COUNT_SHIFT 4
74
75#define PM8XXX_PWM_1KHZ_COUNT_MAX 15
76
77#define PM8XXX_PWM_OUTPUT_EN 0x08
78#define PM8XXX_PWM_PWM_EN 0x04
79#define PM8XXX_PWM_RAMP_GEN_EN 0x02
80#define PM8XXX_PWM_RAMP_START 0x01
81
82#define PM8XXX_PWM_PWM_START (PM8XXX_PWM_OUTPUT_EN \
83 | PM8XXX_PWM_PWM_EN)
84#define PM8XXX_PWM_RAMP_GEN_START (PM8XXX_PWM_RAMP_GEN_EN \
85 | PM8XXX_PWM_RAMP_START)
86
Jay Chokshi57656862011-09-07 12:02:22 -070087/* LPG Control 1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088#define PM8XXX_PWM_REVERSE_EN 0x80
89#define PM8XXX_PWM_BYPASS_LUT 0x40
90#define PM8XXX_PWM_HIGH_INDEX_MASK 0x3F
91
Jay Chokshi57656862011-09-07 12:02:22 -070092/* LPG Control 2 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093#define PM8XXX_PWM_LOOP_EN 0x80
94#define PM8XXX_PWM_RAMP_UP 0x40
95#define PM8XXX_PWM_LOW_INDEX_MASK 0x3F
96
Jay Chokshi57656862011-09-07 12:02:22 -070097/* LPG Control 3 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098#define PM8XXX_PWM_VALUE_BIT7_0 0xFF
99#define PM8XXX_PWM_VALUE_BIT5_0 0x3F
100
Jay Chokshi57656862011-09-07 12:02:22 -0700101/* LPG Control 4 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102#define PM8XXX_PWM_VALUE_BIT8 0x80
103
Jay Chokshi57656862011-09-07 12:02:22 -0700104#define PM8XXX_LPG_PWM_CLK_SEL_MASK 0x60
105#define PM8XXX_LPG_PWM_CLK_SEL_SHIFT 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106
107#define PM8XXX_PWM_CLK_SEL_NO 0
108#define PM8XXX_PWM_CLK_SEL_1KHZ 1
109#define PM8XXX_PWM_CLK_SEL_32KHZ 2
110#define PM8XXX_PWM_CLK_SEL_19P2MHZ 3
111
Jay Chokshi57656862011-09-07 12:02:22 -0700112#define PM8XXX_LPG_PWM_PREDIVIDE_MASK 0x18
113#define PM8XXX_LPG_PWM_PREDIVIDE_SHIFT 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114
115#define PM8XXX_PWM_PREDIVIDE_2 0
116#define PM8XXX_PWM_PREDIVIDE_3 1
117#define PM8XXX_PWM_PREDIVIDE_5 2
118#define PM8XXX_PWM_PREDIVIDE_6 3
119
Jay Chokshi57656862011-09-07 12:02:22 -0700120#define PM8XXX_LPG_PWM_M_MASK 0x07
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121#define PM8XXX_PWM_M_MIN 0
122#define PM8XXX_PWM_M_MAX 7
123
Jay Chokshi57656862011-09-07 12:02:22 -0700124/* LPG Control 5 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125#define PM8XXX_PWM_PAUSE_COUNT_HI_MASK 0xFC
126#define PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT 2
127
128#define PM8XXX_PWM_PAUSE_ENABLE_HIGH 0x02
129#define PM8XXX_PWM_SIZE_9_BIT 0x01
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530130#define PM8XXX_PWM_SIZE_7_BIT 0x04
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131
Jay Chokshi57656862011-09-07 12:02:22 -0700132/* LPG Control 6 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133#define PM8XXX_PWM_PAUSE_COUNT_LO_MASK 0xFC
134#define PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT 2
135
136#define PM8XXX_PWM_PAUSE_ENABLE_LOW 0x02
137#define PM8XXX_PWM_RESERVED 0x01
138
139#define PM8XXX_PWM_PAUSE_COUNT_MAX 56 /* < 2^6 = 64 */
140
Jay Chokshi57656862011-09-07 12:02:22 -0700141/* LPG LUT_CFG1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142#define PM8XXX_PWM_LUT_READ 0x40
143
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800144/* TEST */
145#define PM8XXX_PWM_DTEST_MASK 0x38
146#define PM8XXX_PWM_DTEST_SHIFT 3
147#define PM8XXX_PWM_DTEST_BANK_MASK 0x07
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149/*
150 * PWM Frequency = Clock Frequency / (N * T)
151 * or
152 * PWM Period = Clock Period * (N * T)
153 * where
154 * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
155 * T = Pre-divide * 2^m, where m = 0..7 (exponent)
156 *
157 * This is the formula to figure out m for the best pre-divide and clock:
Willie Ruan4a0a7002012-01-10 15:39:44 -0800158 * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 */
160#define NUM_CLOCKS 3
161
Willie Ruandb78e942012-01-10 15:00:28 -0800162#define NSEC_1024HZ (NSEC_PER_SEC / 1024)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
164#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
165
Willie Ruanb10be972012-01-12 11:30:11 -0800166#define NUM_LPG_PRE_DIVIDE 4
Jay Chokshi57656862011-09-07 12:02:22 -0700167#define NUM_PWM_PRE_DIVIDE 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168
Jay Chokshi0c220cd2011-12-09 17:18:20 -0800169#define PRE_DIVIDE_1 1 /* v1 */
Willie Ruanb10be972012-01-12 11:30:11 -0800170#define PRE_DIVIDE_2 2
171#define PRE_DIVIDE_3 3
172#define PRE_DIVIDE_5 5
173#define PRE_DIVIDE_6 6
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174
Jay Chokshi57656862011-09-07 12:02:22 -0700175static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
Willie Ruandb78e942012-01-10 15:00:28 -0800176 { PRE_DIVIDE_2 * NSEC_1024HZ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177 PRE_DIVIDE_2 * NSEC_32768HZ,
178 PRE_DIVIDE_2 * NSEC_19P2MHZ,
179 },
Willie Ruanb10be972012-01-12 11:30:11 -0800180 { PRE_DIVIDE_3 * NSEC_1024HZ,
181 PRE_DIVIDE_3 * NSEC_32768HZ,
182 PRE_DIVIDE_3 * NSEC_19P2MHZ,
183 },
184 { PRE_DIVIDE_5 * NSEC_1024HZ,
185 PRE_DIVIDE_5 * NSEC_32768HZ,
186 PRE_DIVIDE_5 * NSEC_19P2MHZ,
187 },
188 { PRE_DIVIDE_6 * NSEC_1024HZ,
189 PRE_DIVIDE_6 * NSEC_32768HZ,
190 PRE_DIVIDE_6 * NSEC_19P2MHZ,
191 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192};
193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194/* Private data */
195struct pm8xxx_pwm_chip;
196
197struct pwm_device {
198 int pwm_id; /* = bank/channel id */
199 int in_use;
200 const char *label;
Willie Ruan719c6762011-08-25 11:03:14 -0700201 struct pm8xxx_pwm_period period;
202 int pwm_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 int pwm_period;
204 int pwm_duty;
Jay Chokshi57656862011-09-07 12:02:22 -0700205 u8 pwm_lpg_ctl[PM8XXX_LPG_CTL_REGS];
206 u8 pwm_ctl1;
207 u8 pwm_ctl2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 int irq;
209 struct pm8xxx_pwm_chip *chip;
Willie Ruan719c6762011-08-25 11:03:14 -0700210 int bypass_lut;
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800211 int dtest_mode_supported;
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530212 int banks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213};
214
215struct pm8xxx_pwm_chip {
Jay Chokshi57656862011-09-07 12:02:22 -0700216 struct pwm_device *pwm_dev;
217 u8 pwm_channels;
218 u8 pwm_total_pre_divs;
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530219 u8 lo_bank_mask;
220 u8 hi_bank_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221 struct mutex pwm_mutex;
222 struct device *dev;
Jay Chokshi57656862011-09-07 12:02:22 -0700223 bool is_lpg_supported;
Jay Chokshi90485222012-08-07 20:22:39 -0700224 bool is_pwm_enable_sync_workaround_needed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225};
226
227static struct pm8xxx_pwm_chip *pwm_chip;
228
Willie Ruan719c6762011-08-25 11:03:14 -0700229struct pm8xxx_pwm_lut {
230 /* LUT parameters */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 int lut_duty_ms;
232 int lut_lo_index;
233 int lut_hi_index;
234 int lut_pause_hi;
235 int lut_pause_lo;
236 int flags;
237};
238
239static const u16 duty_msec[PM8XXX_PWM_1KHZ_COUNT_MAX + 1] = {
240 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
241};
242
243static const u16 pause_count[PM8XXX_PWM_PAUSE_COUNT_MAX + 1] = {
244 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
245 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
246 375, 500, 667, 750, 800, 900, 1000, 1100,
247 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
248 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
249 7000
250};
251
252/* Internal functions */
Willie Ruan8de2f382011-08-25 11:04:50 -0700253static void pm8xxx_pwm_save(u8 *u8p, u8 mask, u8 val)
254{
255 *u8p &= ~mask;
256 *u8p |= val & mask;
257}
258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259static int pm8xxx_pwm_bank_enable(struct pwm_device *pwm, int enable)
260{
261 int rc;
262 u8 reg;
263 struct pm8xxx_pwm_chip *chip;
264
265 chip = pwm->chip;
266
Prasad Sodagudi6a79c842013-06-12 19:29:36 +0530267 if (!pwm->banks)
268 pwm->banks = (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
269
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530270 if (pwm->banks & PM_PWM_BANK_LO) {
271 if (enable)
272 reg = chip->lo_bank_mask | (1 << pwm->pwm_id);
273 else
274 reg = chip->lo_bank_mask & ~(1 << pwm->pwm_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530276 rc = pm8xxx_writeb(chip->dev->parent,
277 SSBI_REG_ADDR_LPG_BANK_LOW_EN, reg);
278 if (rc) {
279 pr_err("pm8xxx_writeb(): Enable Bank Low =%d\n", rc);
280 return rc;
281 }
282
283 chip->lo_bank_mask = reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530286 if (pwm->banks & PM_PWM_BANK_HI) {
287 if (enable)
288 reg = chip->hi_bank_mask | (1 << pwm->pwm_id);
289 else
290 reg = chip->hi_bank_mask & ~(1 << pwm->pwm_id);
291
292 rc = pm8xxx_writeb(chip->dev->parent,
293 SSBI_REG_ADDR_LPG_BANK_HIGH_EN, reg);
294 if (rc) {
295 pr_err("pm8xxx_writeb(): Enable Bank High =%d\n", rc);
296 return rc;
297 }
298
299 chip->hi_bank_mask = reg;
300 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301 return 0;
302}
303
304static int pm8xxx_pwm_bank_sel(struct pwm_device *pwm)
305{
306 int rc;
307
308 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_SEL,
309 pwm->pwm_id);
310 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700311 pr_err("pm8xxx_writeb(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 return rc;
313}
314
315static int pm8xxx_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
316{
317 int rc;
318 u8 reg;
319
320 if (start) {
Jay Chokshi57656862011-09-07 12:02:22 -0700321 reg = pwm->pwm_lpg_ctl[0] | PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 if (ramp_start)
323 reg |= PM8XXX_PWM_RAMP_GEN_START;
324 else
325 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
326 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700327 reg = pwm->pwm_lpg_ctl[0] & ~PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
329 }
330
331 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
332 reg);
333 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700334 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 else
Jay Chokshi57656862011-09-07 12:02:22 -0700336 pwm->pwm_lpg_ctl[0] = reg;
337 return rc;
338}
339
340static int pm8xxx_pwm_disable(struct pwm_device *pwm)
341{
342 int rc;
343 u8 reg;
344
345 reg = pwm->pwm_ctl1 & PM8XXX_PWM_DISABLE;
346
347 rc = pm8xxx_writeb(pwm->chip->dev->parent,
348 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), reg);
349
350 if (rc)
351 pr_err("pm8xxx_writeb(): rc=%d (Disable PWM Ctl %d)\n", rc,
352 pwm->pwm_id);
353 return rc;
354}
355
356static int pm8xxx_pwm_enable(struct pwm_device *pwm)
357{
358 /**
359 * A kind of best Effort: Just write the clock information that
360 * we have in the register.
361 */
362 int rc;
363
364 rc = pm8xxx_writeb(pwm->chip->dev->parent,
365 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), pwm->pwm_ctl1);
366
367 if (rc)
368 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl %d)\n", rc,
369 pwm->pwm_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 return rc;
371}
372
373static void pm8xxx_pwm_calc_period(unsigned int period_us,
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530374 struct pwm_device *pwm)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375{
376 int n, m, clk, div;
377 int best_m, best_div, best_clk;
Willie Ruan4a0a7002012-01-10 15:39:44 -0800378 unsigned int last_err, cur_err, min_err;
379 unsigned int tmp_p, period_n;
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530380 struct pm8xxx_pwm_period *period = &pwm->period;
381
382 if (pwm->banks == PM_PWM_BANK_LO)
383 n = 7;
384 else
385 n = 6;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386
387 /* PWM Period / N */
Willie Ruan70f989d2012-01-10 10:09:36 -0800388 if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530389 period_n = (period_us * NSEC_PER_USEC) >> n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 } else {
391 period_n = (period_us >> 9) * NSEC_PER_USEC;
392 n = 9;
393 }
394
Willie Ruan4a0a7002012-01-10 15:39:44 -0800395 min_err = last_err = (unsigned)(-1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 best_m = 0;
397 best_clk = 0;
398 best_div = 0;
399 for (clk = 0; clk < NUM_CLOCKS; clk++) {
Jay Chokshi57656862011-09-07 12:02:22 -0700400 for (div = 0; div < pwm_chip->pwm_total_pre_divs; div++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800401 /* period_n = (PWM Period / N) */
402 /* tmp_p = (Pre-divide * Clock Period) * 2^m */
403 tmp_p = pt_t[div][clk];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 for (m = 0; m <= PM8XXX_PWM_M_MAX; m++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800405 if (period_n > tmp_p)
406 cur_err = period_n - tmp_p;
407 else
408 cur_err = tmp_p - period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409
Willie Ruan4a0a7002012-01-10 15:39:44 -0800410 if (cur_err < min_err) {
411 min_err = cur_err;
412 best_m = m;
413 best_clk = clk;
414 best_div = div;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 }
Willie Ruan4a0a7002012-01-10 15:39:44 -0800416
417 if (m && cur_err > last_err)
418 /* Break for bigger cur_err */
419 break;
420
421 last_err = cur_err;
422 tmp_p <<= 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 }
424 }
425 }
426
Willie Ruan75d9e5b2011-08-25 10:59:17 -0700427 /* Use higher resolution */
428 if (best_m >= 3 && n == 6) {
429 n += 3;
430 best_m -= 3;
431 }
432
Willie Ruan719c6762011-08-25 11:03:14 -0700433 period->pwm_size = n;
434 period->clk = best_clk;
435 period->pre_div = best_div;
436 period->pre_div_exp = best_m;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437}
438
Willie Ruan8de2f382011-08-25 11:04:50 -0700439static void pm8xxx_pwm_calc_pwm_value(struct pwm_device *pwm,
440 unsigned int period_us,
441 unsigned int duty_us)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442{
Willie Ruan8de2f382011-08-25 11:04:50 -0700443 unsigned int max_pwm_value, tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444
Willie Ruan8de2f382011-08-25 11:04:50 -0700445 /* Figure out pwm_value with overflow handling */
446 tmp = 1 << (sizeof(tmp) * 8 - pwm->period.pwm_size);
447 if (duty_us < tmp) {
448 tmp = duty_us << pwm->period.pwm_size;
449 pwm->pwm_value = tmp / period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450 } else {
Willie Ruan8de2f382011-08-25 11:04:50 -0700451 tmp = period_us >> pwm->period.pwm_size;
452 pwm->pwm_value = duty_us / tmp;
453 }
454 max_pwm_value = (1 << pwm->period.pwm_size) - 1;
455 if (pwm->pwm_value > max_pwm_value)
456 pwm->pwm_value = max_pwm_value;
457}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458
Willie Ruan8de2f382011-08-25 11:04:50 -0700459static int pm8xxx_pwm_change_table(struct pwm_device *pwm, int duty_pct[],
460 int start_idx, int len, int raw_value)
461{
462 unsigned int pwm_value, max_pwm_value;
463 u8 cfg0, cfg1;
464 int i, pwm_size;
465 int rc = 0;
466
Jay Chokshi57656862011-09-07 12:02:22 -0700467 pwm_size = (pwm->pwm_lpg_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530468 if (pwm->period.pwm_size == 7)
469 pwm_size = 7;
470
Willie Ruan8de2f382011-08-25 11:04:50 -0700471 max_pwm_value = (1 << pwm_size) - 1;
472 for (i = 0; i < len; i++) {
473 if (raw_value)
474 pwm_value = duty_pct[i];
475 else
476 pwm_value = (duty_pct[i] << pwm_size) / 100;
477
478 if (pwm_value > max_pwm_value)
479 pwm_value = max_pwm_value;
480 cfg0 = pwm_value;
481 cfg1 = (pwm_value >> 1) & 0x80;
482 cfg1 |= start_idx + i;
483
484 rc = pm8xxx_writeb(pwm->chip->dev->parent,
485 SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
486 if (rc)
487 break;
488
489 rc = pm8xxx_writeb(pwm->chip->dev->parent,
490 SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
491 if (rc)
492 break;
493 }
494 return rc;
495}
496
497static void pm8xxx_pwm_save_index(struct pwm_device *pwm,
498 int low_idx, int high_idx, int flags)
499{
Jay Chokshi57656862011-09-07 12:02:22 -0700500 pwm->pwm_lpg_ctl[1] = high_idx & PM8XXX_PWM_HIGH_INDEX_MASK;
501 pwm->pwm_lpg_ctl[2] = low_idx & PM8XXX_PWM_LOW_INDEX_MASK;
Willie Ruan8de2f382011-08-25 11:04:50 -0700502
503 if (flags & PM_PWM_LUT_REVERSE)
Jay Chokshi57656862011-09-07 12:02:22 -0700504 pwm->pwm_lpg_ctl[1] |= PM8XXX_PWM_REVERSE_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700505 if (flags & PM_PWM_LUT_RAMP_UP)
Jay Chokshi57656862011-09-07 12:02:22 -0700506 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_RAMP_UP;
Willie Ruan8de2f382011-08-25 11:04:50 -0700507 if (flags & PM_PWM_LUT_LOOP)
Jay Chokshi57656862011-09-07 12:02:22 -0700508 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_LOOP_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700509}
510
511static void pm8xxx_pwm_save_period(struct pwm_device *pwm)
512{
513 u8 mask, val;
514
Jay Chokshi57656862011-09-07 12:02:22 -0700515 if (pwm_chip->is_lpg_supported) {
516 val = ((pwm->period.clk + 1) << PM8XXX_LPG_PWM_CLK_SEL_SHIFT)
517 & PM8XXX_LPG_PWM_CLK_SEL_MASK;
518 val |= (pwm->period.pre_div << PM8XXX_LPG_PWM_PREDIVIDE_SHIFT)
519 & PM8XXX_LPG_PWM_PREDIVIDE_MASK;
520 val |= pwm->period.pre_div_exp & PM8XXX_LPG_PWM_M_MASK;
521 mask = PM8XXX_LPG_PWM_CLK_SEL_MASK |
522 PM8XXX_LPG_PWM_PREDIVIDE_MASK | PM8XXX_LPG_PWM_M_MASK;
523 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700524
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530525 if (pwm->period.pwm_size == 7) {
526 val = PM8XXX_PWM_SIZE_7_BIT;
527 mask = PM8XXX_PWM_SIZE_7_BIT;
528 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[7], mask, val);
529 } else {
530 val = (pwm->period.pwm_size > 6) ?
531 PM8XXX_PWM_SIZE_9_BIT : 0;
532 mask = PM8XXX_PWM_SIZE_9_BIT;
533 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
534 }
Jay Chokshi57656862011-09-07 12:02:22 -0700535 } else {
536 val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
537 & PM8XXX_PWM_CLK_SEL_MASK;
538 val |= (pwm->period.pre_div << PM8XXX_PWM_PREDIVIDE_SHIFT)
539 & PM8XXX_PWM_PREDIVIDE_MASK;
540 val |= (pwm->period.pre_div_exp << PM8XXX_PWM_M_SHIFT)
541 & PM8XXX_PWM_M_MASK;
542 val |= (((pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0)
543 << PM8XXX_PWM_SIZE_SHIFT) & PM8XXX_PWM_SIZE_MASK;
544
545 mask = PM8XXX_PWM_CLK_SEL_MASK | PM8XXX_PWM_PREDIVIDE_MASK |
546 PM8XXX_PWM_M_MASK | PM8XXX_PWM_SIZE_MASK;
547 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
548 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700549}
550
551static void pm8xxx_pwm_save_pwm_value(struct pwm_device *pwm)
552{
553 u8 mask, val;
554
Jay Chokshi57656862011-09-07 12:02:22 -0700555 if (pwm_chip->is_lpg_supported) {
556 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 1) : 0;
557 pwm->pwm_lpg_ctl[3] = pwm->pwm_value;
558 mask = PM8XXX_PWM_VALUE_BIT8;
559 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
560 } else {
561 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 8) : 0;
562 pwm->pwm_ctl2 = pwm->pwm_value;
563 mask = PM8XXX_PWM_VALUE_BIT0;
564 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
565 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700566}
567
568static void pm8xxx_pwm_save_duty_time(struct pwm_device *pwm,
569 struct pm8xxx_pwm_lut *lut)
570{
571 int i;
572 u8 mask, val;
573
574 /* Linear search for duty time */
575 for (i = 0; i < PM8XXX_PWM_1KHZ_COUNT_MAX; i++) {
576 if (duty_msec[i] >= lut->lut_duty_ms)
577 break;
578 }
579 val = i << PM8XXX_PWM_1KHZ_COUNT_SHIFT;
580
581 mask = PM8XXX_PWM_1KHZ_COUNT_MASK;
Jay Chokshi57656862011-09-07 12:02:22 -0700582 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[0], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700583}
584
585static void pm8xxx_pwm_save_pause(struct pwm_device *pwm,
586 struct pm8xxx_pwm_lut *lut)
587{
588 int i, pause_cnt, time_cnt;
589 u8 mask, val;
590
Jay Chokshi57656862011-09-07 12:02:22 -0700591 time_cnt = (pwm->pwm_lpg_ctl[0] & PM8XXX_PWM_1KHZ_COUNT_MASK)
Willie Ruan8de2f382011-08-25 11:04:50 -0700592 >> PM8XXX_PWM_1KHZ_COUNT_SHIFT;
593 if (lut->flags & PM_PWM_LUT_PAUSE_HI_EN) {
594 pause_cnt = (lut->lut_pause_hi + duty_msec[time_cnt] / 2)
595 / duty_msec[time_cnt];
596 /* Linear search for pause time */
597 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
598 if (pause_count[i] >= pause_cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 break;
600 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700601 val = (i << PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT) &
602 PM8XXX_PWM_PAUSE_COUNT_HI_MASK;
603 val |= PM8XXX_PWM_PAUSE_ENABLE_HIGH;
604 } else {
605 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 }
607
Willie Ruan8de2f382011-08-25 11:04:50 -0700608 mask = PM8XXX_PWM_PAUSE_COUNT_HI_MASK | PM8XXX_PWM_PAUSE_ENABLE_HIGH;
Jay Chokshi57656862011-09-07 12:02:22 -0700609 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610
Willie Ruan8de2f382011-08-25 11:04:50 -0700611 if (lut->flags & PM_PWM_LUT_PAUSE_LO_EN) {
612 /* Linear search for pause time */
613 pause_cnt = (lut->lut_pause_lo + duty_msec[time_cnt] / 2)
614 / duty_msec[time_cnt];
615 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
616 if (pause_count[i] >= pause_cnt)
617 break;
618 }
619 val = (i << PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT) &
620 PM8XXX_PWM_PAUSE_COUNT_LO_MASK;
621 val |= PM8XXX_PWM_PAUSE_ENABLE_LOW;
622 } else {
623 val = 0;
624 }
625
626 mask = PM8XXX_PWM_PAUSE_COUNT_LO_MASK | PM8XXX_PWM_PAUSE_ENABLE_LOW;
Jay Chokshi57656862011-09-07 12:02:22 -0700627 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[6], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700628}
629
Jay Chokshi57656862011-09-07 12:02:22 -0700630static int pm8xxx_pwm_write(struct pwm_device *pwm)
631{
632 int rc = 0;
633
634 rc = pm8xxx_writeb(pwm->chip->dev->parent,
635 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id),
636 pwm->pwm_ctl1);
637 if (rc) {
638 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl1[%d])\n",
639 rc, pwm->pwm_id);
640 return rc;
641 }
642
643 rc = pm8xxx_writeb(pwm->chip->dev->parent,
644 SSBI_REG_ADDR_PWM_CTL2(pwm->pwm_id),
645 pwm->pwm_ctl2);
646 if (rc) {
647 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl2[%d])\n",
648 rc, pwm->pwm_id);
649 return rc;
650 }
651
652 return rc;
653}
654
655static int pm8xxx_lpg_pwm_write(struct pwm_device *pwm, int start, int end)
Willie Ruan8de2f382011-08-25 11:04:50 -0700656{
657 int i, rc;
658
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530659 if (end == 7) {
660 rc = pm8xxx_writeb(pwm->chip->dev->parent,
661 SSBI_REG_ADDR_LPG_CTL_7,
662 pwm->pwm_lpg_ctl[end]);
663 if (rc) {
664 pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[7])\n", rc);
665 return rc;
666 }
667 }
668
Willie Ruan8de2f382011-08-25 11:04:50 -0700669 /* Write in reverse way so 0 would be the last */
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530670 for (i = end - 2; i >= start; i--) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 rc = pm8xxx_writeb(pwm->chip->dev->parent,
672 SSBI_REG_ADDR_LPG_CTL(i),
Jay Chokshi57656862011-09-07 12:02:22 -0700673 pwm->pwm_lpg_ctl[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700675 pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[%d])\n", rc, i);
676 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677 }
678 }
679
Willie Ruan8de2f382011-08-25 11:04:50 -0700680 return 0;
681}
682
683static int pm8xxx_pwm_change_lut(struct pwm_device *pwm,
684 struct pm8xxx_pwm_lut *lut)
685{
686 int rc;
687
688 pm8xxx_pwm_save_index(pwm, lut->lut_lo_index,
689 lut->lut_hi_index, lut->flags);
690 pm8xxx_pwm_save_duty_time(pwm, lut);
691 pm8xxx_pwm_save_pause(pwm, lut);
Jay Chokshi57656862011-09-07 12:02:22 -0700692 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1], PM8XXX_PWM_BYPASS_LUT, 0);
Willie Ruan8de2f382011-08-25 11:04:50 -0700693
694 pm8xxx_pwm_bank_sel(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700695 rc = pm8xxx_lpg_pwm_write(pwm, 0, 7);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696
697 return rc;
698}
699
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800700static int pm8xxx_pwm_set_dtest(struct pwm_device *pwm, int enable)
701{
702 int rc;
703 u8 reg;
704
705 reg = pwm->pwm_id & PM8XXX_PWM_DTEST_BANK_MASK;
706
707 if (enable) {
708 /* Observe LPG_OUT on DTEST1*/
709 reg |= (1 << PM8XXX_PWM_DTEST_SHIFT) &
710 PM8XXX_PWM_DTEST_MASK;
711 }
712
713 rc = pm8xxx_writeb(pwm->chip->dev->parent,
714 SSBI_REG_ADDR_LPG_TEST, reg);
715 if (rc)
716 pr_err("pm8xxx_write(DTEST=0x%x) failed: rc=%d\n",
717 reg, rc);
718
719 return rc;
720}
721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722/* APIs */
723/**
724 * pwm_request - request a PWM device
725 * @pwm_id: PWM id or channel
726 * @label: the label to identify the user
727 */
728struct pwm_device *pwm_request(int pwm_id, const char *label)
729{
730 struct pwm_device *pwm;
731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732 if (pwm_chip == NULL) {
733 pr_err("No pwm_chip\n");
734 return ERR_PTR(-ENODEV);
735 }
736
Jay Chokshi57656862011-09-07 12:02:22 -0700737 if (pwm_id >= pwm_chip->pwm_channels || pwm_id < 0) {
738 pr_err("Invalid pwm_id: %d with %s\n",
739 pwm_id, label ? label : ".");
740 return ERR_PTR(-EINVAL);
741 }
742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 mutex_lock(&pwm_chip->pwm_mutex);
744 pwm = &pwm_chip->pwm_dev[pwm_id];
745 if (!pwm->in_use) {
746 pwm->in_use = 1;
747 pwm->label = label;
748 } else {
749 pwm = ERR_PTR(-EBUSY);
750 }
751 mutex_unlock(&pwm_chip->pwm_mutex);
752
753 return pwm;
754}
755EXPORT_SYMBOL_GPL(pwm_request);
756
757/**
758 * pwm_free - free a PWM device
759 * @pwm: the PWM device
760 */
761void pwm_free(struct pwm_device *pwm)
762{
763 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
764 pr_err("Invalid pwm handle\n");
765 return;
766 }
767
768 mutex_lock(&pwm->chip->pwm_mutex);
769 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700770 if (pwm_chip->is_lpg_supported) {
771 pm8xxx_pwm_bank_sel(pwm);
772 pm8xxx_pwm_start(pwm, 0, 0);
773 } else {
774 pm8xxx_pwm_disable(pwm);
775 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776 pwm->in_use = 0;
777 pwm->label = NULL;
778 }
Jay Chokshi57656862011-09-07 12:02:22 -0700779 if (pwm_chip->is_lpg_supported)
780 pm8xxx_pwm_bank_enable(pwm, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 mutex_unlock(&pwm->chip->pwm_mutex);
782}
783EXPORT_SYMBOL_GPL(pwm_free);
784
785/**
786 * pwm_config - change a PWM device configuration
787 * @pwm: the PWM device
788 * @period_us: period in microseconds
789 * @duty_us: duty cycle in microseconds
790 */
791int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
792{
Willie Ruan719c6762011-08-25 11:03:14 -0700793 struct pm8xxx_pwm_period *period;
Jay Chokshi57656862011-09-07 12:02:22 -0700794 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795
796 if (pwm == NULL || IS_ERR(pwm) ||
797 duty_us > period_us ||
798 (unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
799 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
800 pr_err("Invalid pwm handle or parameters\n");
801 return -EINVAL;
802 }
803 if (pwm->chip == NULL) {
804 pr_err("No pwm_chip\n");
805 return -ENODEV;
806 }
807
Willie Ruan719c6762011-08-25 11:03:14 -0700808 period = &pwm->period;
809
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 mutex_lock(&pwm->chip->pwm_mutex);
811
812 if (!pwm->in_use) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813 rc = -EINVAL;
814 goto out_unlock;
815 }
816
Willie Ruan8de2f382011-08-25 11:04:50 -0700817 if (pwm->pwm_period != period_us) {
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530818 pm8xxx_pwm_calc_period(period_us, pwm);
Willie Ruan8de2f382011-08-25 11:04:50 -0700819 pm8xxx_pwm_save_period(pwm);
820 pwm->pwm_period = period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822
Willie Ruan8de2f382011-08-25 11:04:50 -0700823 pm8xxx_pwm_calc_pwm_value(pwm, period_us, duty_us);
824 pm8xxx_pwm_save_pwm_value(pwm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825
Jay Chokshi57656862011-09-07 12:02:22 -0700826 if (pwm_chip->is_lpg_supported) {
827 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
828 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
829
830 pm8xxx_pwm_bank_sel(pwm);
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530831 rc = pm8xxx_lpg_pwm_write(pwm, 1, 7);
Jay Chokshi57656862011-09-07 12:02:22 -0700832 } else {
833 rc = pm8xxx_pwm_write(pwm);
834 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700835
836 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
837 (unsigned)duty_us, (unsigned)period_us,
838 pwm->pwm_value, 1 << period->pwm_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839
840out_unlock:
841 mutex_unlock(&pwm->chip->pwm_mutex);
842 return rc;
843}
844EXPORT_SYMBOL_GPL(pwm_config);
845
846/**
847 * pwm_enable - start a PWM output toggling
848 * @pwm: the PWM device
849 */
850int pwm_enable(struct pwm_device *pwm)
851{
Jay Chokshi57656862011-09-07 12:02:22 -0700852 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853
854 if (pwm == NULL || IS_ERR(pwm)) {
855 pr_err("Invalid pwm handle\n");
856 return -EINVAL;
857 }
858 if (pwm->chip == NULL) {
859 pr_err("No pwm_chip\n");
860 return -ENODEV;
861 }
862
863 mutex_lock(&pwm->chip->pwm_mutex);
864 if (!pwm->in_use) {
865 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
866 rc = -EINVAL;
867 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700868 if (pwm_chip->is_lpg_supported) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800869 if (pwm->dtest_mode_supported)
870 pm8xxx_pwm_set_dtest(pwm, 1);
Jay Chokshi90485222012-08-07 20:22:39 -0700871
Jay Chokshi57656862011-09-07 12:02:22 -0700872 pm8xxx_pwm_bank_sel(pwm);
Jay Chokshif3db97a2012-08-08 19:32:15 -0700873 rc = pm8xxx_pwm_bank_enable(pwm, 1);
Jay Chokshi57656862011-09-07 12:02:22 -0700874 pm8xxx_pwm_start(pwm, 1, 0);
Jay Chokshi90485222012-08-07 20:22:39 -0700875
876 /* In PM8038, due to hardware bug, PWM_VALUE register
877 * needs to be written one more time after enabling
878 * PWM mode.
879 */
880 if (pwm->chip->is_pwm_enable_sync_workaround_needed)
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530881 rc = pm8xxx_lpg_pwm_write(pwm, 3, 5);
Jay Chokshi90485222012-08-07 20:22:39 -0700882
Jay Chokshi57656862011-09-07 12:02:22 -0700883 } else {
884 pm8xxx_pwm_enable(pwm);
885 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 }
887 mutex_unlock(&pwm->chip->pwm_mutex);
888 return rc;
889}
890EXPORT_SYMBOL_GPL(pwm_enable);
891
892/**
893 * pwm_disable - stop a PWM output toggling
894 * @pwm: the PWM device
895 */
896void pwm_disable(struct pwm_device *pwm)
897{
898 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
899 pr_err("Invalid pwm handle or no pwm_chip\n");
900 return;
901 }
902
903 mutex_lock(&pwm->chip->pwm_mutex);
904 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700905 if (pwm_chip->is_lpg_supported) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800906 if (pwm->dtest_mode_supported)
907 pm8xxx_pwm_set_dtest(pwm, 0);
Jay Chokshi57656862011-09-07 12:02:22 -0700908 pm8xxx_pwm_bank_sel(pwm);
909 pm8xxx_pwm_start(pwm, 0, 0);
910 pm8xxx_pwm_bank_enable(pwm, 0);
911 } else {
912 pm8xxx_pwm_disable(pwm);
913 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700914 }
915 mutex_unlock(&pwm->chip->pwm_mutex);
916}
917EXPORT_SYMBOL_GPL(pwm_disable);
918
919/**
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700920 * pm8xxx_pwm_config_period - change PWM period
921 *
922 * @pwm: the PWM device
923 * @pwm_p: period in struct pm8xxx_pwm_period
924 */
925int pm8xxx_pwm_config_period(struct pwm_device *pwm,
926 struct pm8xxx_pwm_period *period)
927{
928 int rc;
929
930 if (pwm == NULL || IS_ERR(pwm) || period == NULL)
931 return -EINVAL;
932 if (pwm->chip == NULL)
933 return -ENODEV;
934
935 mutex_lock(&pwm->chip->pwm_mutex);
936
937 if (!pwm->in_use) {
938 rc = -EINVAL;
939 goto out_unlock;
940 }
941
942 pwm->period.pwm_size = period->pwm_size;
943 pwm->period.clk = period->clk;
944 pwm->period.pre_div = period->pre_div;
945 pwm->period.pre_div_exp = period->pre_div_exp;
946
947 pm8xxx_pwm_save_period(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700948
949 if (pwm_chip->is_lpg_supported) {
950 pm8xxx_pwm_bank_sel(pwm);
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530951 rc = pm8xxx_lpg_pwm_write(pwm, 4, 7);
Jay Chokshi57656862011-09-07 12:02:22 -0700952 } else {
953 rc = pm8xxx_pwm_write(pwm);
954 }
955
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700956
957out_unlock:
958 mutex_unlock(&pwm->chip->pwm_mutex);
959 return rc;
960}
961EXPORT_SYMBOL(pm8xxx_pwm_config_period);
962
963/**
964 * pm8xxx_pwm_config_pwm_value - change a PWM device configuration
965 * @pwm: the PWM device
966 * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
967 */
968int pm8xxx_pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
969{
970 int rc = 0;
971
972 if (pwm == NULL || IS_ERR(pwm))
973 return -EINVAL;
974 if (pwm->chip == NULL)
975 return -ENODEV;
976
977 mutex_lock(&pwm->chip->pwm_mutex);
978
979 if (!pwm->in_use || !pwm->pwm_period) {
980 rc = -EINVAL;
981 goto out_unlock;
982 }
983
984 if (pwm->pwm_value == pwm_value)
985 goto out_unlock;
986
987 pwm->pwm_value = pwm_value;
988
989 pm8xxx_pwm_save_pwm_value(pwm);
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700990
Jay Chokshi57656862011-09-07 12:02:22 -0700991 if (pwm_chip->is_lpg_supported) {
992 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
993 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
994 pm8xxx_pwm_bank_sel(pwm);
Prasad Sodagudidefd6422013-06-24 22:23:29 +0530995 rc = pm8xxx_lpg_pwm_write(pwm, 1, 7);
Jay Chokshi57656862011-09-07 12:02:22 -0700996 } else {
997 rc = pm8xxx_pwm_write(pwm);
998 }
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700999
1000 if (rc)
1001 pr_err("[%d]: pm8xxx_pwm_write: rc=%d\n", pwm->pwm_id, rc);
1002
1003out_unlock:
1004 mutex_unlock(&pwm->chip->pwm_mutex);
1005 return rc;
1006}
1007EXPORT_SYMBOL_GPL(pm8xxx_pwm_config_pwm_value);
1008
1009/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 * pm8xxx_pwm_lut_config - change a PWM device configuration to use LUT
1011 * @pwm: the PWM device
1012 * @period_us: period in microseconds
1013 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
1014 * @duty_time_ms: time for each duty cycle in milliseconds
1015 * @start_idx: start index in lookup table from 0 to MAX-1
1016 * @idx_len: number of index
1017 * @pause_lo: pause time in milliseconds at low index
1018 * @pause_hi: pause time in milliseconds at high index
1019 * @flags: control flags
1020 */
1021int pm8xxx_pwm_lut_config(struct pwm_device *pwm, int period_us,
1022 int duty_pct[], int duty_time_ms, int start_idx,
1023 int idx_len, int pause_lo, int pause_hi, int flags)
1024{
Willie Ruan719c6762011-08-25 11:03:14 -07001025 struct pm8xxx_pwm_lut lut;
Willie Ruan8de2f382011-08-25 11:04:50 -07001026 int len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 int rc;
1028
1029 if (pwm == NULL || IS_ERR(pwm) || !idx_len) {
1030 pr_err("Invalid pwm handle or idx_len=0\n");
1031 return -EINVAL;
1032 }
1033 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE)) {
1034 pr_err("Invalid duty_pct with flag\n");
1035 return -EINVAL;
1036 }
1037 if (pwm->chip == NULL) {
1038 pr_err("No pwm_chip\n");
1039 return -ENODEV;
1040 }
Jay Chokshi57656862011-09-07 12:02:22 -07001041
1042 if (pwm->chip->is_lpg_supported == 0) {
1043 pr_err("LPG module isn't supported\n");
1044 return -EINVAL;
1045 }
1046
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 if (idx_len >= PM_PWM_LUT_SIZE && start_idx) {
1048 pr_err("Wrong LUT size or index\n");
1049 return -EINVAL;
1050 }
1051 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE) {
1052 pr_err("Exceed LUT limit\n");
1053 return -EINVAL;
1054 }
1055 if ((unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
1056 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
1057 pr_err("Period out of range\n");
1058 return -EINVAL;
1059 }
1060
1061 mutex_lock(&pwm->chip->pwm_mutex);
1062
Prasad Sodagudi5af87922013-06-05 17:33:52 +05301063 if (flags & PM_PWM_BANK_HI)
1064 pwm->banks = PM_PWM_BANK_HI;
1065
1066 if (flags & PM_PWM_BANK_LO)
1067 pwm->banks |= PM_PWM_BANK_LO;
1068
1069 /*Enable both banks if banks information is not shared.*/
1070 if (!pwm->banks)
1071 pwm->banks |= (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
1072
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 if (!pwm->in_use) {
1074 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
1075 rc = -EINVAL;
1076 goto out_unlock;
1077 }
1078
Willie Ruan8de2f382011-08-25 11:04:50 -07001079 if (pwm->pwm_period != period_us) {
Prasad Sodagudidefd6422013-06-24 22:23:29 +05301080 pm8xxx_pwm_calc_period(period_us, pwm);
Willie Ruan8de2f382011-08-25 11:04:50 -07001081 pm8xxx_pwm_save_period(pwm);
1082 pwm->pwm_period = period_us;
1083 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084
1085 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
1086
1087 if (flags & PM_PWM_LUT_NO_TABLE)
1088 goto after_table_write;
1089
Willie Ruan8de2f382011-08-25 11:04:50 -07001090 rc = pm8xxx_pwm_change_table(pwm, duty_pct, start_idx, len, 0);
1091 if (rc) {
1092 pr_err("pm8xxx_pwm_change_table: rc=%d\n", rc);
1093 goto out_unlock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 }
1095
1096after_table_write:
Willie Ruan719c6762011-08-25 11:03:14 -07001097 lut.lut_duty_ms = duty_time_ms;
1098 lut.lut_lo_index = start_idx;
1099 lut.lut_hi_index = start_idx + len - 1;
1100 lut.lut_pause_lo = pause_lo;
1101 lut.lut_pause_hi = pause_hi;
1102 lut.flags = flags;
1103 pwm->bypass_lut = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104
Willie Ruan8de2f382011-08-25 11:04:50 -07001105 rc = pm8xxx_pwm_change_lut(pwm, &lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106
1107out_unlock:
1108 mutex_unlock(&pwm->chip->pwm_mutex);
1109 return rc;
1110}
1111EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_config);
1112
1113/**
1114 * pm8xxx_pwm_lut_enable - control a PWM device to start/stop LUT ramp
1115 * @pwm: the PWM device
1116 * @start: to start (1), or stop (0)
1117 */
1118int pm8xxx_pwm_lut_enable(struct pwm_device *pwm, int start)
1119{
1120 if (pwm == NULL || IS_ERR(pwm)) {
1121 pr_err("Invalid pwm handle\n");
1122 return -EINVAL;
1123 }
1124 if (pwm->chip == NULL) {
1125 pr_err("No pwm_chip\n");
1126 return -ENODEV;
1127 }
Jay Chokshi57656862011-09-07 12:02:22 -07001128 if (pwm->chip->is_lpg_supported == 0) {
1129 pr_err("LPG module isn't supported\n");
1130 return -EINVAL;
1131 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132
1133 mutex_lock(&pwm->chip->pwm_mutex);
1134 if (start) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001135 if (pwm->dtest_mode_supported)
1136 pm8xxx_pwm_set_dtest(pwm, 1);
1137
Jay Chokshif3db97a2012-08-08 19:32:15 -07001138 pm8xxx_pwm_bank_sel(pwm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 pm8xxx_pwm_bank_enable(pwm, 1);
1140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 pm8xxx_pwm_start(pwm, 1, 1);
1142 } else {
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001143 if (pwm->dtest_mode_supported)
1144 pm8xxx_pwm_set_dtest(pwm, 0);
1145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 pm8xxx_pwm_bank_sel(pwm);
1147 pm8xxx_pwm_start(pwm, 0, 0);
1148
1149 pm8xxx_pwm_bank_enable(pwm, 0);
1150 }
1151 mutex_unlock(&pwm->chip->pwm_mutex);
1152 return 0;
1153}
1154EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_enable);
1155
1156#if defined(CONFIG_DEBUG_FS)
1157
1158struct pm8xxx_pwm_dbg_device;
1159
1160struct pm8xxx_pwm_user {
1161 int pwm_id;
1162 struct pwm_device *pwm;
1163 int period;
1164 int duty_cycle;
1165 int enable;
1166 struct pm8xxx_pwm_dbg_device *dbgdev;
1167};
1168
1169struct pm8xxx_pwm_dbg_device {
1170 struct mutex dbg_mutex;
1171 struct device *dev;
1172 struct dentry *dent;
1173
Jay Chokshi57656862011-09-07 12:02:22 -07001174 struct pm8xxx_pwm_user *user;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175};
1176
1177static struct pm8xxx_pwm_dbg_device *pmic_dbg_device;
1178
1179static int dbg_pwm_check_period(int period)
1180{
1181 if (period < PM8XXX_PWM_PERIOD_MIN || period > PM8XXX_PWM_PERIOD_MAX) {
1182 pr_err("period is invalid: %d\n", period);
1183 return -EINVAL;
1184 }
1185 return 0;
1186}
1187
1188static int dbg_pwm_check_duty_cycle(int duty_cycle, const char *func_name)
1189{
1190 if (duty_cycle <= 0 || duty_cycle > 100) {
1191 pr_err("%s: duty_cycle is invalid: %d\n",
1192 func_name, duty_cycle);
1193 return -EINVAL;
1194 }
1195 return 0;
1196}
1197
1198static void dbg_pwm_check_handle(struct pm8xxx_pwm_user *puser)
1199{
1200 struct pwm_device *tmp;
1201
1202 if (puser->pwm == NULL) {
1203 tmp = pwm_request(puser->pwm_id, "pwm-dbg");
1204 if (PTR_ERR(puser->pwm)) {
1205 pr_err("pwm_request: err=%ld\n", PTR_ERR(puser->pwm));
1206 puser->pwm = NULL;
Willie Ruan10976ea2011-08-25 11:01:15 -07001207 } else {
1208 pr_debug("[id=%d] pwm_request ok\n", puser->pwm_id);
1209 puser->pwm = tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 }
1211 }
1212}
1213
1214static int dbg_pwm_enable_set(void *data, u64 val)
1215{
1216 struct pm8xxx_pwm_user *puser = data;
1217 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1218 int rc;
1219
1220 mutex_lock(&dbgdev->dbg_mutex);
1221 rc = dbg_pwm_check_duty_cycle(puser->duty_cycle, __func__);
1222 if (!rc) {
1223 puser->enable = val;
1224 dbg_pwm_check_handle(puser);
1225 if (puser->pwm) {
1226 if (puser->enable)
1227 pwm_enable(puser->pwm);
1228 else
1229 pwm_disable(puser->pwm);
1230 }
1231 }
1232 mutex_unlock(&dbgdev->dbg_mutex);
1233 return 0;
1234}
1235
1236static int dbg_pwm_enable_get(void *data, u64 *val)
1237{
1238 struct pm8xxx_pwm_user *puser = data;
1239 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1240
1241 mutex_lock(&dbgdev->dbg_mutex);
1242 *val = puser->enable;
1243 mutex_unlock(&dbgdev->dbg_mutex);
1244 return 0;
1245}
1246
1247DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_enable_fops,
1248 dbg_pwm_enable_get, dbg_pwm_enable_set,
1249 "%lld\n");
1250
1251static int dbg_pwm_duty_cycle_set(void *data, u64 val)
1252{
1253 struct pm8xxx_pwm_user *puser = data;
1254 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1255 int rc;
1256
1257 mutex_lock(&dbgdev->dbg_mutex);
1258 rc = dbg_pwm_check_duty_cycle(val, __func__);
1259 if (!rc) {
1260 puser->duty_cycle = val;
1261 dbg_pwm_check_handle(puser);
1262 if (puser->pwm) {
1263 int duty_us;
1264
Willie Ruan10976ea2011-08-25 11:01:15 -07001265 duty_us = puser->duty_cycle * puser->period / 100;
1266 pwm_config(puser->pwm, duty_us, puser->period);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 }
1268 }
1269 mutex_unlock(&dbgdev->dbg_mutex);
1270 return 0;
1271}
1272
1273static int dbg_pwm_duty_cycle_get(void *data, u64 *val)
1274{
1275 struct pm8xxx_pwm_user *puser = data;
1276 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1277
1278 mutex_lock(&dbgdev->dbg_mutex);
1279 *val = puser->duty_cycle;
1280 mutex_unlock(&dbgdev->dbg_mutex);
1281 return 0;
1282}
1283
1284DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_duty_cycle_fops,
1285 dbg_pwm_duty_cycle_get, dbg_pwm_duty_cycle_set,
1286 "%lld\n");
1287
1288static int dbg_pwm_period_set(void *data, u64 val)
1289{
1290 struct pm8xxx_pwm_user *puser = data;
1291 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1292 int rc;
1293
1294 mutex_lock(&dbgdev->dbg_mutex);
1295 rc = dbg_pwm_check_period(val);
1296 if (!rc)
1297 puser->period = val;
1298 mutex_unlock(&dbgdev->dbg_mutex);
1299 return 0;
1300}
1301
1302static int dbg_pwm_period_get(void *data, u64 *val)
1303{
1304 struct pm8xxx_pwm_user *puser = data;
1305 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1306
1307 mutex_lock(&dbgdev->dbg_mutex);
1308 *val = puser->period;
1309 mutex_unlock(&dbgdev->dbg_mutex);
1310 return 0;
1311}
1312
1313DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_period_fops,
1314 dbg_pwm_period_get, dbg_pwm_period_set, "%lld\n");
1315
1316static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1317{
1318 struct pm8xxx_pwm_dbg_device *dbgdev;
1319 struct dentry *dent;
1320 struct dentry *temp;
1321 struct pm8xxx_pwm_user *puser;
1322 int i;
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001323 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324
1325 if (dev == NULL) {
1326 pr_err("no parent data passed in.\n");
1327 return -EINVAL;
1328 }
1329
1330 dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
1331 if (dbgdev == NULL) {
1332 pr_err("kzalloc() failed.\n");
1333 return -ENOMEM;
1334 }
1335
Jay Chokshi57656862011-09-07 12:02:22 -07001336 dbgdev->user = kcalloc(pwm_chip->pwm_channels,
1337 sizeof(struct pm8xxx_pwm_user), GFP_KERNEL);
1338 if (dbgdev->user == NULL) {
1339 pr_err("kcalloc() failed.\n");
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001340 rc = -ENOMEM;
1341 goto user_error;
Jay Chokshi57656862011-09-07 12:02:22 -07001342 }
1343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001344 mutex_init(&dbgdev->dbg_mutex);
1345
1346 dbgdev->dev = dev;
1347
1348 dent = debugfs_create_dir("pm8xxx-pwm-dbg", NULL);
1349 if (dent == NULL || IS_ERR(dent)) {
1350 pr_err("ERR debugfs_create_dir: dent=%p\n", dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001351 rc = -ENOMEM;
1352 goto dir_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353 }
1354
1355 dbgdev->dent = dent;
1356
Jay Chokshi57656862011-09-07 12:02:22 -07001357 for (i = 0; i < pwm_chip->pwm_channels; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 char pwm_ch[] = "0";
1359
1360 pwm_ch[0] = '0' + i;
1361 dent = debugfs_create_dir(pwm_ch, dbgdev->dent);
1362 if (dent == NULL || IS_ERR(dent)) {
1363 pr_err("ERR: pwm=%d: dir: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001364 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 goto debug_error;
1366 }
1367
1368 puser = &dbgdev->user[i];
1369 puser->dbgdev = dbgdev;
1370 puser->pwm_id = i;
1371 temp = debugfs_create_file("period", S_IRUGO | S_IWUSR,
1372 dent, puser, &dbg_pwm_period_fops);
1373 if (temp == NULL || IS_ERR(temp)) {
1374 pr_err("ERR: pwm=%d: period: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001375 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 goto debug_error;
1377 }
1378
1379 temp = debugfs_create_file("duty-cycle", S_IRUGO | S_IWUSR,
1380 dent, puser, &dbg_pwm_duty_cycle_fops);
1381 if (temp == NULL || IS_ERR(temp)) {
1382 pr_err("ERR: pwm=%d: duty-cycle: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001383 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 goto debug_error;
1385 }
1386
1387 temp = debugfs_create_file("enable", S_IRUGO | S_IWUSR,
1388 dent, puser, &dbg_pwm_enable_fops);
1389 if (temp == NULL || IS_ERR(temp)) {
1390 pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001391 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 goto debug_error;
1393 }
1394 }
1395
1396 pmic_dbg_device = dbgdev;
1397
1398 return 0;
1399
1400debug_error:
1401 debugfs_remove_recursive(dbgdev->dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001402dir_error:
1403 kfree(dbgdev->user);
1404user_error:
1405 kfree(dbgdev);
1406 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407}
1408
1409static int __devexit pm8xxx_pwm_dbg_remove(void)
1410{
1411 if (pmic_dbg_device) {
Jay Chokshi57656862011-09-07 12:02:22 -07001412 kfree(pmic_dbg_device->user);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 debugfs_remove_recursive(pmic_dbg_device->dent);
1414 kfree(pmic_dbg_device);
1415 }
1416 return 0;
1417}
1418
1419#else
1420
1421static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1422{
1423 return 0;
1424}
1425
1426static int __devexit pm8xxx_pwm_dbg_remove(void)
1427{
1428 return 0;
1429}
1430
1431#endif
1432
1433static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
1434{
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001435 const struct pm8xxx_pwm_platform_data *pdata = pdev->dev.platform_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 struct pm8xxx_pwm_chip *chip;
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001437 int i, dtest_channel;
Jay Chokshi57656862011-09-07 12:02:22 -07001438 enum pm8xxx_version version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439
1440 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1441 if (chip == NULL) {
1442 pr_err("kzalloc() failed.\n");
1443 return -ENOMEM;
1444 }
1445
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001446 if (pdata != NULL)
1447 dtest_channel = pdata->dtest_channel;
1448 else
1449 dtest_channel = -1;
1450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 mutex_init(&chip->pwm_mutex);
1452
1453 chip->dev = &pdev->dev;
1454 pwm_chip = chip;
Jay Chokshi57656862011-09-07 12:02:22 -07001455
1456 version = pm8xxx_get_version(chip->dev->parent);
1457
1458 if (version == PM8XXX_VERSION_8921 ||
David Collins999480d2011-11-16 08:52:30 -08001459 version == PM8XXX_VERSION_8058 ||
Jay Chokshi0c220cd2011-12-09 17:18:20 -08001460 version == PM8XXX_VERSION_8922 ||
1461 version == PM8XXX_VERSION_8038) {
Jay Chokshi57656862011-09-07 12:02:22 -07001462 chip->is_lpg_supported = 1;
1463 }
Jay Chokshi90485222012-08-07 20:22:39 -07001464
1465 if (version == PM8XXX_VERSION_8038)
1466 chip->is_pwm_enable_sync_workaround_needed = 1;
1467 else
1468 chip->is_pwm_enable_sync_workaround_needed = 0;
1469
Jay Chokshi57656862011-09-07 12:02:22 -07001470 if (chip->is_lpg_supported) {
Jay Chokshi0c220cd2011-12-09 17:18:20 -08001471 if (version == PM8XXX_VERSION_8922 ||
1472 version == PM8XXX_VERSION_8038) {
1473 for (i = 0; i < NUM_CLOCKS; i++)
1474 pt_t[0][i] /= PRE_DIVIDE_2;
1475 chip->pwm_channels = PM8XXX_LPG_V1_PWM_CHANNELS;
1476 } else {
1477 chip->pwm_channels = PM8XXX_LPG_V0_PWM_CHANNELS;
1478 }
Jay Chokshi57656862011-09-07 12:02:22 -07001479 chip->pwm_total_pre_divs = NUM_LPG_PRE_DIVIDE;
1480 } else {
1481 chip->pwm_channels = PM8XXX_PWM_CHANNELS;
1482 chip->pwm_total_pre_divs = NUM_PWM_PRE_DIVIDE;
1483 }
1484
1485 chip->pwm_dev = kcalloc(chip->pwm_channels, sizeof(struct pwm_device),
1486 GFP_KERNEL);
1487 if (chip->pwm_dev == NULL) {
1488 pr_err("kcalloc() failed.\n");
1489 mutex_destroy(&chip->pwm_mutex);
1490 kfree(chip);
1491 return -ENOMEM;
1492 }
1493
1494 for (i = 0; i < chip->pwm_channels; i++) {
1495 chip->pwm_dev[i].pwm_id = i;
1496 chip->pwm_dev[i].chip = chip;
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001497 if (i == dtest_channel)
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001498 chip->pwm_dev[i].dtest_mode_supported = 1;
Jay Chokshi57656862011-09-07 12:02:22 -07001499 }
1500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501 platform_set_drvdata(pdev, chip);
1502
1503 if (pm8xxx_pwm_dbg_probe(&pdev->dev) < 0)
1504 pr_err("could not set up debugfs\n");
1505
1506 pr_notice("OK\n");
1507 return 0;
1508}
1509
1510static int __devexit pm8xxx_pwm_remove(struct platform_device *pdev)
1511{
1512 struct pm8xxx_pwm_chip *chip = dev_get_drvdata(pdev->dev.parent);
1513
1514 pm8xxx_pwm_dbg_remove();
Jay Chokshi57656862011-09-07 12:02:22 -07001515 kfree(chip->pwm_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 mutex_destroy(&chip->pwm_mutex);
1517 platform_set_drvdata(pdev, NULL);
1518 kfree(chip);
1519 return 0;
1520}
1521
1522static struct platform_driver pm8xxx_pwm_driver = {
1523 .probe = pm8xxx_pwm_probe,
1524 .remove = __devexit_p(pm8xxx_pwm_remove),
1525 .driver = {
1526 .name = PM8XXX_PWM_DEV_NAME,
1527 .owner = THIS_MODULE,
1528 },
1529};
1530
1531static int __init pm8xxx_pwm_init(void)
1532{
1533 return platform_driver_register(&pm8xxx_pwm_driver);
1534}
1535
1536static void __exit pm8xxx_pwm_exit(void)
1537{
1538 platform_driver_unregister(&pm8xxx_pwm_driver);
1539}
1540
1541subsys_initcall(pm8xxx_pwm_init);
1542module_exit(pm8xxx_pwm_exit);
1543
1544MODULE_LICENSE("GPL v2");
1545MODULE_DESCRIPTION("PM8XXX PWM driver");
1546MODULE_VERSION("1.0");
1547MODULE_ALIAS("platform:" PM8XXX_PWM_DEV_NAME);