1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ECAP PWM driver 4 * 5 * Copyright (C) 2012 Texas Instruments, Inc. - https://www.ti.com/ 6 */ 7 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/io.h> 11 #include <linux/err.h> 12 #include <linux/clk.h> 13 #include <linux/pm_runtime.h> 14 #include <linux/pwm.h> 15 #include <linux/of.h> 16 17 /* ECAP registers and bits definitions */ 18 #define CAP1 0x08 19 #define CAP2 0x0C 20 #define CAP3 0x10 21 #define CAP4 0x14 22 #define ECCTL2 0x2A 23 #define ECCTL2_APWM_POL_LOW BIT(10) 24 #define ECCTL2_APWM_MODE BIT(9) 25 #define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) 26 #define ECCTL2_TSCTR_FREERUN BIT(4) 27 28 struct ecap_context { 29 u32 cap3; 30 u32 cap4; 31 u16 ecctl2; 32 }; 33 34 struct ecap_pwm_chip { 35 unsigned int clk_rate; 36 void __iomem *mmio_base; 37 struct ecap_context ctx; 38 }; 39 40 static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip) 41 { 42 return pwmchip_get_drvdata(chip); 43 } 44 45 /* 46 * period_ns = 10^9 * period_cycles / PWM_CLK_RATE 47 * duty_ns = 10^9 * duty_cycles / PWM_CLK_RATE 48 */ 49 static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 50 int duty_ns, int period_ns, int enabled) 51 { 52 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 53 u32 period_cycles, duty_cycles; 54 unsigned long long c; 55 u16 value; 56 57 c = pc->clk_rate; 58 c = c * period_ns; 59 do_div(c, NSEC_PER_SEC); 60 period_cycles = (u32)c; 61 62 if (period_cycles < 1) { 63 period_cycles = 1; 64 duty_cycles = 1; 65 } else { 66 c = pc->clk_rate; 67 c = c * duty_ns; 68 do_div(c, NSEC_PER_SEC); 69 duty_cycles = (u32)c; 70 } 71 72 pm_runtime_get_sync(pwmchip_parent(chip)); 73 74 value = readw(pc->mmio_base + ECCTL2); 75 76 /* Configure APWM mode & disable sync option */ 77 value |= ECCTL2_APWM_MODE | ECCTL2_SYNC_SEL_DISA; 78 79 writew(value, pc->mmio_base + ECCTL2); 80 81 if (!enabled) { 82 /* Update active registers if not running */ 83 writel(duty_cycles, pc->mmio_base + CAP2); 84 writel(period_cycles, pc->mmio_base + CAP1); 85 } else { 86 /* 87 * Update shadow registers to configure period and 88 * compare values. This helps current PWM period to 89 * complete on reconfiguring 90 */ 91 writel(duty_cycles, pc->mmio_base + CAP4); 92 writel(period_cycles, pc->mmio_base + CAP3); 93 } 94 95 if (!enabled) { 96 value = readw(pc->mmio_base + ECCTL2); 97 /* Disable APWM mode to put APWM output Low */ 98 value &= ~ECCTL2_APWM_MODE; 99 writew(value, pc->mmio_base + ECCTL2); 100 } 101 102 pm_runtime_put_sync(pwmchip_parent(chip)); 103 104 return 0; 105 } 106 107 static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, 108 enum pwm_polarity polarity) 109 { 110 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 111 u16 value; 112 113 pm_runtime_get_sync(pwmchip_parent(chip)); 114 115 value = readw(pc->mmio_base + ECCTL2); 116 117 if (polarity == PWM_POLARITY_INVERSED) 118 /* Duty cycle defines LOW period of PWM */ 119 value |= ECCTL2_APWM_POL_LOW; 120 else 121 /* Duty cycle defines HIGH period of PWM */ 122 value &= ~ECCTL2_APWM_POL_LOW; 123 124 writew(value, pc->mmio_base + ECCTL2); 125 126 pm_runtime_put_sync(pwmchip_parent(chip)); 127 128 return 0; 129 } 130 131 static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 132 { 133 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 134 u16 value; 135 136 /* Leave clock enabled on enabling PWM */ 137 pm_runtime_get_sync(pwmchip_parent(chip)); 138 139 /* 140 * Enable 'Free run Time stamp counter mode' to start counter 141 * and 'APWM mode' to enable APWM output 142 */ 143 value = readw(pc->mmio_base + ECCTL2); 144 value |= ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE; 145 writew(value, pc->mmio_base + ECCTL2); 146 147 return 0; 148 } 149 150 static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 151 { 152 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 153 u16 value; 154 155 /* 156 * Disable 'Free run Time stamp counter mode' to stop counter 157 * and 'APWM mode' to put APWM output to low 158 */ 159 value = readw(pc->mmio_base + ECCTL2); 160 value &= ~(ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE); 161 writew(value, pc->mmio_base + ECCTL2); 162 163 /* Disable clock on PWM disable */ 164 pm_runtime_put_sync(pwmchip_parent(chip)); 165 } 166 167 static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 168 const struct pwm_state *state) 169 { 170 int err; 171 int enabled = pwm->state.enabled; 172 173 if (state->polarity != pwm->state.polarity) { 174 175 if (enabled) { 176 ecap_pwm_disable(chip, pwm); 177 enabled = false; 178 } 179 180 err = ecap_pwm_set_polarity(chip, pwm, state->polarity); 181 if (err) 182 return err; 183 } 184 185 if (!state->enabled) { 186 if (enabled) 187 ecap_pwm_disable(chip, pwm); 188 return 0; 189 } 190 191 if (state->period > NSEC_PER_SEC) 192 return -ERANGE; 193 194 err = ecap_pwm_config(chip, pwm, state->duty_cycle, 195 state->period, enabled); 196 if (err) 197 return err; 198 199 if (!enabled) 200 return ecap_pwm_enable(chip, pwm); 201 202 return 0; 203 } 204 205 static const struct pwm_ops ecap_pwm_ops = { 206 .apply = ecap_pwm_apply, 207 }; 208 209 static const struct of_device_id ecap_of_match[] = { 210 { .compatible = "ti,am3352-ecap" }, 211 { .compatible = "ti,am33xx-ecap" }, 212 {}, 213 }; 214 MODULE_DEVICE_TABLE(of, ecap_of_match); 215 216 static int ecap_pwm_probe(struct platform_device *pdev) 217 { 218 struct device_node *np = pdev->dev.of_node; 219 struct ecap_pwm_chip *pc; 220 struct pwm_chip *chip; 221 struct clk *clk; 222 int ret; 223 224 chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*pc)); 225 if (IS_ERR(chip)) 226 return PTR_ERR(chip); 227 pc = to_ecap_pwm_chip(chip); 228 229 clk = devm_clk_get(&pdev->dev, "fck"); 230 if (IS_ERR(clk)) { 231 if (of_device_is_compatible(np, "ti,am33xx-ecap")) { 232 dev_warn(&pdev->dev, "Binding is obsolete.\n"); 233 clk = devm_clk_get(pdev->dev.parent, "fck"); 234 } 235 } 236 237 if (IS_ERR(clk)) { 238 dev_err(&pdev->dev, "failed to get clock\n"); 239 return PTR_ERR(clk); 240 } 241 242 pc->clk_rate = clk_get_rate(clk); 243 if (!pc->clk_rate) { 244 dev_err(&pdev->dev, "failed to get clock rate\n"); 245 return -EINVAL; 246 } 247 248 chip->ops = &ecap_pwm_ops; 249 250 pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); 251 if (IS_ERR(pc->mmio_base)) 252 return PTR_ERR(pc->mmio_base); 253 254 ret = devm_pwmchip_add(&pdev->dev, chip); 255 if (ret < 0) { 256 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 257 return ret; 258 } 259 260 platform_set_drvdata(pdev, chip); 261 pm_runtime_enable(&pdev->dev); 262 263 return 0; 264 } 265 266 static void ecap_pwm_remove(struct platform_device *pdev) 267 { 268 pm_runtime_disable(&pdev->dev); 269 } 270 271 static void ecap_pwm_save_context(struct pwm_chip *chip) 272 { 273 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 274 275 pm_runtime_get_sync(pwmchip_parent(chip)); 276 pc->ctx.ecctl2 = readw(pc->mmio_base + ECCTL2); 277 pc->ctx.cap4 = readl(pc->mmio_base + CAP4); 278 pc->ctx.cap3 = readl(pc->mmio_base + CAP3); 279 pm_runtime_put_sync(pwmchip_parent(chip)); 280 } 281 282 static void ecap_pwm_restore_context(struct pwm_chip *chip) 283 { 284 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 285 286 writel(pc->ctx.cap3, pc->mmio_base + CAP3); 287 writel(pc->ctx.cap4, pc->mmio_base + CAP4); 288 writew(pc->ctx.ecctl2, pc->mmio_base + ECCTL2); 289 } 290 291 static int ecap_pwm_suspend(struct device *dev) 292 { 293 struct pwm_chip *chip = dev_get_drvdata(dev); 294 struct pwm_device *pwm = chip->pwms; 295 296 ecap_pwm_save_context(chip); 297 298 /* Disable explicitly if PWM is running */ 299 if (pwm_is_enabled(pwm)) 300 pm_runtime_put_sync(dev); 301 302 return 0; 303 } 304 305 static int ecap_pwm_resume(struct device *dev) 306 { 307 struct pwm_chip *chip = dev_get_drvdata(dev); 308 struct pwm_device *pwm = chip->pwms; 309 310 /* Enable explicitly if PWM was running */ 311 if (pwm_is_enabled(pwm)) 312 pm_runtime_get_sync(dev); 313 314 ecap_pwm_restore_context(chip); 315 return 0; 316 } 317 318 static DEFINE_SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume); 319 320 static struct platform_driver ecap_pwm_driver = { 321 .driver = { 322 .name = "ecap", 323 .of_match_table = ecap_of_match, 324 .pm = pm_ptr(&ecap_pwm_pm_ops), 325 }, 326 .probe = ecap_pwm_probe, 327 .remove = ecap_pwm_remove, 328 }; 329 module_platform_driver(ecap_pwm_driver); 330 331 MODULE_DESCRIPTION("ECAP PWM driver"); 332 MODULE_AUTHOR("Texas Instruments"); 333 MODULE_LICENSE("GPL"); 334