xref: /OK3568_Linux_fs/u-boot/drivers/pwm/rk_pwm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 2016 Google, Inc
3  * Written by Simon Glass <sjg@chromium.org>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <clk.h>
10 #include <div64.h>
11 #include <dm.h>
12 #include <dm/pinctrl.h>
13 #include <pwm.h>
14 #include <regmap.h>
15 #include <syscon.h>
16 #include <asm/io.h>
17 #include <asm/arch/pwm.h>
18 #include <power/regulator.h>
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 struct rockchip_pwm_data {
23 	struct rockchip_pwm_regs regs;
24 	unsigned int prescaler;
25 	bool supports_polarity;
26 	bool supports_lock;
27 	bool vop_pwm;
28 	u32 enable_conf;
29 	u32 enable_conf_mask;
30 };
31 
32 struct rk_pwm_priv {
33 	fdt_addr_t base;
34 	ulong freq;
35 	u32 conf_polarity;
36 	bool vop_pwm_en; /* indicate voppwm mirror register state */
37 	const struct rockchip_pwm_data *data;
38 };
39 
rk_pwm_set_invert(struct udevice * dev,uint channel,bool polarity)40 static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
41 {
42 	struct rk_pwm_priv *priv = dev_get_priv(dev);
43 
44 	if (!priv->data->supports_polarity) {
45 		debug("%s: Do not support polarity\n", __func__);
46 		return 0;
47 	}
48 
49 	debug("%s: polarity=%u\n", __func__, polarity);
50 	if (polarity)
51 		priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
52 	else
53 		priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
54 
55 	return 0;
56 }
57 
rk_pwm_set_config(struct udevice * dev,uint channel,uint period_ns,uint duty_ns)58 static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
59 			     uint duty_ns)
60 {
61 	struct rk_pwm_priv *priv = dev_get_priv(dev);
62 	const struct rockchip_pwm_regs *regs = &priv->data->regs;
63 	unsigned long period, duty;
64 	u32 ctrl;
65 
66 	debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
67 
68 	ctrl = readl(priv->base + regs->ctrl);
69 	if (priv->data->vop_pwm) {
70 		if (priv->vop_pwm_en)
71 			ctrl |= RK_PWM_ENABLE;
72 		else
73 			ctrl &= ~RK_PWM_ENABLE;
74 	}
75 
76 	/*
77 	 * Lock the period and duty of previous configuration, then
78 	 * change the duty and period, that would not be effective.
79 	 */
80 	if (priv->data->supports_lock) {
81 		ctrl |= PWM_LOCK;
82 		writel(ctrl, priv->base + regs->ctrl);
83 	}
84 
85 	period = lldiv((uint64_t)(priv->freq / 1000) * period_ns,
86 		       priv->data->prescaler * 1000000);
87 	duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns,
88 		     priv->data->prescaler * 1000000);
89 
90 	writel(period, priv->base + regs->period);
91 	writel(duty, priv->base + regs->duty);
92 
93 	if (priv->data->supports_polarity) {
94 		ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK);
95 		ctrl |= priv->conf_polarity;
96 	}
97 
98 	/*
99 	 * Unlock and set polarity at the same time,
100 	 * the configuration of duty, period and polarity
101 	 * would be effective together at next period.
102 	 */
103 	if (priv->data->supports_lock)
104 		ctrl &= ~PWM_LOCK;
105 	writel(ctrl, priv->base + regs->ctrl);
106 
107 	debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
108 
109 	return 0;
110 }
111 
rk_pwm_set_enable(struct udevice * dev,uint channel,bool enable)112 static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
113 {
114 	struct rk_pwm_priv *priv = dev_get_priv(dev);
115 	const struct rockchip_pwm_regs *regs = &priv->data->regs;
116 	u32 ctrl;
117 
118 	debug("%s: Enable '%s'\n", __func__, dev->name);
119 
120 	ctrl = readl(priv->base + regs->ctrl);
121 	ctrl &= ~priv->data->enable_conf_mask;
122 
123 	if (enable)
124 		ctrl |= priv->data->enable_conf;
125 	else
126 		ctrl &= ~priv->data->enable_conf;
127 
128 	writel(ctrl, priv->base + regs->ctrl);
129 	if (priv->data->vop_pwm)
130 		priv->vop_pwm_en = enable;
131 
132 	if (enable)
133 		pinctrl_select_state(dev, "active");
134 
135 	return 0;
136 }
137 
rk_pwm_ofdata_to_platdata(struct udevice * dev)138 static int rk_pwm_ofdata_to_platdata(struct udevice *dev)
139 {
140 	struct rk_pwm_priv *priv = dev_get_priv(dev);
141 
142 	priv->base = dev_read_addr(dev);
143 
144 	return 0;
145 }
146 
rk_pwm_probe(struct udevice * dev)147 static int rk_pwm_probe(struct udevice *dev)
148 {
149 	struct rk_pwm_priv *priv = dev_get_priv(dev);
150 	struct clk clk;
151 	int ret = 0;
152 
153 	ret = clk_get_by_index(dev, 0, &clk);
154 	if (ret < 0) {
155 		debug("%s get clock fail!\n", __func__);
156 		return -EINVAL;
157 	}
158 
159 	ret = clk_get_rate(&clk);
160 	if (ret < 0) {
161 		debug("%s pwm get clock rate fail!\n", __func__);
162 		return -EINVAL;
163 	}
164 	priv->freq = ret;
165 	priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev);
166 
167 	if (priv->data->supports_polarity)
168 		priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
169 
170 	return 0;
171 }
172 
173 static const struct pwm_ops rk_pwm_ops = {
174 	.set_invert	= rk_pwm_set_invert,
175 	.set_config	= rk_pwm_set_config,
176 	.set_enable	= rk_pwm_set_enable,
177 };
178 
179 static const struct rockchip_pwm_data pwm_data_v1 = {
180 	.regs = {
181 		.duty = 0x04,
182 		.period = 0x08,
183 		.cntr = 0x00,
184 		.ctrl = 0x0c,
185 	},
186 	.prescaler = 2,
187 	.supports_polarity = false,
188 	.supports_lock = false,
189 	.vop_pwm = false,
190 	.enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
191 	.enable_conf_mask = BIT(1) | BIT(3),
192 };
193 
194 static const struct rockchip_pwm_data pwm_data_v2 = {
195 	.regs = {
196 		.duty = 0x08,
197 		.period = 0x04,
198 		.cntr = 0x00,
199 		.ctrl = 0x0c,
200 	},
201 	.prescaler = 1,
202 	.supports_polarity = true,
203 	.supports_lock = false,
204 	.vop_pwm = false,
205 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
206 		       PWM_CONTINUOUS,
207 	.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
208 };
209 
210 static const struct rockchip_pwm_data pwm_data_vop = {
211 	.regs = {
212 		.duty = 0x08,
213 		.period = 0x04,
214 		.cntr = 0x0c,
215 		.ctrl = 0x00,
216 	},
217 	.prescaler = 1,
218 	.supports_polarity = true,
219 	.supports_lock = false,
220 	.vop_pwm = true,
221 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
222 		       PWM_CONTINUOUS,
223 	.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
224 };
225 
226 static const struct rockchip_pwm_data pwm_data_v3 = {
227 	.regs = {
228 		.duty = 0x08,
229 		.period = 0x04,
230 		.cntr = 0x00,
231 		.ctrl = 0x0c,
232 	},
233 	.prescaler = 1,
234 	.supports_polarity = true,
235 	.supports_lock = true,
236 	.vop_pwm = false,
237 	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
238 		       PWM_CONTINUOUS,
239 	.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
240 };
241 
242 static const struct udevice_id rk_pwm_ids[] = {
243 	{ .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1},
244 	{ .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2},
245 	{ .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3},
246 	{ .compatible = "rockchip,vop-pwm", .data = (ulong)&pwm_data_vop},
247 	{ .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2},
248 	{ }
249 };
250 
251 U_BOOT_DRIVER(rk_pwm) = {
252 	.name	= "rk_pwm",
253 	.id	= UCLASS_PWM,
254 	.of_match = rk_pwm_ids,
255 	.ops	= &rk_pwm_ops,
256 	.ofdata_to_platdata	= rk_pwm_ofdata_to_platdata,
257 	.probe		= rk_pwm_probe,
258 	.priv_auto_alloc_size	= sizeof(struct rk_pwm_priv),
259 };
260