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