root/drivers/pwm/pwm-jz4740.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_jz4740
  2. jz4740_pwm_request
  3. jz4740_pwm_free
  4. jz4740_pwm_enable
  5. jz4740_pwm_disable
  6. jz4740_pwm_apply
  7. jz4740_pwm_probe
  8. jz4740_pwm_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
   4  *  JZ4740 platform PWM support
   5  *
   6  * Limitations:
   7  * - The .apply callback doesn't complete the currently running period before
   8  *   reconfiguring the hardware.
   9  * - Each period starts with the inactive part.
  10  */
  11 
  12 #include <linux/clk.h>
  13 #include <linux/err.h>
  14 #include <linux/gpio.h>
  15 #include <linux/kernel.h>
  16 #include <linux/module.h>
  17 #include <linux/of_device.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/pwm.h>
  20 
  21 #include <asm/mach-jz4740/timer.h>
  22 
  23 #define NUM_PWM 8
  24 
  25 struct jz4740_pwm_chip {
  26         struct pwm_chip chip;
  27         struct clk *clk;
  28 };
  29 
  30 static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
  31 {
  32         return container_of(chip, struct jz4740_pwm_chip, chip);
  33 }
  34 
  35 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
  36 {
  37         /*
  38          * Timers 0 and 1 are used for system tasks, so they are unavailable
  39          * for use as PWMs.
  40          */
  41         if (pwm->hwpwm < 2)
  42                 return -EBUSY;
  43 
  44         jz4740_timer_start(pwm->hwpwm);
  45 
  46         return 0;
  47 }
  48 
  49 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
  50 {
  51         jz4740_timer_set_ctrl(pwm->hwpwm, 0);
  52 
  53         jz4740_timer_stop(pwm->hwpwm);
  54 }
  55 
  56 static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
  57 {
  58         uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
  59 
  60         ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
  61         jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
  62         jz4740_timer_enable(pwm->hwpwm);
  63 
  64         return 0;
  65 }
  66 
  67 static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
  68 {
  69         uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
  70 
  71         /*
  72          * Set duty > period. This trick allows the TCU channels in TCU2 mode to
  73          * properly return to their init level.
  74          */
  75         jz4740_timer_set_duty(pwm->hwpwm, 0xffff);
  76         jz4740_timer_set_period(pwm->hwpwm, 0x0);
  77 
  78         /*
  79          * Disable PWM output.
  80          * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the
  81          * counter is stopped, while in TCU1 mode the order does not matter.
  82          */
  83         ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
  84         jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
  85 
  86         /* Stop counter */
  87         jz4740_timer_disable(pwm->hwpwm);
  88 }
  89 
  90 static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
  91                             const struct pwm_state *state)
  92 {
  93         struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
  94         unsigned long long tmp;
  95         unsigned long period, duty;
  96         unsigned int prescaler = 0;
  97         uint16_t ctrl;
  98 
  99         tmp = (unsigned long long)clk_get_rate(jz4740->clk) * state->period;
 100         do_div(tmp, 1000000000);
 101         period = tmp;
 102 
 103         while (period > 0xffff && prescaler < 6) {
 104                 period >>= 2;
 105                 ++prescaler;
 106         }
 107 
 108         if (prescaler == 6)
 109                 return -EINVAL;
 110 
 111         tmp = (unsigned long long)period * state->duty_cycle;
 112         do_div(tmp, state->period);
 113         duty = period - tmp;
 114 
 115         if (duty >= period)
 116                 duty = period - 1;
 117 
 118         jz4740_pwm_disable(chip, pwm);
 119 
 120         jz4740_timer_set_count(pwm->hwpwm, 0);
 121         jz4740_timer_set_duty(pwm->hwpwm, duty);
 122         jz4740_timer_set_period(pwm->hwpwm, period);
 123 
 124         ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
 125                 JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
 126 
 127         jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
 128 
 129         switch (state->polarity) {
 130         case PWM_POLARITY_NORMAL:
 131                 ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
 132                 break;
 133         case PWM_POLARITY_INVERSED:
 134                 ctrl |= JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
 135                 break;
 136         }
 137 
 138         jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
 139 
 140         if (state->enabled)
 141                 jz4740_pwm_enable(chip, pwm);
 142 
 143         return 0;
 144 }
 145 
 146 static const struct pwm_ops jz4740_pwm_ops = {
 147         .request = jz4740_pwm_request,
 148         .free = jz4740_pwm_free,
 149         .apply = jz4740_pwm_apply,
 150         .owner = THIS_MODULE,
 151 };
 152 
 153 static int jz4740_pwm_probe(struct platform_device *pdev)
 154 {
 155         struct jz4740_pwm_chip *jz4740;
 156 
 157         jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL);
 158         if (!jz4740)
 159                 return -ENOMEM;
 160 
 161         jz4740->clk = devm_clk_get(&pdev->dev, "ext");
 162         if (IS_ERR(jz4740->clk))
 163                 return PTR_ERR(jz4740->clk);
 164 
 165         jz4740->chip.dev = &pdev->dev;
 166         jz4740->chip.ops = &jz4740_pwm_ops;
 167         jz4740->chip.npwm = NUM_PWM;
 168         jz4740->chip.base = -1;
 169         jz4740->chip.of_xlate = of_pwm_xlate_with_flags;
 170         jz4740->chip.of_pwm_n_cells = 3;
 171 
 172         platform_set_drvdata(pdev, jz4740);
 173 
 174         return pwmchip_add(&jz4740->chip);
 175 }
 176 
 177 static int jz4740_pwm_remove(struct platform_device *pdev)
 178 {
 179         struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev);
 180 
 181         return pwmchip_remove(&jz4740->chip);
 182 }
 183 
 184 #ifdef CONFIG_OF
 185 static const struct of_device_id jz4740_pwm_dt_ids[] = {
 186         { .compatible = "ingenic,jz4740-pwm", },
 187         {},
 188 };
 189 MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids);
 190 #endif
 191 
 192 static struct platform_driver jz4740_pwm_driver = {
 193         .driver = {
 194                 .name = "jz4740-pwm",
 195                 .of_match_table = of_match_ptr(jz4740_pwm_dt_ids),
 196         },
 197         .probe = jz4740_pwm_probe,
 198         .remove = jz4740_pwm_remove,
 199 };
 200 module_platform_driver(jz4740_pwm_driver);
 201 
 202 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 203 MODULE_DESCRIPTION("Ingenic JZ4740 PWM driver");
 204 MODULE_ALIAS("platform:jz4740-pwm");
 205 MODULE_LICENSE("GPL");

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