FILE
pwm-tiehrpwm.c
File preview with syntax highlighting.
linux-6.19.14/drivers/pwm/pwm-tiehrpwm.c
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * EHRPWM 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/pwm.h> 11#include <linux/io.h> 12#include <linux/err.h> 13#include <linux/clk.h> 14#include <linux/pm_runtime.h> 15#include <linux/of.h> 16 17/* EHRPWM registers and bits definitions */ 18 19/* Time base module registers */ 20#define TBCTL 0x00 21#define TBPRD 0x0A 22 23#define TBCTL_PRDLD_MASK BIT(3) 24#define TBCTL_PRDLD_SHDW 0 25#define TBCTL_PRDLD_IMDT BIT(3) 26#define TBCTL_CLKDIV_MASK (BIT(12) | BIT(11) | BIT(10) | BIT(9) | \ 27 BIT(8) | BIT(7)) 28#define TBCTL_CTRMODE_MASK (BIT(1) | BIT(0)) 29#define TBCTL_CTRMODE_UP 0 30#define TBCTL_CTRMODE_DOWN BIT(0) 31#define TBCTL_CTRMODE_UPDOWN BIT(1) 32#define TBCTL_CTRMODE_FREEZE (BIT(1) | BIT(0)) 33 34#define TBCTL_HSPCLKDIV_SHIFT 7 35#define TBCTL_CLKDIV_SHIFT 10 36 37#define CLKDIV_MAX 7 38#define HSPCLKDIV_MAX 7 39#define PERIOD_MAX 0x10000 40 41/* compare module registers */ 42#define CMPA 0x12 43#define CMPB 0x14 44 45/* Action qualifier module registers */ 46#define AQCTLA 0x16 47#define AQCTLB 0x18 48#define AQSFRC 0x1A 49#define AQCSFRC 0x1C 50 51#define AQCTL_CBU_MASK (BIT(9) | BIT(8)) 52#define AQCTL_CBU_FRCLOW BIT(8) 53#define AQCTL_CBU_FRCHIGH BIT(9) 54#define AQCTL_CBU_FRCTOGGLE (BIT(9) | BIT(8)) 55#define AQCTL_CAU_MASK (BIT(5) | BIT(4)) 56#define AQCTL_CAU_FRCLOW BIT(4) 57#define AQCTL_CAU_FRCHIGH BIT(5) 58#define AQCTL_CAU_FRCTOGGLE (BIT(5) | BIT(4)) 59#define AQCTL_PRD_MASK (BIT(3) | BIT(2)) 60#define AQCTL_PRD_FRCLOW BIT(2) 61#define AQCTL_PRD_FRCHIGH BIT(3) 62#define AQCTL_PRD_FRCTOGGLE (BIT(3) | BIT(2)) 63#define AQCTL_ZRO_MASK (BIT(1) | BIT(0)) 64#define AQCTL_ZRO_FRCLOW BIT(0) 65#define AQCTL_ZRO_FRCHIGH BIT(1) 66#define AQCTL_ZRO_FRCTOGGLE (BIT(1) | BIT(0)) 67 68#define AQCTL_CHANA_POLNORMAL (AQCTL_CAU_FRCLOW | AQCTL_ZRO_FRCHIGH) 69#define AQCTL_CHANA_POLINVERSED (AQCTL_CAU_FRCHIGH | AQCTL_ZRO_FRCLOW) 70#define AQCTL_CHANB_POLNORMAL (AQCTL_CBU_FRCLOW | AQCTL_ZRO_FRCHIGH) 71#define AQCTL_CHANB_POLINVERSED (AQCTL_CBU_FRCHIGH | AQCTL_ZRO_FRCLOW) 72 73#define AQSFRC_RLDCSF_MASK (BIT(7) | BIT(6)) 74#define AQSFRC_RLDCSF_ZRO 0 75#define AQSFRC_RLDCSF_PRD BIT(6) 76#define AQSFRC_RLDCSF_ZROPRD BIT(7) 77#define AQSFRC_RLDCSF_IMDT (BIT(7) | BIT(6)) 78 79#define AQCSFRC_CSFB_MASK (BIT(3) | BIT(2)) 80#define AQCSFRC_CSFB_FRCDIS 0 81#define AQCSFRC_CSFB_FRCLOW BIT(2) 82#define AQCSFRC_CSFB_FRCHIGH BIT(3) 83#define AQCSFRC_CSFB_DISSWFRC (BIT(3) | BIT(2)) 84#define AQCSFRC_CSFA_MASK (BIT(1) | BIT(0)) 85#define AQCSFRC_CSFA_FRCDIS 0 86#define AQCSFRC_CSFA_FRCLOW BIT(0) 87#define AQCSFRC_CSFA_FRCHIGH BIT(1) 88#define AQCSFRC_CSFA_DISSWFRC (BIT(1) | BIT(0)) 89 90#define NUM_PWM_CHANNEL 2 /* EHRPWM channels */ 91 92struct ehrpwm_context { 93 u16 tbctl; 94 u16 tbprd; 95 u16 cmpa; 96 u16 cmpb; 97 u16 aqctla; 98 u16 aqctlb; 99 u16 aqsfrc; 100 u16 aqcsfrc; 101}; 102 103struct ehrpwm_pwm_chip { 104 unsigned long clk_rate; 105 void __iomem *mmio_base; 106 unsigned long period_cycles[NUM_PWM_CHANNEL]; 107 struct clk *tbclk; 108 struct ehrpwm_context ctx; 109}; 110 111static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) 112{ 113 return pwmchip_get_drvdata(chip); 114} 115 116static inline u16 ehrpwm_read(void __iomem *base, unsigned int offset) 117{ 118 return readw(base + offset); 119} 120 121static inline void ehrpwm_write(void __iomem *base, unsigned int offset, 122 u16 value) 123{ 124 writew(value, base + offset); 125} 126 127static void ehrpwm_modify(void __iomem *base, unsigned int offset, u16 mask, 128 u16 value) 129{ 130 unsigned short val; 131 132 val = readw(base + offset); 133 val &= ~mask; 134 val |= value & mask; 135 writew(val, base + offset); 136} 137 138/** 139 * set_prescale_div - Set up the prescaler divider function 140 * @rqst_prescaler: prescaler value min 141 * @prescale_div: prescaler value set 142 * @tb_clk_div: Time Base Control prescaler bits 143 */ 144static int set_prescale_div(unsigned long rqst_prescaler, u16 *prescale_div, 145 u16 *tb_clk_div) 146{ 147 unsigned int clkdiv, hspclkdiv; 148 149 for (clkdiv = 0; clkdiv <= CLKDIV_MAX; clkdiv++) { 150 for (hspclkdiv = 0; hspclkdiv <= HSPCLKDIV_MAX; hspclkdiv++) { 151 /* 152 * calculations for prescaler value : 153 * prescale_div = HSPCLKDIVIDER * CLKDIVIDER. 154 * HSPCLKDIVIDER = 2 ** hspclkdiv 155 * CLKDIVIDER = (1), if clkdiv == 0 *OR* 156 * (2 * clkdiv), if clkdiv != 0 157 * 158 * Configure prescale_div value such that period 159 * register value is less than 65535. 160 */ 161 162 *prescale_div = (1 << clkdiv) * 163 (hspclkdiv ? (hspclkdiv * 2) : 1); 164 if (*prescale_div >= rqst_prescaler) { 165 *tb_clk_div = (clkdiv << TBCTL_CLKDIV_SHIFT) | 166 (hspclkdiv << TBCTL_HSPCLKDIV_SHIFT); 167 return 0; 168 } 169 } 170 } 171 172 return 1; 173} 174 175/* 176 * period_ns = 10^9 * (ps_divval * period_cycles) / PWM_CLK_RATE 177 * duty_ns = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE 178 */ 179static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 180 u64 duty_ns, u64 period_ns, enum pwm_polarity polarity) 181{ 182 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); 183 u32 period_cycles, duty_cycles; 184 u16 ps_divval, tb_divval; 185 unsigned int i, cmp_reg; 186 unsigned long long c; 187 u16 aqctl_val, aqctl_mask; 188 unsigned int aqctl_reg; 189 190 if (period_ns > NSEC_PER_SEC) 191 return -ERANGE; 192 193 c = pc->clk_rate; 194 c = c * period_ns; 195 do_div(c, NSEC_PER_SEC); 196 period_cycles = (unsigned long)c; 197 198 c = pc->clk_rate; 199 c = c * duty_ns; 200 do_div(c, NSEC_PER_SEC); 201 duty_cycles = (unsigned long)c; 202 203 /* 204 * Period values should be same for multiple PWM channels as IP uses 205 * same period register for multiple channels. 206 */ 207 for (i = 0; i < NUM_PWM_CHANNEL; i++) { 208 if (pc->period_cycles[i] && 209 (pc->period_cycles[i] != period_cycles)) { 210 /* 211 * Allow channel to reconfigure period if no other 212 * channels being configured. 213 */ 214 if (i == pwm->hwpwm) 215 continue; 216 217 dev_err(pwmchip_parent(chip), 218 "period value conflicts with channel %u\n", 219 i); 220 return -EINVAL; 221 } 222 } 223 224 pc->period_cycles[pwm->hwpwm] = period_cycles; 225 226 /* Configure clock prescaler to support Low frequency PWM wave */ 227 if (set_prescale_div(DIV_ROUND_UP(period_cycles, PERIOD_MAX), &ps_divval, 228 &tb_divval)) { 229 dev_err(pwmchip_parent(chip), "Unsupported values\n"); 230 return -EINVAL; 231 } 232 233 /* Update period & duty cycle with presacler division */ 234 period_cycles = period_cycles / ps_divval; 235 duty_cycles = duty_cycles / ps_divval; 236 237 if (period_cycles < 1) 238 period_cycles = 1; 239 240 /* Update clock prescaler values */ 241 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval); 242 243 if (pwm->hwpwm == 1) { 244 /* Channel 1 configured with compare B register */ 245 cmp_reg = CMPB; 246 247 aqctl_reg = AQCTLB; 248 aqctl_mask = AQCTL_CBU_MASK; 249 250 if (polarity == PWM_POLARITY_INVERSED) 251 aqctl_val = AQCTL_CHANB_POLINVERSED; 252 else 253 aqctl_val = AQCTL_CHANB_POLNORMAL; 254 255 /* if duty_cycle is big, don't toggle on CBU */ 256 if (duty_cycles > period_cycles) 257 aqctl_val &= ~AQCTL_CBU_MASK; 258 259 } else { 260 /* Channel 0 configured with compare A register */ 261 cmp_reg = CMPA; 262 263 aqctl_reg = AQCTLA; 264 aqctl_mask = AQCTL_CAU_MASK; 265 266 if (polarity == PWM_POLARITY_INVERSED) 267 aqctl_val = AQCTL_CHANA_POLINVERSED; 268 else 269 aqctl_val = AQCTL_CHANA_POLNORMAL; 270 271 /* if duty_cycle is big, don't toggle on CAU */ 272 if (duty_cycles > period_cycles) 273 aqctl_val &= ~AQCTL_CAU_MASK; 274 } 275 276 aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK; 277 ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val); 278 279 /* Configure shadow loading on Period register */ 280 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_PRDLD_MASK, TBCTL_PRDLD_SHDW); 281 282 ehrpwm_write(pc->mmio_base, TBPRD, period_cycles - 1); 283 284 /* Configure ehrpwm counter for up-count mode */ 285 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK, 286 TBCTL_CTRMODE_UP); 287 288 if (!(duty_cycles > period_cycles)) 289 ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles); 290 291 return 0; 292} 293 294static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 295{ 296 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); 297 u16 aqcsfrc_val, aqcsfrc_mask; 298 int ret; 299 300 /* Leave clock enabled on enabling PWM */ 301 pm_runtime_get_sync(pwmchip_parent(chip)); 302 303 /* Disabling Action Qualifier on PWM output */ 304 if (pwm->hwpwm) { 305 aqcsfrc_val = AQCSFRC_CSFB_FRCDIS; 306 aqcsfrc_mask = AQCSFRC_CSFB_MASK; 307 } else { 308 aqcsfrc_val = AQCSFRC_CSFA_FRCDIS; 309 aqcsfrc_mask = AQCSFRC_CSFA_MASK; 310 } 311 312 /* Changes to shadow mode */ 313 ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK, 314 AQSFRC_RLDCSF_ZRO); 315 316 ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); 317 318 /* Enable TBCLK */ 319 ret = clk_enable(pc->tbclk); 320 if (ret) { 321 dev_err(pwmchip_parent(chip), "Failed to enable TBCLK for %s: %d\n", 322 dev_name(pwmchip_parent(chip)), ret); 323 return ret; 324 } 325 326 return 0; 327} 328 329static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 330{ 331 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); 332 u16 aqcsfrc_val, aqcsfrc_mask; 333 334 /* Action Qualifier puts PWM output low forcefully */ 335 if (pwm->hwpwm) { 336 aqcsfrc_val = AQCSFRC_CSFB_FRCLOW; 337 aqcsfrc_mask = AQCSFRC_CSFB_MASK; 338 } else { 339 aqcsfrc_val = AQCSFRC_CSFA_FRCLOW; 340 aqcsfrc_mask = AQCSFRC_CSFA_MASK; 341 } 342 343 /* Update shadow register first before modifying active register */ 344 ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK, 345 AQSFRC_RLDCSF_ZRO); 346 ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); 347 /* 348 * Changes to immediate action on Action Qualifier. This puts 349 * Action Qualifier control on PWM output from next TBCLK 350 */ 351 ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK, 352 AQSFRC_RLDCSF_IMDT); 353 354 ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); 355 356 /* Disabling TBCLK on PWM disable */ 357 clk_disable(pc->tbclk); 358 359 /* Disable clock on PWM disable */ 360 pm_runtime_put_sync(pwmchip_parent(chip)); 361} 362 363static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 364{ 365 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); 366 367 /* Don't let a pwm without consumer block requests to the other channel */ 368 pc->period_cycles[pwm->hwpwm] = 0; 369} 370 371static int ehrpwm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 372 const struct pwm_state *state) 373{ 374 int err; 375 bool enabled = pwm->state.enabled; 376 377 guard(pm_runtime_active)(pwmchip_parent(chip)); 378 379 if (state->polarity != pwm->state.polarity) { 380 if (enabled) { 381 ehrpwm_pwm_disable(chip, pwm); 382 enabled = false; 383 } 384 } 385 386 if (!state->enabled) { 387 if (enabled) 388 ehrpwm_pwm_disable(chip, pwm); 389 return 0; 390 } 391 392 err = ehrpwm_pwm_config(chip, pwm, state->duty_cycle, state->period, state->polarity); 393 if (err) 394 return err; 395 396 if (!enabled) 397 err = ehrpwm_pwm_enable(chip, pwm); 398 399 return err; 400} 401 402static const struct pwm_ops ehrpwm_pwm_ops = { 403 .free = ehrpwm_pwm_free, 404 .apply = ehrpwm_pwm_apply, 405}; 406 407static const struct of_device_id ehrpwm_of_match[] = { 408 { .compatible = "ti,am3352-ehrpwm" }, 409 { .compatible = "ti,am33xx-ehrpwm" }, 410 {}, 411}; 412MODULE_DEVICE_TABLE(of, ehrpwm_of_match); 413 414static int ehrpwm_pwm_probe(struct platform_device *pdev) 415{ 416 struct device_node *np = pdev->dev.of_node; 417 struct ehrpwm_pwm_chip *pc; 418 struct pwm_chip *chip; 419 struct clk *clk; 420 int ret; 421 422 chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM_CHANNEL, sizeof(*pc)); 423 if (IS_ERR(chip)) 424 return PTR_ERR(chip); 425 pc = to_ehrpwm_pwm_chip(chip); 426 427 clk = devm_clk_get(&pdev->dev, "fck"); 428 if (IS_ERR(clk)) { 429 if (of_device_is_compatible(np, "ti,am33xx-ecap")) { 430 dev_warn(&pdev->dev, "Binding is obsolete.\n"); 431 clk = devm_clk_get(pdev->dev.parent, "fck"); 432 } 433 } 434 435 if (IS_ERR(clk)) 436 return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Failed to get fck\n"); 437 438 pc->clk_rate = clk_get_rate(clk); 439 if (!pc->clk_rate) { 440 dev_err(&pdev->dev, "failed to get clock rate\n"); 441 return -EINVAL; 442 } 443 444 chip->ops = &ehrpwm_pwm_ops; 445 446 pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); 447 if (IS_ERR(pc->mmio_base)) 448 return PTR_ERR(pc->mmio_base); 449 450 /* Acquire tbclk for Time Base EHRPWM submodule */ 451 pc->tbclk = devm_clk_get(&pdev->dev, "tbclk"); 452 if (IS_ERR(pc->tbclk)) 453 return dev_err_probe(&pdev->dev, PTR_ERR(pc->tbclk), "Failed to get tbclk\n"); 454 455 ret = clk_prepare(pc->tbclk); 456 if (ret < 0) { 457 dev_err(&pdev->dev, "clk_prepare() failed: %d\n", ret); 458 return ret; 459 } 460 461 ret = pwmchip_add(chip); 462 if (ret < 0) { 463 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 464 goto err_clk_unprepare; 465 } 466 467 platform_set_drvdata(pdev, chip); 468 pm_runtime_enable(&pdev->dev); 469 470 return 0; 471 472err_clk_unprepare: 473 clk_unprepare(pc->tbclk); 474 475 return ret; 476} 477 478static void ehrpwm_pwm_remove(struct platform_device *pdev) 479{ 480 struct pwm_chip *chip = platform_get_drvdata(pdev); 481 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); 482 483 pwmchip_remove(chip); 484 485 clk_unprepare(pc->tbclk); 486 487 pm_runtime_disable(&pdev->dev); 488} 489 490static void ehrpwm_pwm_save_context(struct pwm_chip *chip) 491{ 492 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); 493 494 pm_runtime_get_sync(pwmchip_parent(chip)); 495 496 pc->ctx.tbctl = ehrpwm_read(pc->mmio_base, TBCTL); 497 pc->ctx.tbprd = ehrpwm_read(pc->mmio_base, TBPRD); 498 pc->ctx.cmpa = ehrpwm_read(pc->mmio_base, CMPA); 499 pc->ctx.cmpb = ehrpwm_read(pc->mmio_base, CMPB); 500 pc->ctx.aqctla = ehrpwm_read(pc->mmio_base, AQCTLA); 501 pc->ctx.aqctlb = ehrpwm_read(pc->mmio_base, AQCTLB); 502 pc->ctx.aqsfrc = ehrpwm_read(pc->mmio_base, AQSFRC); 503 pc->ctx.aqcsfrc = ehrpwm_read(pc->mmio_base, AQCSFRC); 504 505 pm_runtime_put_sync(pwmchip_parent(chip)); 506} 507 508static void ehrpwm_pwm_restore_context(struct pwm_chip *chip) 509{ 510 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); 511 512 ehrpwm_write(pc->mmio_base, TBPRD, pc->ctx.tbprd); 513 ehrpwm_write(pc->mmio_base, CMPA, pc->ctx.cmpa); 514 ehrpwm_write(pc->mmio_base, CMPB, pc->ctx.cmpb); 515 ehrpwm_write(pc->mmio_base, AQCTLA, pc->ctx.aqctla); 516 ehrpwm_write(pc->mmio_base, AQCTLB, pc->ctx.aqctlb); 517 ehrpwm_write(pc->mmio_base, AQSFRC, pc->ctx.aqsfrc); 518 ehrpwm_write(pc->mmio_base, AQCSFRC, pc->ctx.aqcsfrc); 519 ehrpwm_write(pc->mmio_base, TBCTL, pc->ctx.tbctl); 520} 521 522static int ehrpwm_pwm_suspend(struct device *dev) 523{ 524 struct pwm_chip *chip = dev_get_drvdata(dev); 525 unsigned int i; 526 527 ehrpwm_pwm_save_context(chip); 528 529 for (i = 0; i < chip->npwm; i++) { 530 struct pwm_device *pwm = &chip->pwms[i]; 531 532 if (!pwm_is_enabled(pwm)) 533 continue; 534 535 /* Disable explicitly if PWM is running */ 536 pm_runtime_put_sync(dev); 537 } 538 539 return 0; 540} 541 542static int ehrpwm_pwm_resume(struct device *dev) 543{ 544 struct pwm_chip *chip = dev_get_drvdata(dev); 545 unsigned int i; 546 547 for (i = 0; i < chip->npwm; i++) { 548 struct pwm_device *pwm = &chip->pwms[i]; 549 550 if (!pwm_is_enabled(pwm)) 551 continue; 552 553 /* Enable explicitly if PWM was running */ 554 pm_runtime_get_sync(dev); 555 } 556 557 ehrpwm_pwm_restore_context(chip); 558 559 return 0; 560} 561 562static DEFINE_SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend, 563 ehrpwm_pwm_resume); 564 565static struct platform_driver ehrpwm_pwm_driver = { 566 .driver = { 567 .name = "ehrpwm", 568 .of_match_table = ehrpwm_of_match, 569 .pm = pm_ptr(&ehrpwm_pwm_pm_ops), 570 }, 571 .probe = ehrpwm_pwm_probe, 572 .remove = ehrpwm_pwm_remove, 573}; 574module_platform_driver(ehrpwm_pwm_driver); 575 576MODULE_DESCRIPTION("EHRPWM PWM driver"); 577MODULE_AUTHOR("Texas Instruments"); 578MODULE_LICENSE("GPL");
~/
Read-only file preview.