root/drivers/pwm/pwm-rockchip.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_rockchip_pwm_chip
  2. rockchip_pwm_get_state
  3. rockchip_pwm_config
  4. rockchip_pwm_enable
  5. rockchip_pwm_apply
  6. rockchip_pwm_probe
  7. rockchip_pwm_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * PWM driver for Rockchip SoCs
   4  *
   5  * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
   6  * Copyright (C) 2014 ROCKCHIP, Inc.
   7  */
   8 
   9 #include <linux/clk.h>
  10 #include <linux/io.h>
  11 #include <linux/module.h>
  12 #include <linux/of.h>
  13 #include <linux/of_device.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/pwm.h>
  16 #include <linux/time.h>
  17 
  18 #define PWM_CTRL_TIMER_EN       (1 << 0)
  19 #define PWM_CTRL_OUTPUT_EN      (1 << 3)
  20 
  21 #define PWM_ENABLE              (1 << 0)
  22 #define PWM_CONTINUOUS          (1 << 1)
  23 #define PWM_DUTY_POSITIVE       (1 << 3)
  24 #define PWM_DUTY_NEGATIVE       (0 << 3)
  25 #define PWM_INACTIVE_NEGATIVE   (0 << 4)
  26 #define PWM_INACTIVE_POSITIVE   (1 << 4)
  27 #define PWM_POLARITY_MASK       (PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE)
  28 #define PWM_OUTPUT_LEFT         (0 << 5)
  29 #define PWM_LOCK_EN             (1 << 6)
  30 #define PWM_LP_DISABLE          (0 << 8)
  31 
  32 struct rockchip_pwm_chip {
  33         struct pwm_chip chip;
  34         struct clk *clk;
  35         struct clk *pclk;
  36         const struct rockchip_pwm_data *data;
  37         void __iomem *base;
  38 };
  39 
  40 struct rockchip_pwm_regs {
  41         unsigned long duty;
  42         unsigned long period;
  43         unsigned long cntr;
  44         unsigned long ctrl;
  45 };
  46 
  47 struct rockchip_pwm_data {
  48         struct rockchip_pwm_regs regs;
  49         unsigned int prescaler;
  50         bool supports_polarity;
  51         bool supports_lock;
  52         u32 enable_conf;
  53 };
  54 
  55 static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
  56 {
  57         return container_of(c, struct rockchip_pwm_chip, chip);
  58 }
  59 
  60 static void rockchip_pwm_get_state(struct pwm_chip *chip,
  61                                    struct pwm_device *pwm,
  62                                    struct pwm_state *state)
  63 {
  64         struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
  65         u32 enable_conf = pc->data->enable_conf;
  66         unsigned long clk_rate;
  67         u64 tmp;
  68         u32 val;
  69         int ret;
  70 
  71         ret = clk_enable(pc->pclk);
  72         if (ret)
  73                 return;
  74 
  75         clk_rate = clk_get_rate(pc->clk);
  76 
  77         tmp = readl_relaxed(pc->base + pc->data->regs.period);
  78         tmp *= pc->data->prescaler * NSEC_PER_SEC;
  79         state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
  80 
  81         tmp = readl_relaxed(pc->base + pc->data->regs.duty);
  82         tmp *= pc->data->prescaler * NSEC_PER_SEC;
  83         state->duty_cycle =  DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
  84 
  85         val = readl_relaxed(pc->base + pc->data->regs.ctrl);
  86         if (pc->data->supports_polarity)
  87                 state->enabled = ((val & enable_conf) != enable_conf) ?
  88                                  false : true;
  89         else
  90                 state->enabled = ((val & enable_conf) == enable_conf) ?
  91                                  true : false;
  92 
  93         if (pc->data->supports_polarity && !(val & PWM_DUTY_POSITIVE))
  94                 state->polarity = PWM_POLARITY_INVERSED;
  95         else
  96                 state->polarity = PWM_POLARITY_NORMAL;
  97 
  98         clk_disable(pc->pclk);
  99 }
 100 
 101 static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 102                                const struct pwm_state *state)
 103 {
 104         struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
 105         unsigned long period, duty;
 106         u64 clk_rate, div;
 107         u32 ctrl;
 108 
 109         clk_rate = clk_get_rate(pc->clk);
 110 
 111         /*
 112          * Since period and duty cycle registers have a width of 32
 113          * bits, every possible input period can be obtained using the
 114          * default prescaler value for all practical clock rate values.
 115          */
 116         div = clk_rate * state->period;
 117         period = DIV_ROUND_CLOSEST_ULL(div,
 118                                        pc->data->prescaler * NSEC_PER_SEC);
 119 
 120         div = clk_rate * state->duty_cycle;
 121         duty = DIV_ROUND_CLOSEST_ULL(div, pc->data->prescaler * NSEC_PER_SEC);
 122 
 123         /*
 124          * Lock the period and duty of previous configuration, then
 125          * change the duty and period, that would not be effective.
 126          */
 127         ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
 128         if (pc->data->supports_lock) {
 129                 ctrl |= PWM_LOCK_EN;
 130                 writel_relaxed(ctrl, pc->base + pc->data->regs.ctrl);
 131         }
 132 
 133         writel(period, pc->base + pc->data->regs.period);
 134         writel(duty, pc->base + pc->data->regs.duty);
 135 
 136         if (pc->data->supports_polarity) {
 137                 ctrl &= ~PWM_POLARITY_MASK;
 138                 if (state->polarity == PWM_POLARITY_INVERSED)
 139                         ctrl |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
 140                 else
 141                         ctrl |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
 142         }
 143 
 144         /*
 145          * Unlock and set polarity at the same time,
 146          * the configuration of duty, period and polarity
 147          * would be effective together at next period.
 148          */
 149         if (pc->data->supports_lock)
 150                 ctrl &= ~PWM_LOCK_EN;
 151 
 152         writel(ctrl, pc->base + pc->data->regs.ctrl);
 153 }
 154 
 155 static int rockchip_pwm_enable(struct pwm_chip *chip,
 156                                struct pwm_device *pwm,
 157                                bool enable)
 158 {
 159         struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
 160         u32 enable_conf = pc->data->enable_conf;
 161         int ret;
 162         u32 val;
 163 
 164         if (enable) {
 165                 ret = clk_enable(pc->clk);
 166                 if (ret)
 167                         return ret;
 168         }
 169 
 170         val = readl_relaxed(pc->base + pc->data->regs.ctrl);
 171 
 172         if (enable)
 173                 val |= enable_conf;
 174         else
 175                 val &= ~enable_conf;
 176 
 177         writel_relaxed(val, pc->base + pc->data->regs.ctrl);
 178 
 179         if (!enable)
 180                 clk_disable(pc->clk);
 181 
 182         return 0;
 183 }
 184 
 185 static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 186                               const struct pwm_state *state)
 187 {
 188         struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
 189         struct pwm_state curstate;
 190         bool enabled;
 191         int ret = 0;
 192 
 193         ret = clk_enable(pc->pclk);
 194         if (ret)
 195                 return ret;
 196 
 197         pwm_get_state(pwm, &curstate);
 198         enabled = curstate.enabled;
 199 
 200         if (state->polarity != curstate.polarity && enabled &&
 201             !pc->data->supports_lock) {
 202                 ret = rockchip_pwm_enable(chip, pwm, false);
 203                 if (ret)
 204                         goto out;
 205                 enabled = false;
 206         }
 207 
 208         rockchip_pwm_config(chip, pwm, state);
 209         if (state->enabled != enabled) {
 210                 ret = rockchip_pwm_enable(chip, pwm, state->enabled);
 211                 if (ret)
 212                         goto out;
 213         }
 214 
 215 out:
 216         clk_disable(pc->pclk);
 217 
 218         return ret;
 219 }
 220 
 221 static const struct pwm_ops rockchip_pwm_ops = {
 222         .get_state = rockchip_pwm_get_state,
 223         .apply = rockchip_pwm_apply,
 224         .owner = THIS_MODULE,
 225 };
 226 
 227 static const struct rockchip_pwm_data pwm_data_v1 = {
 228         .regs = {
 229                 .duty = 0x04,
 230                 .period = 0x08,
 231                 .cntr = 0x00,
 232                 .ctrl = 0x0c,
 233         },
 234         .prescaler = 2,
 235         .supports_polarity = false,
 236         .supports_lock = false,
 237         .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
 238 };
 239 
 240 static const struct rockchip_pwm_data pwm_data_v2 = {
 241         .regs = {
 242                 .duty = 0x08,
 243                 .period = 0x04,
 244                 .cntr = 0x00,
 245                 .ctrl = 0x0c,
 246         },
 247         .prescaler = 1,
 248         .supports_polarity = true,
 249         .supports_lock = false,
 250         .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
 251                        PWM_CONTINUOUS,
 252 };
 253 
 254 static const struct rockchip_pwm_data pwm_data_vop = {
 255         .regs = {
 256                 .duty = 0x08,
 257                 .period = 0x04,
 258                 .cntr = 0x0c,
 259                 .ctrl = 0x00,
 260         },
 261         .prescaler = 1,
 262         .supports_polarity = true,
 263         .supports_lock = false,
 264         .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
 265                        PWM_CONTINUOUS,
 266 };
 267 
 268 static const struct rockchip_pwm_data pwm_data_v3 = {
 269         .regs = {
 270                 .duty = 0x08,
 271                 .period = 0x04,
 272                 .cntr = 0x00,
 273                 .ctrl = 0x0c,
 274         },
 275         .prescaler = 1,
 276         .supports_polarity = true,
 277         .supports_lock = true,
 278         .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
 279                        PWM_CONTINUOUS,
 280 };
 281 
 282 static const struct of_device_id rockchip_pwm_dt_ids[] = {
 283         { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
 284         { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
 285         { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
 286         { .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3},
 287         { /* sentinel */ }
 288 };
 289 MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
 290 
 291 static int rockchip_pwm_probe(struct platform_device *pdev)
 292 {
 293         const struct of_device_id *id;
 294         struct rockchip_pwm_chip *pc;
 295         struct resource *r;
 296         int ret, count;
 297 
 298         id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev);
 299         if (!id)
 300                 return -EINVAL;
 301 
 302         pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
 303         if (!pc)
 304                 return -ENOMEM;
 305 
 306         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 307         pc->base = devm_ioremap_resource(&pdev->dev, r);
 308         if (IS_ERR(pc->base))
 309                 return PTR_ERR(pc->base);
 310 
 311         pc->clk = devm_clk_get(&pdev->dev, "pwm");
 312         if (IS_ERR(pc->clk)) {
 313                 pc->clk = devm_clk_get(&pdev->dev, NULL);
 314                 if (IS_ERR(pc->clk)) {
 315                         ret = PTR_ERR(pc->clk);
 316                         if (ret != -EPROBE_DEFER)
 317                                 dev_err(&pdev->dev, "Can't get bus clk: %d\n",
 318                                         ret);
 319                         return ret;
 320                 }
 321         }
 322 
 323         count = of_count_phandle_with_args(pdev->dev.of_node,
 324                                            "clocks", "#clock-cells");
 325         if (count == 2)
 326                 pc->pclk = devm_clk_get(&pdev->dev, "pclk");
 327         else
 328                 pc->pclk = pc->clk;
 329 
 330         if (IS_ERR(pc->pclk)) {
 331                 ret = PTR_ERR(pc->pclk);
 332                 if (ret != -EPROBE_DEFER)
 333                         dev_err(&pdev->dev, "Can't get APB clk: %d\n", ret);
 334                 return ret;
 335         }
 336 
 337         ret = clk_prepare_enable(pc->clk);
 338         if (ret) {
 339                 dev_err(&pdev->dev, "Can't prepare enable bus clk: %d\n", ret);
 340                 return ret;
 341         }
 342 
 343         ret = clk_prepare(pc->pclk);
 344         if (ret) {
 345                 dev_err(&pdev->dev, "Can't prepare APB clk: %d\n", ret);
 346                 goto err_clk;
 347         }
 348 
 349         platform_set_drvdata(pdev, pc);
 350 
 351         pc->data = id->data;
 352         pc->chip.dev = &pdev->dev;
 353         pc->chip.ops = &rockchip_pwm_ops;
 354         pc->chip.base = -1;
 355         pc->chip.npwm = 1;
 356 
 357         if (pc->data->supports_polarity) {
 358                 pc->chip.of_xlate = of_pwm_xlate_with_flags;
 359                 pc->chip.of_pwm_n_cells = 3;
 360         }
 361 
 362         ret = pwmchip_add(&pc->chip);
 363         if (ret < 0) {
 364                 clk_unprepare(pc->clk);
 365                 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
 366                 goto err_pclk;
 367         }
 368 
 369         /* Keep the PWM clk enabled if the PWM appears to be up and running. */
 370         if (!pwm_is_enabled(pc->chip.pwms))
 371                 clk_disable(pc->clk);
 372 
 373         return 0;
 374 
 375 err_pclk:
 376         clk_unprepare(pc->pclk);
 377 err_clk:
 378         clk_disable_unprepare(pc->clk);
 379 
 380         return ret;
 381 }
 382 
 383 static int rockchip_pwm_remove(struct platform_device *pdev)
 384 {
 385         struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);
 386 
 387         /*
 388          * Disable the PWM clk before unpreparing it if the PWM device is still
 389          * running. This should only happen when the last PWM user left it
 390          * enabled, or when nobody requested a PWM that was previously enabled
 391          * by the bootloader.
 392          *
 393          * FIXME: Maybe the core should disable all PWM devices in
 394          * pwmchip_remove(). In this case we'd only have to call
 395          * clk_unprepare() after pwmchip_remove().
 396          *
 397          */
 398         if (pwm_is_enabled(pc->chip.pwms))
 399                 clk_disable(pc->clk);
 400 
 401         clk_unprepare(pc->pclk);
 402         clk_unprepare(pc->clk);
 403 
 404         return pwmchip_remove(&pc->chip);
 405 }
 406 
 407 static struct platform_driver rockchip_pwm_driver = {
 408         .driver = {
 409                 .name = "rockchip-pwm",
 410                 .of_match_table = rockchip_pwm_dt_ids,
 411         },
 412         .probe = rockchip_pwm_probe,
 413         .remove = rockchip_pwm_remove,
 414 };
 415 module_platform_driver(rockchip_pwm_driver);
 416 
 417 MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
 418 MODULE_DESCRIPTION("Rockchip SoC PWM driver");
 419 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */