Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2012 Alexandre Pereira da Silva <aletes.xgr@gmail.com>
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/err.h>
0008 #include <linux/io.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_address.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/pwm.h>
0015 #include <linux/slab.h>
0016 
0017 struct lpc32xx_pwm_chip {
0018     struct pwm_chip chip;
0019     struct clk *clk;
0020     void __iomem *base;
0021 };
0022 
0023 #define PWM_ENABLE  BIT(31)
0024 #define PWM_PIN_LEVEL   BIT(30)
0025 
0026 #define to_lpc32xx_pwm_chip(_chip) \
0027     container_of(_chip, struct lpc32xx_pwm_chip, chip)
0028 
0029 static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
0030                   int duty_ns, int period_ns)
0031 {
0032     struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip);
0033     unsigned long long c;
0034     int period_cycles, duty_cycles;
0035     u32 val;
0036     c = clk_get_rate(lpc32xx->clk);
0037 
0038     /* The highest acceptable divisor is 256, which is represented by 0 */
0039     period_cycles = div64_u64(c * period_ns,
0040                    (unsigned long long)NSEC_PER_SEC * 256);
0041     if (!period_cycles || period_cycles > 256)
0042         return -ERANGE;
0043     if (period_cycles == 256)
0044         period_cycles = 0;
0045 
0046     /* Compute 256 x #duty/period value and care for corner cases */
0047     duty_cycles = div64_u64((unsigned long long)(period_ns - duty_ns) * 256,
0048                 period_ns);
0049     if (!duty_cycles)
0050         duty_cycles = 1;
0051     if (duty_cycles > 255)
0052         duty_cycles = 255;
0053 
0054     val = readl(lpc32xx->base + (pwm->hwpwm << 2));
0055     val &= ~0xFFFF;
0056     val |= (period_cycles << 8) | duty_cycles;
0057     writel(val, lpc32xx->base + (pwm->hwpwm << 2));
0058 
0059     return 0;
0060 }
0061 
0062 static int lpc32xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
0063 {
0064     struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip);
0065     u32 val;
0066     int ret;
0067 
0068     ret = clk_prepare_enable(lpc32xx->clk);
0069     if (ret)
0070         return ret;
0071 
0072     val = readl(lpc32xx->base + (pwm->hwpwm << 2));
0073     val |= PWM_ENABLE;
0074     writel(val, lpc32xx->base + (pwm->hwpwm << 2));
0075 
0076     return 0;
0077 }
0078 
0079 static void lpc32xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
0080 {
0081     struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip);
0082     u32 val;
0083 
0084     val = readl(lpc32xx->base + (pwm->hwpwm << 2));
0085     val &= ~PWM_ENABLE;
0086     writel(val, lpc32xx->base + (pwm->hwpwm << 2));
0087 
0088     clk_disable_unprepare(lpc32xx->clk);
0089 }
0090 
0091 static int lpc32xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
0092                  const struct pwm_state *state)
0093 {
0094     int err;
0095 
0096     if (state->polarity != PWM_POLARITY_NORMAL)
0097         return -EINVAL;
0098 
0099     if (!state->enabled) {
0100         if (pwm->state.enabled)
0101             lpc32xx_pwm_disable(chip, pwm);
0102 
0103         return 0;
0104     }
0105 
0106     err = lpc32xx_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
0107     if (err)
0108         return err;
0109 
0110     if (!pwm->state.enabled)
0111         err = lpc32xx_pwm_enable(chip, pwm);
0112 
0113     return err;
0114 }
0115 
0116 static const struct pwm_ops lpc32xx_pwm_ops = {
0117     .apply = lpc32xx_pwm_apply,
0118     .owner = THIS_MODULE,
0119 };
0120 
0121 static int lpc32xx_pwm_probe(struct platform_device *pdev)
0122 {
0123     struct lpc32xx_pwm_chip *lpc32xx;
0124     int ret;
0125     u32 val;
0126 
0127     lpc32xx = devm_kzalloc(&pdev->dev, sizeof(*lpc32xx), GFP_KERNEL);
0128     if (!lpc32xx)
0129         return -ENOMEM;
0130 
0131     lpc32xx->base = devm_platform_ioremap_resource(pdev, 0);
0132     if (IS_ERR(lpc32xx->base))
0133         return PTR_ERR(lpc32xx->base);
0134 
0135     lpc32xx->clk = devm_clk_get(&pdev->dev, NULL);
0136     if (IS_ERR(lpc32xx->clk))
0137         return PTR_ERR(lpc32xx->clk);
0138 
0139     lpc32xx->chip.dev = &pdev->dev;
0140     lpc32xx->chip.ops = &lpc32xx_pwm_ops;
0141     lpc32xx->chip.npwm = 1;
0142 
0143     /* If PWM is disabled, configure the output to the default value */
0144     val = readl(lpc32xx->base + (lpc32xx->chip.pwms[0].hwpwm << 2));
0145     val &= ~PWM_PIN_LEVEL;
0146     writel(val, lpc32xx->base + (lpc32xx->chip.pwms[0].hwpwm << 2));
0147 
0148     ret = devm_pwmchip_add(&pdev->dev, &lpc32xx->chip);
0149     if (ret < 0) {
0150         dev_err(&pdev->dev, "failed to add PWM chip, error %d\n", ret);
0151         return ret;
0152     }
0153 
0154     return 0;
0155 }
0156 
0157 static const struct of_device_id lpc32xx_pwm_dt_ids[] = {
0158     { .compatible = "nxp,lpc3220-pwm", },
0159     { /* sentinel */ }
0160 };
0161 MODULE_DEVICE_TABLE(of, lpc32xx_pwm_dt_ids);
0162 
0163 static struct platform_driver lpc32xx_pwm_driver = {
0164     .driver = {
0165         .name = "lpc32xx-pwm",
0166         .of_match_table = lpc32xx_pwm_dt_ids,
0167     },
0168     .probe = lpc32xx_pwm_probe,
0169 };
0170 module_platform_driver(lpc32xx_pwm_driver);
0171 
0172 MODULE_ALIAS("platform:lpc32xx-pwm");
0173 MODULE_AUTHOR("Alexandre Pereira da Silva <aletes.xgr@gmail.com>");
0174 MODULE_DESCRIPTION("LPC32XX PWM Driver");
0175 MODULE_LICENSE("GPL v2");