Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
4836193c SG |
2 | /* |
3 | * Copyright (C) 2017 Sanechips Technology Co., Ltd. | |
4 | * Copyright 2017 Linaro Ltd. | |
4836193c SG |
5 | */ |
6 | ||
7 | #include <linux/clk.h> | |
8 | #include <linux/err.h> | |
9 | #include <linux/io.h> | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/platform_device.h> | |
13 | #include <linux/pwm.h> | |
14 | #include <linux/slab.h> | |
15 | ||
16 | #define ZX_PWM_MODE 0x0 | |
17 | #define ZX_PWM_CLKDIV_SHIFT 2 | |
18 | #define ZX_PWM_CLKDIV_MASK GENMASK(11, 2) | |
19 | #define ZX_PWM_CLKDIV(x) (((x) << ZX_PWM_CLKDIV_SHIFT) & \ | |
20 | ZX_PWM_CLKDIV_MASK) | |
21 | #define ZX_PWM_POLAR BIT(1) | |
22 | #define ZX_PWM_EN BIT(0) | |
23 | #define ZX_PWM_PERIOD 0x4 | |
24 | #define ZX_PWM_DUTY 0x8 | |
25 | ||
26 | #define ZX_PWM_CLKDIV_MAX 1023 | |
27 | #define ZX_PWM_PERIOD_MAX 65535 | |
28 | ||
29 | struct zx_pwm_chip { | |
30 | struct pwm_chip chip; | |
31 | struct clk *pclk; | |
32 | struct clk *wclk; | |
33 | void __iomem *base; | |
34 | }; | |
35 | ||
36 | static inline struct zx_pwm_chip *to_zx_pwm_chip(struct pwm_chip *chip) | |
37 | { | |
38 | return container_of(chip, struct zx_pwm_chip, chip); | |
39 | } | |
40 | ||
41 | static inline u32 zx_pwm_readl(struct zx_pwm_chip *zpc, unsigned int hwpwm, | |
42 | unsigned int offset) | |
43 | { | |
44 | return readl(zpc->base + (hwpwm + 1) * 0x10 + offset); | |
45 | } | |
46 | ||
47 | static inline void zx_pwm_writel(struct zx_pwm_chip *zpc, unsigned int hwpwm, | |
48 | unsigned int offset, u32 value) | |
49 | { | |
50 | writel(value, zpc->base + (hwpwm + 1) * 0x10 + offset); | |
51 | } | |
52 | ||
53 | static void zx_pwm_set_mask(struct zx_pwm_chip *zpc, unsigned int hwpwm, | |
54 | unsigned int offset, u32 mask, u32 value) | |
55 | { | |
56 | u32 data; | |
57 | ||
58 | data = zx_pwm_readl(zpc, hwpwm, offset); | |
59 | data &= ~mask; | |
60 | data |= value & mask; | |
61 | zx_pwm_writel(zpc, hwpwm, offset, data); | |
62 | } | |
63 | ||
64 | static void zx_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, | |
65 | struct pwm_state *state) | |
66 | { | |
67 | struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); | |
68 | unsigned long rate; | |
69 | unsigned int div; | |
70 | u32 value; | |
71 | u64 tmp; | |
72 | ||
73 | value = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_MODE); | |
74 | ||
75 | if (value & ZX_PWM_POLAR) | |
76 | state->polarity = PWM_POLARITY_NORMAL; | |
77 | else | |
78 | state->polarity = PWM_POLARITY_INVERSED; | |
79 | ||
80 | if (value & ZX_PWM_EN) | |
81 | state->enabled = true; | |
82 | else | |
83 | state->enabled = false; | |
84 | ||
85 | div = (value & ZX_PWM_CLKDIV_MASK) >> ZX_PWM_CLKDIV_SHIFT; | |
86 | rate = clk_get_rate(zpc->wclk); | |
87 | ||
88 | tmp = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_PERIOD); | |
89 | tmp *= div * NSEC_PER_SEC; | |
90 | state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); | |
91 | ||
92 | tmp = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_DUTY); | |
93 | tmp *= div * NSEC_PER_SEC; | |
94 | state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); | |
95 | } | |
96 | ||
97 | static int zx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |
98 | unsigned int duty_ns, unsigned int period_ns) | |
99 | { | |
100 | struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); | |
101 | unsigned int period_cycles, duty_cycles; | |
102 | unsigned long long c; | |
103 | unsigned int div = 1; | |
104 | unsigned long rate; | |
105 | ||
106 | /* Find out the best divider */ | |
107 | rate = clk_get_rate(zpc->wclk); | |
108 | ||
109 | while (1) { | |
110 | c = rate / div; | |
111 | c = c * period_ns; | |
112 | do_div(c, NSEC_PER_SEC); | |
113 | ||
114 | if (c < ZX_PWM_PERIOD_MAX) | |
115 | break; | |
116 | ||
117 | div++; | |
118 | ||
119 | if (div > ZX_PWM_CLKDIV_MAX) | |
120 | return -ERANGE; | |
121 | } | |
122 | ||
123 | /* Calculate duty cycles */ | |
124 | period_cycles = c; | |
125 | c *= duty_ns; | |
126 | do_div(c, period_ns); | |
127 | duty_cycles = c; | |
128 | ||
129 | /* | |
130 | * If the PWM is being enabled, we have to temporarily disable it | |
131 | * before configuring the registers. | |
132 | */ | |
133 | if (pwm_is_enabled(pwm)) | |
134 | zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_EN, 0); | |
135 | ||
136 | /* Set up registers */ | |
137 | zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_CLKDIV_MASK, | |
138 | ZX_PWM_CLKDIV(div)); | |
139 | zx_pwm_writel(zpc, pwm->hwpwm, ZX_PWM_PERIOD, period_cycles); | |
140 | zx_pwm_writel(zpc, pwm->hwpwm, ZX_PWM_DUTY, duty_cycles); | |
141 | ||
142 | /* Re-enable the PWM if needed */ | |
143 | if (pwm_is_enabled(pwm)) | |
144 | zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, | |
145 | ZX_PWM_EN, ZX_PWM_EN); | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | static int zx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | |
151 | struct pwm_state *state) | |
152 | { | |
153 | struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); | |
154 | struct pwm_state cstate; | |
155 | int ret; | |
156 | ||
157 | pwm_get_state(pwm, &cstate); | |
158 | ||
159 | if (state->polarity != cstate.polarity) | |
160 | zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_POLAR, | |
161 | (state->polarity == PWM_POLARITY_INVERSED) ? | |
162 | 0 : ZX_PWM_POLAR); | |
163 | ||
164 | if (state->period != cstate.period || | |
165 | state->duty_cycle != cstate.duty_cycle) { | |
166 | ret = zx_pwm_config(chip, pwm, state->duty_cycle, | |
167 | state->period); | |
168 | if (ret) | |
169 | return ret; | |
170 | } | |
171 | ||
172 | if (state->enabled != cstate.enabled) { | |
173 | if (state->enabled) { | |
174 | ret = clk_prepare_enable(zpc->wclk); | |
175 | if (ret) | |
176 | return ret; | |
177 | ||
178 | zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, | |
179 | ZX_PWM_EN, ZX_PWM_EN); | |
180 | } else { | |
181 | zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, | |
182 | ZX_PWM_EN, 0); | |
183 | clk_disable_unprepare(zpc->wclk); | |
184 | } | |
185 | } | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
190 | static const struct pwm_ops zx_pwm_ops = { | |
191 | .apply = zx_pwm_apply, | |
192 | .get_state = zx_pwm_get_state, | |
193 | .owner = THIS_MODULE, | |
194 | }; | |
195 | ||
196 | static int zx_pwm_probe(struct platform_device *pdev) | |
197 | { | |
198 | struct zx_pwm_chip *zpc; | |
199 | struct resource *res; | |
200 | unsigned int i; | |
201 | int ret; | |
202 | ||
203 | zpc = devm_kzalloc(&pdev->dev, sizeof(*zpc), GFP_KERNEL); | |
204 | if (!zpc) | |
205 | return -ENOMEM; | |
206 | ||
207 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
208 | zpc->base = devm_ioremap_resource(&pdev->dev, res); | |
209 | if (IS_ERR(zpc->base)) | |
210 | return PTR_ERR(zpc->base); | |
211 | ||
212 | zpc->pclk = devm_clk_get(&pdev->dev, "pclk"); | |
213 | if (IS_ERR(zpc->pclk)) | |
214 | return PTR_ERR(zpc->pclk); | |
215 | ||
216 | zpc->wclk = devm_clk_get(&pdev->dev, "wclk"); | |
217 | if (IS_ERR(zpc->wclk)) | |
218 | return PTR_ERR(zpc->wclk); | |
219 | ||
220 | ret = clk_prepare_enable(zpc->pclk); | |
221 | if (ret) | |
222 | return ret; | |
223 | ||
224 | zpc->chip.dev = &pdev->dev; | |
225 | zpc->chip.ops = &zx_pwm_ops; | |
226 | zpc->chip.base = -1; | |
227 | zpc->chip.npwm = 4; | |
228 | zpc->chip.of_xlate = of_pwm_xlate_with_flags; | |
229 | zpc->chip.of_pwm_n_cells = 3; | |
230 | ||
231 | /* | |
232 | * PWM devices may be enabled by firmware, and let's disable all of | |
233 | * them initially to save power. | |
234 | */ | |
235 | for (i = 0; i < zpc->chip.npwm; i++) | |
236 | zx_pwm_set_mask(zpc, i, ZX_PWM_MODE, ZX_PWM_EN, 0); | |
237 | ||
238 | ret = pwmchip_add(&zpc->chip); | |
239 | if (ret < 0) { | |
240 | dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); | |
241 | return ret; | |
242 | } | |
243 | ||
244 | platform_set_drvdata(pdev, zpc); | |
245 | ||
246 | return 0; | |
247 | } | |
248 | ||
249 | static int zx_pwm_remove(struct platform_device *pdev) | |
250 | { | |
251 | struct zx_pwm_chip *zpc = platform_get_drvdata(pdev); | |
252 | int ret; | |
253 | ||
254 | ret = pwmchip_remove(&zpc->chip); | |
255 | clk_disable_unprepare(zpc->pclk); | |
256 | ||
257 | return ret; | |
258 | } | |
259 | ||
260 | static const struct of_device_id zx_pwm_dt_ids[] = { | |
261 | { .compatible = "zte,zx296718-pwm", }, | |
262 | { /* sentinel */ } | |
263 | }; | |
264 | MODULE_DEVICE_TABLE(of, zx_pwm_dt_ids); | |
265 | ||
266 | static struct platform_driver zx_pwm_driver = { | |
267 | .driver = { | |
268 | .name = "zx-pwm", | |
269 | .of_match_table = zx_pwm_dt_ids, | |
270 | }, | |
271 | .probe = zx_pwm_probe, | |
272 | .remove = zx_pwm_remove, | |
273 | }; | |
274 | module_platform_driver(zx_pwm_driver); | |
275 | ||
276 | MODULE_ALIAS("platform:zx-pwm"); | |
277 | MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); | |
278 | MODULE_DESCRIPTION("ZTE ZX PWM Driver"); | |
279 | MODULE_LICENSE("GPL v2"); |