1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Generic software PWM for modulating GPIOs 4 * 5 * Copyright (C) 2020 Axis Communications AB 6 * Copyright (C) 2020 Nicola Di Lieto 7 * Copyright (C) 2024 Stefan Wahren 8 * Copyright (C) 2024 Linus Walleij 9 */ 10 11 #include <linux/cleanup.h> 12 #include <linux/container_of.h> 13 #include <linux/device.h> 14 #include <linux/err.h> 15 #include <linux/gpio/consumer.h> 16 #include <linux/hrtimer.h> 17 #include <linux/math.h> 18 #include <linux/module.h> 19 #include <linux/mod_devicetable.h> 20 #include <linux/platform_device.h> 21 #include <linux/property.h> 22 #include <linux/pwm.h> 23 #include <linux/spinlock.h> 24 #include <linux/time.h> 25 #include <linux/types.h> 26 27 struct pwm_gpio { 28 struct hrtimer gpio_timer; 29 struct gpio_desc *gpio; 30 struct pwm_state state; 31 struct pwm_state next_state; 32 33 /* Protect internal state between pwm_ops and hrtimer */ 34 spinlock_t lock; 35 36 bool changing; 37 bool running; 38 bool level; 39 }; 40 41 static void pwm_gpio_round(struct pwm_state *dest, const struct pwm_state *src) 42 { 43 u64 dividend; 44 u32 remainder; 45 46 *dest = *src; 47 48 /* Round down to hrtimer resolution */ 49 dividend = dest->period; 50 remainder = do_div(dividend, hrtimer_resolution); 51 dest->period -= remainder; 52 53 dividend = dest->duty_cycle; 54 remainder = do_div(dividend, hrtimer_resolution); 55 dest->duty_cycle -= remainder; 56 } 57 58 static u64 pwm_gpio_toggle(struct pwm_gpio *gpwm, bool level) 59 { 60 const struct pwm_state *state = &gpwm->state; 61 bool invert = state->polarity == PWM_POLARITY_INVERSED; 62 63 gpwm->level = level; 64 gpiod_set_value(gpwm->gpio, gpwm->level ^ invert); 65 66 if (!state->duty_cycle || state->duty_cycle == state->period) { 67 gpwm->running = false; 68 return 0; 69 } 70 71 gpwm->running = true; 72 return level ? state->duty_cycle : state->period - state->duty_cycle; 73 } 74 75 static enum hrtimer_restart pwm_gpio_timer(struct hrtimer *gpio_timer) 76 { 77 struct pwm_gpio *gpwm = container_of(gpio_timer, struct pwm_gpio, 78 gpio_timer); 79 u64 next_toggle; 80 bool new_level; 81 82 guard(spinlock_irqsave)(&gpwm->lock); 83 84 /* Apply new state at end of current period */ 85 if (!gpwm->level && gpwm->changing) { 86 gpwm->changing = false; 87 gpwm->state = gpwm->next_state; 88 new_level = !!gpwm->state.duty_cycle; 89 } else { 90 new_level = !gpwm->level; 91 } 92 93 next_toggle = pwm_gpio_toggle(gpwm, new_level); 94 if (next_toggle) 95 hrtimer_forward(gpio_timer, hrtimer_get_expires(gpio_timer), 96 ns_to_ktime(next_toggle)); 97 98 return next_toggle ? HRTIMER_RESTART : HRTIMER_NORESTART; 99 } 100 101 static int pwm_gpio_apply(struct pwm_chip *chip, struct pwm_device *pwm, 102 const struct pwm_state *state) 103 { 104 struct pwm_gpio *gpwm = pwmchip_get_drvdata(chip); 105 bool invert = state->polarity == PWM_POLARITY_INVERSED; 106 107 if (state->duty_cycle && state->duty_cycle < hrtimer_resolution) 108 return -EINVAL; 109 110 if (state->duty_cycle != state->period && 111 (state->period - state->duty_cycle < hrtimer_resolution)) 112 return -EINVAL; 113 114 if (!state->enabled) { 115 hrtimer_cancel(&gpwm->gpio_timer); 116 } else if (!gpwm->running) { 117 int ret; 118 119 /* 120 * This just enables the output, but pwm_gpio_toggle() 121 * really starts the duty cycle. 122 */ 123 ret = gpiod_direction_output(gpwm->gpio, invert); 124 if (ret) 125 return ret; 126 } 127 128 guard(spinlock_irqsave)(&gpwm->lock); 129 130 if (!state->enabled) { 131 pwm_gpio_round(&gpwm->state, state); 132 gpwm->running = false; 133 gpwm->changing = false; 134 135 gpiod_set_value(gpwm->gpio, invert); 136 } else if (gpwm->running) { 137 pwm_gpio_round(&gpwm->next_state, state); 138 gpwm->changing = true; 139 } else { 140 unsigned long next_toggle; 141 142 pwm_gpio_round(&gpwm->state, state); 143 gpwm->changing = false; 144 145 next_toggle = pwm_gpio_toggle(gpwm, !!state->duty_cycle); 146 if (next_toggle) 147 hrtimer_start(&gpwm->gpio_timer, next_toggle, 148 HRTIMER_MODE_REL); 149 } 150 151 return 0; 152 } 153 154 static int pwm_gpio_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 155 struct pwm_state *state) 156 { 157 struct pwm_gpio *gpwm = pwmchip_get_drvdata(chip); 158 159 guard(spinlock_irqsave)(&gpwm->lock); 160 161 if (gpwm->changing) 162 *state = gpwm->next_state; 163 else 164 *state = gpwm->state; 165 166 return 0; 167 } 168 169 static const struct pwm_ops pwm_gpio_ops = { 170 .apply = pwm_gpio_apply, 171 .get_state = pwm_gpio_get_state, 172 }; 173 174 static void pwm_gpio_disable_hrtimer(void *data) 175 { 176 struct pwm_gpio *gpwm = data; 177 178 hrtimer_cancel(&gpwm->gpio_timer); 179 } 180 181 static int pwm_gpio_probe(struct platform_device *pdev) 182 { 183 struct device *dev = &pdev->dev; 184 struct pwm_chip *chip; 185 struct pwm_gpio *gpwm; 186 int ret; 187 188 chip = devm_pwmchip_alloc(dev, 1, sizeof(*gpwm)); 189 if (IS_ERR(chip)) 190 return PTR_ERR(chip); 191 192 gpwm = pwmchip_get_drvdata(chip); 193 194 spin_lock_init(&gpwm->lock); 195 196 gpwm->gpio = devm_gpiod_get(dev, NULL, GPIOD_ASIS); 197 if (IS_ERR(gpwm->gpio)) 198 return dev_err_probe(dev, PTR_ERR(gpwm->gpio), 199 "%pfw: could not get gpio\n", 200 dev_fwnode(dev)); 201 202 if (gpiod_cansleep(gpwm->gpio)) 203 return dev_err_probe(dev, -EINVAL, 204 "%pfw: sleeping GPIO not supported\n", 205 dev_fwnode(dev)); 206 207 chip->ops = &pwm_gpio_ops; 208 chip->atomic = true; 209 210 hrtimer_init(&gpwm->gpio_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 211 ret = devm_add_action_or_reset(dev, pwm_gpio_disable_hrtimer, gpwm); 212 if (ret) 213 return ret; 214 215 gpwm->gpio_timer.function = pwm_gpio_timer; 216 217 ret = pwmchip_add(chip); 218 if (ret < 0) 219 return dev_err_probe(dev, ret, "could not add pwmchip\n"); 220 221 return 0; 222 } 223 224 static const struct of_device_id pwm_gpio_dt_ids[] = { 225 { .compatible = "pwm-gpio" }, 226 { /* sentinel */ } 227 }; 228 MODULE_DEVICE_TABLE(of, pwm_gpio_dt_ids); 229 230 static struct platform_driver pwm_gpio_driver = { 231 .driver = { 232 .name = "pwm-gpio", 233 .of_match_table = pwm_gpio_dt_ids, 234 }, 235 .probe = pwm_gpio_probe, 236 }; 237 module_platform_driver(pwm_gpio_driver); 238 239 MODULE_DESCRIPTION("PWM GPIO driver"); 240 MODULE_AUTHOR("Vincent Whitchurch"); 241 MODULE_LICENSE("GPL"); 242