blob: 4e38b8a4624e4b16f73371bb96bce39f42bee743 [file] [log] [blame]
Matt Porter34c65072014-11-13 09:14:13 -05001/*
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>
14#include "greybus.h"
15
16struct gb_pwm_chip {
17 struct gb_connection *connection;
18 u8 version_major;
19 u8 version_minor;
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
28/* Version of the Greybus PWM protocol we support */
29#define GB_PWM_VERSION_MAJOR 0x00
30#define GB_PWM_VERSION_MINOR 0x01
31
32/* Greybus PWM request types */
33#define GB_PWM_TYPE_INVALID 0x00
34#define GB_PWM_TYPE_PROTOCOL_VERSION 0x01
35#define GB_PWM_TYPE_PWM_COUNT 0x02
36#define GB_PWM_TYPE_ACTIVATE 0x03
37#define GB_PWM_TYPE_DEACTIVATE 0x04
38#define GB_PWM_TYPE_CONFIG 0x05
39#define GB_PWM_TYPE_POLARITY 0x06
40#define GB_PWM_TYPE_ENABLE 0x07
41#define GB_PWM_TYPE_DISABLE 0x08
42#define GB_PWM_TYPE_RESPONSE 0x80 /* OR'd with rest */
43
Matt Porter34c65072014-11-13 09:14:13 -050044/* pwm count request has no payload */
45struct gb_pwm_count_response {
Matt Porter34c65072014-11-13 09:14:13 -050046 __u8 count;
47};
48
49struct gb_pwm_activate_request {
50 __u8 which;
51};
52
53struct gb_pwm_deactivate_request {
54 __u8 which;
55};
56
57struct gb_pwm_config_request {
58 __u8 which;
Johan Hovoldb41caa92015-03-17 18:24:29 +010059 __le32 duty __packed;
60 __le32 period __packed;
Matt Porter34c65072014-11-13 09:14:13 -050061};
62
63struct gb_pwm_polarity_request {
64 __u8 which;
65 __u8 polarity;
66};
67
68struct gb_pwm_enable_request {
69 __u8 which;
70};
71
72struct gb_pwm_disable_request {
73 __u8 which;
74};
75
Viresh Kumar36e79de2015-01-21 18:12:36 +053076/* Define get_version() routine */
77define_get_version(gb_pwm_chip, PWM);
Matt Porter34c65072014-11-13 09:14:13 -050078
79static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
80{
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -080081 struct gb_pwm_count_response response;
Matt Porter34c65072014-11-13 09:14:13 -050082 int ret;
83
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -080084 ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT,
85 NULL, 0, &response, sizeof(response));
86 if (ret)
87 return ret;
88 pwmc->pwm_max = response.count;
89 return 0;
Matt Porter34c65072014-11-13 09:14:13 -050090}
91
92static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
93 u8 which)
94{
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -080095 struct gb_pwm_activate_request request;
Matt Porter34c65072014-11-13 09:14:13 -050096
97 if (which > pwmc->pwm_max)
98 return -EINVAL;
99
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800100 request.which = which;
101 return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ACTIVATE,
102 &request, sizeof(request), NULL, 0);
Matt Porter34c65072014-11-13 09:14:13 -0500103}
104
105static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
106 u8 which)
107{
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800108 struct gb_pwm_deactivate_request request;
Matt Porter34c65072014-11-13 09:14:13 -0500109
110 if (which > pwmc->pwm_max)
111 return -EINVAL;
112
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800113 request.which = which;
114 return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DEACTIVATE,
115 &request, sizeof(request), NULL, 0);
Matt Porter34c65072014-11-13 09:14:13 -0500116}
117
118static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
119 u8 which, u32 duty, u32 period)
120{
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800121 struct gb_pwm_config_request request;
Matt Porter34c65072014-11-13 09:14:13 -0500122
123 if (which > pwmc->pwm_max)
124 return -EINVAL;
125
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800126 request.which = which;
Alex Elder583d2332014-12-02 15:48:09 -0600127 request.duty = cpu_to_le32(duty);
128 request.period = cpu_to_le32(period);
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800129 return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_CONFIG,
130 &request, sizeof(request), NULL, 0);
Matt Porter34c65072014-11-13 09:14:13 -0500131}
132
133
134static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
135 u8 which, u8 polarity)
136{
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800137 struct gb_pwm_polarity_request request;
Matt Porter34c65072014-11-13 09:14:13 -0500138
139 if (which > pwmc->pwm_max)
140 return -EINVAL;
141
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800142 request.which = which;
143 request.polarity = polarity;
144 return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_POLARITY,
145 &request, sizeof(request), NULL, 0);
Matt Porter34c65072014-11-13 09:14:13 -0500146}
147
148static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
149 u8 which)
150{
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800151 struct gb_pwm_enable_request request;
Matt Porter34c65072014-11-13 09:14:13 -0500152
153 if (which > pwmc->pwm_max)
154 return -EINVAL;
155
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800156 request.which = which;
157 return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ENABLE,
158 &request, sizeof(request), NULL, 0);
Matt Porter34c65072014-11-13 09:14:13 -0500159}
160
161static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
162 u8 which)
163{
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800164 struct gb_pwm_disable_request request;
Matt Porter34c65072014-11-13 09:14:13 -0500165
166 if (which > pwmc->pwm_max)
167 return -EINVAL;
168
Greg Kroah-Hartmanbf2329f2014-11-23 17:45:24 -0800169 request.which = which;
170 return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,
171 &request, sizeof(request), NULL, 0);
Matt Porter34c65072014-11-13 09:14:13 -0500172}
173
174static int gb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
175{
176 struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
177
178 return gb_pwm_activate_operation(pwmc, pwm->hwpwm);
179};
180
181static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
182{
183 struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
184
185 if (test_bit(PWMF_ENABLED, &pwm->flags))
186 dev_warn(chip->dev, "freeing PWM device without disabling\n");
187
188 gb_pwm_deactivate_operation(pwmc, pwm->hwpwm);
189}
190
191static int gb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
192 int duty_ns, int period_ns)
193{
194 struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
195
196 return gb_pwm_config_operation(pwmc, pwm->hwpwm, duty_ns, period_ns);
197};
198
199static int gb_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
200 enum pwm_polarity polarity)
201{
202 struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
203
204 return gb_pwm_set_polarity_operation(pwmc, pwm->hwpwm, polarity);
205};
206
207static int gb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
208{
209 struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
210
211 return gb_pwm_enable_operation(pwmc, pwm->hwpwm);
212};
213
214static void gb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
215{
216 struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
217
218 gb_pwm_disable_operation(pwmc, pwm->hwpwm);
219};
220
221static const struct pwm_ops gb_pwm_ops = {
222 .request = gb_pwm_request,
223 .free = gb_pwm_free,
224 .config = gb_pwm_config,
225 .set_polarity = gb_pwm_set_polarity,
226 .enable = gb_pwm_enable,
227 .disable = gb_pwm_disable,
228 .owner = THIS_MODULE,
229};
230
231static int gb_pwm_connection_init(struct gb_connection *connection)
232{
233 struct gb_pwm_chip *pwmc;
234 struct pwm_chip *pwm;
235 int ret;
236
237 pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL);
238 if (!pwmc)
239 return -ENOMEM;
240 pwmc->connection = connection;
Alex Elder93bbe852014-12-03 12:27:42 -0600241 connection->private = pwmc;
Matt Porter34c65072014-11-13 09:14:13 -0500242
243 /* Check for compatible protocol version */
Viresh Kumar36e79de2015-01-21 18:12:36 +0530244 ret = get_version(pwmc);
Matt Porter34c65072014-11-13 09:14:13 -0500245 if (ret)
246 goto out_err;
247
248 /* Query number of pwms present */
249 ret = gb_pwm_count_operation(pwmc);
250 if (ret)
251 goto out_err;
252
253 pwm = &pwmc->chip;
254
255 pwm->dev = &connection->dev;
256 pwm->ops = &gb_pwm_ops;
257 pwm->base = -1; /* Allocate base dynamically */
258 pwm->npwm = pwmc->pwm_max + 1;
259 pwm->can_sleep = true; /* FIXME */
260
261 ret = pwmchip_add(pwm);
262 if (ret) {
263 pr_err("Failed to register PWM\n");
Johan Hovold6a80ed42015-03-17 10:55:50 +0100264 goto out_err;
Matt Porter34c65072014-11-13 09:14:13 -0500265 }
Matt Porter34c65072014-11-13 09:14:13 -0500266
267 return 0;
268out_err:
269 kfree(pwmc);
270 return ret;
271}
272
273static void gb_pwm_connection_exit(struct gb_connection *connection)
274{
275 struct gb_pwm_chip *pwmc = connection->private;
276
277 if (!pwmc)
278 return;
279
280 pwmchip_remove(&pwmc->chip);
281 /* kref_put(pwmc->connection) */
282 kfree(pwmc);
283}
284
285static struct gb_protocol pwm_protocol = {
Greg Kroah-Hartman7422a1e2014-12-24 13:01:45 -0800286 .name = "pwm",
Matt Porter34c65072014-11-13 09:14:13 -0500287 .id = GREYBUS_PROTOCOL_PWM,
288 .major = 0,
289 .minor = 1,
290 .connection_init = gb_pwm_connection_init,
291 .connection_exit = gb_pwm_connection_exit,
292 .request_recv = NULL, /* no incoming requests */
293};
294
Greg Kroah-Hartman7c7d5b92014-12-23 15:16:51 -0800295int gb_pwm_protocol_init(void)
Matt Porter34c65072014-11-13 09:14:13 -0500296{
297 return gb_protocol_register(&pwm_protocol);
298}
299
300void gb_pwm_protocol_exit(void)
301{
302 gb_protocol_deregister(&pwm_protocol);
303}