1 /* 2 * Mediatek Pulse Width Modulator driver 3 * 4 * Copyright (C) 2015 John Crispin <blogic@openwrt.org> 5 * Copyright (C) 2017 Zhi Mao <zhi.mao@mediatek.com> 6 * 7 * This file is licensed under the terms of the GNU General Public 8 * License version 2. This program is licensed "as is" without any 9 * warranty of any kind, whether express or implied. 10 */ 11 12 #include <linux/err.h> 13 #include <linux/io.h> 14 #include <linux/ioport.h> 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/clk.h> 18 #include <linux/of.h> 19 #include <linux/of_device.h> 20 #include <linux/platform_device.h> 21 #include <linux/pwm.h> 22 #include <linux/slab.h> 23 #include <linux/types.h> 24 25 /* PWM registers and bits definitions */ 26 #define PWMCON 0x00 27 #define PWMHDUR 0x04 28 #define PWMLDUR 0x08 29 #define PWMGDUR 0x0c 30 #define PWMWAVENUM 0x28 31 #define PWMDWIDTH 0x2c 32 #define PWMTHRES 0x30 33 34 #define PWM_CLK_DIV_MAX 7 35 36 enum { 37 MTK_CLK_MAIN = 0, 38 MTK_CLK_TOP, 39 MTK_CLK_PWM1, 40 MTK_CLK_PWM2, 41 MTK_CLK_PWM3, 42 MTK_CLK_PWM4, 43 MTK_CLK_PWM5, 44 MTK_CLK_PWM6, 45 MTK_CLK_PWM7, 46 MTK_CLK_PWM8, 47 MTK_CLK_MAX, 48 }; 49 50 static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = { 51 "main", "top", "pwm1", "pwm2", "pwm3", "pwm4", "pwm5", "pwm6", "pwm7", 52 "pwm8" 53 }; 54 55 struct mtk_pwm_platform_data { 56 unsigned int num_pwms; 57 }; 58 59 /** 60 * struct mtk_pwm_chip - struct representing PWM chip 61 * @chip: linux PWM chip representation 62 * @regs: base address of PWM chip 63 * @clks: list of clocks 64 */ 65 struct mtk_pwm_chip { 66 struct pwm_chip chip; 67 void __iomem *regs; 68 struct clk *clks[MTK_CLK_MAX]; 69 }; 70 71 static const unsigned int mtk_pwm_reg_offset[] = { 72 0x0010, 0x0050, 0x0090, 0x00d0, 0x0110, 0x0150, 0x0190, 0x0220 73 }; 74 75 static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) 76 { 77 return container_of(chip, struct mtk_pwm_chip, chip); 78 } 79 80 static int mtk_pwm_clk_enable(struct pwm_chip *chip, struct pwm_device *pwm) 81 { 82 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); 83 int ret; 84 85 ret = clk_prepare_enable(pc->clks[MTK_CLK_TOP]); 86 if (ret < 0) 87 return ret; 88 89 ret = clk_prepare_enable(pc->clks[MTK_CLK_MAIN]); 90 if (ret < 0) 91 goto disable_clk_top; 92 93 ret = clk_prepare_enable(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); 94 if (ret < 0) 95 goto disable_clk_main; 96 97 return 0; 98 99 disable_clk_main: 100 clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]); 101 disable_clk_top: 102 clk_disable_unprepare(pc->clks[MTK_CLK_TOP]); 103 104 return ret; 105 } 106 107 static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm) 108 { 109 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); 110 111 clk_disable_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); 112 clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]); 113 clk_disable_unprepare(pc->clks[MTK_CLK_TOP]); 114 } 115 116 static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, 117 unsigned int offset) 118 { 119 return readl(chip->regs + mtk_pwm_reg_offset[num] + offset); 120 } 121 122 static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip, 123 unsigned int num, unsigned int offset, 124 u32 value) 125 { 126 writel(value, chip->regs + mtk_pwm_reg_offset[num] + offset); 127 } 128 129 static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 130 int duty_ns, int period_ns) 131 { 132 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); 133 struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]; 134 u32 resolution, clkdiv = 0; 135 int ret; 136 137 ret = mtk_pwm_clk_enable(chip, pwm); 138 if (ret < 0) 139 return ret; 140 141 resolution = NSEC_PER_SEC / clk_get_rate(clk); 142 143 while (period_ns / resolution > 8191) { 144 resolution *= 2; 145 clkdiv++; 146 } 147 148 if (clkdiv > PWM_CLK_DIV_MAX) { 149 mtk_pwm_clk_disable(chip, pwm); 150 dev_err(chip->dev, "period %d not supported\n", period_ns); 151 return -EINVAL; 152 } 153 154 mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); 155 mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); 156 mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); 157 158 mtk_pwm_clk_disable(chip, pwm); 159 160 return 0; 161 } 162 163 static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 164 { 165 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); 166 u32 value; 167 int ret; 168 169 ret = mtk_pwm_clk_enable(chip, pwm); 170 if (ret < 0) 171 return ret; 172 173 value = readl(pc->regs); 174 value |= BIT(pwm->hwpwm); 175 writel(value, pc->regs); 176 177 return 0; 178 } 179 180 static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 181 { 182 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); 183 u32 value; 184 185 value = readl(pc->regs); 186 value &= ~BIT(pwm->hwpwm); 187 writel(value, pc->regs); 188 189 mtk_pwm_clk_disable(chip, pwm); 190 } 191 192 static const struct pwm_ops mtk_pwm_ops = { 193 .config = mtk_pwm_config, 194 .enable = mtk_pwm_enable, 195 .disable = mtk_pwm_disable, 196 .owner = THIS_MODULE, 197 }; 198 199 static int mtk_pwm_probe(struct platform_device *pdev) 200 { 201 const struct mtk_pwm_platform_data *data; 202 struct mtk_pwm_chip *pc; 203 struct resource *res; 204 unsigned int i; 205 int ret; 206 207 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); 208 if (!pc) 209 return -ENOMEM; 210 211 data = of_device_get_match_data(&pdev->dev); 212 if (data == NULL) 213 return -EINVAL; 214 215 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 216 pc->regs = devm_ioremap_resource(&pdev->dev, res); 217 if (IS_ERR(pc->regs)) 218 return PTR_ERR(pc->regs); 219 220 for (i = 0; i < data->num_pwms + 2; i++) { 221 pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); 222 if (IS_ERR(pc->clks[i])) { 223 dev_err(&pdev->dev, "clock: %s fail: %ld\n", 224 mtk_pwm_clk_name[i], PTR_ERR(pc->clks[i])); 225 return PTR_ERR(pc->clks[i]); 226 } 227 } 228 229 platform_set_drvdata(pdev, pc); 230 231 pc->chip.dev = &pdev->dev; 232 pc->chip.ops = &mtk_pwm_ops; 233 pc->chip.base = -1; 234 pc->chip.npwm = data->num_pwms; 235 236 ret = pwmchip_add(&pc->chip); 237 if (ret < 0) { 238 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 239 return ret; 240 } 241 242 return 0; 243 } 244 245 static int mtk_pwm_remove(struct platform_device *pdev) 246 { 247 struct mtk_pwm_chip *pc = platform_get_drvdata(pdev); 248 249 return pwmchip_remove(&pc->chip); 250 } 251 252 static const struct mtk_pwm_platform_data mt2712_pwm_data = { 253 .num_pwms = 8, 254 }; 255 256 static const struct mtk_pwm_platform_data mt7622_pwm_data = { 257 .num_pwms = 6, 258 }; 259 260 static const struct mtk_pwm_platform_data mt7623_pwm_data = { 261 .num_pwms = 5, 262 }; 263 264 static const struct of_device_id mtk_pwm_of_match[] = { 265 { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data }, 266 { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, 267 { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, 268 { }, 269 }; 270 MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); 271 272 static struct platform_driver mtk_pwm_driver = { 273 .driver = { 274 .name = "mtk-pwm", 275 .of_match_table = mtk_pwm_of_match, 276 }, 277 .probe = mtk_pwm_probe, 278 .remove = mtk_pwm_remove, 279 }; 280 module_platform_driver(mtk_pwm_driver); 281 282 MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); 283 MODULE_ALIAS("platform:mtk-pwm"); 284 MODULE_LICENSE("GPL"); 285