1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * STM32 Low-Power Timer PWM driver |
4 | * |
5 | * Copyright (C) STMicroelectronics 2017 |
6 | * |
7 | * Author: Gerald Baeza <gerald.baeza@st.com> |
8 | * |
9 | * Inspired by Gerald Baeza's pwm-stm32 driver |
10 | */ |
11 | |
12 | #include <linux/bitfield.h> |
13 | #include <linux/mfd/stm32-lptimer.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/pinctrl/consumer.h> |
17 | #include <linux/platform_device.h> |
18 | #include <linux/pwm.h> |
19 | |
20 | struct stm32_pwm_lp { |
21 | struct clk *clk; |
22 | struct regmap *regmap; |
23 | }; |
24 | |
25 | static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip) |
26 | { |
27 | return pwmchip_get_drvdata(chip); |
28 | } |
29 | |
30 | /* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */ |
31 | #define STM32_LPTIM_MAX_PRESCALER 128 |
32 | |
33 | static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, |
34 | const struct pwm_state *state) |
35 | { |
36 | struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip); |
37 | unsigned long long prd, div, dty; |
38 | struct pwm_state cstate; |
39 | u32 val, mask, cfgr, presc = 0; |
40 | bool reenable; |
41 | int ret; |
42 | |
43 | pwm_get_state(pwm, state: &cstate); |
44 | reenable = !cstate.enabled; |
45 | |
46 | if (!state->enabled) { |
47 | if (cstate.enabled) { |
48 | /* Disable LP timer */ |
49 | ret = regmap_write(map: priv->regmap, STM32_LPTIM_CR, val: 0); |
50 | if (ret) |
51 | return ret; |
52 | /* disable clock to PWM counter */ |
53 | clk_disable(clk: priv->clk); |
54 | } |
55 | return 0; |
56 | } |
57 | |
58 | /* Calculate the period and prescaler value */ |
59 | div = (unsigned long long)clk_get_rate(clk: priv->clk) * state->period; |
60 | do_div(div, NSEC_PER_SEC); |
61 | if (!div) { |
62 | /* Clock is too slow to achieve requested period. */ |
63 | dev_dbg(pwmchip_parent(chip), "Can't reach %llu ns\n" , state->period); |
64 | return -EINVAL; |
65 | } |
66 | |
67 | prd = div; |
68 | while (div > STM32_LPTIM_MAX_ARR) { |
69 | presc++; |
70 | if ((1 << presc) > STM32_LPTIM_MAX_PRESCALER) { |
71 | dev_err(pwmchip_parent(chip), "max prescaler exceeded\n" ); |
72 | return -EINVAL; |
73 | } |
74 | div = prd >> presc; |
75 | } |
76 | prd = div; |
77 | |
78 | /* Calculate the duty cycle */ |
79 | dty = prd * state->duty_cycle; |
80 | do_div(dty, state->period); |
81 | |
82 | if (!cstate.enabled) { |
83 | /* enable clock to drive PWM counter */ |
84 | ret = clk_enable(clk: priv->clk); |
85 | if (ret) |
86 | return ret; |
87 | } |
88 | |
89 | ret = regmap_read(map: priv->regmap, STM32_LPTIM_CFGR, val: &cfgr); |
90 | if (ret) |
91 | goto err; |
92 | |
93 | if ((FIELD_GET(STM32_LPTIM_PRESC, cfgr) != presc) || |
94 | (FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity)) { |
95 | val = FIELD_PREP(STM32_LPTIM_PRESC, presc); |
96 | val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity); |
97 | mask = STM32_LPTIM_PRESC | STM32_LPTIM_WAVPOL; |
98 | |
99 | /* Must disable LP timer to modify CFGR */ |
100 | reenable = true; |
101 | ret = regmap_write(map: priv->regmap, STM32_LPTIM_CR, val: 0); |
102 | if (ret) |
103 | goto err; |
104 | |
105 | ret = regmap_update_bits(map: priv->regmap, STM32_LPTIM_CFGR, mask, |
106 | val); |
107 | if (ret) |
108 | goto err; |
109 | } |
110 | |
111 | if (reenable) { |
112 | /* Must (re)enable LP timer to modify CMP & ARR */ |
113 | ret = regmap_write(map: priv->regmap, STM32_LPTIM_CR, |
114 | STM32_LPTIM_ENABLE); |
115 | if (ret) |
116 | goto err; |
117 | } |
118 | |
119 | ret = regmap_write(map: priv->regmap, STM32_LPTIM_ARR, val: prd - 1); |
120 | if (ret) |
121 | goto err; |
122 | |
123 | ret = regmap_write(map: priv->regmap, STM32_LPTIM_CMP, val: prd - (1 + dty)); |
124 | if (ret) |
125 | goto err; |
126 | |
127 | /* ensure CMP & ARR registers are properly written */ |
128 | ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, |
129 | (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK, |
130 | 100, 1000); |
131 | if (ret) { |
132 | dev_err(pwmchip_parent(chip), "ARR/CMP registers write issue\n" ); |
133 | goto err; |
134 | } |
135 | ret = regmap_write(map: priv->regmap, STM32_LPTIM_ICR, |
136 | STM32_LPTIM_CMPOKCF_ARROKCF); |
137 | if (ret) |
138 | goto err; |
139 | |
140 | if (reenable) { |
141 | /* Start LP timer in continuous mode */ |
142 | ret = regmap_set_bits(map: priv->regmap, STM32_LPTIM_CR, |
143 | STM32_LPTIM_CNTSTRT); |
144 | if (ret) { |
145 | regmap_write(map: priv->regmap, STM32_LPTIM_CR, val: 0); |
146 | goto err; |
147 | } |
148 | } |
149 | |
150 | return 0; |
151 | err: |
152 | if (!cstate.enabled) |
153 | clk_disable(clk: priv->clk); |
154 | |
155 | return ret; |
156 | } |
157 | |
158 | static int stm32_pwm_lp_get_state(struct pwm_chip *chip, |
159 | struct pwm_device *pwm, |
160 | struct pwm_state *state) |
161 | { |
162 | struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip); |
163 | unsigned long rate = clk_get_rate(clk: priv->clk); |
164 | u32 val, presc, prd; |
165 | u64 tmp; |
166 | |
167 | regmap_read(map: priv->regmap, STM32_LPTIM_CR, val: &val); |
168 | state->enabled = !!FIELD_GET(STM32_LPTIM_ENABLE, val); |
169 | /* Keep PWM counter clock refcount in sync with PWM initial state */ |
170 | if (state->enabled) |
171 | clk_enable(clk: priv->clk); |
172 | |
173 | regmap_read(map: priv->regmap, STM32_LPTIM_CFGR, val: &val); |
174 | presc = FIELD_GET(STM32_LPTIM_PRESC, val); |
175 | state->polarity = FIELD_GET(STM32_LPTIM_WAVPOL, val); |
176 | |
177 | regmap_read(map: priv->regmap, STM32_LPTIM_ARR, val: &prd); |
178 | tmp = prd + 1; |
179 | tmp = (tmp << presc) * NSEC_PER_SEC; |
180 | state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); |
181 | |
182 | regmap_read(map: priv->regmap, STM32_LPTIM_CMP, val: &val); |
183 | tmp = prd - val; |
184 | tmp = (tmp << presc) * NSEC_PER_SEC; |
185 | state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); |
186 | |
187 | return 0; |
188 | } |
189 | |
190 | static const struct pwm_ops stm32_pwm_lp_ops = { |
191 | .apply = stm32_pwm_lp_apply, |
192 | .get_state = stm32_pwm_lp_get_state, |
193 | }; |
194 | |
195 | static int stm32_pwm_lp_probe(struct platform_device *pdev) |
196 | { |
197 | struct stm32_lptimer *ddata = dev_get_drvdata(dev: pdev->dev.parent); |
198 | struct stm32_pwm_lp *priv; |
199 | struct pwm_chip *chip; |
200 | int ret; |
201 | |
202 | chip = devm_pwmchip_alloc(parent: &pdev->dev, npwm: 1, sizeof_priv: sizeof(*priv)); |
203 | if (IS_ERR(ptr: chip)) |
204 | return PTR_ERR(ptr: chip); |
205 | priv = to_stm32_pwm_lp(chip); |
206 | |
207 | priv->regmap = ddata->regmap; |
208 | priv->clk = ddata->clk; |
209 | chip->ops = &stm32_pwm_lp_ops; |
210 | |
211 | ret = devm_pwmchip_add(&pdev->dev, chip); |
212 | if (ret < 0) |
213 | return ret; |
214 | |
215 | platform_set_drvdata(pdev, data: chip); |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | static int stm32_pwm_lp_suspend(struct device *dev) |
221 | { |
222 | struct pwm_chip *chip = dev_get_drvdata(dev); |
223 | struct pwm_state state; |
224 | |
225 | pwm_get_state(pwm: &chip->pwms[0], state: &state); |
226 | if (state.enabled) { |
227 | dev_err(dev, "The consumer didn't stop us (%s)\n" , |
228 | chip->pwms[0].label); |
229 | return -EBUSY; |
230 | } |
231 | |
232 | return pinctrl_pm_select_sleep_state(dev); |
233 | } |
234 | |
235 | static int stm32_pwm_lp_resume(struct device *dev) |
236 | { |
237 | return pinctrl_pm_select_default_state(dev); |
238 | } |
239 | |
240 | static DEFINE_SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend, |
241 | stm32_pwm_lp_resume); |
242 | |
243 | static const struct of_device_id stm32_pwm_lp_of_match[] = { |
244 | { .compatible = "st,stm32-pwm-lp" , }, |
245 | {}, |
246 | }; |
247 | MODULE_DEVICE_TABLE(of, stm32_pwm_lp_of_match); |
248 | |
249 | static struct platform_driver stm32_pwm_lp_driver = { |
250 | .probe = stm32_pwm_lp_probe, |
251 | .driver = { |
252 | .name = "stm32-pwm-lp" , |
253 | .of_match_table = stm32_pwm_lp_of_match, |
254 | .pm = pm_ptr(&stm32_pwm_lp_pm_ops), |
255 | }, |
256 | }; |
257 | module_platform_driver(stm32_pwm_lp_driver); |
258 | |
259 | MODULE_ALIAS("platform:stm32-pwm-lp" ); |
260 | MODULE_DESCRIPTION("STMicroelectronics STM32 PWM LP driver" ); |
261 | MODULE_LICENSE("GPL v2" ); |
262 | |