linux/drivers/pwm/pwm-imx-tpm.c
<<
>>
Prefs
   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, &param, &real_state, state);
 298        if (ret)
 299                return ret;
 300
 301        mutex_lock(&tpm->lock);
 302        ret = pwm_imx_tpm_apply_hw(chip, &param, &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        tpm->chip.base = -1;
 367        tpm->chip.of_xlate = of_pwm_xlate_with_flags;
 368        tpm->chip.of_pwm_n_cells = 3;
 369
 370        /* get number of channels */
 371        val = readl(tpm->base + PWM_IMX_TPM_PARAM);
 372        tpm->chip.npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val);
 373
 374        mutex_init(&tpm->lock);
 375
 376        ret = pwmchip_add(&tpm->chip);
 377        if (ret) {
 378                dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
 379                clk_disable_unprepare(tpm->clk);
 380        }
 381
 382        return ret;
 383}
 384
 385static int pwm_imx_tpm_remove(struct platform_device *pdev)
 386{
 387        struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev);
 388        int ret = pwmchip_remove(&tpm->chip);
 389
 390        clk_disable_unprepare(tpm->clk);
 391
 392        return ret;
 393}
 394
 395static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
 396{
 397        struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
 398
 399        if (tpm->enable_count > 0)
 400                return -EBUSY;
 401
 402        clk_disable_unprepare(tpm->clk);
 403
 404        return 0;
 405}
 406
 407static int __maybe_unused pwm_imx_tpm_resume(struct device *dev)
 408{
 409        struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
 410        int ret = 0;
 411
 412        ret = clk_prepare_enable(tpm->clk);
 413        if (ret)
 414                dev_err(dev,
 415                        "failed to prepare or enable clock: %d\n",
 416                        ret);
 417
 418        return ret;
 419}
 420
 421static SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm,
 422                         pwm_imx_tpm_suspend, pwm_imx_tpm_resume);
 423
 424static const struct of_device_id imx_tpm_pwm_dt_ids[] = {
 425        { .compatible = "fsl,imx7ulp-pwm", },
 426        { /* sentinel */ }
 427};
 428MODULE_DEVICE_TABLE(of, imx_tpm_pwm_dt_ids);
 429
 430static struct platform_driver imx_tpm_pwm_driver = {
 431        .driver = {
 432                .name = "imx7ulp-tpm-pwm",
 433                .of_match_table = imx_tpm_pwm_dt_ids,
 434                .pm = &imx_tpm_pwm_pm,
 435        },
 436        .probe  = pwm_imx_tpm_probe,
 437        .remove = pwm_imx_tpm_remove,
 438};
 439module_platform_driver(imx_tpm_pwm_driver);
 440
 441MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
 442MODULE_DESCRIPTION("i.MX TPM PWM Driver");
 443MODULE_LICENSE("GPL v2");
 444