10e23fd81SSimon Glass /*
20e23fd81SSimon Glass * Copyright (c) 2016 Google, Inc
30e23fd81SSimon Glass * Written by Simon Glass <sjg@chromium.org>
40e23fd81SSimon Glass *
50e23fd81SSimon Glass * SPDX-License-Identifier: GPL-2.0+
60e23fd81SSimon Glass */
70e23fd81SSimon Glass
80e23fd81SSimon Glass #include <common.h>
912406ae2SKever Yang #include <clk.h>
100e23fd81SSimon Glass #include <div64.h>
110e23fd81SSimon Glass #include <dm.h>
12bab0c55cSDavid Wu #include <dm/pinctrl.h>
130e23fd81SSimon Glass #include <pwm.h>
140e23fd81SSimon Glass #include <regmap.h>
150e23fd81SSimon Glass #include <syscon.h>
160e23fd81SSimon Glass #include <asm/io.h>
170e23fd81SSimon Glass #include <asm/arch/pwm.h>
180e23fd81SSimon Glass #include <power/regulator.h>
190e23fd81SSimon Glass
200e23fd81SSimon Glass DECLARE_GLOBAL_DATA_PTR;
210e23fd81SSimon Glass
226a624b88SDamon Ding /*
236a624b88SDamon Ding * regs for pwm v4
246a624b88SDamon Ding */
256a624b88SDamon Ding #define HIWORD_UPDATE(v, l, h) (((v) << (l)) | (GENMASK(h, l) << 16))
266a624b88SDamon Ding
276a624b88SDamon Ding /* VERSION_ID */
286a624b88SDamon Ding #define VERSION_ID 0x0
296a624b88SDamon Ding #define CHANNEL_NUM_SUPPORT_SHIFT 0
306a624b88SDamon Ding #define CHANNEL_NUM_SUPPORT_MASK (0xf << CHANNEL_NUM_SUPPORT_SHIFT)
316a624b88SDamon Ding #define CHANNLE_INDEX_SHIFT 4
326a624b88SDamon Ding #define CHANNLE_INDEX_MASK (0xf << CHANNLE_INDEX_SHIFT)
336a624b88SDamon Ding /* ENABLE */
346a624b88SDamon Ding #define ENABLE 0x4
356a624b88SDamon Ding #define PWM_ENABLE_V4 (0x3 << 0)
366a624b88SDamon Ding #define PWM_CLK_EN(v) HIWORD_UPDATE(v, 0, 0)
376a624b88SDamon Ding #define PWM_EN(v) HIWORD_UPDATE(v, 1, 1)
386a624b88SDamon Ding #define PWM_CTRL_UPDATE_EN(v) HIWORD_UPDATE(v, 2, 2)
396a624b88SDamon Ding #define PWM_GLOBAL_JOIN_EN(v) HIWORD_UPDATE(v, 4, 4)
406a624b88SDamon Ding /* CLK_CTRL */
416a624b88SDamon Ding #define CLK_CTRL 0x8
426a624b88SDamon Ding #define CLK_PRESCALE(v) HIWORD_UPDATE(v, 0, 2)
436a624b88SDamon Ding #define CLK_SCALE(v) HIWORD_UPDATE(v, 4, 12)
446a624b88SDamon Ding #define CLK_SRC_SEL(v) HIWORD_UPDATE(v, 13, 14)
456a624b88SDamon Ding #define CLK_GLOBAL_SEL(v) HIWORD_UPDATE(v, 15, 15)
466a624b88SDamon Ding /* CTRL */
476a624b88SDamon Ding #define CTRL_V4 0xc
486a624b88SDamon Ding #define PWM_MODE(v) HIWORD_UPDATE(v, 0, 1)
496a624b88SDamon Ding #define ONESHOT_MODE 0
506a624b88SDamon Ding #define CONTINUOUS_MODE 1
516a624b88SDamon Ding #define CAPTURE_MODE 2
526a624b88SDamon Ding #define PWM_POLARITY(v) HIWORD_UPDATE(v, 2, 3)
536a624b88SDamon Ding #define DUTY_NEGATIVE (0 << 0)
546a624b88SDamon Ding #define DUTY_POSITIVE (1 << 0)
556a624b88SDamon Ding #define INACTIVE_NEGATIVE (0 << 1)
566a624b88SDamon Ding #define INACTIVE_POSITIVE (1 << 1)
576a624b88SDamon Ding #define PWM_ALIGNED_INVALID(v) HIWORD_UPDATE(v, 5, 5)
586a624b88SDamon Ding #define PWM_IN_SEL(v) HIWORD_UPDATE(v, 6, 8)
596a624b88SDamon Ding /* PERIOD */
606a624b88SDamon Ding #define PERIOD 0x10
616a624b88SDamon Ding /* DUTY */
626a624b88SDamon Ding #define DUTY 0x14
63fdd40e00SDavid Wu
640e23fd81SSimon Glass struct rk_pwm_priv {
65fdd40e00SDavid Wu fdt_addr_t base;
6612406ae2SKever Yang ulong freq;
67fdd40e00SDavid Wu u32 conf_polarity;
68fdd40e00SDavid Wu bool vop_pwm_en; /* indicate voppwm mirror register state */
69fdd40e00SDavid Wu const struct rockchip_pwm_data *data;
700e23fd81SSimon Glass };
710e23fd81SSimon Glass
726a624b88SDamon Ding struct rockchip_pwm_funcs {
736a624b88SDamon Ding int (*set_invert)(struct udevice *dev, uint channel, bool polarity);
746a624b88SDamon Ding int (*set_config)(struct udevice *dev, uint channel,
756a624b88SDamon Ding uint period_ns, uint duty_ns);
766a624b88SDamon Ding int (*set_enable)(struct udevice *dev, uint channel, bool enable);
776a624b88SDamon Ding };
786a624b88SDamon Ding
796a624b88SDamon Ding struct rockchip_pwm_data {
806a624b88SDamon Ding struct rockchip_pwm_regs regs;
816a624b88SDamon Ding struct rockchip_pwm_funcs funcs;
826a624b88SDamon Ding unsigned int prescaler;
836a624b88SDamon Ding bool supports_polarity;
846a624b88SDamon Ding bool supports_lock;
856a624b88SDamon Ding bool vop_pwm;
866a624b88SDamon Ding u8 main_version;
876a624b88SDamon Ding u32 enable_conf;
886a624b88SDamon Ding u32 enable_conf_mask;
896a624b88SDamon Ding };
906a624b88SDamon Ding
rk_pwm_set_invert_v4(struct udevice * dev,uint channel,bool polarity)916a624b88SDamon Ding static int rk_pwm_set_invert_v4(struct udevice *dev, uint channel, bool polarity)
92874ee59aSKever Yang {
93874ee59aSKever Yang struct rk_pwm_priv *priv = dev_get_priv(dev);
94874ee59aSKever Yang
95874ee59aSKever Yang debug("%s: polarity=%u\n", __func__, polarity);
96874ee59aSKever Yang if (polarity)
97ef59b638SDamon Ding priv->conf_polarity = DUTY_NEGATIVE | INACTIVE_POSITIVE;
98874ee59aSKever Yang else
99ef59b638SDamon Ding priv->conf_polarity = DUTY_POSITIVE | INACTIVE_NEGATIVE;
100874ee59aSKever Yang
101874ee59aSKever Yang return 0;
102874ee59aSKever Yang }
103874ee59aSKever Yang
rk_pwm_set_invert_v1(struct udevice * dev,uint channel,bool polarity)1046a624b88SDamon Ding static int rk_pwm_set_invert_v1(struct udevice *dev, uint channel, bool polarity)
1056a624b88SDamon Ding {
1066a624b88SDamon Ding struct rk_pwm_priv *priv = dev_get_priv(dev);
1076a624b88SDamon Ding
1086a624b88SDamon Ding debug("%s: polarity=%u\n", __func__, polarity);
1096a624b88SDamon Ding if (polarity)
1106a624b88SDamon Ding priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
1116a624b88SDamon Ding else
1126a624b88SDamon Ding priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
1136a624b88SDamon Ding
1146a624b88SDamon Ding return 0;
1156a624b88SDamon Ding }
1166a624b88SDamon Ding
rk_pwm_set_invert(struct udevice * dev,uint channel,bool polarity)1176a624b88SDamon Ding static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
1186a624b88SDamon Ding {
1196a624b88SDamon Ding struct rk_pwm_priv *priv = dev_get_priv(dev);
1206a624b88SDamon Ding
1216a624b88SDamon Ding if (!priv->data->supports_polarity) {
1226a624b88SDamon Ding debug("%s: Do not support polarity\n", __func__);
1236a624b88SDamon Ding return 0;
1246a624b88SDamon Ding }
1256a624b88SDamon Ding
1266a624b88SDamon Ding return priv->data->funcs.set_invert(dev, channel, polarity);
1276a624b88SDamon Ding }
1286a624b88SDamon Ding
rk_pwm_set_config_v4(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)1296a624b88SDamon Ding static int rk_pwm_set_config_v4(struct udevice *dev, uint channel,
1306a624b88SDamon Ding uint period_ns, uint duty_ns)
1316a624b88SDamon Ding {
1326a624b88SDamon Ding struct rk_pwm_priv *priv = dev_get_priv(dev);
1336a624b88SDamon Ding unsigned long period, duty;
1346a624b88SDamon Ding
1356a624b88SDamon Ding period = lldiv((uint64_t)(priv->freq / 1000) * period_ns,
1366a624b88SDamon Ding priv->data->prescaler * 1000000);
1376a624b88SDamon Ding duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns,
1386a624b88SDamon Ding priv->data->prescaler * 1000000);
1396a624b88SDamon Ding
1406a624b88SDamon Ding writel(period, priv->base + PERIOD);
1416a624b88SDamon Ding writel(duty, priv->base + DUTY);
1426a624b88SDamon Ding
1436a624b88SDamon Ding if (priv->data->supports_polarity)
1446a624b88SDamon Ding writel(PWM_POLARITY(priv->conf_polarity), priv->base + CTRL_V4);
1456a624b88SDamon Ding
1466a624b88SDamon Ding writel(PWM_MODE(CONTINUOUS_MODE) | PWM_ALIGNED_INVALID(false),
1476a624b88SDamon Ding priv->base + CTRL_V4);
1486a624b88SDamon Ding
1496a624b88SDamon Ding writel(PWM_CTRL_UPDATE_EN(true), priv->base + ENABLE);
1506a624b88SDamon Ding
1516a624b88SDamon Ding debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
1526a624b88SDamon Ding
1536a624b88SDamon Ding return 0;
1546a624b88SDamon Ding }
1556a624b88SDamon Ding
rk_pwm_set_config_v1(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)1566a624b88SDamon Ding static int rk_pwm_set_config_v1(struct udevice *dev, uint channel,
1576a624b88SDamon Ding uint period_ns, uint duty_ns)
1580e23fd81SSimon Glass {
1590e23fd81SSimon Glass struct rk_pwm_priv *priv = dev_get_priv(dev);
160fdd40e00SDavid Wu const struct rockchip_pwm_regs *regs = &priv->data->regs;
1610e23fd81SSimon Glass unsigned long period, duty;
162fdd40e00SDavid Wu u32 ctrl;
1630e23fd81SSimon Glass
1640e23fd81SSimon Glass debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
165409b7b49SJoseph Chen
166fdd40e00SDavid Wu ctrl = readl(priv->base + regs->ctrl);
167fdd40e00SDavid Wu if (priv->data->vop_pwm) {
168fdd40e00SDavid Wu if (priv->vop_pwm_en)
169fdd40e00SDavid Wu ctrl |= RK_PWM_ENABLE;
170fdd40e00SDavid Wu else
171fdd40e00SDavid Wu ctrl &= ~RK_PWM_ENABLE;
172fdd40e00SDavid Wu }
1730e23fd81SSimon Glass
174fdd40e00SDavid Wu /*
175fdd40e00SDavid Wu * Lock the period and duty of previous configuration, then
176fdd40e00SDavid Wu * change the duty and period, that would not be effective.
177fdd40e00SDavid Wu */
178fdd40e00SDavid Wu if (priv->data->supports_lock) {
179fdd40e00SDavid Wu ctrl |= PWM_LOCK;
180fdd40e00SDavid Wu writel(ctrl, priv->base + regs->ctrl);
181fdd40e00SDavid Wu }
1820e23fd81SSimon Glass
183fdd40e00SDavid Wu period = lldiv((uint64_t)(priv->freq / 1000) * period_ns,
184fdd40e00SDavid Wu priv->data->prescaler * 1000000);
185fdd40e00SDavid Wu duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns,
186fdd40e00SDavid Wu priv->data->prescaler * 1000000);
187fdd40e00SDavid Wu
188fdd40e00SDavid Wu writel(period, priv->base + regs->period);
189fdd40e00SDavid Wu writel(duty, priv->base + regs->duty);
190fdd40e00SDavid Wu
191fdd40e00SDavid Wu if (priv->data->supports_polarity) {
192fdd40e00SDavid Wu ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK);
193fdd40e00SDavid Wu ctrl |= priv->conf_polarity;
194fdd40e00SDavid Wu }
195fdd40e00SDavid Wu
196fdd40e00SDavid Wu /*
197fdd40e00SDavid Wu * Unlock and set polarity at the same time,
198fdd40e00SDavid Wu * the configuration of duty, period and polarity
199fdd40e00SDavid Wu * would be effective together at next period.
200fdd40e00SDavid Wu */
201fdd40e00SDavid Wu if (priv->data->supports_lock)
202fdd40e00SDavid Wu ctrl &= ~PWM_LOCK;
203fdd40e00SDavid Wu writel(ctrl, priv->base + regs->ctrl);
204fdd40e00SDavid Wu
2050e23fd81SSimon Glass debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
2060e23fd81SSimon Glass
2070e23fd81SSimon Glass return 0;
2080e23fd81SSimon Glass }
2090e23fd81SSimon Glass
rk_pwm_set_config(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)2106a624b88SDamon Ding static int rk_pwm_set_config(struct udevice *dev, uint channel,
2116a624b88SDamon Ding uint period_ns, uint duty_ns)
2126a624b88SDamon Ding {
2136a624b88SDamon Ding struct rk_pwm_priv *priv = dev_get_priv(dev);
2146a624b88SDamon Ding
2156a624b88SDamon Ding return priv->data->funcs.set_config(dev, channel, period_ns, duty_ns);
2166a624b88SDamon Ding }
2176a624b88SDamon Ding
rk_pwm_set_enable_v4(struct udevice * dev,uint channel,bool enable)2186a624b88SDamon Ding static int rk_pwm_set_enable_v4(struct udevice *dev, uint channel, bool enable)
2196a624b88SDamon Ding {
2206a624b88SDamon Ding struct rk_pwm_priv *priv = dev_get_priv(dev);
2216a624b88SDamon Ding
2226a624b88SDamon Ding debug("%s: Enable '%s'\n", __func__, dev->name);
2236a624b88SDamon Ding
2246a624b88SDamon Ding writel(PWM_EN(enable) | PWM_CLK_EN(enable), priv->base + ENABLE);
2256a624b88SDamon Ding
2266a624b88SDamon Ding if (enable)
2276a624b88SDamon Ding pinctrl_select_state(dev, "active");
2286a624b88SDamon Ding
2296a624b88SDamon Ding return 0;
2306a624b88SDamon Ding }
2316a624b88SDamon Ding
rk_pwm_set_enable_v1(struct udevice * dev,uint channel,bool enable)2326a624b88SDamon Ding static int rk_pwm_set_enable_v1(struct udevice *dev, uint channel, bool enable)
2330e23fd81SSimon Glass {
2340e23fd81SSimon Glass struct rk_pwm_priv *priv = dev_get_priv(dev);
235fdd40e00SDavid Wu const struct rockchip_pwm_regs *regs = &priv->data->regs;
236fdd40e00SDavid Wu u32 ctrl;
2370e23fd81SSimon Glass
2380e23fd81SSimon Glass debug("%s: Enable '%s'\n", __func__, dev->name);
239fdd40e00SDavid Wu
240fdd40e00SDavid Wu ctrl = readl(priv->base + regs->ctrl);
241fdd40e00SDavid Wu ctrl &= ~priv->data->enable_conf_mask;
242fdd40e00SDavid Wu
243fdd40e00SDavid Wu if (enable)
244fdd40e00SDavid Wu ctrl |= priv->data->enable_conf;
245fdd40e00SDavid Wu else
246fdd40e00SDavid Wu ctrl &= ~priv->data->enable_conf;
247fdd40e00SDavid Wu
248fdd40e00SDavid Wu writel(ctrl, priv->base + regs->ctrl);
249fdd40e00SDavid Wu if (priv->data->vop_pwm)
250fdd40e00SDavid Wu priv->vop_pwm_en = enable;
2510e23fd81SSimon Glass
252bab0c55cSDavid Wu if (enable)
253bab0c55cSDavid Wu pinctrl_select_state(dev, "active");
254bab0c55cSDavid Wu
2550e23fd81SSimon Glass return 0;
2560e23fd81SSimon Glass }
2570e23fd81SSimon Glass
rk_pwm_set_enable(struct udevice * dev,uint channel,bool enable)2586a624b88SDamon Ding static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
2596a624b88SDamon Ding {
2606a624b88SDamon Ding struct rk_pwm_priv *priv = dev_get_priv(dev);
2616a624b88SDamon Ding
2626a624b88SDamon Ding return priv->data->funcs.set_enable(dev, channel, enable);
2636a624b88SDamon Ding }
2646a624b88SDamon Ding
rk_pwm_ofdata_to_platdata(struct udevice * dev)2650e23fd81SSimon Glass static int rk_pwm_ofdata_to_platdata(struct udevice *dev)
2660e23fd81SSimon Glass {
2670e23fd81SSimon Glass struct rk_pwm_priv *priv = dev_get_priv(dev);
2680e23fd81SSimon Glass
269fdd40e00SDavid Wu priv->base = dev_read_addr(dev);
2700e23fd81SSimon Glass
2710e23fd81SSimon Glass return 0;
2720e23fd81SSimon Glass }
2730e23fd81SSimon Glass
274*9424aa84SFinley Xiao #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD)
rk_pwm_clk_init(struct udevice * dev)275*9424aa84SFinley Xiao static int rk_pwm_clk_init(struct udevice *dev)
276*9424aa84SFinley Xiao {
277*9424aa84SFinley Xiao struct clk_bulk clks = { 0 };
278*9424aa84SFinley Xiao int ret = 0;
279*9424aa84SFinley Xiao
280*9424aa84SFinley Xiao ret = clk_get_bulk(dev, &clks);
281*9424aa84SFinley Xiao if (ret == -ENOSYS || ret == -ENOENT)
282*9424aa84SFinley Xiao return 0;
283*9424aa84SFinley Xiao if (ret) {
284*9424aa84SFinley Xiao dev_err(dev, "failed to get clk: %d\n", ret);
285*9424aa84SFinley Xiao return ret;
286*9424aa84SFinley Xiao }
287*9424aa84SFinley Xiao
288*9424aa84SFinley Xiao ret = clk_enable_bulk(&clks);
289*9424aa84SFinley Xiao if (ret) {
290*9424aa84SFinley Xiao dev_err(dev, "failed to enable clk: %d\n", ret);
291*9424aa84SFinley Xiao clk_release_bulk(&clks);
292*9424aa84SFinley Xiao return ret;
293*9424aa84SFinley Xiao }
294*9424aa84SFinley Xiao
295*9424aa84SFinley Xiao return 0;
296*9424aa84SFinley Xiao }
297*9424aa84SFinley Xiao #endif
298*9424aa84SFinley Xiao
rk_pwm_probe(struct udevice * dev)2990e23fd81SSimon Glass static int rk_pwm_probe(struct udevice *dev)
3000e23fd81SSimon Glass {
3010e23fd81SSimon Glass struct rk_pwm_priv *priv = dev_get_priv(dev);
30212406ae2SKever Yang struct clk clk;
30312406ae2SKever Yang int ret = 0;
3040e23fd81SSimon Glass
30512406ae2SKever Yang ret = clk_get_by_index(dev, 0, &clk);
30612406ae2SKever Yang if (ret < 0) {
30712406ae2SKever Yang debug("%s get clock fail!\n", __func__);
30812406ae2SKever Yang return -EINVAL;
30912406ae2SKever Yang }
310fdd40e00SDavid Wu
31168cdac84SSteven Liu ret = clk_get_rate(&clk);
31268cdac84SSteven Liu if (ret < 0) {
31368cdac84SSteven Liu debug("%s pwm get clock rate fail!\n", __func__);
31468cdac84SSteven Liu return -EINVAL;
31568cdac84SSteven Liu }
31668cdac84SSteven Liu priv->freq = ret;
317fdd40e00SDavid Wu priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev);
318fdd40e00SDavid Wu
319ef59b638SDamon Ding if (priv->data->supports_polarity) {
320ef59b638SDamon Ding if (priv->data->main_version >= 4) {
321ef59b638SDamon Ding priv->conf_polarity = DUTY_POSITIVE | INACTIVE_NEGATIVE;
322ef59b638SDamon Ding } else {
323fdd40e00SDavid Wu priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
324ef59b638SDamon Ding }
325ef59b638SDamon Ding }
32612406ae2SKever Yang
327*9424aa84SFinley Xiao #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD)
328*9424aa84SFinley Xiao ret = rk_pwm_clk_init(dev);
329*9424aa84SFinley Xiao if (ret)
330*9424aa84SFinley Xiao return ret;
331*9424aa84SFinley Xiao #endif
332*9424aa84SFinley Xiao
3330e23fd81SSimon Glass return 0;
3340e23fd81SSimon Glass }
3350e23fd81SSimon Glass
3360e23fd81SSimon Glass static const struct pwm_ops rk_pwm_ops = {
337874ee59aSKever Yang .set_invert = rk_pwm_set_invert,
3380e23fd81SSimon Glass .set_config = rk_pwm_set_config,
3390e23fd81SSimon Glass .set_enable = rk_pwm_set_enable,
3400e23fd81SSimon Glass };
3410e23fd81SSimon Glass
342fdd40e00SDavid Wu static const struct rockchip_pwm_data pwm_data_v1 = {
3436a624b88SDamon Ding .main_version = 0x01,
344fdd40e00SDavid Wu .regs = {
3456a624b88SDamon Ding .version = 0x5c,
346fdd40e00SDavid Wu .duty = 0x04,
347fdd40e00SDavid Wu .period = 0x08,
348fdd40e00SDavid Wu .ctrl = 0x0c,
349fdd40e00SDavid Wu },
350fdd40e00SDavid Wu .prescaler = 2,
351fdd40e00SDavid Wu .supports_polarity = false,
352fdd40e00SDavid Wu .supports_lock = false,
353fdd40e00SDavid Wu .vop_pwm = false,
354fdd40e00SDavid Wu .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
355fdd40e00SDavid Wu .enable_conf_mask = BIT(1) | BIT(3),
3566a624b88SDamon Ding .funcs = {
3576a624b88SDamon Ding .set_invert = rk_pwm_set_invert_v1,
3586a624b88SDamon Ding .set_config = rk_pwm_set_config_v1,
3596a624b88SDamon Ding .set_enable = rk_pwm_set_enable_v1,
3606a624b88SDamon Ding },
361fdd40e00SDavid Wu };
362fdd40e00SDavid Wu
363fdd40e00SDavid Wu static const struct rockchip_pwm_data pwm_data_v2 = {
3646a624b88SDamon Ding .main_version = 0x02,
365fdd40e00SDavid Wu .regs = {
3666a624b88SDamon Ding .version = 0x5c,
367fdd40e00SDavid Wu .duty = 0x08,
368fdd40e00SDavid Wu .period = 0x04,
369fdd40e00SDavid Wu .ctrl = 0x0c,
370fdd40e00SDavid Wu },
371fdd40e00SDavid Wu .prescaler = 1,
372fdd40e00SDavid Wu .supports_polarity = true,
373fdd40e00SDavid Wu .supports_lock = false,
374fdd40e00SDavid Wu .vop_pwm = false,
375fdd40e00SDavid Wu .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
376fdd40e00SDavid Wu PWM_CONTINUOUS,
377fdd40e00SDavid Wu .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
3786a624b88SDamon Ding .funcs = {
3796a624b88SDamon Ding .set_invert = rk_pwm_set_invert_v1,
3806a624b88SDamon Ding .set_config = rk_pwm_set_config_v1,
3816a624b88SDamon Ding .set_enable = rk_pwm_set_enable_v1,
3826a624b88SDamon Ding },
383fdd40e00SDavid Wu };
384fdd40e00SDavid Wu
385fdd40e00SDavid Wu static const struct rockchip_pwm_data pwm_data_vop = {
3866a624b88SDamon Ding .main_version = 0x02,
387fdd40e00SDavid Wu .regs = {
3886a624b88SDamon Ding .version = 0x5c,
389fdd40e00SDavid Wu .duty = 0x08,
390fdd40e00SDavid Wu .period = 0x04,
391fdd40e00SDavid Wu .ctrl = 0x00,
392fdd40e00SDavid Wu },
393fdd40e00SDavid Wu .prescaler = 1,
394fdd40e00SDavid Wu .supports_polarity = true,
395fdd40e00SDavid Wu .supports_lock = false,
396fdd40e00SDavid Wu .vop_pwm = true,
397fdd40e00SDavid Wu .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
398fdd40e00SDavid Wu PWM_CONTINUOUS,
399fdd40e00SDavid Wu .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
4006a624b88SDamon Ding .funcs = {
4016a624b88SDamon Ding .set_invert = rk_pwm_set_invert_v1,
4026a624b88SDamon Ding .set_config = rk_pwm_set_config_v1,
4036a624b88SDamon Ding .set_enable = rk_pwm_set_enable_v1,
4046a624b88SDamon Ding },
405fdd40e00SDavid Wu };
406fdd40e00SDavid Wu
407fdd40e00SDavid Wu static const struct rockchip_pwm_data pwm_data_v3 = {
4086a624b88SDamon Ding .main_version = 0x03,
409fdd40e00SDavid Wu .regs = {
4106a624b88SDamon Ding .version = 0x5c,
411fdd40e00SDavid Wu .duty = 0x08,
412fdd40e00SDavid Wu .period = 0x04,
413fdd40e00SDavid Wu .ctrl = 0x0c,
414fdd40e00SDavid Wu },
415fdd40e00SDavid Wu .prescaler = 1,
416fdd40e00SDavid Wu .supports_polarity = true,
417fdd40e00SDavid Wu .supports_lock = true,
418fdd40e00SDavid Wu .vop_pwm = false,
419fdd40e00SDavid Wu .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
420fdd40e00SDavid Wu PWM_CONTINUOUS,
421fdd40e00SDavid Wu .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
4226a624b88SDamon Ding .funcs = {
4236a624b88SDamon Ding .set_invert = rk_pwm_set_invert_v1,
4246a624b88SDamon Ding .set_config = rk_pwm_set_config_v1,
4256a624b88SDamon Ding .set_enable = rk_pwm_set_enable_v1,
4266a624b88SDamon Ding },
4276a624b88SDamon Ding };
4286a624b88SDamon Ding
4296a624b88SDamon Ding static const struct rockchip_pwm_data pwm_data_v4 = {
4306a624b88SDamon Ding .main_version = 0x04,
4316a624b88SDamon Ding .regs = {
4326a624b88SDamon Ding .version = 0x0,
4336a624b88SDamon Ding .enable = 0x4,
4346a624b88SDamon Ding .ctrl = 0xc,
4356a624b88SDamon Ding .period = 0x10,
4366a624b88SDamon Ding .duty = 0x14,
4376a624b88SDamon Ding },
4386a624b88SDamon Ding .prescaler = 1,
4396a624b88SDamon Ding .supports_polarity = true,
4406a624b88SDamon Ding .supports_lock = true,
4416a624b88SDamon Ding .vop_pwm = false,
4426a624b88SDamon Ding .enable_conf = PWM_ENABLE_V4,
4436a624b88SDamon Ding .funcs = {
4446a624b88SDamon Ding .set_invert = rk_pwm_set_invert_v4,
4456a624b88SDamon Ding .set_config = rk_pwm_set_config_v4,
4466a624b88SDamon Ding .set_enable = rk_pwm_set_enable_v4,
4476a624b88SDamon Ding },
448fdd40e00SDavid Wu };
449fdd40e00SDavid Wu
4500e23fd81SSimon Glass static const struct udevice_id rk_pwm_ids[] = {
451fdd40e00SDavid Wu { .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1},
452fdd40e00SDavid Wu { .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2},
453fdd40e00SDavid Wu { .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3},
454fdd40e00SDavid Wu { .compatible = "rockchip,vop-pwm", .data = (ulong)&pwm_data_vop},
455fdd40e00SDavid Wu { .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2},
4566a624b88SDamon Ding { .compatible = "rockchip,rk3576-pwm", .data = (ulong)&pwm_data_v4},
4570e23fd81SSimon Glass { }
4580e23fd81SSimon Glass };
4590e23fd81SSimon Glass
4600e23fd81SSimon Glass U_BOOT_DRIVER(rk_pwm) = {
4610e23fd81SSimon Glass .name = "rk_pwm",
4620e23fd81SSimon Glass .id = UCLASS_PWM,
4630e23fd81SSimon Glass .of_match = rk_pwm_ids,
4640e23fd81SSimon Glass .ops = &rk_pwm_ops,
4650e23fd81SSimon Glass .ofdata_to_platdata = rk_pwm_ofdata_to_platdata,
4660e23fd81SSimon Glass .probe = rk_pwm_probe,
4670e23fd81SSimon Glass .priv_auto_alloc_size = sizeof(struct rk_pwm_priv),
4680e23fd81SSimon Glass };
469