blob: 5fa649b590359c97836cbc8709a23b3032592124 [file] [log] [blame]
Cheick Traore3c4456b2025-03-11 15:30:35 +01001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
4 * Author: Cheick Traore <cheick.traore@foss.st.com>
5 *
6 * Originally based on the Linux kernel v6.10 drivers/pwm/pwm-stm32.c.
7 */
8
9#include <div64.h>
10#include <dm.h>
11#include <pwm.h>
12#include <asm/io.h>
13#include <asm/arch/timers.h>
14#include <dm/device_compat.h>
15#include <linux/time.h>
16
17#define CCMR_CHANNEL_SHIFT 8
18#define CCMR_CHANNEL_MASK 0xFF
19
20struct stm32_pwm_priv {
21 bool have_complementary_output;
22 bool invert_polarity;
23};
24
25static u32 active_channels(struct stm32_timers_plat *plat)
26{
27 return readl(plat->base + TIM_CCER) & TIM_CCER_CCXE;
28}
29
30static int stm32_pwm_set_config(struct udevice *dev, uint channel,
31 uint period_ns, uint duty_ns)
32{
33 struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
34 struct stm32_timers_priv *priv = dev_get_priv(dev_get_parent(dev));
35 unsigned long long prd, div, dty;
36 unsigned int prescaler = 0;
37 u32 ccmr, mask, shift;
38
39 if (duty_ns > period_ns)
40 return -EINVAL;
41
42 /*
43 * Period and prescaler values depends on clock rate
44 * First we need to find the minimal value for prescaler such that
45 *
46 * period_ns * clkrate
47 * ------------------------------ < max_arr + 1
48 * NSEC_PER_SEC * (prescaler + 1)
49 *
50 * This equation is equivalent to
51 *
52 * period_ns * clkrate
53 * ---------------------------- < prescaler + 1
54 * NSEC_PER_SEC * (max_arr + 1)
55 *
56 * Using integer division and knowing that the right hand side is
57 * integer, this is further equivalent to
58 *
59 * (period_ns * clkrate) // (NSEC_PER_SEC * (max_arr + 1)) ≤ prescaler
60 */
61
62 div = (unsigned long long)priv->rate * period_ns;
63 do_div(div, NSEC_PER_SEC);
64 prd = div;
65
66 do_div(div, priv->max_arr + 1);
67 prescaler = div;
68 if (prescaler > MAX_TIM_PSC)
69 return -EINVAL;
70
71 do_div(prd, prescaler + 1);
72 if (!prd)
73 return -EINVAL;
74
75 /*
76 * All channels share the same prescaler and counter so when two
77 * channels are active at the same time we can't change them
78 */
79 if (active_channels(plat) & ~(1 << channel * 4)) {
80 u32 psc, arr;
81
82 psc = readl(plat->base + TIM_PSC);
83 arr = readl(plat->base + TIM_ARR);
84 if (psc != prescaler || arr != prd - 1)
85 return -EBUSY;
86 }
87
88 writel(prescaler, plat->base + TIM_PSC);
89 writel(prd - 1, plat->base + TIM_ARR);
90 setbits_le32(plat->base + TIM_CR1, TIM_CR1_ARPE);
91
92 /* Calculate the duty cycles */
93 dty = prd * duty_ns;
94 do_div(dty, period_ns);
95
96 writel(dty, plat->base + TIM_CCRx(channel + 1));
97
98 /* Configure output mode */
99 shift = (channel & 0x1) * CCMR_CHANNEL_SHIFT;
100 ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
101 mask = CCMR_CHANNEL_MASK << shift;
102 if (channel < 2)
103 clrsetbits_le32(plat->base + TIM_CCMR1, mask, ccmr);
104 else
105 clrsetbits_le32(plat->base + TIM_CCMR2, mask, ccmr);
106
107 setbits_le32(plat->base + TIM_BDTR, TIM_BDTR_MOE);
108
109 return 0;
110}
111
112static int stm32_pwm_set_enable(struct udevice *dev, uint channel,
113 bool enable)
114{
115 struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
116 struct stm32_pwm_priv *priv = dev_get_priv(dev);
117 u32 mask;
118
119 /* Enable channel */
120 mask = TIM_CCER_CC1E << (channel * 4);
121 if (priv->have_complementary_output)
122 mask |= TIM_CCER_CC1NE << (channel * 4);
123
124 if (enable) {
125 setbits_le32(plat->base + TIM_CCER, mask);
126 /* Make sure that registers are updated */
127 setbits_le32(plat->base + TIM_EGR, TIM_EGR_UG);
128 /* Enable controller */
129 setbits_le32(plat->base + TIM_CR1, TIM_CR1_CEN);
130 } else {
131 clrbits_le32(plat->base + TIM_CCER, mask);
132 /* When all channels are disabled, we can disable the controller */
133 if (!active_channels(plat))
134 clrbits_le32(plat->base + TIM_CR1, TIM_CR1_CEN);
135 }
136
137 return 0;
138}
139
140static int stm32_pwm_set_invert(struct udevice *dev, uint channel,
141 bool polarity)
142{
143 struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
144 struct stm32_pwm_priv *priv = dev_get_priv(dev);
145 u32 mask;
146
147 mask = TIM_CCER_CC1P << (channel * 4);
148 if (priv->have_complementary_output)
149 mask |= TIM_CCER_CC1NP << (channel * 4);
150
151 clrsetbits_le32(plat->base + TIM_CCER, mask, polarity ? mask : 0);
152
153 return 0;
154}
155
156static void stm32_pwm_detect_complementary(struct udevice *dev)
157{
158 struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
159 struct stm32_pwm_priv *priv = dev_get_priv(dev);
160 u32 ccer;
161
162 /*
163 * If complementary bit doesn't exist writing 1 will have no
164 * effect so we can detect it.
165 */
166 setbits_le32(plat->base + TIM_CCER, TIM_CCER_CC1NE);
167 ccer = readl(plat->base + TIM_CCER);
168 clrbits_le32(plat->base + TIM_CCER, TIM_CCER_CC1NE);
169
170 priv->have_complementary_output = (ccer != 0);
171}
172
173static int stm32_pwm_probe(struct udevice *dev)
174{
175 struct stm32_timers_priv *timer = dev_get_priv(dev_get_parent(dev));
176
177 if (timer->rate > 1000000000) {
178 dev_err(dev, "Clock freq too high (%lu)\n", timer->rate);
179 return -EINVAL;
180 }
181
182 stm32_pwm_detect_complementary(dev);
183
184 return 0;
185}
186
187static const struct pwm_ops stm32_pwm_ops = {
188 .set_config = stm32_pwm_set_config,
189 .set_enable = stm32_pwm_set_enable,
190 .set_invert = stm32_pwm_set_invert,
191};
192
193static const struct udevice_id stm32_pwm_ids[] = {
194 { .compatible = "st,stm32-pwm" },
195 { }
196};
197
198U_BOOT_DRIVER(stm32_pwm) = {
199 .name = "stm32_pwm",
200 .id = UCLASS_PWM,
201 .of_match = stm32_pwm_ids,
202 .ops = &stm32_pwm_ops,
203 .probe = stm32_pwm_probe,
204 .priv_auto = sizeof(struct stm32_pwm_priv),
205};