pwm-imx-tpm.c (11759B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright 2018-2019 NXP. 4 * 5 * Limitations: 6 * - The TPM counter and period counter are shared between 7 * multiple channels, so all channels should use same period 8 * settings. 9 * - Changes to polarity cannot be latched at the time of the 10 * next period start. 11 * - Changing period and duty cycle together isn't atomic, 12 * with the wrong timing it might happen that a period is 13 * produced with old duty cycle but new period settings. 14 */ 15 16#include <linux/bitfield.h> 17#include <linux/bitops.h> 18#include <linux/clk.h> 19#include <linux/err.h> 20#include <linux/io.h> 21#include <linux/module.h> 22#include <linux/of.h> 23#include <linux/platform_device.h> 24#include <linux/pwm.h> 25#include <linux/slab.h> 26 27#define PWM_IMX_TPM_PARAM 0x4 28#define PWM_IMX_TPM_GLOBAL 0x8 29#define PWM_IMX_TPM_SC 0x10 30#define PWM_IMX_TPM_CNT 0x14 31#define PWM_IMX_TPM_MOD 0x18 32#define PWM_IMX_TPM_CnSC(n) (0x20 + (n) * 0x8) 33#define PWM_IMX_TPM_CnV(n) (0x24 + (n) * 0x8) 34 35#define PWM_IMX_TPM_PARAM_CHAN GENMASK(7, 0) 36 37#define PWM_IMX_TPM_SC_PS GENMASK(2, 0) 38#define PWM_IMX_TPM_SC_CMOD GENMASK(4, 3) 39#define PWM_IMX_TPM_SC_CMOD_INC_EVERY_CLK FIELD_PREP(PWM_IMX_TPM_SC_CMOD, 1) 40#define PWM_IMX_TPM_SC_CPWMS BIT(5) 41 42#define PWM_IMX_TPM_CnSC_CHF BIT(7) 43#define PWM_IMX_TPM_CnSC_MSB BIT(5) 44#define PWM_IMX_TPM_CnSC_MSA BIT(4) 45 46/* 47 * The reference manual describes this field as two separate bits. The 48 * semantic of the two bits isn't orthogonal though, so they are treated 49 * together as a 2-bit field here. 50 */ 51#define PWM_IMX_TPM_CnSC_ELS GENMASK(3, 2) 52#define PWM_IMX_TPM_CnSC_ELS_INVERSED FIELD_PREP(PWM_IMX_TPM_CnSC_ELS, 1) 53#define PWM_IMX_TPM_CnSC_ELS_NORMAL FIELD_PREP(PWM_IMX_TPM_CnSC_ELS, 2) 54 55 56#define PWM_IMX_TPM_MOD_WIDTH 16 57#define PWM_IMX_TPM_MOD_MOD GENMASK(PWM_IMX_TPM_MOD_WIDTH - 1, 0) 58 59struct imx_tpm_pwm_chip { 60 struct pwm_chip chip; 61 struct clk *clk; 62 void __iomem *base; 63 struct mutex lock; 64 u32 user_count; 65 u32 enable_count; 66 u32 real_period; 67}; 68 69struct imx_tpm_pwm_param { 70 u8 prescale; 71 u32 mod; 72 u32 val; 73}; 74 75static inline struct imx_tpm_pwm_chip * 76to_imx_tpm_pwm_chip(struct pwm_chip *chip) 77{ 78 return container_of(chip, struct imx_tpm_pwm_chip, chip); 79} 80 81/* 82 * This function determines for a given pwm_state *state that a consumer 83 * might request the pwm_state *real_state that eventually is implemented 84 * by the hardware and the necessary register values (in *p) to achieve 85 * this. 86 */ 87static int pwm_imx_tpm_round_state(struct pwm_chip *chip, 88 struct imx_tpm_pwm_param *p, 89 struct pwm_state *real_state, 90 const struct pwm_state *state) 91{ 92 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); 93 u32 rate, prescale, period_count, clock_unit; 94 u64 tmp; 95 96 rate = clk_get_rate(tpm->clk); 97 tmp = (u64)state->period * rate; 98 clock_unit = DIV_ROUND_CLOSEST_ULL(tmp, NSEC_PER_SEC); 99 if (clock_unit <= PWM_IMX_TPM_MOD_MOD) 100 prescale = 0; 101 else 102 prescale = ilog2(clock_unit) + 1 - PWM_IMX_TPM_MOD_WIDTH; 103 104 if ((!FIELD_FIT(PWM_IMX_TPM_SC_PS, prescale))) 105 return -ERANGE; 106 p->prescale = prescale; 107 108 period_count = (clock_unit + ((1 << prescale) >> 1)) >> prescale; 109 p->mod = period_count; 110 111 /* calculate real period HW can support */ 112 tmp = (u64)period_count << prescale; 113 tmp *= NSEC_PER_SEC; 114 real_state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); 115 116 /* 117 * if eventually the PWM output is inactive, either 118 * duty cycle is 0 or status is disabled, need to 119 * make sure the output pin is inactive. 120 */ 121 if (!state->enabled) 122 real_state->duty_cycle = 0; 123 else 124 real_state->duty_cycle = state->duty_cycle; 125 126 tmp = (u64)p->mod * real_state->duty_cycle; 127 p->val = DIV64_U64_ROUND_CLOSEST(tmp, real_state->period); 128 129 real_state->polarity = state->polarity; 130 real_state->enabled = state->enabled; 131 132 return 0; 133} 134 135static void pwm_imx_tpm_get_state(struct pwm_chip *chip, 136 struct pwm_device *pwm, 137 struct pwm_state *state) 138{ 139 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); 140 u32 rate, val, prescale; 141 u64 tmp; 142 143 /* get period */ 144 state->period = tpm->real_period; 145 146 /* get duty cycle */ 147 rate = clk_get_rate(tpm->clk); 148 val = readl(tpm->base + PWM_IMX_TPM_SC); 149 prescale = FIELD_GET(PWM_IMX_TPM_SC_PS, val); 150 tmp = readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)); 151 tmp = (tmp << prescale) * NSEC_PER_SEC; 152 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); 153 154 /* get polarity */ 155 val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); 156 if ((val & PWM_IMX_TPM_CnSC_ELS) == PWM_IMX_TPM_CnSC_ELS_INVERSED) 157 state->polarity = PWM_POLARITY_INVERSED; 158 else 159 /* 160 * Assume reserved values (2b00 and 2b11) to yield 161 * normal polarity. 162 */ 163 state->polarity = PWM_POLARITY_NORMAL; 164 165 /* get channel status */ 166 state->enabled = FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val) ? true : false; 167} 168 169/* this function is supposed to be called with mutex hold */ 170static int pwm_imx_tpm_apply_hw(struct pwm_chip *chip, 171 struct imx_tpm_pwm_param *p, 172 struct pwm_state *state, 173 struct pwm_device *pwm) 174{ 175 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); 176 bool period_update = false; 177 bool duty_update = false; 178 u32 val, cmod, cur_prescale; 179 unsigned long timeout; 180 struct pwm_state c; 181 182 if (state->period != tpm->real_period) { 183 /* 184 * TPM counter is shared by multiple channels, so 185 * prescale and period can NOT be modified when 186 * there are multiple channels in use with different 187 * period settings. 188 */ 189 if (tpm->user_count > 1) 190 return -EBUSY; 191 192 val = readl(tpm->base + PWM_IMX_TPM_SC); 193 cmod = FIELD_GET(PWM_IMX_TPM_SC_CMOD, val); 194 cur_prescale = FIELD_GET(PWM_IMX_TPM_SC_PS, val); 195 if (cmod && cur_prescale != p->prescale) 196 return -EBUSY; 197 198 /* set TPM counter prescale */ 199 val &= ~PWM_IMX_TPM_SC_PS; 200 val |= FIELD_PREP(PWM_IMX_TPM_SC_PS, p->prescale); 201 writel(val, tpm->base + PWM_IMX_TPM_SC); 202 203 /* 204 * set period count: 205 * if the PWM is disabled (CMOD[1:0] = 2b00), then MOD register 206 * is updated when MOD register is written. 207 * 208 * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the period length 209 * is latched into hardware when the next period starts. 210 */ 211 writel(p->mod, tpm->base + PWM_IMX_TPM_MOD); 212 tpm->real_period = state->period; 213 period_update = true; 214 } 215 216 pwm_imx_tpm_get_state(chip, pwm, &c); 217 218 /* polarity is NOT allowed to be changed if PWM is active */ 219 if (c.enabled && c.polarity != state->polarity) 220 return -EBUSY; 221 222 if (state->duty_cycle != c.duty_cycle) { 223 /* 224 * set channel value: 225 * if the PWM is disabled (CMOD[1:0] = 2b00), then CnV register 226 * is updated when CnV register is written. 227 * 228 * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the duty length 229 * is latched into hardware when the next period starts. 230 */ 231 writel(p->val, tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)); 232 duty_update = true; 233 } 234 235 /* make sure MOD & CnV registers are updated */ 236 if (period_update || duty_update) { 237 timeout = jiffies + msecs_to_jiffies(tpm->real_period / 238 NSEC_PER_MSEC + 1); 239 while (readl(tpm->base + PWM_IMX_TPM_MOD) != p->mod 240 || readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)) 241 != p->val) { 242 if (time_after(jiffies, timeout)) 243 return -ETIME; 244 cpu_relax(); 245 } 246 } 247 248 /* 249 * polarity settings will enabled/disable output status 250 * immediately, so if the channel is disabled, need to 251 * make sure MSA/MSB/ELS are set to 0 which means channel 252 * disabled. 253 */ 254 val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); 255 val &= ~(PWM_IMX_TPM_CnSC_ELS | PWM_IMX_TPM_CnSC_MSA | 256 PWM_IMX_TPM_CnSC_MSB); 257 if (state->enabled) { 258 /* 259 * set polarity (for edge-aligned PWM modes) 260 * 261 * ELS[1:0] = 2b10 yields normal polarity behaviour, 262 * ELS[1:0] = 2b01 yields inversed polarity. 263 * The other values are reserved. 264 */ 265 val |= PWM_IMX_TPM_CnSC_MSB; 266 val |= (state->polarity == PWM_POLARITY_NORMAL) ? 267 PWM_IMX_TPM_CnSC_ELS_NORMAL : 268 PWM_IMX_TPM_CnSC_ELS_INVERSED; 269 } 270 writel(val, tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); 271 272 /* control the counter status */ 273 if (state->enabled != c.enabled) { 274 val = readl(tpm->base + PWM_IMX_TPM_SC); 275 if (state->enabled) { 276 if (++tpm->enable_count == 1) 277 val |= PWM_IMX_TPM_SC_CMOD_INC_EVERY_CLK; 278 } else { 279 if (--tpm->enable_count == 0) 280 val &= ~PWM_IMX_TPM_SC_CMOD; 281 } 282 writel(val, tpm->base + PWM_IMX_TPM_SC); 283 } 284 285 return 0; 286} 287 288static int pwm_imx_tpm_apply(struct pwm_chip *chip, 289 struct pwm_device *pwm, 290 const struct pwm_state *state) 291{ 292 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); 293 struct imx_tpm_pwm_param param; 294 struct pwm_state real_state; 295 int ret; 296 297 ret = pwm_imx_tpm_round_state(chip, ¶m, &real_state, state); 298 if (ret) 299 return ret; 300 301 mutex_lock(&tpm->lock); 302 ret = pwm_imx_tpm_apply_hw(chip, ¶m, &real_state, pwm); 303 mutex_unlock(&tpm->lock); 304 305 return ret; 306} 307 308static int pwm_imx_tpm_request(struct pwm_chip *chip, struct pwm_device *pwm) 309{ 310 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); 311 312 mutex_lock(&tpm->lock); 313 tpm->user_count++; 314 mutex_unlock(&tpm->lock); 315 316 return 0; 317} 318 319static void pwm_imx_tpm_free(struct pwm_chip *chip, struct pwm_device *pwm) 320{ 321 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); 322 323 mutex_lock(&tpm->lock); 324 tpm->user_count--; 325 mutex_unlock(&tpm->lock); 326} 327 328static const struct pwm_ops imx_tpm_pwm_ops = { 329 .request = pwm_imx_tpm_request, 330 .free = pwm_imx_tpm_free, 331 .get_state = pwm_imx_tpm_get_state, 332 .apply = pwm_imx_tpm_apply, 333 .owner = THIS_MODULE, 334}; 335 336static int pwm_imx_tpm_probe(struct platform_device *pdev) 337{ 338 struct imx_tpm_pwm_chip *tpm; 339 int ret; 340 u32 val; 341 342 tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL); 343 if (!tpm) 344 return -ENOMEM; 345 346 platform_set_drvdata(pdev, tpm); 347 348 tpm->base = devm_platform_ioremap_resource(pdev, 0); 349 if (IS_ERR(tpm->base)) 350 return PTR_ERR(tpm->base); 351 352 tpm->clk = devm_clk_get(&pdev->dev, NULL); 353 if (IS_ERR(tpm->clk)) 354 return dev_err_probe(&pdev->dev, PTR_ERR(tpm->clk), 355 "failed to get PWM clock\n"); 356 357 ret = clk_prepare_enable(tpm->clk); 358 if (ret) { 359 dev_err(&pdev->dev, 360 "failed to prepare or enable clock: %d\n", ret); 361 return ret; 362 } 363 364 tpm->chip.dev = &pdev->dev; 365 tpm->chip.ops = &imx_tpm_pwm_ops; 366 367 /* get number of channels */ 368 val = readl(tpm->base + PWM_IMX_TPM_PARAM); 369 tpm->chip.npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val); 370 371 mutex_init(&tpm->lock); 372 373 ret = pwmchip_add(&tpm->chip); 374 if (ret) { 375 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); 376 clk_disable_unprepare(tpm->clk); 377 } 378 379 return ret; 380} 381 382static int pwm_imx_tpm_remove(struct platform_device *pdev) 383{ 384 struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev); 385 386 pwmchip_remove(&tpm->chip); 387 388 clk_disable_unprepare(tpm->clk); 389 390 return 0; 391} 392 393static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev) 394{ 395 struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev); 396 397 if (tpm->enable_count > 0) 398 return -EBUSY; 399 400 clk_disable_unprepare(tpm->clk); 401 402 return 0; 403} 404 405static int __maybe_unused pwm_imx_tpm_resume(struct device *dev) 406{ 407 struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev); 408 int ret = 0; 409 410 ret = clk_prepare_enable(tpm->clk); 411 if (ret) 412 dev_err(dev, "failed to prepare or enable clock: %d\n", ret); 413 414 return ret; 415} 416 417static SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm, 418 pwm_imx_tpm_suspend, pwm_imx_tpm_resume); 419 420static const struct of_device_id imx_tpm_pwm_dt_ids[] = { 421 { .compatible = "fsl,imx7ulp-pwm", }, 422 { /* sentinel */ } 423}; 424MODULE_DEVICE_TABLE(of, imx_tpm_pwm_dt_ids); 425 426static struct platform_driver imx_tpm_pwm_driver = { 427 .driver = { 428 .name = "imx7ulp-tpm-pwm", 429 .of_match_table = imx_tpm_pwm_dt_ids, 430 .pm = &imx_tpm_pwm_pm, 431 }, 432 .probe = pwm_imx_tpm_probe, 433 .remove = pwm_imx_tpm_remove, 434}; 435module_platform_driver(imx_tpm_pwm_driver); 436 437MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); 438MODULE_DESCRIPTION("i.MX TPM PWM Driver"); 439MODULE_LICENSE("GPL v2");