1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * MediaTek Pulse Width Modulator driver 4 * 5 * Copyright (C) 2015 John Crispin <blogic@openwrt.org> 6 * Copyright (C) 2017 Zhi Mao <zhi.mao@mediatek.com> 7 * 8 */ 9 10 #include <linux/err.h> 11 #include <linux/io.h> 12 #include <linux/ioport.h> 13 #include <linux/kernel.h> 14 #include <linux/module.h> 15 #include <linux/clk.h> 16 #include <linux/of.h> 17 #include <linux/platform_device.h> 18 #include <linux/pwm.h> 19 #include <linux/slab.h> 20 #include <linux/types.h> 21 22 /* PWM registers and bits definitions */ 23 #define PWMCON 0x00 24 #define PWMHDUR 0x04 25 #define PWMLDUR 0x08 26 #define PWMGDUR 0x0c 27 #define PWMWAVENUM 0x28 28 #define PWMDWIDTH 0x2c 29 #define PWM45DWIDTH_FIXUP 0x30 30 #define PWMTHRES 0x30 31 #define PWM45THRES_FIXUP 0x34 32 #define PWM_CK_26M_SEL 0x210 33 34 #define PWM_CLK_DIV_MAX 7 35 36 struct pwm_mediatek_of_data { 37 unsigned int num_pwms; 38 bool pwm45_fixup; 39 bool has_ck_26m_sel; 40 const unsigned int *reg_offset; 41 }; 42 43 /** 44 * struct pwm_mediatek_chip - struct representing PWM chip 45 * @chip: linux PWM chip representation 46 * @regs: base address of PWM chip 47 * @clk_top: the top clock generator 48 * @clk_main: the clock used by PWM core 49 * @clk_pwms: the clock used by each PWM channel 50 * @clk_freq: the fix clock frequency of legacy MIPS SoC 51 * @soc: pointer to chip's platform data 52 */ 53 struct pwm_mediatek_chip { 54 struct pwm_chip chip; 55 void __iomem *regs; 56 struct clk *clk_top; 57 struct clk *clk_main; 58 struct clk **clk_pwms; 59 const struct pwm_mediatek_of_data *soc; 60 }; 61 62 static const unsigned int mtk_pwm_reg_offset_v1[] = { 63 0x0010, 0x0050, 0x0090, 0x00d0, 0x0110, 0x0150, 0x0190, 0x0220 64 }; 65 66 static const unsigned int mtk_pwm_reg_offset_v2[] = { 67 0x0080, 0x00c0, 0x0100, 0x0140, 0x0180, 0x01c0, 0x0200, 0x0240 68 }; 69 70 static inline struct pwm_mediatek_chip * 71 to_pwm_mediatek_chip(struct pwm_chip *chip) 72 { 73 return container_of(chip, struct pwm_mediatek_chip, chip); 74 } 75 76 static int pwm_mediatek_clk_enable(struct pwm_chip *chip, 77 struct pwm_device *pwm) 78 { 79 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); 80 int ret; 81 82 ret = clk_prepare_enable(pc->clk_top); 83 if (ret < 0) 84 return ret; 85 86 ret = clk_prepare_enable(pc->clk_main); 87 if (ret < 0) 88 goto disable_clk_top; 89 90 ret = clk_prepare_enable(pc->clk_pwms[pwm->hwpwm]); 91 if (ret < 0) 92 goto disable_clk_main; 93 94 return 0; 95 96 disable_clk_main: 97 clk_disable_unprepare(pc->clk_main); 98 disable_clk_top: 99 clk_disable_unprepare(pc->clk_top); 100 101 return ret; 102 } 103 104 static void pwm_mediatek_clk_disable(struct pwm_chip *chip, 105 struct pwm_device *pwm) 106 { 107 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); 108 109 clk_disable_unprepare(pc->clk_pwms[pwm->hwpwm]); 110 clk_disable_unprepare(pc->clk_main); 111 clk_disable_unprepare(pc->clk_top); 112 } 113 114 static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip, 115 unsigned int num, unsigned int offset, 116 u32 value) 117 { 118 writel(value, chip->regs + chip->soc->reg_offset[num] + offset); 119 } 120 121 static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm, 122 int duty_ns, int period_ns) 123 { 124 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); 125 u32 clkdiv = 0, cnt_period, cnt_duty, reg_width = PWMDWIDTH, 126 reg_thres = PWMTHRES; 127 u64 resolution; 128 int ret; 129 130 ret = pwm_mediatek_clk_enable(chip, pwm); 131 132 if (ret < 0) 133 return ret; 134 135 /* Make sure we use the bus clock and not the 26MHz clock */ 136 if (pc->soc->has_ck_26m_sel) 137 writel(0, pc->regs + PWM_CK_26M_SEL); 138 139 /* Using resolution in picosecond gets accuracy higher */ 140 resolution = (u64)NSEC_PER_SEC * 1000; 141 do_div(resolution, clk_get_rate(pc->clk_pwms[pwm->hwpwm])); 142 143 cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution); 144 while (cnt_period > 8191) { 145 resolution *= 2; 146 clkdiv++; 147 cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, 148 resolution); 149 } 150 151 if (clkdiv > PWM_CLK_DIV_MAX) { 152 pwm_mediatek_clk_disable(chip, pwm); 153 dev_err(chip->dev, "period of %d ns not supported\n", period_ns); 154 return -EINVAL; 155 } 156 157 if (pc->soc->pwm45_fixup && pwm->hwpwm > 2) { 158 /* 159 * PWM[4,5] has distinct offset for PWMDWIDTH and PWMTHRES 160 * from the other PWMs on MT7623. 161 */ 162 reg_width = PWM45DWIDTH_FIXUP; 163 reg_thres = PWM45THRES_FIXUP; 164 } 165 166 cnt_duty = DIV_ROUND_CLOSEST_ULL((u64)duty_ns * 1000, resolution); 167 pwm_mediatek_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); 168 pwm_mediatek_writel(pc, pwm->hwpwm, reg_width, cnt_period); 169 pwm_mediatek_writel(pc, pwm->hwpwm, reg_thres, cnt_duty); 170 171 pwm_mediatek_clk_disable(chip, pwm); 172 173 return 0; 174 } 175 176 static int pwm_mediatek_enable(struct pwm_chip *chip, struct pwm_device *pwm) 177 { 178 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); 179 u32 value; 180 int ret; 181 182 ret = pwm_mediatek_clk_enable(chip, pwm); 183 if (ret < 0) 184 return ret; 185 186 value = readl(pc->regs); 187 value |= BIT(pwm->hwpwm); 188 writel(value, pc->regs); 189 190 return 0; 191 } 192 193 static void pwm_mediatek_disable(struct pwm_chip *chip, struct pwm_device *pwm) 194 { 195 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); 196 u32 value; 197 198 value = readl(pc->regs); 199 value &= ~BIT(pwm->hwpwm); 200 writel(value, pc->regs); 201 202 pwm_mediatek_clk_disable(chip, pwm); 203 } 204 205 static int pwm_mediatek_apply(struct pwm_chip *chip, struct pwm_device *pwm, 206 const struct pwm_state *state) 207 { 208 int err; 209 210 if (state->polarity != PWM_POLARITY_NORMAL) 211 return -EINVAL; 212 213 if (!state->enabled) { 214 if (pwm->state.enabled) 215 pwm_mediatek_disable(chip, pwm); 216 217 return 0; 218 } 219 220 err = pwm_mediatek_config(pwm->chip, pwm, state->duty_cycle, state->period); 221 if (err) 222 return err; 223 224 if (!pwm->state.enabled) 225 err = pwm_mediatek_enable(chip, pwm); 226 227 return err; 228 } 229 230 static const struct pwm_ops pwm_mediatek_ops = { 231 .apply = pwm_mediatek_apply, 232 }; 233 234 static int pwm_mediatek_probe(struct platform_device *pdev) 235 { 236 struct pwm_mediatek_chip *pc; 237 unsigned int i; 238 int ret; 239 240 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); 241 if (!pc) 242 return -ENOMEM; 243 244 pc->soc = of_device_get_match_data(&pdev->dev); 245 246 pc->regs = devm_platform_ioremap_resource(pdev, 0); 247 if (IS_ERR(pc->regs)) 248 return PTR_ERR(pc->regs); 249 250 pc->clk_pwms = devm_kmalloc_array(&pdev->dev, pc->soc->num_pwms, 251 sizeof(*pc->clk_pwms), GFP_KERNEL); 252 if (!pc->clk_pwms) 253 return -ENOMEM; 254 255 pc->clk_top = devm_clk_get(&pdev->dev, "top"); 256 if (IS_ERR(pc->clk_top)) 257 return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_top), 258 "Failed to get top clock\n"); 259 260 pc->clk_main = devm_clk_get(&pdev->dev, "main"); 261 if (IS_ERR(pc->clk_main)) 262 return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_main), 263 "Failed to get main clock\n"); 264 265 for (i = 0; i < pc->soc->num_pwms; i++) { 266 char name[8]; 267 268 snprintf(name, sizeof(name), "pwm%d", i + 1); 269 270 pc->clk_pwms[i] = devm_clk_get(&pdev->dev, name); 271 if (IS_ERR(pc->clk_pwms[i])) 272 return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_pwms[i]), 273 "Failed to get %s clock\n", name); 274 } 275 276 pc->chip.dev = &pdev->dev; 277 pc->chip.ops = &pwm_mediatek_ops; 278 pc->chip.npwm = pc->soc->num_pwms; 279 280 ret = devm_pwmchip_add(&pdev->dev, &pc->chip); 281 if (ret < 0) 282 return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n"); 283 284 return 0; 285 } 286 287 static const struct pwm_mediatek_of_data mt2712_pwm_data = { 288 .num_pwms = 8, 289 .pwm45_fixup = false, 290 .has_ck_26m_sel = false, 291 .reg_offset = mtk_pwm_reg_offset_v1, 292 }; 293 294 static const struct pwm_mediatek_of_data mt6795_pwm_data = { 295 .num_pwms = 7, 296 .pwm45_fixup = false, 297 .has_ck_26m_sel = false, 298 .reg_offset = mtk_pwm_reg_offset_v1, 299 }; 300 301 static const struct pwm_mediatek_of_data mt7622_pwm_data = { 302 .num_pwms = 6, 303 .pwm45_fixup = false, 304 .has_ck_26m_sel = true, 305 .reg_offset = mtk_pwm_reg_offset_v1, 306 }; 307 308 static const struct pwm_mediatek_of_data mt7623_pwm_data = { 309 .num_pwms = 5, 310 .pwm45_fixup = true, 311 .has_ck_26m_sel = false, 312 .reg_offset = mtk_pwm_reg_offset_v1, 313 }; 314 315 static const struct pwm_mediatek_of_data mt7628_pwm_data = { 316 .num_pwms = 4, 317 .pwm45_fixup = true, 318 .has_ck_26m_sel = false, 319 .reg_offset = mtk_pwm_reg_offset_v1, 320 }; 321 322 static const struct pwm_mediatek_of_data mt7629_pwm_data = { 323 .num_pwms = 1, 324 .pwm45_fixup = false, 325 .has_ck_26m_sel = false, 326 .reg_offset = mtk_pwm_reg_offset_v1, 327 }; 328 329 static const struct pwm_mediatek_of_data mt7981_pwm_data = { 330 .num_pwms = 3, 331 .pwm45_fixup = false, 332 .has_ck_26m_sel = true, 333 .reg_offset = mtk_pwm_reg_offset_v2, 334 }; 335 336 static const struct pwm_mediatek_of_data mt7986_pwm_data = { 337 .num_pwms = 2, 338 .pwm45_fixup = false, 339 .has_ck_26m_sel = true, 340 .reg_offset = mtk_pwm_reg_offset_v1, 341 }; 342 343 static const struct pwm_mediatek_of_data mt8183_pwm_data = { 344 .num_pwms = 4, 345 .pwm45_fixup = false, 346 .has_ck_26m_sel = true, 347 .reg_offset = mtk_pwm_reg_offset_v1, 348 }; 349 350 static const struct pwm_mediatek_of_data mt8365_pwm_data = { 351 .num_pwms = 3, 352 .pwm45_fixup = false, 353 .has_ck_26m_sel = true, 354 .reg_offset = mtk_pwm_reg_offset_v1, 355 }; 356 357 static const struct pwm_mediatek_of_data mt8516_pwm_data = { 358 .num_pwms = 5, 359 .pwm45_fixup = false, 360 .has_ck_26m_sel = true, 361 .reg_offset = mtk_pwm_reg_offset_v1, 362 }; 363 364 static const struct of_device_id pwm_mediatek_of_match[] = { 365 { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data }, 366 { .compatible = "mediatek,mt6795-pwm", .data = &mt6795_pwm_data }, 367 { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, 368 { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, 369 { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, 370 { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data }, 371 { .compatible = "mediatek,mt7981-pwm", .data = &mt7981_pwm_data }, 372 { .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data }, 373 { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data }, 374 { .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data }, 375 { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data }, 376 { }, 377 }; 378 MODULE_DEVICE_TABLE(of, pwm_mediatek_of_match); 379 380 static struct platform_driver pwm_mediatek_driver = { 381 .driver = { 382 .name = "pwm-mediatek", 383 .of_match_table = pwm_mediatek_of_match, 384 }, 385 .probe = pwm_mediatek_probe, 386 }; 387 module_platform_driver(pwm_mediatek_driver); 388 389 MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); 390 MODULE_LICENSE("GPL v2"); 391