1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
13 #include <linux/bitops.h>
16 /* PWM registers and bits definitions */
21 #define PWMWAVENUM 0x28
22 #define PWMDWIDTH 0x2c
23 #define PWM45DWIDTH_FIXUP 0x30
25 #define PWM45THRES_FIXUP 0x34
27 #define PWM_CLK_DIV_MAX 7
30 #define NSEC_PER_SEC 1000000000L
32 static const unsigned int mtk_pwm_reg_offset[] = {
33 0x0010, 0x0050, 0x0090, 0x00d0, 0x0110, 0x0150, 0x0190, 0x0220
37 unsigned int num_pwms;
45 struct clk pwm_clks[MAX_PWM_NUM];
46 const struct mtk_pwm_soc *soc;
49 static void mtk_pwm_w32(struct udevice *dev, uint channel, uint reg, uint val)
51 struct mtk_pwm_priv *priv = dev_get_priv(dev);
52 u32 offset = mtk_pwm_reg_offset[channel];
54 writel(val, priv->base + offset + reg);
57 static int mtk_pwm_set_config(struct udevice *dev, uint channel,
58 uint period_ns, uint duty_ns)
60 struct mtk_pwm_priv *priv = dev_get_priv(dev);
61 u32 clkdiv = 0, clksel = 0, cnt_period, cnt_duty,
62 reg_width = PWMDWIDTH, reg_thres = PWMTHRES;
66 clk_enable(&priv->top_clk);
67 clk_enable(&priv->main_clk);
68 /* Using resolution in picosecond gets accuracy higher */
69 resolution = (u64)NSEC_PER_SEC * 1000;
70 do_div(resolution, clk_get_rate(&priv->pwm_clks[channel]));
71 cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution);
72 while (cnt_period > 8191) {
75 cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000,
77 if (clkdiv > PWM_CLK_DIV_MAX && clksel == 0) {
80 resolution = (u64)NSEC_PER_SEC * 1000 * 1625;
82 clk_get_rate(&priv->pwm_clks[channel]));
83 cnt_period = DIV_ROUND_CLOSEST_ULL(
84 (u64)period_ns * 1000, resolution);
85 clk_enable(&priv->pwm_clks[channel]);
88 if (clkdiv > PWM_CLK_DIV_MAX && clksel == 1) {
89 printf("pwm period %u not supported\n", period_ns);
92 if (priv->soc->pwm45_fixup && channel > 2) {
94 * PWM[4,5] has distinct offset for PWMDWIDTH and PWMTHRES
95 * from the other PWMs on MT7623.
97 reg_width = PWM45DWIDTH_FIXUP;
98 reg_thres = PWM45THRES_FIXUP;
100 cnt_duty = DIV_ROUND_CLOSEST_ULL((u64)duty_ns * 1000, resolution);
102 mtk_pwm_w32(dev, channel, PWMCON, BIT(15) | BIT(3) | clkdiv);
104 mtk_pwm_w32(dev, channel, PWMCON, BIT(15) | clkdiv);
105 mtk_pwm_w32(dev, channel, reg_width, cnt_period);
106 mtk_pwm_w32(dev, channel, reg_thres, cnt_duty);
111 static int mtk_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
113 struct mtk_pwm_priv *priv = dev_get_priv(dev);
116 val = readl(priv->base);
120 val &= ~BIT(channel);
121 writel(val, priv->base);
126 static int mtk_pwm_probe(struct udevice *dev)
128 struct mtk_pwm_priv *priv = dev_get_priv(dev);
132 priv->soc = (struct mtk_pwm_soc *)dev_get_driver_data(dev);
133 priv->base = (void __iomem *)devfdt_get_addr(dev);
136 ret = clk_get_by_name(dev, "top", &priv->top_clk);
139 ret = clk_get_by_name(dev, "main", &priv->main_clk);
142 for (i = 0; i < priv->soc->num_pwms; i++) {
145 snprintf(name, sizeof(name), "pwm%d", i + 1);
146 ret = clk_get_by_name(dev, name, &priv->pwm_clks[i]);
154 static const struct pwm_ops mtk_pwm_ops = {
155 .set_config = mtk_pwm_set_config,
156 .set_enable = mtk_pwm_set_enable,
159 static const struct mtk_pwm_soc mt7622_data = {
161 .pwm45_fixup = false,
164 static const struct mtk_pwm_soc mt7623_data = {
169 static const struct mtk_pwm_soc mt7629_data = {
171 .pwm45_fixup = false,
174 static const struct udevice_id mtk_pwm_ids[] = {
175 { .compatible = "mediatek,mt7622-pwm", .data = (ulong)&mt7622_data },
176 { .compatible = "mediatek,mt7623-pwm", .data = (ulong)&mt7623_data },
177 { .compatible = "mediatek,mt7629-pwm", .data = (ulong)&mt7629_data },
181 U_BOOT_DRIVER(mtk_pwm) = {
184 .of_match = mtk_pwm_ids,
186 .probe = mtk_pwm_probe,
187 .priv_auto_alloc_size = sizeof(struct mtk_pwm_priv),