Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright 2014 Bart Tanghe <bart.tanghe@thomasmore.be>
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/err.h>
0008 #include <linux/io.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/pwm.h>
0013 
0014 #define PWM_CONTROL     0x000
0015 #define PWM_CONTROL_SHIFT(x)    ((x) * 8)
0016 #define PWM_CONTROL_MASK    0xff
0017 #define PWM_MODE        0x80        /* set timer in PWM mode */
0018 #define PWM_ENABLE      (1 << 0)
0019 #define PWM_POLARITY        (1 << 4)
0020 
0021 #define PERIOD(x)       (((x) * 0x10) + 0x10)
0022 #define DUTY(x)         (((x) * 0x10) + 0x14)
0023 
0024 #define PERIOD_MIN      0x2
0025 
0026 struct bcm2835_pwm {
0027     struct pwm_chip chip;
0028     struct device *dev;
0029     void __iomem *base;
0030     struct clk *clk;
0031 };
0032 
0033 static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip)
0034 {
0035     return container_of(chip, struct bcm2835_pwm, chip);
0036 }
0037 
0038 static int bcm2835_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
0039 {
0040     struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
0041     u32 value;
0042 
0043     value = readl(pc->base + PWM_CONTROL);
0044     value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm));
0045     value |= (PWM_MODE << PWM_CONTROL_SHIFT(pwm->hwpwm));
0046     writel(value, pc->base + PWM_CONTROL);
0047 
0048     return 0;
0049 }
0050 
0051 static void bcm2835_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
0052 {
0053     struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
0054     u32 value;
0055 
0056     value = readl(pc->base + PWM_CONTROL);
0057     value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm));
0058     writel(value, pc->base + PWM_CONTROL);
0059 }
0060 
0061 static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
0062                  const struct pwm_state *state)
0063 {
0064 
0065     struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
0066     unsigned long rate = clk_get_rate(pc->clk);
0067     unsigned long long period_cycles;
0068     u64 max_period;
0069 
0070     u32 val;
0071 
0072     if (!rate) {
0073         dev_err(pc->dev, "failed to get clock rate\n");
0074         return -EINVAL;
0075     }
0076 
0077     /*
0078      * period_cycles must be a 32 bit value, so period * rate / NSEC_PER_SEC
0079      * must be <= U32_MAX. As U32_MAX * NSEC_PER_SEC < U64_MAX the
0080      * multiplication period * rate doesn't overflow.
0081      * To calculate the maximal possible period that guarantees the
0082      * above inequality:
0083      *
0084      *     round(period * rate / NSEC_PER_SEC) <= U32_MAX
0085      * <=> period * rate / NSEC_PER_SEC < U32_MAX + 0.5
0086      * <=> period * rate < (U32_MAX + 0.5) * NSEC_PER_SEC
0087      * <=> period < ((U32_MAX + 0.5) * NSEC_PER_SEC) / rate
0088      * <=> period < ((U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate
0089      * <=> period <= ceil((U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate) - 1
0090      */
0091     max_period = DIV_ROUND_UP_ULL((u64)U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC / 2, rate) - 1;
0092 
0093     if (state->period > max_period)
0094         return -EINVAL;
0095 
0096     /* set period */
0097     period_cycles = DIV_ROUND_CLOSEST_ULL(state->period * rate, NSEC_PER_SEC);
0098 
0099     /* don't accept a period that is too small */
0100     if (period_cycles < PERIOD_MIN)
0101         return -EINVAL;
0102 
0103     writel(period_cycles, pc->base + PERIOD(pwm->hwpwm));
0104 
0105     /* set duty cycle */
0106     val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * rate, NSEC_PER_SEC);
0107     writel(val, pc->base + DUTY(pwm->hwpwm));
0108 
0109     /* set polarity */
0110     val = readl(pc->base + PWM_CONTROL);
0111 
0112     if (state->polarity == PWM_POLARITY_NORMAL)
0113         val &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm));
0114     else
0115         val |= PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm);
0116 
0117     /* enable/disable */
0118     if (state->enabled)
0119         val |= PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm);
0120     else
0121         val &= ~(PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm));
0122 
0123     writel(val, pc->base + PWM_CONTROL);
0124 
0125     return 0;
0126 }
0127 
0128 static const struct pwm_ops bcm2835_pwm_ops = {
0129     .request = bcm2835_pwm_request,
0130     .free = bcm2835_pwm_free,
0131     .apply = bcm2835_pwm_apply,
0132     .owner = THIS_MODULE,
0133 };
0134 
0135 static int bcm2835_pwm_probe(struct platform_device *pdev)
0136 {
0137     struct bcm2835_pwm *pc;
0138     int ret;
0139 
0140     pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
0141     if (!pc)
0142         return -ENOMEM;
0143 
0144     pc->dev = &pdev->dev;
0145 
0146     pc->base = devm_platform_ioremap_resource(pdev, 0);
0147     if (IS_ERR(pc->base))
0148         return PTR_ERR(pc->base);
0149 
0150     pc->clk = devm_clk_get(&pdev->dev, NULL);
0151     if (IS_ERR(pc->clk))
0152         return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
0153                      "clock not found\n");
0154 
0155     ret = clk_prepare_enable(pc->clk);
0156     if (ret)
0157         return ret;
0158 
0159     pc->chip.dev = &pdev->dev;
0160     pc->chip.ops = &bcm2835_pwm_ops;
0161     pc->chip.npwm = 2;
0162 
0163     platform_set_drvdata(pdev, pc);
0164 
0165     ret = pwmchip_add(&pc->chip);
0166     if (ret < 0)
0167         goto add_fail;
0168 
0169     return 0;
0170 
0171 add_fail:
0172     clk_disable_unprepare(pc->clk);
0173     return ret;
0174 }
0175 
0176 static int bcm2835_pwm_remove(struct platform_device *pdev)
0177 {
0178     struct bcm2835_pwm *pc = platform_get_drvdata(pdev);
0179 
0180     pwmchip_remove(&pc->chip);
0181 
0182     clk_disable_unprepare(pc->clk);
0183 
0184     return 0;
0185 }
0186 
0187 static const struct of_device_id bcm2835_pwm_of_match[] = {
0188     { .compatible = "brcm,bcm2835-pwm", },
0189     { /* sentinel */ }
0190 };
0191 MODULE_DEVICE_TABLE(of, bcm2835_pwm_of_match);
0192 
0193 static struct platform_driver bcm2835_pwm_driver = {
0194     .driver = {
0195         .name = "bcm2835-pwm",
0196         .of_match_table = bcm2835_pwm_of_match,
0197     },
0198     .probe = bcm2835_pwm_probe,
0199     .remove = bcm2835_pwm_remove,
0200 };
0201 module_platform_driver(bcm2835_pwm_driver);
0202 
0203 MODULE_AUTHOR("Bart Tanghe <bart.tanghe@thomasmore.be>");
0204 MODULE_DESCRIPTION("Broadcom BCM2835 PWM driver");
0205 MODULE_LICENSE("GPL v2");