xref: /linux/drivers/pwm/pwm-dwc-core.c (revision f6154d8babbb8a98f0d3ea325aafae2e33bfd8be)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * DesignWare PWM Controller driver core
4  *
5  * Copyright (C) 2018-2020 Intel Corporation
6  *
7  * Author: Felipe Balbi (Intel)
8  * Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
9  * Author: Raymond Tan <raymond.tan@intel.com>
10  */
11 
12 #define DEFAULT_SYMBOL_NAMESPACE dwc_pwm
13 
14 #include <linux/bitops.h>
15 #include <linux/export.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/pci.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/pwm.h>
21 
22 #include "pwm-dwc.h"
23 
24 static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled)
25 {
26 	u32 reg;
27 
28 	reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm));
29 
30 	if (enabled)
31 		reg |= DWC_TIM_CTRL_EN;
32 	else
33 		reg &= ~DWC_TIM_CTRL_EN;
34 
35 	dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm));
36 }
37 
38 static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc,
39 				     struct pwm_device *pwm,
40 				     const struct pwm_state *state)
41 {
42 	u64 tmp;
43 	u32 ctrl;
44 	u32 high;
45 	u32 low;
46 
47 	/*
48 	 * Calculate width of low and high period in terms of input clock
49 	 * periods and check are the result within HW limits between 1 and
50 	 * 2^32 periods.
51 	 */
52 	tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns);
53 	if (tmp < 1 || tmp > (1ULL << 32))
54 		return -ERANGE;
55 	low = tmp - 1;
56 
57 	tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle,
58 				    dwc->clk_ns);
59 	if (tmp < 1 || tmp > (1ULL << 32))
60 		return -ERANGE;
61 	high = tmp - 1;
62 
63 	/*
64 	 * Specification says timer usage flow is to disable timer, then
65 	 * program it followed by enable. It also says Load Count is loaded
66 	 * into timer after it is enabled - either after a disable or
67 	 * a reset. Based on measurements it happens also without disable
68 	 * whenever Load Count is updated. But follow the specification.
69 	 */
70 	__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
71 
72 	/*
73 	 * Write Load Count and Load Count 2 registers. Former defines the
74 	 * width of low period and latter the width of high period in terms
75 	 * multiple of input clock periods:
76 	 * Width = ((Count + 1) * input clock period).
77 	 */
78 	dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm));
79 	dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm));
80 
81 	/*
82 	 * Set user-defined mode, timer reloads from Load Count registers
83 	 * when it counts down to 0.
84 	 * Set PWM mode, it makes output to toggle and width of low and high
85 	 * periods are set by Load Count registers.
86 	 */
87 	ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM;
88 	dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm));
89 
90 	/*
91 	 * Enable timer. Output starts from low period.
92 	 */
93 	__dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled);
94 
95 	return 0;
96 }
97 
98 static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
99 			 const struct pwm_state *state)
100 {
101 	struct dwc_pwm *dwc = to_dwc_pwm(chip);
102 
103 	if (state->polarity != PWM_POLARITY_INVERSED)
104 		return -EINVAL;
105 
106 	if (state->enabled) {
107 		if (!pwm->state.enabled)
108 			pm_runtime_get_sync(chip->dev);
109 		return __dwc_pwm_configure_timer(dwc, pwm, state);
110 	} else {
111 		if (pwm->state.enabled) {
112 			__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
113 			pm_runtime_put_sync(chip->dev);
114 		}
115 	}
116 
117 	return 0;
118 }
119 
120 static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
121 			     struct pwm_state *state)
122 {
123 	struct dwc_pwm *dwc = to_dwc_pwm(chip);
124 	u64 duty, period;
125 	u32 ctrl, ld, ld2;
126 
127 	pm_runtime_get_sync(chip->dev);
128 
129 	ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm->hwpwm));
130 	ld = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm));
131 	ld2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm));
132 
133 	state->enabled = !!(ctrl & DWC_TIM_CTRL_EN);
134 
135 	/*
136 	 * If we're not in PWM, technically the output is a 50-50
137 	 * based on the timer load-count only.
138 	 */
139 	if (ctrl & DWC_TIM_CTRL_PWM) {
140 		duty = (ld + 1) * dwc->clk_ns;
141 		period = (ld2 + 1)  * dwc->clk_ns;
142 		period += duty;
143 	} else {
144 		duty = (ld + 1) * dwc->clk_ns;
145 		period = duty * 2;
146 	}
147 
148 	state->polarity = PWM_POLARITY_INVERSED;
149 	state->period = period;
150 	state->duty_cycle = duty;
151 
152 	pm_runtime_put_sync(chip->dev);
153 
154 	return 0;
155 }
156 
157 static const struct pwm_ops dwc_pwm_ops = {
158 	.apply = dwc_pwm_apply,
159 	.get_state = dwc_pwm_get_state,
160 };
161 
162 struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
163 {
164 	struct dwc_pwm *dwc;
165 
166 	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
167 	if (!dwc)
168 		return NULL;
169 
170 	dwc->clk_ns = 10;
171 	dwc->chip.dev = dev;
172 	dwc->chip.ops = &dwc_pwm_ops;
173 	dwc->chip.npwm = DWC_TIMERS_TOTAL;
174 
175 	dev_set_drvdata(dev, dwc);
176 	return dwc;
177 }
178 EXPORT_SYMBOL_GPL(dwc_pwm_alloc);
179 
180 MODULE_AUTHOR("Felipe Balbi (Intel)");
181 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
182 MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
183 MODULE_DESCRIPTION("DesignWare PWM Controller");
184 MODULE_LICENSE("GPL");
185