xref: /linux/drivers/pwm/pwm-cros-ec.c (revision c5dbf04160005e07e8ca7232a7faa77ab1547ae0)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Expose a PWM controlled by the ChromeOS EC to the host processor.
4  *
5  * Copyright (C) 2016 Google, Inc.
6  */
7 
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/platform_data/cros_ec_commands.h>
11 #include <linux/platform_data/cros_ec_proto.h>
12 #include <linux/platform_device.h>
13 #include <linux/pwm.h>
14 #include <linux/slab.h>
15 
16 #include <dt-bindings/mfd/cros_ec.h>
17 
18 /**
19  * struct cros_ec_pwm_device - Driver data for EC PWM
20  *
21  * @dev: Device node
22  * @ec: Pointer to EC device
23  * @chip: PWM controller chip
24  * @use_pwm_type: Use PWM types instead of generic channels
25  * @channel: array with per-channel data
26  */
27 struct cros_ec_pwm_device {
28 	struct device *dev;
29 	struct cros_ec_device *ec;
30 	struct pwm_chip chip;
31 	bool use_pwm_type;
32 	struct cros_ec_pwm *channel;
33 };
34 
35 /**
36  * struct cros_ec_pwm - per-PWM driver data
37  * @duty_cycle: cached duty cycle
38  */
39 struct cros_ec_pwm {
40 	u16 duty_cycle;
41 };
42 
43 static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *chip)
44 {
45 	return container_of(chip, struct cros_ec_pwm_device, chip);
46 }
47 
48 static int cros_ec_dt_type_to_pwm_type(u8 dt_index, u8 *pwm_type)
49 {
50 	switch (dt_index) {
51 	case CROS_EC_PWM_DT_KB_LIGHT:
52 		*pwm_type = EC_PWM_TYPE_KB_LIGHT;
53 		return 0;
54 	case CROS_EC_PWM_DT_DISPLAY_LIGHT:
55 		*pwm_type = EC_PWM_TYPE_DISPLAY_LIGHT;
56 		return 0;
57 	default:
58 		return -EINVAL;
59 	}
60 }
61 
62 static int cros_ec_pwm_set_duty(struct cros_ec_pwm_device *ec_pwm, u8 index,
63 				u16 duty)
64 {
65 	struct cros_ec_device *ec = ec_pwm->ec;
66 	struct {
67 		struct cros_ec_command msg;
68 		struct ec_params_pwm_set_duty params;
69 	} __packed buf;
70 	struct ec_params_pwm_set_duty *params = &buf.params;
71 	struct cros_ec_command *msg = &buf.msg;
72 	int ret;
73 
74 	memset(&buf, 0, sizeof(buf));
75 
76 	msg->version = 0;
77 	msg->command = EC_CMD_PWM_SET_DUTY;
78 	msg->insize = 0;
79 	msg->outsize = sizeof(*params);
80 
81 	params->duty = duty;
82 
83 	if (ec_pwm->use_pwm_type) {
84 		ret = cros_ec_dt_type_to_pwm_type(index, &params->pwm_type);
85 		if (ret) {
86 			dev_err(ec->dev, "Invalid PWM type index: %d\n", index);
87 			return ret;
88 		}
89 		params->index = 0;
90 	} else {
91 		params->pwm_type = EC_PWM_TYPE_GENERIC;
92 		params->index = index;
93 	}
94 
95 	return cros_ec_cmd_xfer_status(ec, msg);
96 }
97 
98 static int cros_ec_pwm_get_duty(struct cros_ec_pwm_device *ec_pwm, u8 index)
99 {
100 	struct cros_ec_device *ec = ec_pwm->ec;
101 	struct {
102 		struct cros_ec_command msg;
103 		union {
104 			struct ec_params_pwm_get_duty params;
105 			struct ec_response_pwm_get_duty resp;
106 		};
107 	} __packed buf;
108 	struct ec_params_pwm_get_duty *params = &buf.params;
109 	struct ec_response_pwm_get_duty *resp = &buf.resp;
110 	struct cros_ec_command *msg = &buf.msg;
111 	int ret;
112 
113 	memset(&buf, 0, sizeof(buf));
114 
115 	msg->version = 0;
116 	msg->command = EC_CMD_PWM_GET_DUTY;
117 	msg->insize = sizeof(*resp);
118 	msg->outsize = sizeof(*params);
119 
120 	if (ec_pwm->use_pwm_type) {
121 		ret = cros_ec_dt_type_to_pwm_type(index, &params->pwm_type);
122 		if (ret) {
123 			dev_err(ec->dev, "Invalid PWM type index: %d\n", index);
124 			return ret;
125 		}
126 		params->index = 0;
127 	} else {
128 		params->pwm_type = EC_PWM_TYPE_GENERIC;
129 		params->index = index;
130 	}
131 
132 	ret = cros_ec_cmd_xfer_status(ec, msg);
133 	if (ret < 0)
134 		return ret;
135 
136 	return resp->duty;
137 }
138 
139 static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
140 			     const struct pwm_state *state)
141 {
142 	struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
143 	struct cros_ec_pwm *channel = &ec_pwm->channel[pwm->hwpwm];
144 	u16 duty_cycle;
145 	int ret;
146 
147 	/* The EC won't let us change the period */
148 	if (state->period != EC_PWM_MAX_DUTY)
149 		return -EINVAL;
150 
151 	if (state->polarity != PWM_POLARITY_NORMAL)
152 		return -EINVAL;
153 
154 	/*
155 	 * EC doesn't separate the concept of duty cycle and enabled, but
156 	 * kernel does. Translate.
157 	 */
158 	duty_cycle = state->enabled ? state->duty_cycle : 0;
159 
160 	ret = cros_ec_pwm_set_duty(ec_pwm, pwm->hwpwm, duty_cycle);
161 	if (ret < 0)
162 		return ret;
163 
164 	channel->duty_cycle = state->duty_cycle;
165 
166 	return 0;
167 }
168 
169 static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
170 				 struct pwm_state *state)
171 {
172 	struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
173 	struct cros_ec_pwm *channel = &ec_pwm->channel[pwm->hwpwm];
174 	int ret;
175 
176 	ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm);
177 	if (ret < 0) {
178 		dev_err(chip->dev, "error getting initial duty: %d\n", ret);
179 		return ret;
180 	}
181 
182 	state->enabled = (ret > 0);
183 	state->period = EC_PWM_MAX_DUTY;
184 	state->polarity = PWM_POLARITY_NORMAL;
185 
186 	/*
187 	 * Note that "disabled" and "duty cycle == 0" are treated the same. If
188 	 * the cached duty cycle is not zero, used the cached duty cycle. This
189 	 * ensures that the configured duty cycle is kept across a disable and
190 	 * enable operation and avoids potentially confusing consumers.
191 	 *
192 	 * For the case of the initial hardware readout, channel->duty_cycle
193 	 * will be 0 and the actual duty cycle read from the EC is used.
194 	 */
195 	if (ret == 0 && channel->duty_cycle > 0)
196 		state->duty_cycle = channel->duty_cycle;
197 	else
198 		state->duty_cycle = ret;
199 
200 	return 0;
201 }
202 
203 static struct pwm_device *
204 cros_ec_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args)
205 {
206 	struct pwm_device *pwm;
207 
208 	if (args->args[0] >= chip->npwm)
209 		return ERR_PTR(-EINVAL);
210 
211 	pwm = pwm_request_from_chip(chip, args->args[0], NULL);
212 	if (IS_ERR(pwm))
213 		return pwm;
214 
215 	/* The EC won't let us change the period */
216 	pwm->args.period = EC_PWM_MAX_DUTY;
217 
218 	return pwm;
219 }
220 
221 static const struct pwm_ops cros_ec_pwm_ops = {
222 	.get_state	= cros_ec_pwm_get_state,
223 	.apply		= cros_ec_pwm_apply,
224 };
225 
226 /*
227  * Determine the number of supported PWMs. The EC does not return the number
228  * of PWMs it supports directly, so we have to read the pwm duty cycle for
229  * subsequent channels until we get an error.
230  */
231 static int cros_ec_num_pwms(struct cros_ec_pwm_device *ec_pwm)
232 {
233 	int i, ret;
234 
235 	/* The index field is only 8 bits */
236 	for (i = 0; i <= U8_MAX; i++) {
237 		ret = cros_ec_pwm_get_duty(ec_pwm, i);
238 		/*
239 		 * We look for SUCCESS, INVALID_COMMAND, or INVALID_PARAM
240 		 * responses; everything else is treated as an error.
241 		 * The EC error codes map to -EOPNOTSUPP and -EINVAL,
242 		 * so check for those.
243 		 */
244 		switch (ret) {
245 		case -EOPNOTSUPP:	/* invalid command */
246 			return -ENODEV;
247 		case -EINVAL:		/* invalid parameter */
248 			return i;
249 		default:
250 			if (ret < 0)
251 				return ret;
252 			break;
253 		}
254 	}
255 
256 	return U8_MAX;
257 }
258 
259 static int cros_ec_pwm_probe(struct platform_device *pdev)
260 {
261 	struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
262 	struct device *dev = &pdev->dev;
263 	struct device_node *np = pdev->dev.of_node;
264 	struct cros_ec_pwm_device *ec_pwm;
265 	struct pwm_chip *chip;
266 	int ret;
267 
268 	if (!ec)
269 		return dev_err_probe(dev, -EINVAL, "no parent EC device\n");
270 
271 	ec_pwm = devm_kzalloc(dev, sizeof(*ec_pwm), GFP_KERNEL);
272 	if (!ec_pwm)
273 		return -ENOMEM;
274 	chip = &ec_pwm->chip;
275 	ec_pwm->ec = ec;
276 
277 	if (of_device_is_compatible(np, "google,cros-ec-pwm-type"))
278 		ec_pwm->use_pwm_type = true;
279 
280 	/* PWM chip */
281 	chip->dev = dev;
282 	chip->ops = &cros_ec_pwm_ops;
283 	chip->of_xlate = cros_ec_pwm_xlate;
284 	chip->of_pwm_n_cells = 1;
285 
286 	if (ec_pwm->use_pwm_type) {
287 		chip->npwm = CROS_EC_PWM_DT_COUNT;
288 	} else {
289 		ret = cros_ec_num_pwms(ec_pwm);
290 		if (ret < 0)
291 			return dev_err_probe(dev, ret, "Couldn't find PWMs\n");
292 		chip->npwm = ret;
293 	}
294 
295 	ec_pwm->channel = devm_kcalloc(dev, chip->npwm, sizeof(*ec_pwm->channel),
296 					GFP_KERNEL);
297 	if (!ec_pwm->channel)
298 		return -ENOMEM;
299 
300 	dev_dbg(dev, "Probed %u PWMs\n", chip->npwm);
301 
302 	ret = devm_pwmchip_add(dev, chip);
303 	if (ret < 0)
304 		return dev_err_probe(dev, ret, "cannot register PWM\n");
305 
306 	return 0;
307 }
308 
309 #ifdef CONFIG_OF
310 static const struct of_device_id cros_ec_pwm_of_match[] = {
311 	{ .compatible = "google,cros-ec-pwm" },
312 	{ .compatible = "google,cros-ec-pwm-type" },
313 	{},
314 };
315 MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match);
316 #endif
317 
318 static struct platform_driver cros_ec_pwm_driver = {
319 	.probe = cros_ec_pwm_probe,
320 	.driver = {
321 		.name = "cros-ec-pwm",
322 		.of_match_table = of_match_ptr(cros_ec_pwm_of_match),
323 	},
324 };
325 module_platform_driver(cros_ec_pwm_driver);
326 
327 MODULE_ALIAS("platform:cros-ec-pwm");
328 MODULE_DESCRIPTION("ChromeOS EC PWM driver");
329 MODULE_LICENSE("GPL v2");
330