Commit | Line | Data |
---|---|---|
34c6507c MP |
1 | /* |
2 | * PWM Greybus driver. | |
3 | * | |
4 | * Copyright 2014 Google Inc. | |
5 | * Copyright 2014 Linaro Ltd. | |
6 | * | |
7 | * Released under the GPLv2 only. | |
8 | */ | |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/slab.h> | |
13 | #include <linux/pwm.h> | |
e9385e5d | 14 | |
34c6507c | 15 | #include "greybus.h" |
e54b106d | 16 | #include "gbphy.h" |
34c6507c MP |
17 | |
18 | struct gb_pwm_chip { | |
19 | struct gb_connection *connection; | |
34c6507c MP |
20 | u8 pwm_max; /* max pwm number */ |
21 | ||
22 | struct pwm_chip chip; | |
23 | struct pwm_chip *pwm; | |
24 | }; | |
25 | #define pwm_chip_to_gb_pwm_chip(chip) \ | |
26 | container_of(chip, struct gb_pwm_chip, chip) | |
27 | ||
34c6507c | 28 | |
34c6507c MP |
29 | static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc) |
30 | { | |
bf2329fd | 31 | struct gb_pwm_count_response response; |
34c6507c MP |
32 | int ret; |
33 | ||
bf2329fd GKH |
34 | ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT, |
35 | NULL, 0, &response, sizeof(response)); | |
36 | if (ret) | |
37 | return ret; | |
38 | pwmc->pwm_max = response.count; | |
39 | return 0; | |
34c6507c MP |
40 | } |
41 | ||
42 | static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc, | |
43 | u8 which) | |
44 | { | |
bf2329fd | 45 | struct gb_pwm_activate_request request; |
afa807b8 AH |
46 | struct gbphy_device *gbphy_dev; |
47 | int ret; | |
34c6507c MP |
48 | |
49 | if (which > pwmc->pwm_max) | |
50 | return -EINVAL; | |
51 | ||
bf2329fd | 52 | request.which = which; |
afa807b8 AH |
53 | |
54 | gbphy_dev = to_gbphy_dev(pwmc->chip.dev); | |
55 | ret = gbphy_runtime_get_sync(gbphy_dev); | |
56 | if (ret) | |
57 | return ret; | |
58 | ||
59 | ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ACTIVATE, | |
60 | &request, sizeof(request), NULL, 0); | |
61 | ||
62 | gbphy_runtime_put_autosuspend(gbphy_dev); | |
63 | ||
64 | return ret; | |
34c6507c MP |
65 | } |
66 | ||
67 | static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc, | |
68 | u8 which) | |
69 | { | |
bf2329fd | 70 | struct gb_pwm_deactivate_request request; |
afa807b8 AH |
71 | struct gbphy_device *gbphy_dev; |
72 | int ret; | |
34c6507c MP |
73 | |
74 | if (which > pwmc->pwm_max) | |
75 | return -EINVAL; | |
76 | ||
bf2329fd | 77 | request.which = which; |
afa807b8 AH |
78 | |
79 | gbphy_dev = to_gbphy_dev(pwmc->chip.dev); | |
80 | ret = gbphy_runtime_get_sync(gbphy_dev); | |
81 | if (ret) | |
82 | return ret; | |
83 | ||
84 | ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DEACTIVATE, | |
85 | &request, sizeof(request), NULL, 0); | |
86 | ||
87 | gbphy_runtime_put_autosuspend(gbphy_dev); | |
88 | ||
89 | return ret; | |
34c6507c MP |
90 | } |
91 | ||
92 | static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc, | |
93 | u8 which, u32 duty, u32 period) | |
94 | { | |
bf2329fd | 95 | struct gb_pwm_config_request request; |
afa807b8 AH |
96 | struct gbphy_device *gbphy_dev; |
97 | int ret; | |
34c6507c MP |
98 | |
99 | if (which > pwmc->pwm_max) | |
100 | return -EINVAL; | |
101 | ||
bf2329fd | 102 | request.which = which; |
583d233f AE |
103 | request.duty = cpu_to_le32(duty); |
104 | request.period = cpu_to_le32(period); | |
afa807b8 AH |
105 | |
106 | gbphy_dev = to_gbphy_dev(pwmc->chip.dev); | |
107 | ret = gbphy_runtime_get_sync(gbphy_dev); | |
108 | if (ret) | |
109 | return ret; | |
110 | ||
111 | ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_CONFIG, | |
112 | &request, sizeof(request), NULL, 0); | |
113 | ||
114 | gbphy_runtime_put_autosuspend(gbphy_dev); | |
115 | ||
116 | return ret; | |
34c6507c MP |
117 | } |
118 | ||
34c6507c MP |
119 | static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc, |
120 | u8 which, u8 polarity) | |
121 | { | |
bf2329fd | 122 | struct gb_pwm_polarity_request request; |
afa807b8 AH |
123 | struct gbphy_device *gbphy_dev; |
124 | int ret; | |
34c6507c MP |
125 | |
126 | if (which > pwmc->pwm_max) | |
127 | return -EINVAL; | |
128 | ||
bf2329fd GKH |
129 | request.which = which; |
130 | request.polarity = polarity; | |
afa807b8 AH |
131 | |
132 | gbphy_dev = to_gbphy_dev(pwmc->chip.dev); | |
133 | ret = gbphy_runtime_get_sync(gbphy_dev); | |
134 | if (ret) | |
135 | return ret; | |
136 | ||
137 | ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_POLARITY, | |
138 | &request, sizeof(request), NULL, 0); | |
139 | ||
140 | gbphy_runtime_put_autosuspend(gbphy_dev); | |
141 | ||
142 | return ret; | |
34c6507c MP |
143 | } |
144 | ||
145 | static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc, | |
146 | u8 which) | |
147 | { | |
bf2329fd | 148 | struct gb_pwm_enable_request request; |
afa807b8 AH |
149 | struct gbphy_device *gbphy_dev; |
150 | int ret; | |
34c6507c MP |
151 | |
152 | if (which > pwmc->pwm_max) | |
153 | return -EINVAL; | |
154 | ||
bf2329fd | 155 | request.which = which; |
afa807b8 AH |
156 | |
157 | gbphy_dev = to_gbphy_dev(pwmc->chip.dev); | |
158 | ret = gbphy_runtime_get_sync(gbphy_dev); | |
159 | if (ret) | |
160 | return ret; | |
161 | ||
162 | ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ENABLE, | |
163 | &request, sizeof(request), NULL, 0); | |
164 | if (ret) | |
165 | gbphy_runtime_put_autosuspend(gbphy_dev); | |
166 | ||
167 | return ret; | |
34c6507c MP |
168 | } |
169 | ||
170 | static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc, | |
171 | u8 which) | |
172 | { | |
bf2329fd | 173 | struct gb_pwm_disable_request request; |
afa807b8 AH |
174 | struct gbphy_device *gbphy_dev; |
175 | int ret; | |
34c6507c MP |
176 | |
177 | if (which > pwmc->pwm_max) | |
178 | return -EINVAL; | |
179 | ||
bf2329fd | 180 | request.which = which; |
afa807b8 AH |
181 | |
182 | ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE, | |
183 | &request, sizeof(request), NULL, 0); | |
184 | ||
185 | gbphy_dev = to_gbphy_dev(pwmc->chip.dev); | |
186 | gbphy_runtime_put_autosuspend(gbphy_dev); | |
187 | ||
188 | return ret; | |
34c6507c MP |
189 | } |
190 | ||
191 | static int gb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) | |
192 | { | |
193 | struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip); | |
194 | ||
195 | return gb_pwm_activate_operation(pwmc, pwm->hwpwm); | |
196 | }; | |
197 | ||
198 | static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | |
199 | { | |
200 | struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip); | |
201 | ||
44d64493 | 202 | if (pwm_is_enabled(pwm)) |
34c6507c MP |
203 | dev_warn(chip->dev, "freeing PWM device without disabling\n"); |
204 | ||
205 | gb_pwm_deactivate_operation(pwmc, pwm->hwpwm); | |
206 | } | |
207 | ||
208 | static int gb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |
209 | int duty_ns, int period_ns) | |
210 | { | |
211 | struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip); | |
212 | ||
213 | return gb_pwm_config_operation(pwmc, pwm->hwpwm, duty_ns, period_ns); | |
214 | }; | |
215 | ||
216 | static int gb_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, | |
217 | enum pwm_polarity polarity) | |
218 | { | |
219 | struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip); | |
220 | ||
221 | return gb_pwm_set_polarity_operation(pwmc, pwm->hwpwm, polarity); | |
222 | }; | |
223 | ||
224 | static int gb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |
225 | { | |
226 | struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip); | |
227 | ||
228 | return gb_pwm_enable_operation(pwmc, pwm->hwpwm); | |
229 | }; | |
230 | ||
231 | static void gb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |
232 | { | |
233 | struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip); | |
234 | ||
235 | gb_pwm_disable_operation(pwmc, pwm->hwpwm); | |
236 | }; | |
237 | ||
238 | static const struct pwm_ops gb_pwm_ops = { | |
239 | .request = gb_pwm_request, | |
240 | .free = gb_pwm_free, | |
241 | .config = gb_pwm_config, | |
242 | .set_polarity = gb_pwm_set_polarity, | |
243 | .enable = gb_pwm_enable, | |
244 | .disable = gb_pwm_disable, | |
245 | .owner = THIS_MODULE, | |
246 | }; | |
247 | ||
e54b106d SP |
248 | static int gb_pwm_probe(struct gbphy_device *gbphy_dev, |
249 | const struct gbphy_device_id *id) | |
34c6507c | 250 | { |
32054908 | 251 | struct gb_connection *connection; |
34c6507c MP |
252 | struct gb_pwm_chip *pwmc; |
253 | struct pwm_chip *pwm; | |
254 | int ret; | |
255 | ||
256 | pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL); | |
257 | if (!pwmc) | |
258 | return -ENOMEM; | |
32054908 | 259 | |
e54b106d SP |
260 | connection = gb_connection_create(gbphy_dev->bundle, |
261 | le16_to_cpu(gbphy_dev->cport_desc->id), | |
32054908 GKH |
262 | NULL); |
263 | if (IS_ERR(connection)) { | |
264 | ret = PTR_ERR(connection); | |
265 | goto exit_pwmc_free; | |
266 | } | |
267 | ||
34c6507c | 268 | pwmc->connection = connection; |
0ec30632 | 269 | gb_connection_set_data(connection, pwmc); |
e54b106d | 270 | gb_gbphy_set_data(gbphy_dev, pwmc); |
32054908 GKH |
271 | |
272 | ret = gb_connection_enable(connection); | |
273 | if (ret) | |
274 | goto exit_connection_destroy; | |
275 | ||
34c6507c MP |
276 | /* Query number of pwms present */ |
277 | ret = gb_pwm_count_operation(pwmc); | |
278 | if (ret) | |
32054908 | 279 | goto exit_connection_disable; |
34c6507c MP |
280 | |
281 | pwm = &pwmc->chip; | |
282 | ||
e54b106d | 283 | pwm->dev = &gbphy_dev->dev; |
34c6507c MP |
284 | pwm->ops = &gb_pwm_ops; |
285 | pwm->base = -1; /* Allocate base dynamically */ | |
286 | pwm->npwm = pwmc->pwm_max + 1; | |
34c6507c MP |
287 | |
288 | ret = pwmchip_add(pwm); | |
289 | if (ret) { | |
e54b106d | 290 | dev_err(&gbphy_dev->dev, |
8d5732f4 | 291 | "failed to register PWM: %d\n", ret); |
32054908 | 292 | goto exit_connection_disable; |
34c6507c | 293 | } |
34c6507c | 294 | |
afa807b8 | 295 | gbphy_runtime_put_autosuspend(gbphy_dev); |
34c6507c | 296 | return 0; |
32054908 GKH |
297 | |
298 | exit_connection_disable: | |
299 | gb_connection_disable(connection); | |
300 | exit_connection_destroy: | |
301 | gb_connection_destroy(connection); | |
302 | exit_pwmc_free: | |
34c6507c MP |
303 | kfree(pwmc); |
304 | return ret; | |
305 | } | |
306 | ||
e54b106d | 307 | static void gb_pwm_remove(struct gbphy_device *gbphy_dev) |
34c6507c | 308 | { |
e54b106d | 309 | struct gb_pwm_chip *pwmc = gb_gbphy_get_data(gbphy_dev); |
32054908 | 310 | struct gb_connection *connection = pwmc->connection; |
afa807b8 AH |
311 | int ret; |
312 | ||
313 | ret = gbphy_runtime_get_sync(gbphy_dev); | |
314 | if (ret) | |
315 | gbphy_runtime_get_noresume(gbphy_dev); | |
34c6507c MP |
316 | |
317 | pwmchip_remove(&pwmc->chip); | |
32054908 GKH |
318 | gb_connection_disable(connection); |
319 | gb_connection_destroy(connection); | |
34c6507c MP |
320 | kfree(pwmc); |
321 | } | |
322 | ||
e54b106d SP |
323 | static const struct gbphy_device_id gb_pwm_id_table[] = { |
324 | { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_PWM) }, | |
32054908 | 325 | { }, |
34c6507c | 326 | }; |
e54b106d | 327 | MODULE_DEVICE_TABLE(gbphy, gb_pwm_id_table); |
34c6507c | 328 | |
e54b106d | 329 | static struct gbphy_driver pwm_driver = { |
32054908 GKH |
330 | .name = "pwm", |
331 | .probe = gb_pwm_probe, | |
332 | .remove = gb_pwm_remove, | |
333 | .id_table = gb_pwm_id_table, | |
334 | }; | |
dca8060d | 335 | |
e54b106d | 336 | module_gbphy_driver(pwm_driver); |
dca8060d | 337 | MODULE_LICENSE("GPL v2"); |