1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2012 Alexandre Pereira da Silva <aletes.xgr@gmail.com> 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/err.h> 8 #include <linux/io.h> 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/of_address.h> 13 #include <linux/platform_device.h> 14 #include <linux/pwm.h> 15 #include <linux/slab.h> 16 17 struct lpc32xx_pwm_chip { 18 struct clk *clk; 19 void __iomem *base; 20 }; 21 22 #define PWM_ENABLE BIT(31) 23 #define PWM_PIN_LEVEL BIT(30) 24 25 static inline struct lpc32xx_pwm_chip *to_lpc32xx_pwm_chip(struct pwm_chip *chip) 26 { 27 return pwmchip_get_drvdata(chip); 28 } 29 30 static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 31 int duty_ns, int period_ns) 32 { 33 struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); 34 unsigned long long c; 35 int period_cycles, duty_cycles; 36 u32 val; 37 c = clk_get_rate(lpc32xx->clk); 38 39 /* The highest acceptable divisor is 256, which is represented by 0 */ 40 period_cycles = div64_u64(c * period_ns, 41 (unsigned long long)NSEC_PER_SEC * 256); 42 if (!period_cycles || period_cycles > 256) 43 return -ERANGE; 44 if (period_cycles == 256) 45 period_cycles = 0; 46 47 /* Compute 256 x #duty/period value and care for corner cases */ 48 duty_cycles = div64_u64((unsigned long long)(period_ns - duty_ns) * 256, 49 period_ns); 50 if (!duty_cycles) 51 duty_cycles = 1; 52 if (duty_cycles > 255) 53 duty_cycles = 255; 54 55 val = readl(lpc32xx->base); 56 val &= ~0xFFFF; 57 val |= (period_cycles << 8) | duty_cycles; 58 writel(val, lpc32xx->base); 59 60 return 0; 61 } 62 63 static int lpc32xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 64 { 65 struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); 66 u32 val; 67 int ret; 68 69 ret = clk_prepare_enable(lpc32xx->clk); 70 if (ret) 71 return ret; 72 73 val = readl(lpc32xx->base); 74 val |= PWM_ENABLE; 75 writel(val, lpc32xx->base); 76 77 return 0; 78 } 79 80 static void lpc32xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 81 { 82 struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); 83 u32 val; 84 85 val = readl(lpc32xx->base); 86 val &= ~PWM_ENABLE; 87 writel(val, lpc32xx->base); 88 89 clk_disable_unprepare(lpc32xx->clk); 90 } 91 92 static int lpc32xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 93 const struct pwm_state *state) 94 { 95 int err; 96 97 if (state->polarity != PWM_POLARITY_NORMAL) 98 return -EINVAL; 99 100 if (!state->enabled) { 101 if (pwm->state.enabled) 102 lpc32xx_pwm_disable(chip, pwm); 103 104 return 0; 105 } 106 107 err = lpc32xx_pwm_config(chip, pwm, state->duty_cycle, state->period); 108 if (err) 109 return err; 110 111 if (!pwm->state.enabled) 112 err = lpc32xx_pwm_enable(chip, pwm); 113 114 return err; 115 } 116 117 static const struct pwm_ops lpc32xx_pwm_ops = { 118 .apply = lpc32xx_pwm_apply, 119 }; 120 121 static int lpc32xx_pwm_probe(struct platform_device *pdev) 122 { 123 struct pwm_chip *chip; 124 struct lpc32xx_pwm_chip *lpc32xx; 125 int ret; 126 u32 val; 127 128 chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*lpc32xx)); 129 if (IS_ERR(chip)) 130 return PTR_ERR(chip); 131 lpc32xx = to_lpc32xx_pwm_chip(chip); 132 133 lpc32xx->base = devm_platform_ioremap_resource(pdev, 0); 134 if (IS_ERR(lpc32xx->base)) 135 return PTR_ERR(lpc32xx->base); 136 137 lpc32xx->clk = devm_clk_get(&pdev->dev, NULL); 138 if (IS_ERR(lpc32xx->clk)) 139 return PTR_ERR(lpc32xx->clk); 140 141 chip->ops = &lpc32xx_pwm_ops; 142 143 /* If PWM is disabled, configure the output to the default value */ 144 val = readl(lpc32xx->base); 145 val &= ~PWM_PIN_LEVEL; 146 writel(val, lpc32xx->base); 147 148 ret = devm_pwmchip_add(&pdev->dev, chip); 149 if (ret < 0) { 150 dev_err(&pdev->dev, "failed to add PWM chip, error %d\n", ret); 151 return ret; 152 } 153 154 return 0; 155 } 156 157 static const struct of_device_id lpc32xx_pwm_dt_ids[] = { 158 { .compatible = "nxp,lpc3220-pwm", }, 159 { /* sentinel */ } 160 }; 161 MODULE_DEVICE_TABLE(of, lpc32xx_pwm_dt_ids); 162 163 static struct platform_driver lpc32xx_pwm_driver = { 164 .driver = { 165 .name = "lpc32xx-pwm", 166 .of_match_table = lpc32xx_pwm_dt_ids, 167 }, 168 .probe = lpc32xx_pwm_probe, 169 }; 170 module_platform_driver(lpc32xx_pwm_driver); 171 172 MODULE_ALIAS("platform:lpc32xx-pwm"); 173 MODULE_AUTHOR("Alexandre Pereira da Silva <aletes.xgr@gmail.com>"); 174 MODULE_DESCRIPTION("LPC32XX PWM Driver"); 175 MODULE_LICENSE("GPL v2"); 176