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