blob: 85a5ea0a4c0e5591508f0ade5b9a876450beee84 [file] [log] [blame]
Fenglin Wu50b1eba2017-11-16 08:39:11 +08001/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
2 *
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#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/bitops.h>
16#include <linux/device.h>
17#include <linux/err.h>
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/mutex.h>
22#include <linux/of.h>
23#include <linux/of_address.h>
24#include <linux/platform_device.h>
25#include <linux/pwm.h>
26#include <linux/regmap.h>
27#include <linux/types.h>
28
29#define REG_SIZE_PER_LPG 0x100
30
Fenglin Wu93824d72018-03-05 15:06:42 +080031#define REG_LPG_PERPH_SUBTYPE 0x05
Fenglin Wu50b1eba2017-11-16 08:39:11 +080032#define REG_LPG_PWM_SIZE_CLK 0x41
33#define REG_LPG_PWM_FREQ_PREDIV_CLK 0x42
34#define REG_LPG_PWM_TYPE_CONFIG 0x43
35#define REG_LPG_PWM_VALUE_LSB 0x44
36#define REG_LPG_PWM_VALUE_MSB 0x45
37#define REG_LPG_ENABLE_CONTROL 0x46
38#define REG_LPG_PWM_SYNC 0x47
39
Fenglin Wu93824d72018-03-05 15:06:42 +080040/* REG_LPG_PERPH_SUBTYPE */
41#define SUBTYPE_PWM 0x0b
42#define SUBTYPE_LPG_LITE 0x11
43
Fenglin Wu50b1eba2017-11-16 08:39:11 +080044/* REG_LPG_PWM_SIZE_CLK */
Fenglin Wu93824d72018-03-05 15:06:42 +080045#define LPG_PWM_SIZE_MASK_LPG BIT(4)
46#define LPG_PWM_SIZE_MASK_PWM BIT(2)
47#define LPG_PWM_SIZE_SHIFT_LPG 4
48#define LPG_PWM_SIZE_SHIFT_PWM 2
Fenglin Wu50b1eba2017-11-16 08:39:11 +080049#define LPG_PWM_CLK_FREQ_SEL_MASK GENMASK(1, 0)
50
51/* REG_LPG_PWM_FREQ_PREDIV_CLK */
52#define LPG_PWM_FREQ_PREDIV_MASK GENMASK(6, 5)
53#define LPG_PWM_FREQ_PREDIV_SHIFT 5
54#define LPG_PWM_FREQ_EXPONENT_MASK GENMASK(2, 0)
55
56/* REG_LPG_PWM_TYPE_CONFIG */
57#define LPG_PWM_EN_GLITCH_REMOVAL_MASK BIT(5)
58
59/* REG_LPG_PWM_VALUE_LSB */
60#define LPG_PWM_VALUE_LSB_MASK GENMASK(7, 0)
61
62/* REG_LPG_PWM_VALUE_MSB */
63#define LPG_PWM_VALUE_MSB_MASK BIT(0)
64
65/* REG_LPG_ENABLE_CONTROL */
66#define LPG_EN_LPG_OUT_BIT BIT(7)
67#define LPG_PWM_SRC_SELECT_MASK BIT(2)
68#define LPG_PWM_SRC_SELECT_SHIFT 2
69#define LPG_EN_RAMP_GEN_MASK BIT(1)
70#define LPG_EN_RAMP_GEN_SHIFT 1
71
72/* REG_LPG_PWM_SYNC */
73#define LPG_PWM_VALUE_SYNC BIT(0)
74
75#define NUM_PWM_SIZE 2
76#define NUM_PWM_CLK 3
77#define NUM_CLK_PREDIV 4
78#define NUM_PWM_EXP 8
79
80enum {
81 LUT_PATTERN = 0,
82 PWM_OUTPUT,
83};
84
85static const int pwm_size[NUM_PWM_SIZE] = {6, 9};
86static const int clk_freq_hz[NUM_PWM_CLK] = {1024, 32768, 19200000};
87static const int clk_prediv[NUM_CLK_PREDIV] = {1, 3, 5, 6};
88static const int pwm_exponent[NUM_PWM_EXP] = {0, 1, 2, 3, 4, 5, 6, 7};
89
90struct lpg_pwm_config {
91 u32 pwm_size;
92 u32 pwm_clk;
93 u32 prediv;
94 u32 clk_exp;
95 u16 pwm_value;
96 u32 best_period_ns;
97};
98
99struct qpnp_lpg_channel {
100 struct qpnp_lpg_chip *chip;
101 struct lpg_pwm_config pwm_config;
102 u32 lpg_idx;
103 u32 reg_base;
104 u8 src_sel;
Fenglin Wu93824d72018-03-05 15:06:42 +0800105 u8 subtype;
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800106 int current_period_ns;
107 int current_duty_ns;
108};
109
110struct qpnp_lpg_chip {
111 struct pwm_chip pwm_chip;
112 struct regmap *regmap;
113 struct device *dev;
114 struct qpnp_lpg_channel *lpgs;
115 struct mutex bus_lock;
116 u32 num_lpgs;
117};
118
Fenglin Wu93824d72018-03-05 15:06:42 +0800119static int qpnp_lpg_read(struct qpnp_lpg_channel *lpg, u16 addr, u8 *val)
120{
121 int rc;
122 unsigned int tmp;
123
124 mutex_lock(&lpg->chip->bus_lock);
125 rc = regmap_read(lpg->chip->regmap, lpg->reg_base + addr, &tmp);
126 if (rc < 0)
127 dev_err(lpg->chip->dev, "Read addr 0x%x failed, rc=%d\n",
128 lpg->reg_base + addr, rc);
129 else
130 *val = (u8)tmp;
131 mutex_unlock(&lpg->chip->bus_lock);
132
133 return rc;
134}
135
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800136static int qpnp_lpg_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val)
137{
138 int rc;
139
140 mutex_lock(&lpg->chip->bus_lock);
141 rc = regmap_write(lpg->chip->regmap, lpg->reg_base + addr, val);
142 if (rc < 0)
143 dev_err(lpg->chip->dev, "Write addr 0x%x with value %d failed, rc=%d\n",
144 lpg->reg_base + addr, val, rc);
145 mutex_unlock(&lpg->chip->bus_lock);
146
147 return rc;
148}
149
150static int qpnp_lpg_masked_write(struct qpnp_lpg_channel *lpg,
151 u16 addr, u8 mask, u8 val)
152{
153 int rc;
154
155 mutex_lock(&lpg->chip->bus_lock);
156 rc = regmap_update_bits(lpg->chip->regmap, lpg->reg_base + addr,
157 mask, val);
158 if (rc < 0)
159 dev_err(lpg->chip->dev, "Update addr 0x%x to val 0x%x with mask 0x%x failed, rc=%d\n",
160 lpg->reg_base + addr, val, mask, rc);
161 mutex_unlock(&lpg->chip->bus_lock);
162
163 return rc;
164}
165
166static struct qpnp_lpg_channel *pwm_dev_to_qpnp_lpg(struct pwm_chip *pwm_chip,
167 struct pwm_device *pwm) {
168
169 struct qpnp_lpg_chip *chip = container_of(pwm_chip,
170 struct qpnp_lpg_chip, pwm_chip);
171 u32 hw_idx = pwm->hwpwm;
172
173 if (hw_idx >= chip->num_lpgs) {
174 dev_err(chip->dev, "hw index %d out of range [0-%d]\n",
175 hw_idx, chip->num_lpgs - 1);
176 return NULL;
177 }
178
179 return &chip->lpgs[hw_idx];
180}
181
182static int __find_index_in_array(int member, const int array[], int length)
183{
184 int i;
185
186 for (i = 0; i < length; i++) {
187 if (member == array[i])
188 return i;
189 }
190
191 return -EINVAL;
192}
193
Fenglin Wu03dcd1b2018-03-01 12:23:05 +0800194static int qpnp_lpg_set_glitch_removal(struct qpnp_lpg_channel *lpg, bool en)
195{
196 int rc;
197 u8 mask, val;
198
199 val = en ? LPG_PWM_EN_GLITCH_REMOVAL_MASK : 0;
200 mask = LPG_PWM_EN_GLITCH_REMOVAL_MASK;
201 rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_TYPE_CONFIG, mask, val);
202 if (rc < 0)
203 dev_err(lpg->chip->dev, "Write LPG_PWM_TYPE_CONFIG failed, rc=%d\n",
204 rc);
205 return rc;
206}
207
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800208static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg)
209{
210 int rc;
Fenglin Wu93824d72018-03-05 15:06:42 +0800211 u8 val, mask, shift;
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800212 int pwm_size_idx, pwm_clk_idx, prediv_idx, clk_exp_idx;
213
214 pwm_size_idx = __find_index_in_array(lpg->pwm_config.pwm_size,
215 pwm_size, ARRAY_SIZE(pwm_size));
216 pwm_clk_idx = __find_index_in_array(lpg->pwm_config.pwm_clk,
217 clk_freq_hz, ARRAY_SIZE(clk_freq_hz));
218 prediv_idx = __find_index_in_array(lpg->pwm_config.prediv,
219 clk_prediv, ARRAY_SIZE(clk_prediv));
220 clk_exp_idx = __find_index_in_array(lpg->pwm_config.clk_exp,
221 pwm_exponent, ARRAY_SIZE(pwm_exponent));
222
223 if (pwm_size_idx < 0 || pwm_clk_idx < 0
224 || prediv_idx < 0 || clk_exp_idx < 0)
225 return -EINVAL;
226
227 /* pwm_clk_idx is 1 bit lower than the register value */
228 pwm_clk_idx += 1;
Fenglin Wu93824d72018-03-05 15:06:42 +0800229 if (lpg->subtype == SUBTYPE_PWM) {
230 shift = LPG_PWM_SIZE_SHIFT_PWM;
231 mask = LPG_PWM_SIZE_MASK_PWM;
232 } else {
233 shift = LPG_PWM_SIZE_SHIFT_LPG;
234 mask = LPG_PWM_SIZE_MASK_LPG;
235 }
236
237 val = pwm_size_idx << shift | pwm_clk_idx;
238 mask |= LPG_PWM_CLK_FREQ_SEL_MASK;
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800239 rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_SIZE_CLK, mask, val);
240 if (rc < 0) {
241 dev_err(lpg->chip->dev, "Write LPG_PWM_SIZE_CLK failed, rc=%d\n",
242 rc);
243 return rc;
244 }
245
246 val = prediv_idx << LPG_PWM_FREQ_PREDIV_SHIFT | clk_exp_idx;
247 mask = LPG_PWM_FREQ_PREDIV_MASK | LPG_PWM_FREQ_EXPONENT_MASK;
248 rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_FREQ_PREDIV_CLK, mask, val);
249 if (rc < 0) {
250 dev_err(lpg->chip->dev, "Write LPG_PWM_FREQ_PREDIV_CLK failed, rc=%d\n",
251 rc);
252 return rc;
253 }
254
255 val = lpg->pwm_config.pwm_value & LPG_PWM_VALUE_LSB_MASK;
256 rc = qpnp_lpg_write(lpg, REG_LPG_PWM_VALUE_LSB, val);
257 if (rc < 0) {
258 dev_err(lpg->chip->dev, "Write LPG_PWM_VALUE_LSB failed, rc=%d\n",
259 rc);
260 return rc;
261 }
262
263 val = lpg->pwm_config.pwm_value >> 8;
264 mask = LPG_PWM_VALUE_MSB_MASK;
265 rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_VALUE_MSB, mask, val);
266 if (rc < 0) {
267 dev_err(lpg->chip->dev, "Write LPG_PWM_VALUE_MSB failed, rc=%d\n",
268 rc);
269 return rc;
270 }
271
272 val = LPG_PWM_VALUE_SYNC;
273 rc = qpnp_lpg_write(lpg, REG_LPG_PWM_SYNC, val);
274 if (rc < 0) {
275 dev_err(lpg->chip->dev, "Write LPG_PWM_SYNC failed, rc=%d\n",
276 rc);
277 return rc;
278 }
279
280 return rc;
281}
282
283static void __qpnp_lpg_calc_pwm_period(int period_ns,
284 struct lpg_pwm_config *pwm_config)
285{
286 struct lpg_pwm_config configs[NUM_PWM_SIZE];
287 int i, j, m, n;
288 int tmp1, tmp2;
289 int clk_period_ns = 0, pwm_clk_period_ns;
290 int clk_delta_ns = INT_MAX, min_clk_delta_ns = INT_MAX;
291 int pwm_period_delta = INT_MAX, min_pwm_period_delta = INT_MAX;
292 int pwm_size_step;
293
294 /*
295 * (2^pwm_size) * (2^pwm_exp) * prediv * NSEC_PER_SEC
296 * pwm_period = ---------------------------------------------------
297 * clk_freq_hz
298 *
299 * Searching the closest settings for the requested PWM period.
300 */
301 for (n = 0; n < ARRAY_SIZE(pwm_size); n++) {
302 pwm_clk_period_ns = period_ns >> pwm_size[n];
303 for (i = ARRAY_SIZE(clk_freq_hz) - 1; i >= 0; i--) {
304 for (j = 0; j < ARRAY_SIZE(clk_prediv); j++) {
305 for (m = 0; m < ARRAY_SIZE(pwm_exponent); m++) {
306 tmp1 = 1 << pwm_exponent[m];
307 tmp1 *= clk_prediv[j];
308 tmp2 = NSEC_PER_SEC / clk_freq_hz[i];
309
310 clk_period_ns = tmp1 * tmp2;
311
312 clk_delta_ns = abs(pwm_clk_period_ns
313 - clk_period_ns);
314 /*
315 * Find the closest setting for
316 * PWM frequency predivide value
317 */
318 if (clk_delta_ns < min_clk_delta_ns) {
319 min_clk_delta_ns
320 = clk_delta_ns;
321 configs[n].pwm_clk
322 = clk_freq_hz[i];
323 configs[n].prediv
324 = clk_prediv[j];
325 configs[n].clk_exp
326 = pwm_exponent[m];
327 configs[n].pwm_size
328 = pwm_size[n];
329 configs[n].best_period_ns
330 = clk_period_ns;
331 }
332 }
333 }
334 }
335
336 configs[n].best_period_ns *= 1 << pwm_size[n];
337 /* Find the closest setting for PWM period */
338 if (min_clk_delta_ns < INT_MAX >> pwm_size[n])
339 pwm_period_delta = min_clk_delta_ns << pwm_size[n];
340 else
341 pwm_period_delta = INT_MAX;
342 if (pwm_period_delta < min_pwm_period_delta) {
343 min_pwm_period_delta = pwm_period_delta;
344 memcpy(pwm_config, &configs[n],
345 sizeof(struct lpg_pwm_config));
346 }
347 }
348
349 /* Larger PWM size can achieve better resolution for PWM duty */
350 for (n = ARRAY_SIZE(pwm_size) - 1; n > 0; n--) {
351 if (pwm_config->pwm_size >= pwm_size[n])
352 break;
353 pwm_size_step = pwm_size[n] - pwm_config->pwm_size;
354 if (pwm_config->clk_exp >= pwm_size_step) {
355 pwm_config->pwm_size = pwm_size[n];
356 pwm_config->clk_exp -= pwm_size_step;
357 }
358 }
359 pr_debug("PWM setting for period_ns %d: pwm_clk = %dHZ, prediv = %d, exponent = %d, pwm_size = %d\n",
360 period_ns, pwm_config->pwm_clk, pwm_config->prediv,
361 pwm_config->clk_exp, pwm_config->pwm_size);
362 pr_debug("Actual period: %dns\n", pwm_config->best_period_ns);
363}
364
365static void __qpnp_lpg_calc_pwm_duty(int period_ns, int duty_ns,
366 struct lpg_pwm_config *pwm_config)
367{
368 u16 pwm_value, max_pwm_value;
369
370 if ((1 << pwm_config->pwm_size) > (INT_MAX / duty_ns))
371 pwm_value = duty_ns / (period_ns >> pwm_config->pwm_size);
372 else
373 pwm_value = (duty_ns << pwm_config->pwm_size) / period_ns;
374
375 max_pwm_value = (1 << pwm_config->pwm_size) - 1;
376 if (pwm_value > max_pwm_value)
377 pwm_value = max_pwm_value;
378 pwm_config->pwm_value = pwm_value;
379}
380
381static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip,
382 struct pwm_device *pwm, int duty_ns, int period_ns)
383{
384 struct qpnp_lpg_channel *lpg;
385 int rc = 0;
386
387 lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
388 if (lpg == NULL) {
389 dev_err(pwm_chip->dev, "lpg not found\n");
390 return -ENODEV;
391 }
392
393 if (duty_ns > period_ns) {
394 dev_err(pwm_chip->dev, "Duty %dns is larger than period %dns\n",
395 duty_ns, period_ns);
396 return -EINVAL;
397 }
398
399 if (period_ns != lpg->current_period_ns)
400 __qpnp_lpg_calc_pwm_period(period_ns, &lpg->pwm_config);
401
402 if (period_ns != lpg->current_period_ns ||
403 duty_ns != lpg->current_duty_ns)
404 __qpnp_lpg_calc_pwm_duty(period_ns, duty_ns, &lpg->pwm_config);
405
406 rc = qpnp_lpg_set_pwm_config(lpg);
407 if (rc < 0)
408 dev_err(pwm_chip->dev, "Config PWM failed for channel %d, rc=%d\n",
409 lpg->lpg_idx, rc);
410
411 return rc;
412}
413
414static int qpnp_lpg_pwm_enable(struct pwm_chip *pwm_chip,
415 struct pwm_device *pwm)
416{
417 struct qpnp_lpg_channel *lpg;
418 int rc = 0;
419 u8 mask, val;
420
421 lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
422 if (lpg == NULL) {
423 dev_err(pwm_chip->dev, "lpg not found\n");
424 return -ENODEV;
425 }
426
Fenglin Wu03dcd1b2018-03-01 12:23:05 +0800427 rc = qpnp_lpg_set_glitch_removal(lpg, true);
428 if (rc < 0) {
429 dev_err(lpg->chip->dev, "Enable glitch-removal failed, rc=%d\n",
430 rc);
431 return rc;
432 }
433
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800434 mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT;
435 val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT | LPG_EN_LPG_OUT_BIT;
436
437 rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val);
438 if (rc < 0)
439 dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n",
440 lpg->lpg_idx, rc);
441
442 return rc;
443}
444
445static void qpnp_lpg_pwm_disable(struct pwm_chip *pwm_chip,
446 struct pwm_device *pwm)
447{
448 struct qpnp_lpg_channel *lpg;
449 int rc;
450 u8 mask, val;
451
452 lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
453 if (lpg == NULL) {
454 dev_err(pwm_chip->dev, "lpg not found\n");
455 return;
456 }
457
458 mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT;
459 val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT;
460
461 rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val);
Fenglin Wu03dcd1b2018-03-01 12:23:05 +0800462 if (rc < 0) {
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800463 dev_err(pwm_chip->dev, "Disable PWM output failed for channel %d, rc=%d\n",
464 lpg->lpg_idx, rc);
Fenglin Wu03dcd1b2018-03-01 12:23:05 +0800465 return;
466 }
467
468 rc = qpnp_lpg_set_glitch_removal(lpg, false);
469 if (rc < 0)
470 dev_err(lpg->chip->dev, "Disable glitch-removal failed, rc=%d\n",
471 rc);
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800472}
473
474#ifdef CONFIG_DEBUG_FS
475static void qpnp_lpg_pwm_dbg_show(struct pwm_chip *pwm_chip, struct seq_file *s)
476{
477 struct qpnp_lpg_channel *lpg;
478 struct lpg_pwm_config *cfg;
479 struct pwm_device *pwm;
480 int i;
481
482 for (i = 0; i < pwm_chip->npwm; i++) {
483 pwm = &pwm_chip->pwms[i];
484
485 lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
486 if (lpg == NULL) {
487 dev_err(pwm_chip->dev, "lpg not found\n");
488 return;
489 }
490
491 if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
492 seq_printf(s, "LPG %d is requested by %s\n",
493 lpg->lpg_idx + 1, pwm->label);
494 } else {
495 seq_printf(s, "LPG %d is free\n",
496 lpg->lpg_idx + 1);
497 continue;
498 }
499
500 if (pwm_is_enabled(pwm)) {
501 seq_puts(s, " enabled\n");
502 } else {
503 seq_puts(s, " disabled\n");
504 continue;
505 }
506
507 cfg = &lpg->pwm_config;
508 seq_printf(s, " clk = %dHz\n", cfg->pwm_clk);
509 seq_printf(s, " pwm_size = %d\n", cfg->pwm_size);
510 seq_printf(s, " prediv = %d\n", cfg->prediv);
511 seq_printf(s, " exponent = %d\n", cfg->clk_exp);
512 seq_printf(s, " pwm_value = %d\n", cfg->pwm_value);
513 seq_printf(s, " Requested period: %dns, best period = %dns\n",
514 pwm_get_period(pwm), cfg->best_period_ns);
515 }
516}
517#endif
518
519static const struct pwm_ops qpnp_lpg_pwm_ops = {
520 .config = qpnp_lpg_pwm_config,
521 .enable = qpnp_lpg_pwm_enable,
522 .disable = qpnp_lpg_pwm_disable,
523#ifdef CONFIG_DEBUG_FS
524 .dbg_show = qpnp_lpg_pwm_dbg_show,
525#endif
526 .owner = THIS_MODULE,
527};
528
529static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip)
530{
531 int rc = 0, i;
532 u64 base, length;
533 const __be32 *addr;
534
535 addr = of_get_address(chip->dev->of_node, 0, NULL, NULL);
536 if (!addr) {
537 dev_err(chip->dev, "Getting address failed\n");
538 return -EINVAL;
539 }
540 base = be32_to_cpu(addr[0]);
541 length = be32_to_cpu(addr[1]);
542
543 chip->num_lpgs = length / REG_SIZE_PER_LPG;
544 chip->lpgs = devm_kcalloc(chip->dev, chip->num_lpgs,
545 sizeof(*chip->lpgs), GFP_KERNEL);
546 if (!chip->lpgs)
547 return -ENOMEM;
548
549 for (i = 0; i < chip->num_lpgs; i++) {
550 chip->lpgs[i].chip = chip;
551 chip->lpgs[i].lpg_idx = i;
552 chip->lpgs[i].reg_base = base + i * REG_SIZE_PER_LPG;
553 chip->lpgs[i].src_sel = PWM_OUTPUT;
Fenglin Wu93824d72018-03-05 15:06:42 +0800554 rc = qpnp_lpg_read(&chip->lpgs[i], REG_LPG_PERPH_SUBTYPE,
555 &chip->lpgs[i].subtype);
556 if (rc < 0) {
557 dev_err(chip->dev, "Read subtype failed, rc=%d\n", rc);
558 return rc;
559 }
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800560 }
561
562 return rc;
563}
564
565static int qpnp_lpg_probe(struct platform_device *pdev)
566{
567 int rc;
568 struct qpnp_lpg_chip *chip;
569
570 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
571 if (!chip)
572 return -ENOMEM;
573
574 chip->dev = &pdev->dev;
575 chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
576 if (!chip->regmap) {
577 dev_err(chip->dev, "Getting regmap failed\n");
578 return -EINVAL;
579 }
580
Fenglin Wu93824d72018-03-05 15:06:42 +0800581 mutex_init(&chip->bus_lock);
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800582 rc = qpnp_lpg_parse_dt(chip);
583 if (rc < 0) {
584 dev_err(chip->dev, "Devicetree properties parsing failed, rc=%d\n",
585 rc);
Fenglin Wu93824d72018-03-05 15:06:42 +0800586 goto destroy;
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800587 }
588
589 dev_set_drvdata(chip->dev, chip);
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800590 chip->pwm_chip.dev = chip->dev;
591 chip->pwm_chip.base = -1;
592 chip->pwm_chip.npwm = chip->num_lpgs;
593 chip->pwm_chip.ops = &qpnp_lpg_pwm_ops;
594
595 rc = pwmchip_add(&chip->pwm_chip);
596 if (rc < 0) {
597 dev_err(chip->dev, "Add pwmchip failed, rc=%d\n", rc);
Fenglin Wu93824d72018-03-05 15:06:42 +0800598 goto destroy;
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800599 }
600
Fenglin Wu93824d72018-03-05 15:06:42 +0800601 return 0;
602destroy:
603 mutex_destroy(&chip->bus_lock);
Fenglin Wu50b1eba2017-11-16 08:39:11 +0800604 return rc;
605}
606
607static int qpnp_lpg_remove(struct platform_device *pdev)
608{
609 struct qpnp_lpg_chip *chip = dev_get_drvdata(&pdev->dev);
610 int rc = 0;
611
612 rc = pwmchip_remove(&chip->pwm_chip);
613 if (rc < 0)
614 dev_err(chip->dev, "Remove pwmchip failed, rc=%d\n", rc);
615
616 mutex_destroy(&chip->bus_lock);
617 dev_set_drvdata(chip->dev, NULL);
618
619 return rc;
620}
621
622static const struct of_device_id qpnp_lpg_of_match[] = {
623 { .compatible = "qcom,pwm-lpg",},
624 { },
625};
626
627static struct platform_driver qpnp_lpg_driver = {
628 .driver = {
629 .name = "qcom,pwm-lpg",
630 .of_match_table = qpnp_lpg_of_match,
631 },
632 .probe = qpnp_lpg_probe,
633 .remove = qpnp_lpg_remove,
634};
635module_platform_driver(qpnp_lpg_driver);
636
637MODULE_DESCRIPTION("QTI LPG driver");
638MODULE_LICENSE("GPL v2");
639MODULE_ALIAS("pwm:pwm-lpg");