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 .owner = THIS_MODULE, 233 }; 234 235 static int pwm_mediatek_probe(struct platform_device *pdev) 236 { 237 struct pwm_mediatek_chip *pc; 238 unsigned int i; 239 int ret; 240 241 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); 242 if (!pc) 243 return -ENOMEM; 244 245 pc->soc = of_device_get_match_data(&pdev->dev); 246 247 pc->regs = devm_platform_ioremap_resource(pdev, 0); 248 if (IS_ERR(pc->regs)) 249 return PTR_ERR(pc->regs); 250 251 pc->clk_pwms = devm_kmalloc_array(&pdev->dev, pc->soc->num_pwms, 252 sizeof(*pc->clk_pwms), GFP_KERNEL); 253 if (!pc->clk_pwms) 254 return -ENOMEM; 255 256 pc->clk_top = devm_clk_get(&pdev->dev, "top"); 257 if (IS_ERR(pc->clk_top)) 258 return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_top), 259 "Failed to get top clock\n"); 260 261 pc->clk_main = devm_clk_get(&pdev->dev, "main"); 262 if (IS_ERR(pc->clk_main)) 263 return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_main), 264 "Failed to get main clock\n"); 265 266 for (i = 0; i < pc->soc->num_pwms; i++) { 267 char name[8]; 268 269 snprintf(name, sizeof(name), "pwm%d", i + 1); 270 271 pc->clk_pwms[i] = devm_clk_get(&pdev->dev, name); 272 if (IS_ERR(pc->clk_pwms[i])) 273 return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_pwms[i]), 274 "Failed to get %s clock\n", name); 275 } 276 277 pc->chip.dev = &pdev->dev; 278 pc->chip.ops = &pwm_mediatek_ops; 279 pc->chip.npwm = pc->soc->num_pwms; 280 281 ret = devm_pwmchip_add(&pdev->dev, &pc->chip); 282 if (ret < 0) 283 return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n"); 284 285 return 0; 286 } 287 288 static const struct pwm_mediatek_of_data mt2712_pwm_data = { 289 .num_pwms = 8, 290 .pwm45_fixup = false, 291 .has_ck_26m_sel = false, 292 .reg_offset = mtk_pwm_reg_offset_v1, 293 }; 294 295 static const struct pwm_mediatek_of_data mt6795_pwm_data = { 296 .num_pwms = 7, 297 .pwm45_fixup = false, 298 .has_ck_26m_sel = false, 299 .reg_offset = mtk_pwm_reg_offset_v1, 300 }; 301 302 static const struct pwm_mediatek_of_data mt7622_pwm_data = { 303 .num_pwms = 6, 304 .pwm45_fixup = false, 305 .has_ck_26m_sel = true, 306 .reg_offset = mtk_pwm_reg_offset_v1, 307 }; 308 309 static const struct pwm_mediatek_of_data mt7623_pwm_data = { 310 .num_pwms = 5, 311 .pwm45_fixup = true, 312 .has_ck_26m_sel = false, 313 .reg_offset = mtk_pwm_reg_offset_v1, 314 }; 315 316 static const struct pwm_mediatek_of_data mt7628_pwm_data = { 317 .num_pwms = 4, 318 .pwm45_fixup = true, 319 .has_ck_26m_sel = false, 320 .reg_offset = mtk_pwm_reg_offset_v1, 321 }; 322 323 static const struct pwm_mediatek_of_data mt7629_pwm_data = { 324 .num_pwms = 1, 325 .pwm45_fixup = false, 326 .has_ck_26m_sel = false, 327 .reg_offset = mtk_pwm_reg_offset_v1, 328 }; 329 330 static const struct pwm_mediatek_of_data mt7981_pwm_data = { 331 .num_pwms = 3, 332 .pwm45_fixup = false, 333 .has_ck_26m_sel = true, 334 .reg_offset = mtk_pwm_reg_offset_v2, 335 }; 336 337 static const struct pwm_mediatek_of_data mt7986_pwm_data = { 338 .num_pwms = 2, 339 .pwm45_fixup = false, 340 .has_ck_26m_sel = true, 341 .reg_offset = mtk_pwm_reg_offset_v1, 342 }; 343 344 static const struct pwm_mediatek_of_data mt8183_pwm_data = { 345 .num_pwms = 4, 346 .pwm45_fixup = false, 347 .has_ck_26m_sel = true, 348 .reg_offset = mtk_pwm_reg_offset_v1, 349 }; 350 351 static const struct pwm_mediatek_of_data mt8365_pwm_data = { 352 .num_pwms = 3, 353 .pwm45_fixup = false, 354 .has_ck_26m_sel = true, 355 .reg_offset = mtk_pwm_reg_offset_v1, 356 }; 357 358 static const struct pwm_mediatek_of_data mt8516_pwm_data = { 359 .num_pwms = 5, 360 .pwm45_fixup = false, 361 .has_ck_26m_sel = true, 362 .reg_offset = mtk_pwm_reg_offset_v1, 363 }; 364 365 static const struct of_device_id pwm_mediatek_of_match[] = { 366 { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data }, 367 { .compatible = "mediatek,mt6795-pwm", .data = &mt6795_pwm_data }, 368 { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, 369 { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, 370 { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, 371 { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data }, 372 { .compatible = "mediatek,mt7981-pwm", .data = &mt7981_pwm_data }, 373 { .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data }, 374 { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data }, 375 { .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data }, 376 { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data }, 377 { }, 378 }; 379 MODULE_DEVICE_TABLE(of, pwm_mediatek_of_match); 380 381 static struct platform_driver pwm_mediatek_driver = { 382 .driver = { 383 .name = "pwm-mediatek", 384 .of_match_table = pwm_mediatek_of_match, 385 }, 386 .probe = pwm_mediatek_probe, 387 }; 388 module_platform_driver(pwm_mediatek_driver); 389 390 MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); 391 MODULE_LICENSE("GPL v2"); 392