xref: /openbmc/linux/drivers/staging/greybus/pwm.c (revision ad536aa5)
1eb50fd3aSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
25357cf32SViresh Kumar /*
35357cf32SViresh Kumar  * PWM Greybus driver.
45357cf32SViresh Kumar  *
55357cf32SViresh Kumar  * Copyright 2014 Google Inc.
65357cf32SViresh Kumar  * Copyright 2014 Linaro Ltd.
75357cf32SViresh Kumar  */
85357cf32SViresh Kumar 
95357cf32SViresh Kumar #include <linux/kernel.h>
105357cf32SViresh Kumar #include <linux/module.h>
115357cf32SViresh Kumar #include <linux/slab.h>
125357cf32SViresh Kumar #include <linux/pwm.h>
13ec0ad868SGreg Kroah-Hartman #include <linux/greybus.h>
14e9385e5dSAlex Elder 
15e54b106dSSandeep Patil #include "gbphy.h"
165357cf32SViresh Kumar 
175357cf32SViresh Kumar struct gb_pwm_chip {
185357cf32SViresh Kumar 	struct gb_connection	*connection;
195357cf32SViresh Kumar 	u8			pwm_max;	/* max pwm number */
205357cf32SViresh Kumar 
215357cf32SViresh Kumar 	struct pwm_chip		chip;
225357cf32SViresh Kumar };
23*b07c8ef8SSumitra Sharma 
pwm_chip_to_gb_pwm_chip(struct pwm_chip * chip)24*b07c8ef8SSumitra Sharma static inline struct gb_pwm_chip *pwm_chip_to_gb_pwm_chip(struct pwm_chip *chip)
25*b07c8ef8SSumitra Sharma {
26*b07c8ef8SSumitra Sharma 	return container_of(chip, struct gb_pwm_chip, chip);
27*b07c8ef8SSumitra Sharma }
285357cf32SViresh Kumar 
gb_pwm_count_operation(struct gb_pwm_chip * pwmc)295357cf32SViresh Kumar static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
305357cf32SViresh Kumar {
315357cf32SViresh Kumar 	struct gb_pwm_count_response response;
325357cf32SViresh Kumar 	int ret;
335357cf32SViresh Kumar 
345357cf32SViresh Kumar 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT,
355357cf32SViresh Kumar 				NULL, 0, &response, sizeof(response));
365357cf32SViresh Kumar 	if (ret)
375357cf32SViresh Kumar 		return ret;
385357cf32SViresh Kumar 	pwmc->pwm_max = response.count;
395357cf32SViresh Kumar 	return 0;
405357cf32SViresh Kumar }
415357cf32SViresh Kumar 
gb_pwm_activate_operation(struct gb_pwm_chip * pwmc,u8 which)425357cf32SViresh Kumar static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
435357cf32SViresh Kumar 				     u8 which)
445357cf32SViresh Kumar {
455357cf32SViresh Kumar 	struct gb_pwm_activate_request request;
46afa807b8SAxel Haslam 	struct gbphy_device *gbphy_dev;
47afa807b8SAxel Haslam 	int ret;
485357cf32SViresh Kumar 
495357cf32SViresh Kumar 	if (which > pwmc->pwm_max)
505357cf32SViresh Kumar 		return -EINVAL;
515357cf32SViresh Kumar 
525357cf32SViresh Kumar 	request.which = which;
53afa807b8SAxel Haslam 
54afa807b8SAxel Haslam 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
55afa807b8SAxel Haslam 	ret = gbphy_runtime_get_sync(gbphy_dev);
56afa807b8SAxel Haslam 	if (ret)
57afa807b8SAxel Haslam 		return ret;
58afa807b8SAxel Haslam 
59afa807b8SAxel Haslam 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ACTIVATE,
605357cf32SViresh Kumar 				&request, sizeof(request), NULL, 0);
61afa807b8SAxel Haslam 
62afa807b8SAxel Haslam 	gbphy_runtime_put_autosuspend(gbphy_dev);
63afa807b8SAxel Haslam 
64afa807b8SAxel Haslam 	return ret;
655357cf32SViresh Kumar }
665357cf32SViresh Kumar 
gb_pwm_deactivate_operation(struct gb_pwm_chip * pwmc,u8 which)675357cf32SViresh Kumar static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
685357cf32SViresh Kumar 				       u8 which)
695357cf32SViresh Kumar {
705357cf32SViresh Kumar 	struct gb_pwm_deactivate_request request;
71afa807b8SAxel Haslam 	struct gbphy_device *gbphy_dev;
72afa807b8SAxel Haslam 	int ret;
735357cf32SViresh Kumar 
745357cf32SViresh Kumar 	if (which > pwmc->pwm_max)
755357cf32SViresh Kumar 		return -EINVAL;
765357cf32SViresh Kumar 
775357cf32SViresh Kumar 	request.which = which;
78afa807b8SAxel Haslam 
79afa807b8SAxel Haslam 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
80afa807b8SAxel Haslam 	ret = gbphy_runtime_get_sync(gbphy_dev);
81afa807b8SAxel Haslam 	if (ret)
82afa807b8SAxel Haslam 		return ret;
83afa807b8SAxel Haslam 
84afa807b8SAxel Haslam 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DEACTIVATE,
855357cf32SViresh Kumar 				&request, sizeof(request), NULL, 0);
86afa807b8SAxel Haslam 
87afa807b8SAxel Haslam 	gbphy_runtime_put_autosuspend(gbphy_dev);
88afa807b8SAxel Haslam 
89afa807b8SAxel Haslam 	return ret;
905357cf32SViresh Kumar }
915357cf32SViresh Kumar 
gb_pwm_config_operation(struct gb_pwm_chip * pwmc,u8 which,u32 duty,u32 period)925357cf32SViresh Kumar static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
935357cf32SViresh Kumar 				   u8 which, u32 duty, u32 period)
945357cf32SViresh Kumar {
955357cf32SViresh Kumar 	struct gb_pwm_config_request request;
96afa807b8SAxel Haslam 	struct gbphy_device *gbphy_dev;
97afa807b8SAxel Haslam 	int ret;
985357cf32SViresh Kumar 
995357cf32SViresh Kumar 	if (which > pwmc->pwm_max)
1005357cf32SViresh Kumar 		return -EINVAL;
1015357cf32SViresh Kumar 
1025357cf32SViresh Kumar 	request.which = which;
1035357cf32SViresh Kumar 	request.duty = cpu_to_le32(duty);
1045357cf32SViresh Kumar 	request.period = cpu_to_le32(period);
105afa807b8SAxel Haslam 
106afa807b8SAxel Haslam 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
107afa807b8SAxel Haslam 	ret = gbphy_runtime_get_sync(gbphy_dev);
108afa807b8SAxel Haslam 	if (ret)
109afa807b8SAxel Haslam 		return ret;
110afa807b8SAxel Haslam 
111afa807b8SAxel Haslam 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_CONFIG,
1125357cf32SViresh Kumar 				&request, sizeof(request), NULL, 0);
113afa807b8SAxel Haslam 
114afa807b8SAxel Haslam 	gbphy_runtime_put_autosuspend(gbphy_dev);
115afa807b8SAxel Haslam 
116afa807b8SAxel Haslam 	return ret;
1175357cf32SViresh Kumar }
1185357cf32SViresh Kumar 
gb_pwm_set_polarity_operation(struct gb_pwm_chip * pwmc,u8 which,u8 polarity)1195357cf32SViresh Kumar static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
1205357cf32SViresh Kumar 					 u8 which, u8 polarity)
1215357cf32SViresh Kumar {
1225357cf32SViresh Kumar 	struct gb_pwm_polarity_request request;
123afa807b8SAxel Haslam 	struct gbphy_device *gbphy_dev;
124afa807b8SAxel Haslam 	int ret;
1255357cf32SViresh Kumar 
1265357cf32SViresh Kumar 	if (which > pwmc->pwm_max)
1275357cf32SViresh Kumar 		return -EINVAL;
1285357cf32SViresh Kumar 
1295357cf32SViresh Kumar 	request.which = which;
1305357cf32SViresh Kumar 	request.polarity = polarity;
131afa807b8SAxel Haslam 
132afa807b8SAxel Haslam 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
133afa807b8SAxel Haslam 	ret = gbphy_runtime_get_sync(gbphy_dev);
134afa807b8SAxel Haslam 	if (ret)
135afa807b8SAxel Haslam 		return ret;
136afa807b8SAxel Haslam 
137afa807b8SAxel Haslam 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_POLARITY,
1385357cf32SViresh Kumar 				&request, sizeof(request), NULL, 0);
139afa807b8SAxel Haslam 
140afa807b8SAxel Haslam 	gbphy_runtime_put_autosuspend(gbphy_dev);
141afa807b8SAxel Haslam 
142afa807b8SAxel Haslam 	return ret;
1435357cf32SViresh Kumar }
1445357cf32SViresh Kumar 
gb_pwm_enable_operation(struct gb_pwm_chip * pwmc,u8 which)1455357cf32SViresh Kumar static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
1465357cf32SViresh Kumar 				   u8 which)
1475357cf32SViresh Kumar {
1485357cf32SViresh Kumar 	struct gb_pwm_enable_request request;
149afa807b8SAxel Haslam 	struct gbphy_device *gbphy_dev;
150afa807b8SAxel Haslam 	int ret;
1515357cf32SViresh Kumar 
1525357cf32SViresh Kumar 	if (which > pwmc->pwm_max)
1535357cf32SViresh Kumar 		return -EINVAL;
1545357cf32SViresh Kumar 
1555357cf32SViresh Kumar 	request.which = which;
156afa807b8SAxel Haslam 
157afa807b8SAxel Haslam 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
158afa807b8SAxel Haslam 	ret = gbphy_runtime_get_sync(gbphy_dev);
159afa807b8SAxel Haslam 	if (ret)
160afa807b8SAxel Haslam 		return ret;
161afa807b8SAxel Haslam 
162afa807b8SAxel Haslam 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ENABLE,
1635357cf32SViresh Kumar 				&request, sizeof(request), NULL, 0);
164afa807b8SAxel Haslam 	if (ret)
165afa807b8SAxel Haslam 		gbphy_runtime_put_autosuspend(gbphy_dev);
166afa807b8SAxel Haslam 
167afa807b8SAxel Haslam 	return ret;
1685357cf32SViresh Kumar }
1695357cf32SViresh Kumar 
gb_pwm_disable_operation(struct gb_pwm_chip * pwmc,u8 which)1705357cf32SViresh Kumar static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
1715357cf32SViresh Kumar 				    u8 which)
1725357cf32SViresh Kumar {
1735357cf32SViresh Kumar 	struct gb_pwm_disable_request request;
174afa807b8SAxel Haslam 	struct gbphy_device *gbphy_dev;
175afa807b8SAxel Haslam 	int ret;
1765357cf32SViresh Kumar 
1775357cf32SViresh Kumar 	if (which > pwmc->pwm_max)
1785357cf32SViresh Kumar 		return -EINVAL;
1795357cf32SViresh Kumar 
1805357cf32SViresh Kumar 	request.which = which;
181afa807b8SAxel Haslam 
182afa807b8SAxel Haslam 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,
1835357cf32SViresh Kumar 				&request, sizeof(request), NULL, 0);
184afa807b8SAxel Haslam 
185afa807b8SAxel Haslam 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
186afa807b8SAxel Haslam 	gbphy_runtime_put_autosuspend(gbphy_dev);
187afa807b8SAxel Haslam 
188afa807b8SAxel Haslam 	return ret;
1895357cf32SViresh Kumar }
1905357cf32SViresh Kumar 
gb_pwm_request(struct pwm_chip * chip,struct pwm_device * pwm)1915357cf32SViresh Kumar static int gb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
1925357cf32SViresh Kumar {
1935357cf32SViresh Kumar 	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
1945357cf32SViresh Kumar 
1955357cf32SViresh Kumar 	return gb_pwm_activate_operation(pwmc, pwm->hwpwm);
1965357cf32SViresh Kumar };
1975357cf32SViresh Kumar 
gb_pwm_free(struct pwm_chip * chip,struct pwm_device * pwm)1985357cf32SViresh Kumar static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
1995357cf32SViresh Kumar {
2005357cf32SViresh Kumar 	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
2015357cf32SViresh Kumar 
20244d64493SGreg Kroah-Hartman 	if (pwm_is_enabled(pwm))
2035357cf32SViresh Kumar 		dev_warn(chip->dev, "freeing PWM device without disabling\n");
2045357cf32SViresh Kumar 
2055357cf32SViresh Kumar 	gb_pwm_deactivate_operation(pwmc, pwm->hwpwm);
2065357cf32SViresh Kumar }
2075357cf32SViresh Kumar 
gb_pwm_apply(struct pwm_chip * chip,struct pwm_device * pwm,const struct pwm_state * state)208832ce36fSSong Chen static int gb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
209832ce36fSSong Chen 			const struct pwm_state *state)
2105357cf32SViresh Kumar {
211832ce36fSSong Chen 	int err;
212832ce36fSSong Chen 	bool enabled = pwm->state.enabled;
213832ce36fSSong Chen 	u64 period = state->period;
214832ce36fSSong Chen 	u64 duty_cycle = state->duty_cycle;
2155357cf32SViresh Kumar 	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
2165357cf32SViresh Kumar 
217832ce36fSSong Chen 	/* Set polarity */
218832ce36fSSong Chen 	if (state->polarity != pwm->state.polarity) {
219832ce36fSSong Chen 		if (enabled) {
2205357cf32SViresh Kumar 			gb_pwm_disable_operation(pwmc, pwm->hwpwm);
221832ce36fSSong Chen 			enabled = false;
222832ce36fSSong Chen 		}
223832ce36fSSong Chen 		err = gb_pwm_set_polarity_operation(pwmc, pwm->hwpwm, state->polarity);
224832ce36fSSong Chen 		if (err)
225832ce36fSSong Chen 			return err;
226832ce36fSSong Chen 	}
227832ce36fSSong Chen 
228832ce36fSSong Chen 	if (!state->enabled) {
229832ce36fSSong Chen 		if (enabled)
230832ce36fSSong Chen 			gb_pwm_disable_operation(pwmc, pwm->hwpwm);
231832ce36fSSong Chen 		return 0;
232832ce36fSSong Chen 	}
233832ce36fSSong Chen 
234832ce36fSSong Chen 	/*
235832ce36fSSong Chen 	 * Set period and duty cycle
236832ce36fSSong Chen 	 *
237832ce36fSSong Chen 	 * PWM privodes 64-bit period and duty_cycle, but greybus only accepts
238832ce36fSSong Chen 	 * 32-bit, so their values have to be limited to U32_MAX.
239832ce36fSSong Chen 	 */
240832ce36fSSong Chen 	if (period > U32_MAX)
241832ce36fSSong Chen 		period = U32_MAX;
242832ce36fSSong Chen 
243832ce36fSSong Chen 	if (duty_cycle > period)
244832ce36fSSong Chen 		duty_cycle = period;
245832ce36fSSong Chen 
246832ce36fSSong Chen 	err = gb_pwm_config_operation(pwmc, pwm->hwpwm, duty_cycle, period);
247832ce36fSSong Chen 	if (err)
248832ce36fSSong Chen 		return err;
249832ce36fSSong Chen 
250832ce36fSSong Chen 	/* enable/disable */
251832ce36fSSong Chen 	if (!enabled)
252832ce36fSSong Chen 		return gb_pwm_enable_operation(pwmc, pwm->hwpwm);
253832ce36fSSong Chen 
254832ce36fSSong Chen 	return 0;
255832ce36fSSong Chen }
2565357cf32SViresh Kumar 
2575357cf32SViresh Kumar static const struct pwm_ops gb_pwm_ops = {
2585357cf32SViresh Kumar 	.request = gb_pwm_request,
2595357cf32SViresh Kumar 	.free = gb_pwm_free,
260832ce36fSSong Chen 	.apply = gb_pwm_apply,
2615357cf32SViresh Kumar 	.owner = THIS_MODULE,
2625357cf32SViresh Kumar };
2635357cf32SViresh Kumar 
gb_pwm_probe(struct gbphy_device * gbphy_dev,const struct gbphy_device_id * id)264e54b106dSSandeep Patil static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
265e54b106dSSandeep Patil 			const struct gbphy_device_id *id)
2665357cf32SViresh Kumar {
26732054908SGreg Kroah-Hartman 	struct gb_connection *connection;
2685357cf32SViresh Kumar 	struct gb_pwm_chip *pwmc;
2695357cf32SViresh Kumar 	struct pwm_chip *chip;
2705357cf32SViresh Kumar 	int ret;
2715357cf32SViresh Kumar 
2725357cf32SViresh Kumar 	pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL);
2735357cf32SViresh Kumar 	if (!pwmc)
2745357cf32SViresh Kumar 		return -ENOMEM;
27532054908SGreg Kroah-Hartman 
276e54b106dSSandeep Patil 	connection = gb_connection_create(gbphy_dev->bundle,
277e54b106dSSandeep Patil 					  le16_to_cpu(gbphy_dev->cport_desc->id),
27832054908SGreg Kroah-Hartman 					  NULL);
27932054908SGreg Kroah-Hartman 	if (IS_ERR(connection)) {
28032054908SGreg Kroah-Hartman 		ret = PTR_ERR(connection);
28132054908SGreg Kroah-Hartman 		goto exit_pwmc_free;
28232054908SGreg Kroah-Hartman 	}
28332054908SGreg Kroah-Hartman 
2845357cf32SViresh Kumar 	pwmc->connection = connection;
2850ec30632SGreg Kroah-Hartman 	gb_connection_set_data(connection, pwmc);
286e54b106dSSandeep Patil 	gb_gbphy_set_data(gbphy_dev, pwmc);
28732054908SGreg Kroah-Hartman 
28832054908SGreg Kroah-Hartman 	ret = gb_connection_enable(connection);
28932054908SGreg Kroah-Hartman 	if (ret)
29032054908SGreg Kroah-Hartman 		goto exit_connection_destroy;
29132054908SGreg Kroah-Hartman 
2925357cf32SViresh Kumar 	/* Query number of pwms present */
2935357cf32SViresh Kumar 	ret = gb_pwm_count_operation(pwmc);
2945357cf32SViresh Kumar 	if (ret)
29532054908SGreg Kroah-Hartman 		goto exit_connection_disable;
2965357cf32SViresh Kumar 
2975357cf32SViresh Kumar 	chip = &pwmc->chip;
2985357cf32SViresh Kumar 
299e54b106dSSandeep Patil 	chip->dev = &gbphy_dev->dev;
3005357cf32SViresh Kumar 	chip->ops = &gb_pwm_ops;
3015357cf32SViresh Kumar 	chip->npwm = pwmc->pwm_max + 1;
3025357cf32SViresh Kumar 
3035357cf32SViresh Kumar 	ret = pwmchip_add(chip);
3045357cf32SViresh Kumar 	if (ret) {
305e54b106dSSandeep Patil 		dev_err(&gbphy_dev->dev,
3068d5732f4SGreg Kroah-Hartman 			"failed to register PWM: %d\n", ret);
30732054908SGreg Kroah-Hartman 		goto exit_connection_disable;
3085357cf32SViresh Kumar 	}
3095357cf32SViresh Kumar 
310afa807b8SAxel Haslam 	gbphy_runtime_put_autosuspend(gbphy_dev);
3115357cf32SViresh Kumar 	return 0;
31232054908SGreg Kroah-Hartman 
31332054908SGreg Kroah-Hartman exit_connection_disable:
31432054908SGreg Kroah-Hartman 	gb_connection_disable(connection);
31532054908SGreg Kroah-Hartman exit_connection_destroy:
31632054908SGreg Kroah-Hartman 	gb_connection_destroy(connection);
31732054908SGreg Kroah-Hartman exit_pwmc_free:
3185357cf32SViresh Kumar 	kfree(pwmc);
3195357cf32SViresh Kumar 	return ret;
3205357cf32SViresh Kumar }
3215357cf32SViresh Kumar 
gb_pwm_remove(struct gbphy_device * gbphy_dev)322e54b106dSSandeep Patil static void gb_pwm_remove(struct gbphy_device *gbphy_dev)
3235357cf32SViresh Kumar {
324e54b106dSSandeep Patil 	struct gb_pwm_chip *pwmc = gb_gbphy_get_data(gbphy_dev);
32532054908SGreg Kroah-Hartman 	struct gb_connection *connection = pwmc->connection;
326afa807b8SAxel Haslam 	int ret;
327afa807b8SAxel Haslam 
328afa807b8SAxel Haslam 	ret = gbphy_runtime_get_sync(gbphy_dev);
329afa807b8SAxel Haslam 	if (ret)
330afa807b8SAxel Haslam 		gbphy_runtime_get_noresume(gbphy_dev);
3315357cf32SViresh Kumar 
3325357cf32SViresh Kumar 	pwmchip_remove(&pwmc->chip);
33332054908SGreg Kroah-Hartman 	gb_connection_disable(connection);
33432054908SGreg Kroah-Hartman 	gb_connection_destroy(connection);
3355357cf32SViresh Kumar 	kfree(pwmc);
3365357cf32SViresh Kumar }
3375357cf32SViresh Kumar 
338e54b106dSSandeep Patil static const struct gbphy_device_id gb_pwm_id_table[] = {
339e54b106dSSandeep Patil 	{ GBPHY_PROTOCOL(GREYBUS_PROTOCOL_PWM) },
34032054908SGreg Kroah-Hartman 	{ },
3415357cf32SViresh Kumar };
342e54b106dSSandeep Patil MODULE_DEVICE_TABLE(gbphy, gb_pwm_id_table);
3435357cf32SViresh Kumar 
344e54b106dSSandeep Patil static struct gbphy_driver pwm_driver = {
34532054908SGreg Kroah-Hartman 	.name		= "pwm",
34632054908SGreg Kroah-Hartman 	.probe		= gb_pwm_probe,
34732054908SGreg Kroah-Hartman 	.remove		= gb_pwm_remove,
34832054908SGreg Kroah-Hartman 	.id_table	= gb_pwm_id_table,
34932054908SGreg Kroah-Hartman };
350dca8060dSViresh Kumar 
351e54b106dSSandeep Patil module_gbphy_driver(pwm_driver);
352dca8060dSViresh Kumar MODULE_LICENSE("GPL v2");
353