root/drivers/pwm/pwm-tiecap.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_ecap_pwm_chip
  2. ecap_pwm_config
  3. ecap_pwm_set_polarity
  4. ecap_pwm_enable
  5. ecap_pwm_disable
  6. ecap_pwm_free
  7. ecap_pwm_probe
  8. ecap_pwm_remove
  9. ecap_pwm_save_context
  10. ecap_pwm_restore_context
  11. ecap_pwm_suspend
  12. ecap_pwm_resume

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * ECAP PWM driver
   4  *
   5  * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.com/
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/platform_device.h>
  10 #include <linux/io.h>
  11 #include <linux/err.h>
  12 #include <linux/clk.h>
  13 #include <linux/pm_runtime.h>
  14 #include <linux/pwm.h>
  15 #include <linux/of_device.h>
  16 
  17 /* ECAP registers and bits definitions */
  18 #define CAP1                    0x08
  19 #define CAP2                    0x0C
  20 #define CAP3                    0x10
  21 #define CAP4                    0x14
  22 #define ECCTL2                  0x2A
  23 #define ECCTL2_APWM_POL_LOW     BIT(10)
  24 #define ECCTL2_APWM_MODE        BIT(9)
  25 #define ECCTL2_SYNC_SEL_DISA    (BIT(7) | BIT(6))
  26 #define ECCTL2_TSCTR_FREERUN    BIT(4)
  27 
  28 struct ecap_context {
  29         u32 cap3;
  30         u32 cap4;
  31         u16 ecctl2;
  32 };
  33 
  34 struct ecap_pwm_chip {
  35         struct pwm_chip chip;
  36         unsigned int clk_rate;
  37         void __iomem *mmio_base;
  38         struct ecap_context ctx;
  39 };
  40 
  41 static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip)
  42 {
  43         return container_of(chip, struct ecap_pwm_chip, chip);
  44 }
  45 
  46 /*
  47  * period_ns = 10^9 * period_cycles / PWM_CLK_RATE
  48  * duty_ns   = 10^9 * duty_cycles / PWM_CLK_RATE
  49  */
  50 static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
  51                 int duty_ns, int period_ns)
  52 {
  53         struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
  54         u32 period_cycles, duty_cycles;
  55         unsigned long long c;
  56         u16 value;
  57 
  58         if (period_ns > NSEC_PER_SEC)
  59                 return -ERANGE;
  60 
  61         c = pc->clk_rate;
  62         c = c * period_ns;
  63         do_div(c, NSEC_PER_SEC);
  64         period_cycles = (u32)c;
  65 
  66         if (period_cycles < 1) {
  67                 period_cycles = 1;
  68                 duty_cycles = 1;
  69         } else {
  70                 c = pc->clk_rate;
  71                 c = c * duty_ns;
  72                 do_div(c, NSEC_PER_SEC);
  73                 duty_cycles = (u32)c;
  74         }
  75 
  76         pm_runtime_get_sync(pc->chip.dev);
  77 
  78         value = readw(pc->mmio_base + ECCTL2);
  79 
  80         /* Configure APWM mode & disable sync option */
  81         value |= ECCTL2_APWM_MODE | ECCTL2_SYNC_SEL_DISA;
  82 
  83         writew(value, pc->mmio_base + ECCTL2);
  84 
  85         if (!pwm_is_enabled(pwm)) {
  86                 /* Update active registers if not running */
  87                 writel(duty_cycles, pc->mmio_base + CAP2);
  88                 writel(period_cycles, pc->mmio_base + CAP1);
  89         } else {
  90                 /*
  91                  * Update shadow registers to configure period and
  92                  * compare values. This helps current PWM period to
  93                  * complete on reconfiguring
  94                  */
  95                 writel(duty_cycles, pc->mmio_base + CAP4);
  96                 writel(period_cycles, pc->mmio_base + CAP3);
  97         }
  98 
  99         if (!pwm_is_enabled(pwm)) {
 100                 value = readw(pc->mmio_base + ECCTL2);
 101                 /* Disable APWM mode to put APWM output Low */
 102                 value &= ~ECCTL2_APWM_MODE;
 103                 writew(value, pc->mmio_base + ECCTL2);
 104         }
 105 
 106         pm_runtime_put_sync(pc->chip.dev);
 107 
 108         return 0;
 109 }
 110 
 111 static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 112                                  enum pwm_polarity polarity)
 113 {
 114         struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
 115         u16 value;
 116 
 117         pm_runtime_get_sync(pc->chip.dev);
 118 
 119         value = readw(pc->mmio_base + ECCTL2);
 120 
 121         if (polarity == PWM_POLARITY_INVERSED)
 122                 /* Duty cycle defines LOW period of PWM */
 123                 value |= ECCTL2_APWM_POL_LOW;
 124         else
 125                 /* Duty cycle defines HIGH period of PWM */
 126                 value &= ~ECCTL2_APWM_POL_LOW;
 127 
 128         writew(value, pc->mmio_base + ECCTL2);
 129 
 130         pm_runtime_put_sync(pc->chip.dev);
 131 
 132         return 0;
 133 }
 134 
 135 static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 136 {
 137         struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
 138         u16 value;
 139 
 140         /* Leave clock enabled on enabling PWM */
 141         pm_runtime_get_sync(pc->chip.dev);
 142 
 143         /*
 144          * Enable 'Free run Time stamp counter mode' to start counter
 145          * and  'APWM mode' to enable APWM output
 146          */
 147         value = readw(pc->mmio_base + ECCTL2);
 148         value |= ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE;
 149         writew(value, pc->mmio_base + ECCTL2);
 150 
 151         return 0;
 152 }
 153 
 154 static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 155 {
 156         struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
 157         u16 value;
 158 
 159         /*
 160          * Disable 'Free run Time stamp counter mode' to stop counter
 161          * and 'APWM mode' to put APWM output to low
 162          */
 163         value = readw(pc->mmio_base + ECCTL2);
 164         value &= ~(ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE);
 165         writew(value, pc->mmio_base + ECCTL2);
 166 
 167         /* Disable clock on PWM disable */
 168         pm_runtime_put_sync(pc->chip.dev);
 169 }
 170 
 171 static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 172 {
 173         if (pwm_is_enabled(pwm)) {
 174                 dev_warn(chip->dev, "Removing PWM device without disabling\n");
 175                 pm_runtime_put_sync(chip->dev);
 176         }
 177 }
 178 
 179 static const struct pwm_ops ecap_pwm_ops = {
 180         .free = ecap_pwm_free,
 181         .config = ecap_pwm_config,
 182         .set_polarity = ecap_pwm_set_polarity,
 183         .enable = ecap_pwm_enable,
 184         .disable = ecap_pwm_disable,
 185         .owner = THIS_MODULE,
 186 };
 187 
 188 static const struct of_device_id ecap_of_match[] = {
 189         { .compatible   = "ti,am3352-ecap" },
 190         { .compatible   = "ti,am33xx-ecap" },
 191         {},
 192 };
 193 MODULE_DEVICE_TABLE(of, ecap_of_match);
 194 
 195 static int ecap_pwm_probe(struct platform_device *pdev)
 196 {
 197         struct device_node *np = pdev->dev.of_node;
 198         struct ecap_pwm_chip *pc;
 199         struct resource *r;
 200         struct clk *clk;
 201         int ret;
 202 
 203         pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
 204         if (!pc)
 205                 return -ENOMEM;
 206 
 207         clk = devm_clk_get(&pdev->dev, "fck");
 208         if (IS_ERR(clk)) {
 209                 if (of_device_is_compatible(np, "ti,am33xx-ecap")) {
 210                         dev_warn(&pdev->dev, "Binding is obsolete.\n");
 211                         clk = devm_clk_get(pdev->dev.parent, "fck");
 212                 }
 213         }
 214 
 215         if (IS_ERR(clk)) {
 216                 dev_err(&pdev->dev, "failed to get clock\n");
 217                 return PTR_ERR(clk);
 218         }
 219 
 220         pc->clk_rate = clk_get_rate(clk);
 221         if (!pc->clk_rate) {
 222                 dev_err(&pdev->dev, "failed to get clock rate\n");
 223                 return -EINVAL;
 224         }
 225 
 226         pc->chip.dev = &pdev->dev;
 227         pc->chip.ops = &ecap_pwm_ops;
 228         pc->chip.of_xlate = of_pwm_xlate_with_flags;
 229         pc->chip.of_pwm_n_cells = 3;
 230         pc->chip.base = -1;
 231         pc->chip.npwm = 1;
 232 
 233         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 234         pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
 235         if (IS_ERR(pc->mmio_base))
 236                 return PTR_ERR(pc->mmio_base);
 237 
 238         ret = pwmchip_add(&pc->chip);
 239         if (ret < 0) {
 240                 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
 241                 return ret;
 242         }
 243 
 244         platform_set_drvdata(pdev, pc);
 245         pm_runtime_enable(&pdev->dev);
 246 
 247         return 0;
 248 }
 249 
 250 static int ecap_pwm_remove(struct platform_device *pdev)
 251 {
 252         struct ecap_pwm_chip *pc = platform_get_drvdata(pdev);
 253 
 254         pm_runtime_disable(&pdev->dev);
 255 
 256         return pwmchip_remove(&pc->chip);
 257 }
 258 
 259 #ifdef CONFIG_PM_SLEEP
 260 static void ecap_pwm_save_context(struct ecap_pwm_chip *pc)
 261 {
 262         pm_runtime_get_sync(pc->chip.dev);
 263         pc->ctx.ecctl2 = readw(pc->mmio_base + ECCTL2);
 264         pc->ctx.cap4 = readl(pc->mmio_base + CAP4);
 265         pc->ctx.cap3 = readl(pc->mmio_base + CAP3);
 266         pm_runtime_put_sync(pc->chip.dev);
 267 }
 268 
 269 static void ecap_pwm_restore_context(struct ecap_pwm_chip *pc)
 270 {
 271         writel(pc->ctx.cap3, pc->mmio_base + CAP3);
 272         writel(pc->ctx.cap4, pc->mmio_base + CAP4);
 273         writew(pc->ctx.ecctl2, pc->mmio_base + ECCTL2);
 274 }
 275 
 276 static int ecap_pwm_suspend(struct device *dev)
 277 {
 278         struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
 279         struct pwm_device *pwm = pc->chip.pwms;
 280 
 281         ecap_pwm_save_context(pc);
 282 
 283         /* Disable explicitly if PWM is running */
 284         if (pwm_is_enabled(pwm))
 285                 pm_runtime_put_sync(dev);
 286 
 287         return 0;
 288 }
 289 
 290 static int ecap_pwm_resume(struct device *dev)
 291 {
 292         struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
 293         struct pwm_device *pwm = pc->chip.pwms;
 294 
 295         /* Enable explicitly if PWM was running */
 296         if (pwm_is_enabled(pwm))
 297                 pm_runtime_get_sync(dev);
 298 
 299         ecap_pwm_restore_context(pc);
 300         return 0;
 301 }
 302 #endif
 303 
 304 static SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume);
 305 
 306 static struct platform_driver ecap_pwm_driver = {
 307         .driver = {
 308                 .name = "ecap",
 309                 .of_match_table = ecap_of_match,
 310                 .pm = &ecap_pwm_pm_ops,
 311         },
 312         .probe = ecap_pwm_probe,
 313         .remove = ecap_pwm_remove,
 314 };
 315 module_platform_driver(ecap_pwm_driver);
 316 
 317 MODULE_DESCRIPTION("ECAP PWM driver");
 318 MODULE_AUTHOR("Texas Instruments");
 319 MODULE_LICENSE("GPL");

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