1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2014 Bart Tanghe <bart.tanghe@thomasmore.be> 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/err.h> 8 #include <linux/io.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/platform_device.h> 12 #include <linux/pwm.h> 13 14 #define PWM_CONTROL 0x000 15 #define PWM_CONTROL_SHIFT(x) ((x) * 8) 16 #define PWM_CONTROL_MASK 0xff 17 #define PWM_MODE 0x80 /* set timer in PWM mode */ 18 #define PWM_ENABLE (1 << 0) 19 #define PWM_POLARITY (1 << 4) 20 21 #define PERIOD(x) (((x) * 0x10) + 0x10) 22 #define DUTY(x) (((x) * 0x10) + 0x14) 23 24 #define PERIOD_MIN 0x2 25 26 struct bcm2835_pwm { 27 struct pwm_chip chip; 28 struct device *dev; 29 void __iomem *base; 30 struct clk *clk; 31 }; 32 33 static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip) 34 { 35 return container_of(chip, struct bcm2835_pwm, chip); 36 } 37 38 static int bcm2835_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 39 { 40 struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); 41 u32 value; 42 43 value = readl(pc->base + PWM_CONTROL); 44 value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm)); 45 value |= (PWM_MODE << PWM_CONTROL_SHIFT(pwm->hwpwm)); 46 writel(value, pc->base + PWM_CONTROL); 47 48 return 0; 49 } 50 51 static void bcm2835_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 52 { 53 struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); 54 u32 value; 55 56 value = readl(pc->base + PWM_CONTROL); 57 value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm)); 58 writel(value, pc->base + PWM_CONTROL); 59 } 60 61 static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 62 const struct pwm_state *state) 63 { 64 65 struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); 66 unsigned long rate = clk_get_rate(pc->clk); 67 unsigned long long period; 68 unsigned long scaler; 69 u32 val; 70 71 if (!rate) { 72 dev_err(pc->dev, "failed to get clock rate\n"); 73 return -EINVAL; 74 } 75 76 scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate); 77 /* set period */ 78 period = DIV_ROUND_CLOSEST_ULL(state->period, scaler); 79 80 /* dont accept a period that is too small or has been truncated */ 81 if ((period < PERIOD_MIN) || (period > U32_MAX)) 82 return -EINVAL; 83 84 writel(period, pc->base + PERIOD(pwm->hwpwm)); 85 86 /* set duty cycle */ 87 val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, scaler); 88 writel(val, pc->base + DUTY(pwm->hwpwm)); 89 90 /* set polarity */ 91 val = readl(pc->base + PWM_CONTROL); 92 93 if (state->polarity == PWM_POLARITY_NORMAL) 94 val &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm)); 95 else 96 val |= PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm); 97 98 /* enable/disable */ 99 if (state->enabled) 100 val |= PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm); 101 else 102 val &= ~(PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm)); 103 104 writel(val, pc->base + PWM_CONTROL); 105 106 return 0; 107 } 108 109 static const struct pwm_ops bcm2835_pwm_ops = { 110 .request = bcm2835_pwm_request, 111 .free = bcm2835_pwm_free, 112 .apply = bcm2835_pwm_apply, 113 .owner = THIS_MODULE, 114 }; 115 116 static int bcm2835_pwm_probe(struct platform_device *pdev) 117 { 118 struct bcm2835_pwm *pc; 119 int ret; 120 121 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); 122 if (!pc) 123 return -ENOMEM; 124 125 pc->dev = &pdev->dev; 126 127 pc->base = devm_platform_ioremap_resource(pdev, 0); 128 if (IS_ERR(pc->base)) 129 return PTR_ERR(pc->base); 130 131 pc->clk = devm_clk_get(&pdev->dev, NULL); 132 if (IS_ERR(pc->clk)) 133 return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), 134 "clock not found\n"); 135 136 ret = clk_prepare_enable(pc->clk); 137 if (ret) 138 return ret; 139 140 pc->chip.dev = &pdev->dev; 141 pc->chip.ops = &bcm2835_pwm_ops; 142 pc->chip.base = -1; 143 pc->chip.npwm = 2; 144 pc->chip.of_xlate = of_pwm_xlate_with_flags; 145 pc->chip.of_pwm_n_cells = 3; 146 147 platform_set_drvdata(pdev, pc); 148 149 ret = pwmchip_add(&pc->chip); 150 if (ret < 0) 151 goto add_fail; 152 153 return 0; 154 155 add_fail: 156 clk_disable_unprepare(pc->clk); 157 return ret; 158 } 159 160 static int bcm2835_pwm_remove(struct platform_device *pdev) 161 { 162 struct bcm2835_pwm *pc = platform_get_drvdata(pdev); 163 164 clk_disable_unprepare(pc->clk); 165 166 return pwmchip_remove(&pc->chip); 167 } 168 169 static const struct of_device_id bcm2835_pwm_of_match[] = { 170 { .compatible = "brcm,bcm2835-pwm", }, 171 { /* sentinel */ } 172 }; 173 MODULE_DEVICE_TABLE(of, bcm2835_pwm_of_match); 174 175 static struct platform_driver bcm2835_pwm_driver = { 176 .driver = { 177 .name = "bcm2835-pwm", 178 .of_match_table = bcm2835_pwm_of_match, 179 }, 180 .probe = bcm2835_pwm_probe, 181 .remove = bcm2835_pwm_remove, 182 }; 183 module_platform_driver(bcm2835_pwm_driver); 184 185 MODULE_AUTHOR("Bart Tanghe <bart.tanghe@thomasmore.be>"); 186 MODULE_DESCRIPTION("Broadcom BCM2835 PWM driver"); 187 MODULE_LICENSE("GPL v2"); 188