blob: 0388484e9b025e4b416a7003e5484ec5b040b53c [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#define PM8XXX_LPG_CTL_REGS 7
39
40/* PM8XXX PWM */
Jay Chokshi57656862011-09-07 12:02:22 -070041#define SSBI_REG_ADDR_PWM1_CTRL1 0x88
42#define SSBI_REG_ADDR_PWM1_CTRL2 0x89
43#define SSBI_REG_ADDR_PWM_CTL(id, base) (id == 0 ? base : (base + (id << 1)))
44#define SSBI_REG_ADDR_PWM_CTL1(id) SSBI_REG_ADDR_PWM_CTL(id, \
45 SSBI_REG_ADDR_PWM1_CTRL1)
46#define SSBI_REG_ADDR_PWM_CTL2(id) SSBI_REG_ADDR_PWM_CTL(id, \
47 SSBI_REG_ADDR_PWM1_CTRL2)
48
49#define PM8XXX_PWM_CLK_SEL_SHIFT 6
50#define PM8XXX_PWM_CLK_SEL_MASK 0xC0
51#define PM8XXX_PWM_PREDIVIDE_SHIFT 5
52#define PM8XXX_PWM_PREDIVIDE_MASK 0x20
53#define PM8XXX_PWM_M_SHIFT 2
54#define PM8XXX_PWM_M_MASK 0x1C
55#define PM8XXX_PWM_SIZE_SHIFT 1
56#define PM8XXX_PWM_SIZE_MASK 0x02
57#define PM8XXX_PWM_VALUE_BIT0 0x01
58#define PM8XXX_PWM_DISABLE 0x3F
59
60/* PM8XXX LPG PWM */
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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069
Jay Chokshi57656862011-09-07 12:02:22 -070070/* LPG Control 0 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071#define PM8XXX_PWM_1KHZ_COUNT_MASK 0xF0
72#define PM8XXX_PWM_1KHZ_COUNT_SHIFT 4
73
74#define PM8XXX_PWM_1KHZ_COUNT_MAX 15
75
76#define PM8XXX_PWM_OUTPUT_EN 0x08
77#define PM8XXX_PWM_PWM_EN 0x04
78#define PM8XXX_PWM_RAMP_GEN_EN 0x02
79#define PM8XXX_PWM_RAMP_START 0x01
80
81#define PM8XXX_PWM_PWM_START (PM8XXX_PWM_OUTPUT_EN \
82 | PM8XXX_PWM_PWM_EN)
83#define PM8XXX_PWM_RAMP_GEN_START (PM8XXX_PWM_RAMP_GEN_EN \
84 | PM8XXX_PWM_RAMP_START)
85
Jay Chokshi57656862011-09-07 12:02:22 -070086/* LPG Control 1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087#define PM8XXX_PWM_REVERSE_EN 0x80
88#define PM8XXX_PWM_BYPASS_LUT 0x40
89#define PM8XXX_PWM_HIGH_INDEX_MASK 0x3F
90
Jay Chokshi57656862011-09-07 12:02:22 -070091/* LPG Control 2 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092#define PM8XXX_PWM_LOOP_EN 0x80
93#define PM8XXX_PWM_RAMP_UP 0x40
94#define PM8XXX_PWM_LOW_INDEX_MASK 0x3F
95
Jay Chokshi57656862011-09-07 12:02:22 -070096/* LPG Control 3 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097#define PM8XXX_PWM_VALUE_BIT7_0 0xFF
98#define PM8XXX_PWM_VALUE_BIT5_0 0x3F
99
Jay Chokshi57656862011-09-07 12:02:22 -0700100/* LPG Control 4 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101#define PM8XXX_PWM_VALUE_BIT8 0x80
102
Jay Chokshi57656862011-09-07 12:02:22 -0700103#define PM8XXX_LPG_PWM_CLK_SEL_MASK 0x60
104#define PM8XXX_LPG_PWM_CLK_SEL_SHIFT 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105
106#define PM8XXX_PWM_CLK_SEL_NO 0
107#define PM8XXX_PWM_CLK_SEL_1KHZ 1
108#define PM8XXX_PWM_CLK_SEL_32KHZ 2
109#define PM8XXX_PWM_CLK_SEL_19P2MHZ 3
110
Jay Chokshi57656862011-09-07 12:02:22 -0700111#define PM8XXX_LPG_PWM_PREDIVIDE_MASK 0x18
112#define PM8XXX_LPG_PWM_PREDIVIDE_SHIFT 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700113
114#define PM8XXX_PWM_PREDIVIDE_2 0
115#define PM8XXX_PWM_PREDIVIDE_3 1
116#define PM8XXX_PWM_PREDIVIDE_5 2
117#define PM8XXX_PWM_PREDIVIDE_6 3
118
Jay Chokshi57656862011-09-07 12:02:22 -0700119#define PM8XXX_LPG_PWM_M_MASK 0x07
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120#define PM8XXX_PWM_M_MIN 0
121#define PM8XXX_PWM_M_MAX 7
122
Jay Chokshi57656862011-09-07 12:02:22 -0700123/* LPG Control 5 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124#define PM8XXX_PWM_PAUSE_COUNT_HI_MASK 0xFC
125#define PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT 2
126
127#define PM8XXX_PWM_PAUSE_ENABLE_HIGH 0x02
128#define PM8XXX_PWM_SIZE_9_BIT 0x01
129
Jay Chokshi57656862011-09-07 12:02:22 -0700130/* LPG Control 6 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131#define PM8XXX_PWM_PAUSE_COUNT_LO_MASK 0xFC
132#define PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT 2
133
134#define PM8XXX_PWM_PAUSE_ENABLE_LOW 0x02
135#define PM8XXX_PWM_RESERVED 0x01
136
137#define PM8XXX_PWM_PAUSE_COUNT_MAX 56 /* < 2^6 = 64 */
138
Jay Chokshi57656862011-09-07 12:02:22 -0700139/* LPG LUT_CFG1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140#define PM8XXX_PWM_LUT_READ 0x40
141
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800142/* TEST */
143#define PM8XXX_PWM_DTEST_MASK 0x38
144#define PM8XXX_PWM_DTEST_SHIFT 3
145#define PM8XXX_PWM_DTEST_BANK_MASK 0x07
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147/*
148 * PWM Frequency = Clock Frequency / (N * T)
149 * or
150 * PWM Period = Clock Period * (N * T)
151 * where
152 * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
153 * T = Pre-divide * 2^m, where m = 0..7 (exponent)
154 *
155 * This is the formula to figure out m for the best pre-divide and clock:
Willie Ruan4a0a7002012-01-10 15:39:44 -0800156 * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 */
158#define NUM_CLOCKS 3
159
Willie Ruandb78e942012-01-10 15:00:28 -0800160#define NSEC_1024HZ (NSEC_PER_SEC / 1024)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
162#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
163
Willie Ruanb10be972012-01-12 11:30:11 -0800164#define NUM_LPG_PRE_DIVIDE 4
Jay Chokshi57656862011-09-07 12:02:22 -0700165#define NUM_PWM_PRE_DIVIDE 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166
Jay Chokshi0c220cd2011-12-09 17:18:20 -0800167#define PRE_DIVIDE_1 1 /* v1 */
Willie Ruanb10be972012-01-12 11:30:11 -0800168#define PRE_DIVIDE_2 2
169#define PRE_DIVIDE_3 3
170#define PRE_DIVIDE_5 5
171#define PRE_DIVIDE_6 6
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700172
Jay Chokshi57656862011-09-07 12:02:22 -0700173static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
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 },
Willie Ruanb10be972012-01-12 11:30:11 -0800178 { PRE_DIVIDE_3 * NSEC_1024HZ,
179 PRE_DIVIDE_3 * NSEC_32768HZ,
180 PRE_DIVIDE_3 * NSEC_19P2MHZ,
181 },
182 { PRE_DIVIDE_5 * NSEC_1024HZ,
183 PRE_DIVIDE_5 * NSEC_32768HZ,
184 PRE_DIVIDE_5 * NSEC_19P2MHZ,
185 },
186 { PRE_DIVIDE_6 * NSEC_1024HZ,
187 PRE_DIVIDE_6 * NSEC_32768HZ,
188 PRE_DIVIDE_6 * NSEC_19P2MHZ,
189 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190};
191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192/* Private data */
193struct pm8xxx_pwm_chip;
194
195struct pwm_device {
196 int pwm_id; /* = bank/channel id */
197 int in_use;
198 const char *label;
Willie Ruan719c6762011-08-25 11:03:14 -0700199 struct pm8xxx_pwm_period period;
200 int pwm_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 int pwm_period;
202 int pwm_duty;
Jay Chokshi57656862011-09-07 12:02:22 -0700203 u8 pwm_lpg_ctl[PM8XXX_LPG_CTL_REGS];
204 u8 pwm_ctl1;
205 u8 pwm_ctl2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206 int irq;
207 struct pm8xxx_pwm_chip *chip;
Willie Ruan719c6762011-08-25 11:03:14 -0700208 int bypass_lut;
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800209 int dtest_mode_supported;
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530210 int banks;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211};
212
213struct pm8xxx_pwm_chip {
Jay Chokshi57656862011-09-07 12:02:22 -0700214 struct pwm_device *pwm_dev;
215 u8 pwm_channels;
216 u8 pwm_total_pre_divs;
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530217 u8 lo_bank_mask;
218 u8 hi_bank_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219 struct mutex pwm_mutex;
220 struct device *dev;
Jay Chokshi57656862011-09-07 12:02:22 -0700221 bool is_lpg_supported;
Jay Chokshi90485222012-08-07 20:22:39 -0700222 bool is_pwm_enable_sync_workaround_needed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223};
224
225static struct pm8xxx_pwm_chip *pwm_chip;
226
Willie Ruan719c6762011-08-25 11:03:14 -0700227struct pm8xxx_pwm_lut {
228 /* LUT parameters */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 int lut_duty_ms;
230 int lut_lo_index;
231 int lut_hi_index;
232 int lut_pause_hi;
233 int lut_pause_lo;
234 int flags;
235};
236
237static const u16 duty_msec[PM8XXX_PWM_1KHZ_COUNT_MAX + 1] = {
238 0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
239};
240
241static const u16 pause_count[PM8XXX_PWM_PAUSE_COUNT_MAX + 1] = {
242 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
243 23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
244 375, 500, 667, 750, 800, 900, 1000, 1100,
245 1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
246 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
247 7000
248};
249
250/* Internal functions */
Willie Ruan8de2f382011-08-25 11:04:50 -0700251static void pm8xxx_pwm_save(u8 *u8p, u8 mask, u8 val)
252{
253 *u8p &= ~mask;
254 *u8p |= val & mask;
255}
256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257static int pm8xxx_pwm_bank_enable(struct pwm_device *pwm, int enable)
258{
259 int rc;
260 u8 reg;
261 struct pm8xxx_pwm_chip *chip;
262
263 chip = pwm->chip;
264
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530265 if (pwm->banks & PM_PWM_BANK_LO) {
266 if (enable)
267 reg = chip->lo_bank_mask | (1 << pwm->pwm_id);
268 else
269 reg = chip->lo_bank_mask & ~(1 << pwm->pwm_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530271 rc = pm8xxx_writeb(chip->dev->parent,
272 SSBI_REG_ADDR_LPG_BANK_LOW_EN, reg);
273 if (rc) {
274 pr_err("pm8xxx_writeb(): Enable Bank Low =%d\n", rc);
275 return rc;
276 }
277
278 chip->lo_bank_mask = reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280
Prasad Sodagudi5af87922013-06-05 17:33:52 +0530281 if (pwm->banks & PM_PWM_BANK_HI) {
282 if (enable)
283 reg = chip->hi_bank_mask | (1 << pwm->pwm_id);
284 else
285 reg = chip->hi_bank_mask & ~(1 << pwm->pwm_id);
286
287 rc = pm8xxx_writeb(chip->dev->parent,
288 SSBI_REG_ADDR_LPG_BANK_HIGH_EN, reg);
289 if (rc) {
290 pr_err("pm8xxx_writeb(): Enable Bank High =%d\n", rc);
291 return rc;
292 }
293
294 chip->hi_bank_mask = reg;
295 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 return 0;
297}
298
299static int pm8xxx_pwm_bank_sel(struct pwm_device *pwm)
300{
301 int rc;
302
303 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_SEL,
304 pwm->pwm_id);
305 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700306 pr_err("pm8xxx_writeb(): rc=%d (Select PWM Bank)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307 return rc;
308}
309
310static int pm8xxx_pwm_start(struct pwm_device *pwm, int start, int ramp_start)
311{
312 int rc;
313 u8 reg;
314
315 if (start) {
Jay Chokshi57656862011-09-07 12:02:22 -0700316 reg = pwm->pwm_lpg_ctl[0] | PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 if (ramp_start)
318 reg |= PM8XXX_PWM_RAMP_GEN_START;
319 else
320 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
321 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700322 reg = pwm->pwm_lpg_ctl[0] & ~PM8XXX_PWM_PWM_START;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 reg &= ~PM8XXX_PWM_RAMP_GEN_START;
324 }
325
326 rc = pm8xxx_writeb(pwm->chip->dev->parent, SSBI_REG_ADDR_LPG_CTL(0),
327 reg);
328 if (rc)
Willie Ruan8de2f382011-08-25 11:04:50 -0700329 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl 0)\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 else
Jay Chokshi57656862011-09-07 12:02:22 -0700331 pwm->pwm_lpg_ctl[0] = reg;
332 return rc;
333}
334
335static int pm8xxx_pwm_disable(struct pwm_device *pwm)
336{
337 int rc;
338 u8 reg;
339
340 reg = pwm->pwm_ctl1 & PM8XXX_PWM_DISABLE;
341
342 rc = pm8xxx_writeb(pwm->chip->dev->parent,
343 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), reg);
344
345 if (rc)
346 pr_err("pm8xxx_writeb(): rc=%d (Disable PWM Ctl %d)\n", rc,
347 pwm->pwm_id);
348 return rc;
349}
350
351static int pm8xxx_pwm_enable(struct pwm_device *pwm)
352{
353 /**
354 * A kind of best Effort: Just write the clock information that
355 * we have in the register.
356 */
357 int rc;
358
359 rc = pm8xxx_writeb(pwm->chip->dev->parent,
360 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id), pwm->pwm_ctl1);
361
362 if (rc)
363 pr_err("pm8xxx_writeb(): rc=%d (Enable PWM Ctl %d)\n", rc,
364 pwm->pwm_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 return rc;
366}
367
368static void pm8xxx_pwm_calc_period(unsigned int period_us,
Willie Ruan719c6762011-08-25 11:03:14 -0700369 struct pm8xxx_pwm_period *period)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370{
371 int n, m, clk, div;
372 int best_m, best_div, best_clk;
Willie Ruan4a0a7002012-01-10 15:39:44 -0800373 unsigned int last_err, cur_err, min_err;
374 unsigned int tmp_p, period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375
376 /* PWM Period / N */
Willie Ruan70f989d2012-01-10 10:09:36 -0800377 if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 period_n = (period_us * NSEC_PER_USEC) >> 6;
379 n = 6;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 } else {
381 period_n = (period_us >> 9) * NSEC_PER_USEC;
382 n = 9;
383 }
384
Willie Ruan4a0a7002012-01-10 15:39:44 -0800385 min_err = last_err = (unsigned)(-1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 best_m = 0;
387 best_clk = 0;
388 best_div = 0;
389 for (clk = 0; clk < NUM_CLOCKS; clk++) {
Jay Chokshi57656862011-09-07 12:02:22 -0700390 for (div = 0; div < pwm_chip->pwm_total_pre_divs; div++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800391 /* period_n = (PWM Period / N) */
392 /* tmp_p = (Pre-divide * Clock Period) * 2^m */
393 tmp_p = pt_t[div][clk];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 for (m = 0; m <= PM8XXX_PWM_M_MAX; m++) {
Willie Ruan4a0a7002012-01-10 15:39:44 -0800395 if (period_n > tmp_p)
396 cur_err = period_n - tmp_p;
397 else
398 cur_err = tmp_p - period_n;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399
Willie Ruan4a0a7002012-01-10 15:39:44 -0800400 if (cur_err < min_err) {
401 min_err = cur_err;
402 best_m = m;
403 best_clk = clk;
404 best_div = div;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 }
Willie Ruan4a0a7002012-01-10 15:39:44 -0800406
407 if (m && cur_err > last_err)
408 /* Break for bigger cur_err */
409 break;
410
411 last_err = cur_err;
412 tmp_p <<= 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413 }
414 }
415 }
416
Willie Ruan75d9e5b2011-08-25 10:59:17 -0700417 /* Use higher resolution */
418 if (best_m >= 3 && n == 6) {
419 n += 3;
420 best_m -= 3;
421 }
422
Willie Ruan719c6762011-08-25 11:03:14 -0700423 period->pwm_size = n;
424 period->clk = best_clk;
425 period->pre_div = best_div;
426 period->pre_div_exp = best_m;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427}
428
Willie Ruan8de2f382011-08-25 11:04:50 -0700429static void pm8xxx_pwm_calc_pwm_value(struct pwm_device *pwm,
430 unsigned int period_us,
431 unsigned int duty_us)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432{
Willie Ruan8de2f382011-08-25 11:04:50 -0700433 unsigned int max_pwm_value, tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434
Willie Ruan8de2f382011-08-25 11:04:50 -0700435 /* Figure out pwm_value with overflow handling */
436 tmp = 1 << (sizeof(tmp) * 8 - pwm->period.pwm_size);
437 if (duty_us < tmp) {
438 tmp = duty_us << pwm->period.pwm_size;
439 pwm->pwm_value = tmp / period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 } else {
Willie Ruan8de2f382011-08-25 11:04:50 -0700441 tmp = period_us >> pwm->period.pwm_size;
442 pwm->pwm_value = duty_us / tmp;
443 }
444 max_pwm_value = (1 << pwm->period.pwm_size) - 1;
445 if (pwm->pwm_value > max_pwm_value)
446 pwm->pwm_value = max_pwm_value;
447}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448
Willie Ruan8de2f382011-08-25 11:04:50 -0700449static int pm8xxx_pwm_change_table(struct pwm_device *pwm, int duty_pct[],
450 int start_idx, int len, int raw_value)
451{
452 unsigned int pwm_value, max_pwm_value;
453 u8 cfg0, cfg1;
454 int i, pwm_size;
455 int rc = 0;
456
Jay Chokshi57656862011-09-07 12:02:22 -0700457 pwm_size = (pwm->pwm_lpg_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
Willie Ruan8de2f382011-08-25 11:04:50 -0700458 max_pwm_value = (1 << pwm_size) - 1;
459 for (i = 0; i < len; i++) {
460 if (raw_value)
461 pwm_value = duty_pct[i];
462 else
463 pwm_value = (duty_pct[i] << pwm_size) / 100;
464
465 if (pwm_value > max_pwm_value)
466 pwm_value = max_pwm_value;
467 cfg0 = pwm_value;
468 cfg1 = (pwm_value >> 1) & 0x80;
469 cfg1 |= start_idx + i;
470
471 rc = pm8xxx_writeb(pwm->chip->dev->parent,
472 SSBI_REG_ADDR_LPG_LUT_CFG0, cfg0);
473 if (rc)
474 break;
475
476 rc = pm8xxx_writeb(pwm->chip->dev->parent,
477 SSBI_REG_ADDR_LPG_LUT_CFG1, cfg1);
478 if (rc)
479 break;
480 }
481 return rc;
482}
483
484static void pm8xxx_pwm_save_index(struct pwm_device *pwm,
485 int low_idx, int high_idx, int flags)
486{
Jay Chokshi57656862011-09-07 12:02:22 -0700487 pwm->pwm_lpg_ctl[1] = high_idx & PM8XXX_PWM_HIGH_INDEX_MASK;
488 pwm->pwm_lpg_ctl[2] = low_idx & PM8XXX_PWM_LOW_INDEX_MASK;
Willie Ruan8de2f382011-08-25 11:04:50 -0700489
490 if (flags & PM_PWM_LUT_REVERSE)
Jay Chokshi57656862011-09-07 12:02:22 -0700491 pwm->pwm_lpg_ctl[1] |= PM8XXX_PWM_REVERSE_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700492 if (flags & PM_PWM_LUT_RAMP_UP)
Jay Chokshi57656862011-09-07 12:02:22 -0700493 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_RAMP_UP;
Willie Ruan8de2f382011-08-25 11:04:50 -0700494 if (flags & PM_PWM_LUT_LOOP)
Jay Chokshi57656862011-09-07 12:02:22 -0700495 pwm->pwm_lpg_ctl[2] |= PM8XXX_PWM_LOOP_EN;
Willie Ruan8de2f382011-08-25 11:04:50 -0700496}
497
498static void pm8xxx_pwm_save_period(struct pwm_device *pwm)
499{
500 u8 mask, val;
501
Jay Chokshi57656862011-09-07 12:02:22 -0700502 if (pwm_chip->is_lpg_supported) {
503 val = ((pwm->period.clk + 1) << PM8XXX_LPG_PWM_CLK_SEL_SHIFT)
504 & PM8XXX_LPG_PWM_CLK_SEL_MASK;
505 val |= (pwm->period.pre_div << PM8XXX_LPG_PWM_PREDIVIDE_SHIFT)
506 & PM8XXX_LPG_PWM_PREDIVIDE_MASK;
507 val |= pwm->period.pre_div_exp & PM8XXX_LPG_PWM_M_MASK;
508 mask = PM8XXX_LPG_PWM_CLK_SEL_MASK |
509 PM8XXX_LPG_PWM_PREDIVIDE_MASK | PM8XXX_LPG_PWM_M_MASK;
510 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700511
Jay Chokshi57656862011-09-07 12:02:22 -0700512 val = (pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0;
513 mask = PM8XXX_PWM_SIZE_9_BIT;
514 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
515 } else {
516 val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
517 & PM8XXX_PWM_CLK_SEL_MASK;
518 val |= (pwm->period.pre_div << PM8XXX_PWM_PREDIVIDE_SHIFT)
519 & PM8XXX_PWM_PREDIVIDE_MASK;
520 val |= (pwm->period.pre_div_exp << PM8XXX_PWM_M_SHIFT)
521 & PM8XXX_PWM_M_MASK;
522 val |= (((pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0)
523 << PM8XXX_PWM_SIZE_SHIFT) & PM8XXX_PWM_SIZE_MASK;
524
525 mask = PM8XXX_PWM_CLK_SEL_MASK | PM8XXX_PWM_PREDIVIDE_MASK |
526 PM8XXX_PWM_M_MASK | PM8XXX_PWM_SIZE_MASK;
527 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
528 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700529}
530
531static void pm8xxx_pwm_save_pwm_value(struct pwm_device *pwm)
532{
533 u8 mask, val;
534
Jay Chokshi57656862011-09-07 12:02:22 -0700535 if (pwm_chip->is_lpg_supported) {
536 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 1) : 0;
537 pwm->pwm_lpg_ctl[3] = pwm->pwm_value;
538 mask = PM8XXX_PWM_VALUE_BIT8;
539 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
540 } else {
541 val = (pwm->period.pwm_size > 6) ? (pwm->pwm_value >> 8) : 0;
542 pwm->pwm_ctl2 = pwm->pwm_value;
543 mask = PM8XXX_PWM_VALUE_BIT0;
544 pm8xxx_pwm_save(&pwm->pwm_ctl1, mask, val);
545 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700546}
547
548static void pm8xxx_pwm_save_duty_time(struct pwm_device *pwm,
549 struct pm8xxx_pwm_lut *lut)
550{
551 int i;
552 u8 mask, val;
553
554 /* Linear search for duty time */
555 for (i = 0; i < PM8XXX_PWM_1KHZ_COUNT_MAX; i++) {
556 if (duty_msec[i] >= lut->lut_duty_ms)
557 break;
558 }
559 val = i << PM8XXX_PWM_1KHZ_COUNT_SHIFT;
560
561 mask = PM8XXX_PWM_1KHZ_COUNT_MASK;
Jay Chokshi57656862011-09-07 12:02:22 -0700562 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[0], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700563}
564
565static void pm8xxx_pwm_save_pause(struct pwm_device *pwm,
566 struct pm8xxx_pwm_lut *lut)
567{
568 int i, pause_cnt, time_cnt;
569 u8 mask, val;
570
Jay Chokshi57656862011-09-07 12:02:22 -0700571 time_cnt = (pwm->pwm_lpg_ctl[0] & PM8XXX_PWM_1KHZ_COUNT_MASK)
Willie Ruan8de2f382011-08-25 11:04:50 -0700572 >> PM8XXX_PWM_1KHZ_COUNT_SHIFT;
573 if (lut->flags & PM_PWM_LUT_PAUSE_HI_EN) {
574 pause_cnt = (lut->lut_pause_hi + duty_msec[time_cnt] / 2)
575 / duty_msec[time_cnt];
576 /* Linear search for pause time */
577 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
578 if (pause_count[i] >= pause_cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579 break;
580 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700581 val = (i << PM8XXX_PWM_PAUSE_COUNT_HI_SHIFT) &
582 PM8XXX_PWM_PAUSE_COUNT_HI_MASK;
583 val |= PM8XXX_PWM_PAUSE_ENABLE_HIGH;
584 } else {
585 val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586 }
587
Willie Ruan8de2f382011-08-25 11:04:50 -0700588 mask = PM8XXX_PWM_PAUSE_COUNT_HI_MASK | PM8XXX_PWM_PAUSE_ENABLE_HIGH;
Jay Chokshi57656862011-09-07 12:02:22 -0700589 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590
Willie Ruan8de2f382011-08-25 11:04:50 -0700591 if (lut->flags & PM_PWM_LUT_PAUSE_LO_EN) {
592 /* Linear search for pause time */
593 pause_cnt = (lut->lut_pause_lo + duty_msec[time_cnt] / 2)
594 / duty_msec[time_cnt];
595 for (i = 0; i < PM8XXX_PWM_PAUSE_COUNT_MAX; i++) {
596 if (pause_count[i] >= pause_cnt)
597 break;
598 }
599 val = (i << PM8XXX_PWM_PAUSE_COUNT_LO_SHIFT) &
600 PM8XXX_PWM_PAUSE_COUNT_LO_MASK;
601 val |= PM8XXX_PWM_PAUSE_ENABLE_LOW;
602 } else {
603 val = 0;
604 }
605
606 mask = PM8XXX_PWM_PAUSE_COUNT_LO_MASK | PM8XXX_PWM_PAUSE_ENABLE_LOW;
Jay Chokshi57656862011-09-07 12:02:22 -0700607 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[6], mask, val);
Willie Ruan8de2f382011-08-25 11:04:50 -0700608}
609
Jay Chokshi57656862011-09-07 12:02:22 -0700610static int pm8xxx_pwm_write(struct pwm_device *pwm)
611{
612 int rc = 0;
613
614 rc = pm8xxx_writeb(pwm->chip->dev->parent,
615 SSBI_REG_ADDR_PWM_CTL1(pwm->pwm_id),
616 pwm->pwm_ctl1);
617 if (rc) {
618 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl1[%d])\n",
619 rc, pwm->pwm_id);
620 return rc;
621 }
622
623 rc = pm8xxx_writeb(pwm->chip->dev->parent,
624 SSBI_REG_ADDR_PWM_CTL2(pwm->pwm_id),
625 pwm->pwm_ctl2);
626 if (rc) {
627 pr_err("pm8xxx_writeb() failed: rc=%d (PWM Ctl2[%d])\n",
628 rc, pwm->pwm_id);
629 return rc;
630 }
631
632 return rc;
633}
634
635static int pm8xxx_lpg_pwm_write(struct pwm_device *pwm, int start, int end)
Willie Ruan8de2f382011-08-25 11:04:50 -0700636{
637 int i, rc;
638
639 /* Write in reverse way so 0 would be the last */
640 for (i = end - 1; i >= start; i--) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641 rc = pm8xxx_writeb(pwm->chip->dev->parent,
642 SSBI_REG_ADDR_LPG_CTL(i),
Jay Chokshi57656862011-09-07 12:02:22 -0700643 pwm->pwm_lpg_ctl[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644 if (rc) {
Willie Ruan8de2f382011-08-25 11:04:50 -0700645 pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[%d])\n", rc, i);
646 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647 }
648 }
649
Willie Ruan8de2f382011-08-25 11:04:50 -0700650 return 0;
651}
652
653static int pm8xxx_pwm_change_lut(struct pwm_device *pwm,
654 struct pm8xxx_pwm_lut *lut)
655{
656 int rc;
657
658 pm8xxx_pwm_save_index(pwm, lut->lut_lo_index,
659 lut->lut_hi_index, lut->flags);
660 pm8xxx_pwm_save_duty_time(pwm, lut);
661 pm8xxx_pwm_save_pause(pwm, lut);
Jay Chokshi57656862011-09-07 12:02:22 -0700662 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1], PM8XXX_PWM_BYPASS_LUT, 0);
Willie Ruan8de2f382011-08-25 11:04:50 -0700663
664 pm8xxx_pwm_bank_sel(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700665 rc = pm8xxx_lpg_pwm_write(pwm, 0, 7);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666
667 return rc;
668}
669
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800670static int pm8xxx_pwm_set_dtest(struct pwm_device *pwm, int enable)
671{
672 int rc;
673 u8 reg;
674
675 reg = pwm->pwm_id & PM8XXX_PWM_DTEST_BANK_MASK;
676
677 if (enable) {
678 /* Observe LPG_OUT on DTEST1*/
679 reg |= (1 << PM8XXX_PWM_DTEST_SHIFT) &
680 PM8XXX_PWM_DTEST_MASK;
681 }
682
683 rc = pm8xxx_writeb(pwm->chip->dev->parent,
684 SSBI_REG_ADDR_LPG_TEST, reg);
685 if (rc)
686 pr_err("pm8xxx_write(DTEST=0x%x) failed: rc=%d\n",
687 reg, rc);
688
689 return rc;
690}
691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692/* APIs */
693/**
694 * pwm_request - request a PWM device
695 * @pwm_id: PWM id or channel
696 * @label: the label to identify the user
697 */
698struct pwm_device *pwm_request(int pwm_id, const char *label)
699{
700 struct pwm_device *pwm;
701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 if (pwm_chip == NULL) {
703 pr_err("No pwm_chip\n");
704 return ERR_PTR(-ENODEV);
705 }
706
Jay Chokshi57656862011-09-07 12:02:22 -0700707 if (pwm_id >= pwm_chip->pwm_channels || pwm_id < 0) {
708 pr_err("Invalid pwm_id: %d with %s\n",
709 pwm_id, label ? label : ".");
710 return ERR_PTR(-EINVAL);
711 }
712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 mutex_lock(&pwm_chip->pwm_mutex);
714 pwm = &pwm_chip->pwm_dev[pwm_id];
715 if (!pwm->in_use) {
716 pwm->in_use = 1;
717 pwm->label = label;
718 } else {
719 pwm = ERR_PTR(-EBUSY);
720 }
721 mutex_unlock(&pwm_chip->pwm_mutex);
722
723 return pwm;
724}
725EXPORT_SYMBOL_GPL(pwm_request);
726
727/**
728 * pwm_free - free a PWM device
729 * @pwm: the PWM device
730 */
731void pwm_free(struct pwm_device *pwm)
732{
733 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
734 pr_err("Invalid pwm handle\n");
735 return;
736 }
737
738 mutex_lock(&pwm->chip->pwm_mutex);
739 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700740 if (pwm_chip->is_lpg_supported) {
741 pm8xxx_pwm_bank_sel(pwm);
742 pm8xxx_pwm_start(pwm, 0, 0);
743 } else {
744 pm8xxx_pwm_disable(pwm);
745 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 pwm->in_use = 0;
747 pwm->label = NULL;
748 }
Jay Chokshi57656862011-09-07 12:02:22 -0700749 if (pwm_chip->is_lpg_supported)
750 pm8xxx_pwm_bank_enable(pwm, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 mutex_unlock(&pwm->chip->pwm_mutex);
752}
753EXPORT_SYMBOL_GPL(pwm_free);
754
755/**
756 * pwm_config - change a PWM device configuration
757 * @pwm: the PWM device
758 * @period_us: period in microseconds
759 * @duty_us: duty cycle in microseconds
760 */
761int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
762{
Willie Ruan719c6762011-08-25 11:03:14 -0700763 struct pm8xxx_pwm_period *period;
Jay Chokshi57656862011-09-07 12:02:22 -0700764 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765
766 if (pwm == NULL || IS_ERR(pwm) ||
767 duty_us > period_us ||
768 (unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
769 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
770 pr_err("Invalid pwm handle or parameters\n");
771 return -EINVAL;
772 }
773 if (pwm->chip == NULL) {
774 pr_err("No pwm_chip\n");
775 return -ENODEV;
776 }
777
Willie Ruan719c6762011-08-25 11:03:14 -0700778 period = &pwm->period;
779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780 mutex_lock(&pwm->chip->pwm_mutex);
781
782 if (!pwm->in_use) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783 rc = -EINVAL;
784 goto out_unlock;
785 }
786
Willie Ruan8de2f382011-08-25 11:04:50 -0700787 if (pwm->pwm_period != period_us) {
788 pm8xxx_pwm_calc_period(period_us, period);
789 pm8xxx_pwm_save_period(pwm);
790 pwm->pwm_period = period_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792
Willie Ruan8de2f382011-08-25 11:04:50 -0700793 pm8xxx_pwm_calc_pwm_value(pwm, period_us, duty_us);
794 pm8xxx_pwm_save_pwm_value(pwm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795
Jay Chokshi57656862011-09-07 12:02:22 -0700796 if (pwm_chip->is_lpg_supported) {
797 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
798 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
799
800 pm8xxx_pwm_bank_sel(pwm);
801 rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
802 } else {
803 rc = pm8xxx_pwm_write(pwm);
804 }
Willie Ruan8de2f382011-08-25 11:04:50 -0700805
806 pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
807 (unsigned)duty_us, (unsigned)period_us,
808 pwm->pwm_value, 1 << period->pwm_size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700809
810out_unlock:
811 mutex_unlock(&pwm->chip->pwm_mutex);
812 return rc;
813}
814EXPORT_SYMBOL_GPL(pwm_config);
815
816/**
817 * pwm_enable - start a PWM output toggling
818 * @pwm: the PWM device
819 */
820int pwm_enable(struct pwm_device *pwm)
821{
Jay Chokshi57656862011-09-07 12:02:22 -0700822 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823
824 if (pwm == NULL || IS_ERR(pwm)) {
825 pr_err("Invalid pwm handle\n");
826 return -EINVAL;
827 }
828 if (pwm->chip == NULL) {
829 pr_err("No pwm_chip\n");
830 return -ENODEV;
831 }
832
833 mutex_lock(&pwm->chip->pwm_mutex);
834 if (!pwm->in_use) {
835 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
836 rc = -EINVAL;
837 } else {
Jay Chokshi57656862011-09-07 12:02:22 -0700838 if (pwm_chip->is_lpg_supported) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800839 if (pwm->dtest_mode_supported)
840 pm8xxx_pwm_set_dtest(pwm, 1);
Jay Chokshi90485222012-08-07 20:22:39 -0700841
Jay Chokshi57656862011-09-07 12:02:22 -0700842 pm8xxx_pwm_bank_sel(pwm);
Jay Chokshif3db97a2012-08-08 19:32:15 -0700843 rc = pm8xxx_pwm_bank_enable(pwm, 1);
Jay Chokshi57656862011-09-07 12:02:22 -0700844 pm8xxx_pwm_start(pwm, 1, 0);
Jay Chokshi90485222012-08-07 20:22:39 -0700845
846 /* In PM8038, due to hardware bug, PWM_VALUE register
847 * needs to be written one more time after enabling
848 * PWM mode.
849 */
850 if (pwm->chip->is_pwm_enable_sync_workaround_needed)
851 rc = pm8xxx_lpg_pwm_write(pwm, 3, 4);
852
Jay Chokshi57656862011-09-07 12:02:22 -0700853 } else {
854 pm8xxx_pwm_enable(pwm);
855 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856 }
857 mutex_unlock(&pwm->chip->pwm_mutex);
858 return rc;
859}
860EXPORT_SYMBOL_GPL(pwm_enable);
861
862/**
863 * pwm_disable - stop a PWM output toggling
864 * @pwm: the PWM device
865 */
866void pwm_disable(struct pwm_device *pwm)
867{
868 if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
869 pr_err("Invalid pwm handle or no pwm_chip\n");
870 return;
871 }
872
873 mutex_lock(&pwm->chip->pwm_mutex);
874 if (pwm->in_use) {
Jay Chokshi57656862011-09-07 12:02:22 -0700875 if (pwm_chip->is_lpg_supported) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -0800876 if (pwm->dtest_mode_supported)
877 pm8xxx_pwm_set_dtest(pwm, 0);
Jay Chokshi57656862011-09-07 12:02:22 -0700878 pm8xxx_pwm_bank_sel(pwm);
879 pm8xxx_pwm_start(pwm, 0, 0);
880 pm8xxx_pwm_bank_enable(pwm, 0);
881 } else {
882 pm8xxx_pwm_disable(pwm);
883 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884 }
885 mutex_unlock(&pwm->chip->pwm_mutex);
886}
887EXPORT_SYMBOL_GPL(pwm_disable);
888
889/**
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700890 * pm8xxx_pwm_config_period - change PWM period
891 *
892 * @pwm: the PWM device
893 * @pwm_p: period in struct pm8xxx_pwm_period
894 */
895int pm8xxx_pwm_config_period(struct pwm_device *pwm,
896 struct pm8xxx_pwm_period *period)
897{
898 int rc;
899
900 if (pwm == NULL || IS_ERR(pwm) || period == NULL)
901 return -EINVAL;
902 if (pwm->chip == NULL)
903 return -ENODEV;
904
905 mutex_lock(&pwm->chip->pwm_mutex);
906
907 if (!pwm->in_use) {
908 rc = -EINVAL;
909 goto out_unlock;
910 }
911
912 pwm->period.pwm_size = period->pwm_size;
913 pwm->period.clk = period->clk;
914 pwm->period.pre_div = period->pre_div;
915 pwm->period.pre_div_exp = period->pre_div_exp;
916
917 pm8xxx_pwm_save_period(pwm);
Jay Chokshi57656862011-09-07 12:02:22 -0700918
919 if (pwm_chip->is_lpg_supported) {
920 pm8xxx_pwm_bank_sel(pwm);
921 rc = pm8xxx_lpg_pwm_write(pwm, 4, 6);
922 } else {
923 rc = pm8xxx_pwm_write(pwm);
924 }
925
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700926
927out_unlock:
928 mutex_unlock(&pwm->chip->pwm_mutex);
929 return rc;
930}
931EXPORT_SYMBOL(pm8xxx_pwm_config_period);
932
933/**
934 * pm8xxx_pwm_config_pwm_value - change a PWM device configuration
935 * @pwm: the PWM device
936 * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
937 */
938int pm8xxx_pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
939{
940 int rc = 0;
941
942 if (pwm == NULL || IS_ERR(pwm))
943 return -EINVAL;
944 if (pwm->chip == NULL)
945 return -ENODEV;
946
947 mutex_lock(&pwm->chip->pwm_mutex);
948
949 if (!pwm->in_use || !pwm->pwm_period) {
950 rc = -EINVAL;
951 goto out_unlock;
952 }
953
954 if (pwm->pwm_value == pwm_value)
955 goto out_unlock;
956
957 pwm->pwm_value = pwm_value;
958
959 pm8xxx_pwm_save_pwm_value(pwm);
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700960
Jay Chokshi57656862011-09-07 12:02:22 -0700961 if (pwm_chip->is_lpg_supported) {
962 pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
963 PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
964 pm8xxx_pwm_bank_sel(pwm);
965 rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
966 } else {
967 rc = pm8xxx_pwm_write(pwm);
968 }
Jay Chokshi4acbdd52011-09-16 17:09:44 -0700969
970 if (rc)
971 pr_err("[%d]: pm8xxx_pwm_write: rc=%d\n", pwm->pwm_id, rc);
972
973out_unlock:
974 mutex_unlock(&pwm->chip->pwm_mutex);
975 return rc;
976}
977EXPORT_SYMBOL_GPL(pm8xxx_pwm_config_pwm_value);
978
979/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980 * pm8xxx_pwm_lut_config - change a PWM device configuration to use LUT
981 * @pwm: the PWM device
982 * @period_us: period in microseconds
983 * @duty_pct: arrary of duty cycles in percent, like 20, 50.
984 * @duty_time_ms: time for each duty cycle in milliseconds
985 * @start_idx: start index in lookup table from 0 to MAX-1
986 * @idx_len: number of index
987 * @pause_lo: pause time in milliseconds at low index
988 * @pause_hi: pause time in milliseconds at high index
989 * @flags: control flags
990 */
991int pm8xxx_pwm_lut_config(struct pwm_device *pwm, int period_us,
992 int duty_pct[], int duty_time_ms, int start_idx,
993 int idx_len, int pause_lo, int pause_hi, int flags)
994{
Willie Ruan719c6762011-08-25 11:03:14 -0700995 struct pm8xxx_pwm_lut lut;
996 struct pm8xxx_pwm_period *period;
Willie Ruan8de2f382011-08-25 11:04:50 -0700997 int len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 int rc;
999
1000 if (pwm == NULL || IS_ERR(pwm) || !idx_len) {
1001 pr_err("Invalid pwm handle or idx_len=0\n");
1002 return -EINVAL;
1003 }
1004 if (duty_pct == NULL && !(flags & PM_PWM_LUT_NO_TABLE)) {
1005 pr_err("Invalid duty_pct with flag\n");
1006 return -EINVAL;
1007 }
1008 if (pwm->chip == NULL) {
1009 pr_err("No pwm_chip\n");
1010 return -ENODEV;
1011 }
Jay Chokshi57656862011-09-07 12:02:22 -07001012
1013 if (pwm->chip->is_lpg_supported == 0) {
1014 pr_err("LPG module isn't supported\n");
1015 return -EINVAL;
1016 }
1017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 if (idx_len >= PM_PWM_LUT_SIZE && start_idx) {
1019 pr_err("Wrong LUT size or index\n");
1020 return -EINVAL;
1021 }
1022 if ((start_idx + idx_len) > PM_PWM_LUT_SIZE) {
1023 pr_err("Exceed LUT limit\n");
1024 return -EINVAL;
1025 }
1026 if ((unsigned)period_us > PM8XXX_PWM_PERIOD_MAX ||
1027 (unsigned)period_us < PM8XXX_PWM_PERIOD_MIN) {
1028 pr_err("Period out of range\n");
1029 return -EINVAL;
1030 }
1031
Willie Ruan719c6762011-08-25 11:03:14 -07001032 period = &pwm->period;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 mutex_lock(&pwm->chip->pwm_mutex);
1034
Prasad Sodagudi5af87922013-06-05 17:33:52 +05301035 if (flags & PM_PWM_BANK_HI)
1036 pwm->banks = PM_PWM_BANK_HI;
1037
1038 if (flags & PM_PWM_BANK_LO)
1039 pwm->banks |= PM_PWM_BANK_LO;
1040
1041 /*Enable both banks if banks information is not shared.*/
1042 if (!pwm->banks)
1043 pwm->banks |= (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
1044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 if (!pwm->in_use) {
1046 pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
1047 rc = -EINVAL;
1048 goto out_unlock;
1049 }
1050
Willie Ruan8de2f382011-08-25 11:04:50 -07001051 if (pwm->pwm_period != period_us) {
1052 pm8xxx_pwm_calc_period(period_us, period);
1053 pm8xxx_pwm_save_period(pwm);
1054 pwm->pwm_period = period_us;
1055 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056
1057 len = (idx_len > PM_PWM_LUT_SIZE) ? PM_PWM_LUT_SIZE : idx_len;
1058
1059 if (flags & PM_PWM_LUT_NO_TABLE)
1060 goto after_table_write;
1061
Willie Ruan8de2f382011-08-25 11:04:50 -07001062 rc = pm8xxx_pwm_change_table(pwm, duty_pct, start_idx, len, 0);
1063 if (rc) {
1064 pr_err("pm8xxx_pwm_change_table: rc=%d\n", rc);
1065 goto out_unlock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 }
1067
1068after_table_write:
Willie Ruan719c6762011-08-25 11:03:14 -07001069 lut.lut_duty_ms = duty_time_ms;
1070 lut.lut_lo_index = start_idx;
1071 lut.lut_hi_index = start_idx + len - 1;
1072 lut.lut_pause_lo = pause_lo;
1073 lut.lut_pause_hi = pause_hi;
1074 lut.flags = flags;
1075 pwm->bypass_lut = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076
Willie Ruan8de2f382011-08-25 11:04:50 -07001077 rc = pm8xxx_pwm_change_lut(pwm, &lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078
1079out_unlock:
1080 mutex_unlock(&pwm->chip->pwm_mutex);
1081 return rc;
1082}
1083EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_config);
1084
1085/**
1086 * pm8xxx_pwm_lut_enable - control a PWM device to start/stop LUT ramp
1087 * @pwm: the PWM device
1088 * @start: to start (1), or stop (0)
1089 */
1090int pm8xxx_pwm_lut_enable(struct pwm_device *pwm, int start)
1091{
1092 if (pwm == NULL || IS_ERR(pwm)) {
1093 pr_err("Invalid pwm handle\n");
1094 return -EINVAL;
1095 }
1096 if (pwm->chip == NULL) {
1097 pr_err("No pwm_chip\n");
1098 return -ENODEV;
1099 }
Jay Chokshi57656862011-09-07 12:02:22 -07001100 if (pwm->chip->is_lpg_supported == 0) {
1101 pr_err("LPG module isn't supported\n");
1102 return -EINVAL;
1103 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104
1105 mutex_lock(&pwm->chip->pwm_mutex);
1106 if (start) {
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001107 if (pwm->dtest_mode_supported)
1108 pm8xxx_pwm_set_dtest(pwm, 1);
1109
Jay Chokshif3db97a2012-08-08 19:32:15 -07001110 pm8xxx_pwm_bank_sel(pwm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111 pm8xxx_pwm_bank_enable(pwm, 1);
1112
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001113 pm8xxx_pwm_start(pwm, 1, 1);
1114 } else {
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001115 if (pwm->dtest_mode_supported)
1116 pm8xxx_pwm_set_dtest(pwm, 0);
1117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 pm8xxx_pwm_bank_sel(pwm);
1119 pm8xxx_pwm_start(pwm, 0, 0);
1120
1121 pm8xxx_pwm_bank_enable(pwm, 0);
1122 }
1123 mutex_unlock(&pwm->chip->pwm_mutex);
1124 return 0;
1125}
1126EXPORT_SYMBOL_GPL(pm8xxx_pwm_lut_enable);
1127
1128#if defined(CONFIG_DEBUG_FS)
1129
1130struct pm8xxx_pwm_dbg_device;
1131
1132struct pm8xxx_pwm_user {
1133 int pwm_id;
1134 struct pwm_device *pwm;
1135 int period;
1136 int duty_cycle;
1137 int enable;
1138 struct pm8xxx_pwm_dbg_device *dbgdev;
1139};
1140
1141struct pm8xxx_pwm_dbg_device {
1142 struct mutex dbg_mutex;
1143 struct device *dev;
1144 struct dentry *dent;
1145
Jay Chokshi57656862011-09-07 12:02:22 -07001146 struct pm8xxx_pwm_user *user;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147};
1148
1149static struct pm8xxx_pwm_dbg_device *pmic_dbg_device;
1150
1151static int dbg_pwm_check_period(int period)
1152{
1153 if (period < PM8XXX_PWM_PERIOD_MIN || period > PM8XXX_PWM_PERIOD_MAX) {
1154 pr_err("period is invalid: %d\n", period);
1155 return -EINVAL;
1156 }
1157 return 0;
1158}
1159
1160static int dbg_pwm_check_duty_cycle(int duty_cycle, const char *func_name)
1161{
1162 if (duty_cycle <= 0 || duty_cycle > 100) {
1163 pr_err("%s: duty_cycle is invalid: %d\n",
1164 func_name, duty_cycle);
1165 return -EINVAL;
1166 }
1167 return 0;
1168}
1169
1170static void dbg_pwm_check_handle(struct pm8xxx_pwm_user *puser)
1171{
1172 struct pwm_device *tmp;
1173
1174 if (puser->pwm == NULL) {
1175 tmp = pwm_request(puser->pwm_id, "pwm-dbg");
1176 if (PTR_ERR(puser->pwm)) {
1177 pr_err("pwm_request: err=%ld\n", PTR_ERR(puser->pwm));
1178 puser->pwm = NULL;
Willie Ruan10976ea2011-08-25 11:01:15 -07001179 } else {
1180 pr_debug("[id=%d] pwm_request ok\n", puser->pwm_id);
1181 puser->pwm = tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 }
1183 }
1184}
1185
1186static int dbg_pwm_enable_set(void *data, u64 val)
1187{
1188 struct pm8xxx_pwm_user *puser = data;
1189 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1190 int rc;
1191
1192 mutex_lock(&dbgdev->dbg_mutex);
1193 rc = dbg_pwm_check_duty_cycle(puser->duty_cycle, __func__);
1194 if (!rc) {
1195 puser->enable = val;
1196 dbg_pwm_check_handle(puser);
1197 if (puser->pwm) {
1198 if (puser->enable)
1199 pwm_enable(puser->pwm);
1200 else
1201 pwm_disable(puser->pwm);
1202 }
1203 }
1204 mutex_unlock(&dbgdev->dbg_mutex);
1205 return 0;
1206}
1207
1208static int dbg_pwm_enable_get(void *data, u64 *val)
1209{
1210 struct pm8xxx_pwm_user *puser = data;
1211 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1212
1213 mutex_lock(&dbgdev->dbg_mutex);
1214 *val = puser->enable;
1215 mutex_unlock(&dbgdev->dbg_mutex);
1216 return 0;
1217}
1218
1219DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_enable_fops,
1220 dbg_pwm_enable_get, dbg_pwm_enable_set,
1221 "%lld\n");
1222
1223static int dbg_pwm_duty_cycle_set(void *data, u64 val)
1224{
1225 struct pm8xxx_pwm_user *puser = data;
1226 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1227 int rc;
1228
1229 mutex_lock(&dbgdev->dbg_mutex);
1230 rc = dbg_pwm_check_duty_cycle(val, __func__);
1231 if (!rc) {
1232 puser->duty_cycle = val;
1233 dbg_pwm_check_handle(puser);
1234 if (puser->pwm) {
1235 int duty_us;
1236
Willie Ruan10976ea2011-08-25 11:01:15 -07001237 duty_us = puser->duty_cycle * puser->period / 100;
1238 pwm_config(puser->pwm, duty_us, puser->period);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 }
1240 }
1241 mutex_unlock(&dbgdev->dbg_mutex);
1242 return 0;
1243}
1244
1245static int dbg_pwm_duty_cycle_get(void *data, u64 *val)
1246{
1247 struct pm8xxx_pwm_user *puser = data;
1248 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1249
1250 mutex_lock(&dbgdev->dbg_mutex);
1251 *val = puser->duty_cycle;
1252 mutex_unlock(&dbgdev->dbg_mutex);
1253 return 0;
1254}
1255
1256DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_duty_cycle_fops,
1257 dbg_pwm_duty_cycle_get, dbg_pwm_duty_cycle_set,
1258 "%lld\n");
1259
1260static int dbg_pwm_period_set(void *data, u64 val)
1261{
1262 struct pm8xxx_pwm_user *puser = data;
1263 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1264 int rc;
1265
1266 mutex_lock(&dbgdev->dbg_mutex);
1267 rc = dbg_pwm_check_period(val);
1268 if (!rc)
1269 puser->period = val;
1270 mutex_unlock(&dbgdev->dbg_mutex);
1271 return 0;
1272}
1273
1274static int dbg_pwm_period_get(void *data, u64 *val)
1275{
1276 struct pm8xxx_pwm_user *puser = data;
1277 struct pm8xxx_pwm_dbg_device *dbgdev = puser->dbgdev;
1278
1279 mutex_lock(&dbgdev->dbg_mutex);
1280 *val = puser->period;
1281 mutex_unlock(&dbgdev->dbg_mutex);
1282 return 0;
1283}
1284
1285DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_period_fops,
1286 dbg_pwm_period_get, dbg_pwm_period_set, "%lld\n");
1287
1288static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1289{
1290 struct pm8xxx_pwm_dbg_device *dbgdev;
1291 struct dentry *dent;
1292 struct dentry *temp;
1293 struct pm8xxx_pwm_user *puser;
1294 int i;
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001295 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296
1297 if (dev == NULL) {
1298 pr_err("no parent data passed in.\n");
1299 return -EINVAL;
1300 }
1301
1302 dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
1303 if (dbgdev == NULL) {
1304 pr_err("kzalloc() failed.\n");
1305 return -ENOMEM;
1306 }
1307
Jay Chokshi57656862011-09-07 12:02:22 -07001308 dbgdev->user = kcalloc(pwm_chip->pwm_channels,
1309 sizeof(struct pm8xxx_pwm_user), GFP_KERNEL);
1310 if (dbgdev->user == NULL) {
1311 pr_err("kcalloc() failed.\n");
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001312 rc = -ENOMEM;
1313 goto user_error;
Jay Chokshi57656862011-09-07 12:02:22 -07001314 }
1315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 mutex_init(&dbgdev->dbg_mutex);
1317
1318 dbgdev->dev = dev;
1319
1320 dent = debugfs_create_dir("pm8xxx-pwm-dbg", NULL);
1321 if (dent == NULL || IS_ERR(dent)) {
1322 pr_err("ERR debugfs_create_dir: dent=%p\n", dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001323 rc = -ENOMEM;
1324 goto dir_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 }
1326
1327 dbgdev->dent = dent;
1328
Jay Chokshi57656862011-09-07 12:02:22 -07001329 for (i = 0; i < pwm_chip->pwm_channels; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 char pwm_ch[] = "0";
1331
1332 pwm_ch[0] = '0' + i;
1333 dent = debugfs_create_dir(pwm_ch, dbgdev->dent);
1334 if (dent == NULL || IS_ERR(dent)) {
1335 pr_err("ERR: pwm=%d: dir: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001336 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 goto debug_error;
1338 }
1339
1340 puser = &dbgdev->user[i];
1341 puser->dbgdev = dbgdev;
1342 puser->pwm_id = i;
1343 temp = debugfs_create_file("period", S_IRUGO | S_IWUSR,
1344 dent, puser, &dbg_pwm_period_fops);
1345 if (temp == NULL || IS_ERR(temp)) {
1346 pr_err("ERR: pwm=%d: period: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001347 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348 goto debug_error;
1349 }
1350
1351 temp = debugfs_create_file("duty-cycle", S_IRUGO | S_IWUSR,
1352 dent, puser, &dbg_pwm_duty_cycle_fops);
1353 if (temp == NULL || IS_ERR(temp)) {
1354 pr_err("ERR: pwm=%d: duty-cycle: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001355 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 goto debug_error;
1357 }
1358
1359 temp = debugfs_create_file("enable", S_IRUGO | S_IWUSR,
1360 dent, puser, &dbg_pwm_enable_fops);
1361 if (temp == NULL || IS_ERR(temp)) {
1362 pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001363 rc = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001364 goto debug_error;
1365 }
1366 }
1367
1368 pmic_dbg_device = dbgdev;
1369
1370 return 0;
1371
1372debug_error:
1373 debugfs_remove_recursive(dbgdev->dent);
Jay Chokshi00c07cc2011-10-27 15:50:03 -07001374dir_error:
1375 kfree(dbgdev->user);
1376user_error:
1377 kfree(dbgdev);
1378 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001379}
1380
1381static int __devexit pm8xxx_pwm_dbg_remove(void)
1382{
1383 if (pmic_dbg_device) {
Jay Chokshi57656862011-09-07 12:02:22 -07001384 kfree(pmic_dbg_device->user);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385 debugfs_remove_recursive(pmic_dbg_device->dent);
1386 kfree(pmic_dbg_device);
1387 }
1388 return 0;
1389}
1390
1391#else
1392
1393static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev)
1394{
1395 return 0;
1396}
1397
1398static int __devexit pm8xxx_pwm_dbg_remove(void)
1399{
1400 return 0;
1401}
1402
1403#endif
1404
1405static int __devinit pm8xxx_pwm_probe(struct platform_device *pdev)
1406{
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001407 const struct pm8xxx_pwm_platform_data *pdata = pdev->dev.platform_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 struct pm8xxx_pwm_chip *chip;
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001409 int i, dtest_channel;
Jay Chokshi57656862011-09-07 12:02:22 -07001410 enum pm8xxx_version version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411
1412 chip = kzalloc(sizeof *chip, GFP_KERNEL);
1413 if (chip == NULL) {
1414 pr_err("kzalloc() failed.\n");
1415 return -ENOMEM;
1416 }
1417
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001418 if (pdata != NULL)
1419 dtest_channel = pdata->dtest_channel;
1420 else
1421 dtest_channel = -1;
1422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 mutex_init(&chip->pwm_mutex);
1424
1425 chip->dev = &pdev->dev;
1426 pwm_chip = chip;
Jay Chokshi57656862011-09-07 12:02:22 -07001427
1428 version = pm8xxx_get_version(chip->dev->parent);
1429
1430 if (version == PM8XXX_VERSION_8921 ||
David Collins999480d2011-11-16 08:52:30 -08001431 version == PM8XXX_VERSION_8058 ||
Jay Chokshi0c220cd2011-12-09 17:18:20 -08001432 version == PM8XXX_VERSION_8922 ||
1433 version == PM8XXX_VERSION_8038) {
Jay Chokshi57656862011-09-07 12:02:22 -07001434 chip->is_lpg_supported = 1;
1435 }
Jay Chokshi90485222012-08-07 20:22:39 -07001436
1437 if (version == PM8XXX_VERSION_8038)
1438 chip->is_pwm_enable_sync_workaround_needed = 1;
1439 else
1440 chip->is_pwm_enable_sync_workaround_needed = 0;
1441
Jay Chokshi57656862011-09-07 12:02:22 -07001442 if (chip->is_lpg_supported) {
Jay Chokshi0c220cd2011-12-09 17:18:20 -08001443 if (version == PM8XXX_VERSION_8922 ||
1444 version == PM8XXX_VERSION_8038) {
1445 for (i = 0; i < NUM_CLOCKS; i++)
1446 pt_t[0][i] /= PRE_DIVIDE_2;
1447 chip->pwm_channels = PM8XXX_LPG_V1_PWM_CHANNELS;
1448 } else {
1449 chip->pwm_channels = PM8XXX_LPG_V0_PWM_CHANNELS;
1450 }
Jay Chokshi57656862011-09-07 12:02:22 -07001451 chip->pwm_total_pre_divs = NUM_LPG_PRE_DIVIDE;
1452 } else {
1453 chip->pwm_channels = PM8XXX_PWM_CHANNELS;
1454 chip->pwm_total_pre_divs = NUM_PWM_PRE_DIVIDE;
1455 }
1456
1457 chip->pwm_dev = kcalloc(chip->pwm_channels, sizeof(struct pwm_device),
1458 GFP_KERNEL);
1459 if (chip->pwm_dev == NULL) {
1460 pr_err("kcalloc() failed.\n");
1461 mutex_destroy(&chip->pwm_mutex);
1462 kfree(chip);
1463 return -ENOMEM;
1464 }
1465
1466 for (i = 0; i < chip->pwm_channels; i++) {
1467 chip->pwm_dev[i].pwm_id = i;
1468 chip->pwm_dev[i].chip = chip;
Jay Chokshid9e4bc22012-03-02 15:13:44 -08001469 if (i == dtest_channel)
Jay Chokshib0a0fa52012-02-23 16:18:44 -08001470 chip->pwm_dev[i].dtest_mode_supported = 1;
Jay Chokshi57656862011-09-07 12:02:22 -07001471 }
1472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 platform_set_drvdata(pdev, chip);
1474
1475 if (pm8xxx_pwm_dbg_probe(&pdev->dev) < 0)
1476 pr_err("could not set up debugfs\n");
1477
1478 pr_notice("OK\n");
1479 return 0;
1480}
1481
1482static int __devexit pm8xxx_pwm_remove(struct platform_device *pdev)
1483{
1484 struct pm8xxx_pwm_chip *chip = dev_get_drvdata(pdev->dev.parent);
1485
1486 pm8xxx_pwm_dbg_remove();
Jay Chokshi57656862011-09-07 12:02:22 -07001487 kfree(chip->pwm_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 mutex_destroy(&chip->pwm_mutex);
1489 platform_set_drvdata(pdev, NULL);
1490 kfree(chip);
1491 return 0;
1492}
1493
1494static struct platform_driver pm8xxx_pwm_driver = {
1495 .probe = pm8xxx_pwm_probe,
1496 .remove = __devexit_p(pm8xxx_pwm_remove),
1497 .driver = {
1498 .name = PM8XXX_PWM_DEV_NAME,
1499 .owner = THIS_MODULE,
1500 },
1501};
1502
1503static int __init pm8xxx_pwm_init(void)
1504{
1505 return platform_driver_register(&pm8xxx_pwm_driver);
1506}
1507
1508static void __exit pm8xxx_pwm_exit(void)
1509{
1510 platform_driver_unregister(&pm8xxx_pwm_driver);
1511}
1512
1513subsys_initcall(pm8xxx_pwm_init);
1514module_exit(pm8xxx_pwm_exit);
1515
1516MODULE_LICENSE("GPL v2");
1517MODULE_DESCRIPTION("PM8XXX PWM driver");
1518MODULE_VERSION("1.0");
1519MODULE_ALIAS("platform:" PM8XXX_PWM_DEV_NAME);