linux/drivers/pwm/pwm-tiehrpwm.c
<<
>>
Prefs
   1/*
   2 * EHRPWM PWM driver
   3 *
   4 * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.com/
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19 */
  20
  21#include <linux/module.h>
  22#include <linux/platform_device.h>
  23#include <linux/pwm.h>
  24#include <linux/io.h>
  25#include <linux/err.h>
  26#include <linux/clk.h>
  27#include <linux/pm_runtime.h>
  28
  29/* EHRPWM registers and bits definitions */
  30
  31/* Time base module registers */
  32#define TBCTL                   0x00
  33#define TBPRD                   0x0A
  34
  35#define TBCTL_RUN_MASK          (BIT(15) | BIT(14))
  36#define TBCTL_STOP_NEXT         0
  37#define TBCTL_STOP_ON_CYCLE     BIT(14)
  38#define TBCTL_FREE_RUN          (BIT(15) | BIT(14))
  39#define TBCTL_PRDLD_MASK        BIT(3)
  40#define TBCTL_PRDLD_SHDW        0
  41#define TBCTL_PRDLD_IMDT        BIT(3)
  42#define TBCTL_CLKDIV_MASK       (BIT(12) | BIT(11) | BIT(10) | BIT(9) | \
  43                                BIT(8) | BIT(7))
  44#define TBCTL_CTRMODE_MASK      (BIT(1) | BIT(0))
  45#define TBCTL_CTRMODE_UP        0
  46#define TBCTL_CTRMODE_DOWN      BIT(0)
  47#define TBCTL_CTRMODE_UPDOWN    BIT(1)
  48#define TBCTL_CTRMODE_FREEZE    (BIT(1) | BIT(0))
  49
  50#define TBCTL_HSPCLKDIV_SHIFT   7
  51#define TBCTL_CLKDIV_SHIFT      10
  52
  53#define CLKDIV_MAX              7
  54#define HSPCLKDIV_MAX           7
  55#define PERIOD_MAX              0xFFFF
  56
  57/* compare module registers */
  58#define CMPA                    0x12
  59#define CMPB                    0x14
  60
  61/* Action qualifier module registers */
  62#define AQCTLA                  0x16
  63#define AQCTLB                  0x18
  64#define AQSFRC                  0x1A
  65#define AQCSFRC                 0x1C
  66
  67#define AQCTL_CBU_MASK          (BIT(9) | BIT(8))
  68#define AQCTL_CBU_FRCLOW        BIT(8)
  69#define AQCTL_CBU_FRCHIGH       BIT(9)
  70#define AQCTL_CBU_FRCTOGGLE     (BIT(9) | BIT(8))
  71#define AQCTL_CAU_MASK          (BIT(5) | BIT(4))
  72#define AQCTL_CAU_FRCLOW        BIT(4)
  73#define AQCTL_CAU_FRCHIGH       BIT(5)
  74#define AQCTL_CAU_FRCTOGGLE     (BIT(5) | BIT(4))
  75#define AQCTL_PRD_MASK          (BIT(3) | BIT(2))
  76#define AQCTL_PRD_FRCLOW        BIT(2)
  77#define AQCTL_PRD_FRCHIGH       BIT(3)
  78#define AQCTL_PRD_FRCTOGGLE     (BIT(3) | BIT(2))
  79#define AQCTL_ZRO_MASK          (BIT(1) | BIT(0))
  80#define AQCTL_ZRO_FRCLOW        BIT(0)
  81#define AQCTL_ZRO_FRCHIGH       BIT(1)
  82#define AQCTL_ZRO_FRCTOGGLE     (BIT(1) | BIT(0))
  83
  84#define AQSFRC_RLDCSF_MASK      (BIT(7) | BIT(6))
  85#define AQSFRC_RLDCSF_ZRO       0
  86#define AQSFRC_RLDCSF_PRD       BIT(6)
  87#define AQSFRC_RLDCSF_ZROPRD    BIT(7)
  88#define AQSFRC_RLDCSF_IMDT      (BIT(7) | BIT(6))
  89
  90#define AQCSFRC_CSFB_MASK       (BIT(3) | BIT(2))
  91#define AQCSFRC_CSFB_FRCDIS     0
  92#define AQCSFRC_CSFB_FRCLOW     BIT(2)
  93#define AQCSFRC_CSFB_FRCHIGH    BIT(3)
  94#define AQCSFRC_CSFB_DISSWFRC   (BIT(3) | BIT(2))
  95#define AQCSFRC_CSFA_MASK       (BIT(1) | BIT(0))
  96#define AQCSFRC_CSFA_FRCDIS     0
  97#define AQCSFRC_CSFA_FRCLOW     BIT(0)
  98#define AQCSFRC_CSFA_FRCHIGH    BIT(1)
  99#define AQCSFRC_CSFA_DISSWFRC   (BIT(1) | BIT(0))
 100
 101#define NUM_PWM_CHANNEL         2       /* EHRPWM channels */
 102
 103struct ehrpwm_pwm_chip {
 104        struct pwm_chip chip;
 105        unsigned int    clk_rate;
 106        void __iomem    *mmio_base;
 107        unsigned long period_cycles[NUM_PWM_CHANNEL];
 108};
 109
 110static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
 111{
 112        return container_of(chip, struct ehrpwm_pwm_chip, chip);
 113}
 114
 115static void ehrpwm_write(void *base, int offset, unsigned int val)
 116{
 117        writew(val & 0xFFFF, base + offset);
 118}
 119
 120static void ehrpwm_modify(void *base, int offset,
 121                unsigned short mask, unsigned short val)
 122{
 123        unsigned short regval;
 124
 125        regval = readw(base + offset);
 126        regval &= ~mask;
 127        regval |= val & mask;
 128        writew(regval, base + offset);
 129}
 130
 131/**
 132 * set_prescale_div -   Set up the prescaler divider function
 133 * @rqst_prescaler:     prescaler value min
 134 * @prescale_div:       prescaler value set
 135 * @tb_clk_div:         Time Base Control prescaler bits
 136 */
 137static int set_prescale_div(unsigned long rqst_prescaler,
 138                unsigned short *prescale_div, unsigned short *tb_clk_div)
 139{
 140        unsigned int clkdiv, hspclkdiv;
 141
 142        for (clkdiv = 0; clkdiv <= CLKDIV_MAX; clkdiv++) {
 143                for (hspclkdiv = 0; hspclkdiv <= HSPCLKDIV_MAX; hspclkdiv++) {
 144
 145                        /*
 146                         * calculations for prescaler value :
 147                         * prescale_div = HSPCLKDIVIDER * CLKDIVIDER.
 148                         * HSPCLKDIVIDER =  2 ** hspclkdiv
 149                         * CLKDIVIDER = (1),            if clkdiv == 0 *OR*
 150                         *              (2 * clkdiv),   if clkdiv != 0
 151                         *
 152                         * Configure prescale_div value such that period
 153                         * register value is less than 65535.
 154                         */
 155
 156                        *prescale_div = (1 << clkdiv) *
 157                                        (hspclkdiv ? (hspclkdiv * 2) : 1);
 158                        if (*prescale_div > rqst_prescaler) {
 159                                *tb_clk_div = (clkdiv << TBCTL_CLKDIV_SHIFT) |
 160                                        (hspclkdiv << TBCTL_HSPCLKDIV_SHIFT);
 161                                return 0;
 162                        }
 163                }
 164        }
 165        return 1;
 166}
 167
 168static void configure_chans(struct ehrpwm_pwm_chip *pc, int chan,
 169                unsigned long duty_cycles)
 170{
 171        int cmp_reg, aqctl_reg;
 172        unsigned short aqctl_val, aqctl_mask;
 173
 174        /*
 175         * Channels can be configured from action qualifier module.
 176         * Channel 0 configured with compare A register and for
 177         * up-counter mode.
 178         * Channel 1 configured with compare B register and for
 179         * up-counter mode.
 180         */
 181        if (chan == 1) {
 182                aqctl_reg = AQCTLB;
 183                cmp_reg = CMPB;
 184                /* Configure PWM Low from compare B value */
 185                aqctl_val = AQCTL_CBU_FRCLOW;
 186                aqctl_mask = AQCTL_CBU_MASK;
 187        } else {
 188                cmp_reg = CMPA;
 189                aqctl_reg = AQCTLA;
 190                /* Configure PWM Low from compare A value*/
 191                aqctl_val = AQCTL_CAU_FRCLOW;
 192                aqctl_mask = AQCTL_CAU_MASK;
 193        }
 194
 195        /* Configure PWM High from period value and zero value */
 196        aqctl_val |= AQCTL_PRD_FRCHIGH | AQCTL_ZRO_FRCHIGH;
 197        aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK;
 198        ehrpwm_modify(pc->mmio_base,  aqctl_reg, aqctl_mask, aqctl_val);
 199
 200        ehrpwm_write(pc->mmio_base,  cmp_reg, duty_cycles);
 201}
 202
 203/*
 204 * period_ns = 10^9 * (ps_divval * period_cycles) / PWM_CLK_RATE
 205 * duty_ns   = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE
 206 */
 207static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 208                int duty_ns, int period_ns)
 209{
 210        struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
 211        unsigned long long c;
 212        unsigned long period_cycles, duty_cycles;
 213        unsigned short ps_divval, tb_divval;
 214        int i;
 215
 216        if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
 217                return -ERANGE;
 218
 219        c = pc->clk_rate;
 220        c = c * period_ns;
 221        do_div(c, NSEC_PER_SEC);
 222        period_cycles = (unsigned long)c;
 223
 224        if (period_cycles < 1) {
 225                period_cycles = 1;
 226                duty_cycles = 1;
 227        } else {
 228                c = pc->clk_rate;
 229                c = c * duty_ns;
 230                do_div(c, NSEC_PER_SEC);
 231                duty_cycles = (unsigned long)c;
 232        }
 233
 234        /*
 235         * Period values should be same for multiple PWM channels as IP uses
 236         * same period register for multiple channels.
 237         */
 238        for (i = 0; i < NUM_PWM_CHANNEL; i++) {
 239                if (pc->period_cycles[i] &&
 240                                (pc->period_cycles[i] != period_cycles)) {
 241                        /*
 242                         * Allow channel to reconfigure period if no other
 243                         * channels being configured.
 244                         */
 245                        if (i == pwm->hwpwm)
 246                                continue;
 247
 248                        dev_err(chip->dev, "Period value conflicts with channel %d\n",
 249                                        i);
 250                        return -EINVAL;
 251                }
 252        }
 253
 254        pc->period_cycles[pwm->hwpwm] = period_cycles;
 255
 256        /* Configure clock prescaler to support Low frequency PWM wave */
 257        if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
 258                                &tb_divval)) {
 259                dev_err(chip->dev, "Unsupported values\n");
 260                return -EINVAL;
 261        }
 262
 263        pm_runtime_get_sync(chip->dev);
 264
 265        /* Update clock prescaler values */
 266        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval);
 267
 268        /* Update period & duty cycle with presacler division */
 269        period_cycles = period_cycles / ps_divval;
 270        duty_cycles = duty_cycles / ps_divval;
 271
 272        /* Configure shadow loading on Period register */
 273        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_PRDLD_MASK, TBCTL_PRDLD_SHDW);
 274
 275        ehrpwm_write(pc->mmio_base, TBPRD, period_cycles);
 276
 277        /* Configure ehrpwm counter for up-count mode */
 278        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK,
 279                        TBCTL_CTRMODE_UP);
 280
 281        /* Configure the channel for duty cycle */
 282        configure_chans(pc, pwm->hwpwm, duty_cycles);
 283        pm_runtime_put_sync(chip->dev);
 284        return 0;
 285}
 286
 287static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 288{
 289        struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
 290        unsigned short aqcsfrc_val, aqcsfrc_mask;
 291
 292        /* Leave clock enabled on enabling PWM */
 293        pm_runtime_get_sync(chip->dev);
 294
 295        /* Disabling Action Qualifier on PWM output */
 296        if (pwm->hwpwm) {
 297                aqcsfrc_val = AQCSFRC_CSFB_FRCDIS;
 298                aqcsfrc_mask = AQCSFRC_CSFB_MASK;
 299        } else {
 300                aqcsfrc_val = AQCSFRC_CSFA_FRCDIS;
 301                aqcsfrc_mask = AQCSFRC_CSFA_MASK;
 302        }
 303
 304        /* Changes to shadow mode */
 305        ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,
 306                        AQSFRC_RLDCSF_ZRO);
 307
 308        ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
 309
 310        /* Enable time counter for free_run */
 311        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
 312        return 0;
 313}
 314
 315static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 316{
 317        struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
 318        unsigned short aqcsfrc_val, aqcsfrc_mask;
 319
 320        /* Action Qualifier puts PWM output low forcefully */
 321        if (pwm->hwpwm) {
 322                aqcsfrc_val = AQCSFRC_CSFB_FRCLOW;
 323                aqcsfrc_mask = AQCSFRC_CSFB_MASK;
 324        } else {
 325                aqcsfrc_val = AQCSFRC_CSFA_FRCLOW;
 326                aqcsfrc_mask = AQCSFRC_CSFA_MASK;
 327        }
 328
 329        /*
 330         * Changes to immediate action on Action Qualifier. This puts
 331         * Action Qualifier control on PWM output from next TBCLK
 332         */
 333        ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,
 334                        AQSFRC_RLDCSF_IMDT);
 335
 336        ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
 337
 338        /* Stop Time base counter */
 339        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);
 340
 341        /* Disable clock on PWM disable */
 342        pm_runtime_put_sync(chip->dev);
 343}
 344
 345static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 346{
 347        struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
 348
 349        if (test_bit(PWMF_ENABLED, &pwm->flags)) {
 350                dev_warn(chip->dev, "Removing PWM device without disabling\n");
 351                pm_runtime_put_sync(chip->dev);
 352        }
 353
 354        /* set period value to zero on free */
 355        pc->period_cycles[pwm->hwpwm] = 0;
 356}
 357
 358static const struct pwm_ops ehrpwm_pwm_ops = {
 359        .free           = ehrpwm_pwm_free,
 360        .config         = ehrpwm_pwm_config,
 361        .enable         = ehrpwm_pwm_enable,
 362        .disable        = ehrpwm_pwm_disable,
 363        .owner          = THIS_MODULE,
 364};
 365
 366static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
 367{
 368        int ret;
 369        struct resource *r;
 370        struct clk *clk;
 371        struct ehrpwm_pwm_chip *pc;
 372
 373        pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
 374        if (!pc) {
 375                dev_err(&pdev->dev, "failed to allocate memory\n");
 376                return -ENOMEM;
 377        }
 378
 379        clk = devm_clk_get(&pdev->dev, "fck");
 380        if (IS_ERR(clk)) {
 381                dev_err(&pdev->dev, "failed to get clock\n");
 382                return PTR_ERR(clk);
 383        }
 384
 385        pc->clk_rate = clk_get_rate(clk);
 386        if (!pc->clk_rate) {
 387                dev_err(&pdev->dev, "failed to get clock rate\n");
 388                return -EINVAL;
 389        }
 390
 391        pc->chip.dev = &pdev->dev;
 392        pc->chip.ops = &ehrpwm_pwm_ops;
 393        pc->chip.base = -1;
 394        pc->chip.npwm = NUM_PWM_CHANNEL;
 395
 396        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 397        if (!r) {
 398                dev_err(&pdev->dev, "no memory resource defined\n");
 399                return -ENODEV;
 400        }
 401
 402        pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
 403        if (!pc->mmio_base)
 404                return  -EADDRNOTAVAIL;
 405
 406        ret = pwmchip_add(&pc->chip);
 407        if (ret < 0) {
 408                dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
 409                return ret;
 410        }
 411
 412        pm_runtime_enable(&pdev->dev);
 413        platform_set_drvdata(pdev, pc);
 414        return 0;
 415}
 416
 417static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev)
 418{
 419        struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
 420
 421        pm_runtime_put_sync(&pdev->dev);
 422        pm_runtime_disable(&pdev->dev);
 423        return pwmchip_remove(&pc->chip);
 424}
 425
 426static struct platform_driver ehrpwm_pwm_driver = {
 427        .driver = {
 428                .name = "ehrpwm",
 429        },
 430        .probe = ehrpwm_pwm_probe,
 431        .remove = __devexit_p(ehrpwm_pwm_remove),
 432};
 433
 434module_platform_driver(ehrpwm_pwm_driver);
 435
 436MODULE_DESCRIPTION("EHRPWM PWM driver");
 437MODULE_AUTHOR("Texas Instruments");
 438MODULE_LICENSE("GPL");
 439
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.