linux/drivers/pwm/pwm-sti.c
<<
>>
Prefs
   1/*
   2 * PWM device driver for ST SoCs.
   3 * Author: Ajit Pal Singh <ajitpal.singh@st.com>
   4 *
   5 * Copyright (C) 2013-2014 STMicroelectronics (R&D) Limited
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 */
  12
  13#include <linux/clk.h>
  14#include <linux/math64.h>
  15#include <linux/mfd/syscon.h>
  16#include <linux/module.h>
  17#include <linux/of.h>
  18#include <linux/platform_device.h>
  19#include <linux/pwm.h>
  20#include <linux/regmap.h>
  21#include <linux/slab.h>
  22#include <linux/time.h>
  23
  24#define STI_DS_REG(ch)  (4 * (ch))      /* Channel's Duty Cycle register */
  25#define STI_PWMCR       0x50            /* Control/Config register */
  26#define STI_INTEN       0x54            /* Interrupt Enable/Disable register */
  27#define PWM_PRESCALE_LOW_MASK           0x0f
  28#define PWM_PRESCALE_HIGH_MASK          0xf0
  29
  30/* Regfield IDs */
  31enum {
  32        PWMCLK_PRESCALE_LOW,
  33        PWMCLK_PRESCALE_HIGH,
  34        PWM_EN,
  35        PWM_INT_EN,
  36
  37        /* Keep last */
  38        MAX_REGFIELDS
  39};
  40
  41struct sti_pwm_compat_data {
  42        const struct reg_field *reg_fields;
  43        unsigned int num_chan;
  44        unsigned int max_pwm_cnt;
  45        unsigned int max_prescale;
  46};
  47
  48struct sti_pwm_chip {
  49        struct device *dev;
  50        struct clk *clk;
  51        unsigned long clk_rate;
  52        struct regmap *regmap;
  53        struct sti_pwm_compat_data *cdata;
  54        struct regmap_field *prescale_low;
  55        struct regmap_field *prescale_high;
  56        struct regmap_field *pwm_en;
  57        struct regmap_field *pwm_int_en;
  58        struct pwm_chip chip;
  59        struct pwm_device *cur;
  60        unsigned long configured;
  61        unsigned int en_count;
  62        struct mutex sti_pwm_lock; /* To sync between enable/disable calls */
  63        void __iomem *mmio;
  64};
  65
  66static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = {
  67        [PWMCLK_PRESCALE_LOW]   = REG_FIELD(STI_PWMCR, 0, 3),
  68        [PWMCLK_PRESCALE_HIGH]  = REG_FIELD(STI_PWMCR, 11, 14),
  69        [PWM_EN]                = REG_FIELD(STI_PWMCR, 9, 9),
  70        [PWM_INT_EN]            = REG_FIELD(STI_INTEN, 0, 0),
  71};
  72
  73static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip)
  74{
  75        return container_of(chip, struct sti_pwm_chip, chip);
  76}
  77
  78/*
  79 * Calculate the prescaler value corresponding to the period.
  80 */
  81static int sti_pwm_get_prescale(struct sti_pwm_chip *pc, unsigned long period,
  82                                unsigned int *prescale)
  83{
  84        struct sti_pwm_compat_data *cdata = pc->cdata;
  85        unsigned long val;
  86        unsigned int ps;
  87
  88        /*
  89         * prescale = ((period_ns * clk_rate) / (10^9 * (max_pwm_count + 1)) - 1
  90         */
  91        val = NSEC_PER_SEC / pc->clk_rate;
  92        val *= cdata->max_pwm_cnt + 1;
  93
  94        if (period % val) {
  95                return -EINVAL;
  96        } else {
  97                ps  = period / val - 1;
  98                if (ps > cdata->max_prescale)
  99                        return -EINVAL;
 100        }
 101        *prescale = ps;
 102
 103        return 0;
 104}
 105
 106/*
 107 * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles.
 108 * The only way to change the period (apart from changing the PWM input clock)
 109 * is to change the PWM clock prescaler.
 110 * The prescaler is of 8 bits, so 256 prescaler values and hence
 111 * 256 possible period values are supported (for a particular clock rate).
 112 * The requested period will be applied only if it matches one of these
 113 * 256 values.
 114 */
 115static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 116                         int duty_ns, int period_ns)
 117{
 118        struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
 119        struct sti_pwm_compat_data *cdata = pc->cdata;
 120        struct pwm_device *cur = pc->cur;
 121        struct device *dev = pc->dev;
 122        unsigned int prescale = 0, pwmvalx;
 123        int ret;
 124        unsigned int ncfg;
 125        bool period_same = false;
 126
 127        ncfg = hweight_long(pc->configured);
 128        if (ncfg)
 129                period_same = (period_ns == pwm_get_period(cur));
 130
 131        /* Allow configuration changes if one of the
 132         * following conditions satisfy.
 133         * 1. No channels have been configured.
 134         * 2. Only one channel has been configured and the new request
 135         *    is for the same channel.
 136         * 3. Only one channel has been configured and the new request is
 137         *    for a new channel and period of the new channel is same as
 138         *    the current configured period.
 139         * 4. More than one channels are configured and period of the new
 140         *    requestis the same as the current period.
 141         */
 142        if (!ncfg ||
 143            ((ncfg == 1) && (pwm->hwpwm == cur->hwpwm)) ||
 144            ((ncfg == 1) && (pwm->hwpwm != cur->hwpwm) && period_same) ||
 145            ((ncfg > 1) && period_same)) {
 146                /* Enable clock before writing to PWM registers. */
 147                ret = clk_enable(pc->clk);
 148                if (ret)
 149                        return ret;
 150
 151                if (!period_same) {
 152                        ret = sti_pwm_get_prescale(pc, period_ns, &prescale);
 153                        if (ret)
 154                                goto clk_dis;
 155
 156                        ret =
 157                        regmap_field_write(pc->prescale_low,
 158                                           prescale & PWM_PRESCALE_LOW_MASK);
 159                        if (ret)
 160                                goto clk_dis;
 161
 162                        ret =
 163                        regmap_field_write(pc->prescale_high,
 164                                (prescale & PWM_PRESCALE_HIGH_MASK) >> 4);
 165                        if (ret)
 166                                goto clk_dis;
 167                }
 168
 169                /*
 170                 * When PWMVal == 0, PWM pulse = 1 local clock cycle.
 171                 * When PWMVal == max_pwm_count,
 172                 * PWM pulse = (max_pwm_count + 1) local cycles,
 173                 * that is continuous pulse: signal never goes low.
 174                 */
 175                pwmvalx = cdata->max_pwm_cnt * duty_ns / period_ns;
 176
 177                ret = regmap_write(pc->regmap, STI_DS_REG(pwm->hwpwm), pwmvalx);
 178                if (ret)
 179                        goto clk_dis;
 180
 181                ret = regmap_field_write(pc->pwm_int_en, 0);
 182
 183                set_bit(pwm->hwpwm, &pc->configured);
 184                pc->cur = pwm;
 185
 186                dev_dbg(dev, "prescale:%u, period:%i, duty:%i, pwmvalx:%u\n",
 187                        prescale, period_ns, duty_ns, pwmvalx);
 188        } else {
 189                return -EINVAL;
 190        }
 191
 192clk_dis:
 193        clk_disable(pc->clk);
 194        return ret;
 195}
 196
 197static int sti_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 198{
 199        struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
 200        struct device *dev = pc->dev;
 201        int ret = 0;
 202
 203        /*
 204         * Since we have a common enable for all PWM channels,
 205         * do not enable if already enabled.
 206         */
 207        mutex_lock(&pc->sti_pwm_lock);
 208        if (!pc->en_count) {
 209                ret = clk_enable(pc->clk);
 210                if (ret)
 211                        goto out;
 212
 213                ret = regmap_field_write(pc->pwm_en, 1);
 214                if (ret) {
 215                        dev_err(dev, "failed to enable PWM device:%d\n",
 216                                pwm->hwpwm);
 217                        goto out;
 218                }
 219        }
 220        pc->en_count++;
 221out:
 222        mutex_unlock(&pc->sti_pwm_lock);
 223        return ret;
 224}
 225
 226static void sti_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 227{
 228        struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
 229
 230        mutex_lock(&pc->sti_pwm_lock);
 231        if (--pc->en_count) {
 232                mutex_unlock(&pc->sti_pwm_lock);
 233                return;
 234        }
 235        regmap_field_write(pc->pwm_en, 0);
 236
 237        clk_disable(pc->clk);
 238        mutex_unlock(&pc->sti_pwm_lock);
 239}
 240
 241static void sti_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 242{
 243        struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
 244
 245        clear_bit(pwm->hwpwm, &pc->configured);
 246}
 247
 248static const struct pwm_ops sti_pwm_ops = {
 249        .config = sti_pwm_config,
 250        .enable = sti_pwm_enable,
 251        .disable = sti_pwm_disable,
 252        .free = sti_pwm_free,
 253        .owner = THIS_MODULE,
 254};
 255
 256static int sti_pwm_probe_dt(struct sti_pwm_chip *pc)
 257{
 258        struct device *dev = pc->dev;
 259        const struct reg_field *reg_fields;
 260        struct device_node *np = dev->of_node;
 261        struct sti_pwm_compat_data *cdata = pc->cdata;
 262        u32 num_chan;
 263
 264        of_property_read_u32(np, "st,pwm-num-chan", &num_chan);
 265        if (num_chan)
 266                cdata->num_chan = num_chan;
 267
 268        reg_fields = cdata->reg_fields;
 269
 270        pc->prescale_low = devm_regmap_field_alloc(dev, pc->regmap,
 271                                        reg_fields[PWMCLK_PRESCALE_LOW]);
 272        if (IS_ERR(pc->prescale_low))
 273                return PTR_ERR(pc->prescale_low);
 274
 275        pc->prescale_high = devm_regmap_field_alloc(dev, pc->regmap,
 276                                        reg_fields[PWMCLK_PRESCALE_HIGH]);
 277        if (IS_ERR(pc->prescale_high))
 278                return PTR_ERR(pc->prescale_high);
 279
 280        pc->pwm_en = devm_regmap_field_alloc(dev, pc->regmap,
 281                                             reg_fields[PWM_EN]);
 282        if (IS_ERR(pc->pwm_en))
 283                return PTR_ERR(pc->pwm_en);
 284
 285        pc->pwm_int_en = devm_regmap_field_alloc(dev, pc->regmap,
 286                                                 reg_fields[PWM_INT_EN]);
 287        if (IS_ERR(pc->pwm_int_en))
 288                return PTR_ERR(pc->pwm_int_en);
 289
 290        return 0;
 291}
 292
 293static const struct regmap_config sti_pwm_regmap_config = {
 294        .reg_bits = 32,
 295        .val_bits = 32,
 296        .reg_stride = 4,
 297};
 298
 299static int sti_pwm_probe(struct platform_device *pdev)
 300{
 301        struct device *dev = &pdev->dev;
 302        struct sti_pwm_compat_data *cdata;
 303        struct sti_pwm_chip *pc;
 304        struct resource *res;
 305        int ret;
 306
 307        pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
 308        if (!pc)
 309                return -ENOMEM;
 310
 311        cdata = devm_kzalloc(dev, sizeof(*cdata), GFP_KERNEL);
 312        if (!cdata)
 313                return -ENOMEM;
 314
 315        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 316
 317        pc->mmio = devm_ioremap_resource(dev, res);
 318        if (IS_ERR(pc->mmio))
 319                return PTR_ERR(pc->mmio);
 320
 321        pc->regmap = devm_regmap_init_mmio(dev, pc->mmio,
 322                                           &sti_pwm_regmap_config);
 323        if (IS_ERR(pc->regmap))
 324                return PTR_ERR(pc->regmap);
 325
 326        /*
 327         * Setup PWM data with default values: some values could be replaced
 328         * with specific ones provided from Device Tree.
 329         */
 330        cdata->reg_fields   = &sti_pwm_regfields[0];
 331        cdata->max_prescale = 0xff;
 332        cdata->max_pwm_cnt  = 255;
 333        cdata->num_chan     = 1;
 334
 335        pc->cdata = cdata;
 336        pc->dev = dev;
 337        pc->en_count = 0;
 338        mutex_init(&pc->sti_pwm_lock);
 339
 340        ret = sti_pwm_probe_dt(pc);
 341        if (ret)
 342                return ret;
 343
 344        pc->clk = of_clk_get_by_name(dev->of_node, "pwm");
 345        if (IS_ERR(pc->clk)) {
 346                dev_err(dev, "failed to get PWM clock\n");
 347                return PTR_ERR(pc->clk);
 348        }
 349
 350        pc->clk_rate = clk_get_rate(pc->clk);
 351        if (!pc->clk_rate) {
 352                dev_err(dev, "failed to get clock rate\n");
 353                return -EINVAL;
 354        }
 355
 356        ret = clk_prepare(pc->clk);
 357        if (ret) {
 358                dev_err(dev, "failed to prepare clock\n");
 359                return ret;
 360        }
 361
 362        pc->chip.dev = dev;
 363        pc->chip.ops = &sti_pwm_ops;
 364        pc->chip.base = -1;
 365        pc->chip.npwm = pc->cdata->num_chan;
 366        pc->chip.can_sleep = true;
 367
 368        ret = pwmchip_add(&pc->chip);
 369        if (ret < 0) {
 370                clk_unprepare(pc->clk);
 371                return ret;
 372        }
 373
 374        platform_set_drvdata(pdev, pc);
 375
 376        return 0;
 377}
 378
 379static int sti_pwm_remove(struct platform_device *pdev)
 380{
 381        struct sti_pwm_chip *pc = platform_get_drvdata(pdev);
 382        unsigned int i;
 383
 384        for (i = 0; i < pc->cdata->num_chan; i++)
 385                pwm_disable(&pc->chip.pwms[i]);
 386
 387        clk_unprepare(pc->clk);
 388
 389        return pwmchip_remove(&pc->chip);
 390}
 391
 392static const struct of_device_id sti_pwm_of_match[] = {
 393        { .compatible = "st,sti-pwm", },
 394        { /* sentinel */ }
 395};
 396MODULE_DEVICE_TABLE(of, sti_pwm_of_match);
 397
 398static struct platform_driver sti_pwm_driver = {
 399        .driver = {
 400                .name = "sti-pwm",
 401                .of_match_table = sti_pwm_of_match,
 402        },
 403        .probe = sti_pwm_probe,
 404        .remove = sti_pwm_remove,
 405};
 406module_platform_driver(sti_pwm_driver);
 407
 408MODULE_AUTHOR("Ajit Pal Singh <ajitpal.singh@st.com>");
 409MODULE_DESCRIPTION("STMicroelectronics ST PWM driver");
 410MODULE_LICENSE("GPL");
 411