[U-Boot] [PATCH] pwm: rk_pwm: Make PWM driver to support all Rockchip Socs

The new PWM driver supports PWM polarity, lock and more functions.
Signed-off-by: David Wu david.wu@rock-chips.com --- arch/arm/include/asm/arch-rockchip/pwm.h | 17 ++- drivers/pwm/rk_pwm.c | 139 +++++++++++++++++++---- 2 files changed, 131 insertions(+), 25 deletions(-)
diff --git a/arch/arm/include/asm/arch-rockchip/pwm.h b/arch/arm/include/asm/arch-rockchip/pwm.h index b5178db394..e8594055cd 100644 --- a/arch/arm/include/asm/arch-rockchip/pwm.h +++ b/arch/arm/include/asm/arch-rockchip/pwm.h @@ -7,13 +7,15 @@ #ifndef _ASM_ARCH_PWM_H #define _ASM_ARCH_PWM_H
-struct rk3288_pwm { - u32 cnt; - u32 period_hpr; - u32 duty_lpr; - u32 ctrl; +struct rockchip_pwm_regs { + unsigned long duty; + unsigned long period; + unsigned long cntr; + unsigned long ctrl; }; -check_member(rk3288_pwm, ctrl, 0xc); + +#define PWM_CTRL_TIMER_EN (1 << 0) +#define PWM_CTRL_OUTPUT_EN (1 << 3)
#define RK_PWM_DISABLE (0 << 0) #define RK_PWM_ENABLE (1 << 0) @@ -33,6 +35,9 @@ check_member(rk3288_pwm, ctrl, 0xc); #define PWM_OUTPUT_LEFT (0 << 5) #define PWM_OUTPUT_CENTER (1 << 5)
+#define PWM_LOCK (1 << 6) +#define PWM_UNLOCK (0 << 6) + #define PWM_LP_ENABLE (1 << 8) #define PWM_LP_DISABLE (0 << 8)
diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c index 88db294cf1..c9d9b7c11b 100644 --- a/drivers/pwm/rk_pwm.c +++ b/drivers/pwm/rk_pwm.c @@ -15,22 +15,38 @@ #include <asm/arch-rockchip/pwm.h> #include <power/regulator.h>
+DECLARE_GLOBAL_DATA_PTR; + +struct rockchip_pwm_data { + struct rockchip_pwm_regs regs; + unsigned int prescaler; + bool supports_polarity; + bool supports_lock; + u32 enable_conf; + u32 enable_conf_mask; +}; + struct rk_pwm_priv { - struct rk3288_pwm *regs; + fdt_addr_t base; ulong freq; - uint enable_conf; + u32 conf_polarity; + const struct rockchip_pwm_data *data; };
static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity) { struct rk_pwm_priv *priv = dev_get_priv(dev);
+ if (!priv->data->supports_polarity) { + debug("%s: Do not support polarity\n", __func__); + return 0; + } + debug("%s: polarity=%u\n", __func__, polarity); - priv->enable_conf &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK); if (polarity) - priv->enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE; + priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE; else - priv->enable_conf |= PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE; + priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
return 0; } @@ -39,20 +55,44 @@ static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns, uint duty_ns) { struct rk_pwm_priv *priv = dev_get_priv(dev); - struct rk3288_pwm *regs = priv->regs; + const struct rockchip_pwm_regs *regs = &priv->data->regs; unsigned long period, duty; + u32 ctrl;
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns); - writel(PWM_SEL_SRC_CLK | PWM_OUTPUT_LEFT | PWM_LP_DISABLE | - PWM_CONTINUOUS | priv->enable_conf | - RK_PWM_DISABLE, - ®s->ctrl);
- period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 1000000); - duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 1000000); + ctrl = readl(priv->base + regs->ctrl); + /* + * Lock the period and duty of previous configuration, then + * change the duty and period, that would not be effective. + */ + if (priv->data->supports_lock) { + ctrl |= PWM_LOCK; + writel(ctrl, priv->base + regs->ctrl); + } + + period = lldiv((uint64_t)priv->freq * period_ns, + priv->data->prescaler * 1000000000); + duty = lldiv((uint64_t)priv->freq * duty_ns, + priv->data->prescaler * 1000000000); + + writel(period, priv->base + regs->period); + writel(duty, priv->base + regs->duty); + + if (priv->data->supports_polarity) { + ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK); + ctrl |= priv->conf_polarity; + } + + /* + * Unlock and set polarity at the same time, + * the configuration of duty, period and polarity + * would be effective together at next period. + */ + if (priv->data->supports_lock) + ctrl &= ~PWM_LOCK; + writel(ctrl, priv->base + regs->ctrl);
- writel(period, ®s->period_hpr); - writel(duty, ®s->duty_lpr); debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
return 0; @@ -61,10 +101,20 @@ static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns, static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable) { struct rk_pwm_priv *priv = dev_get_priv(dev); - struct rk3288_pwm *regs = priv->regs; + const struct rockchip_pwm_regs *regs = &priv->data->regs; + u32 ctrl;
debug("%s: Enable '%s'\n", __func__, dev->name); - clrsetbits_le32(®s->ctrl, RK_PWM_ENABLE, enable ? RK_PWM_ENABLE : 0); + + ctrl = readl(priv->base + regs->ctrl); + ctrl &= ~priv->data->enable_conf_mask; + + if (enable) + ctrl |= priv->data->enable_conf; + else + ctrl &= ~priv->data->enable_conf; + + writel(ctrl, priv->base + regs->ctrl);
return 0; } @@ -73,7 +123,7 @@ static int rk_pwm_ofdata_to_platdata(struct udevice *dev) { struct rk_pwm_priv *priv = dev_get_priv(dev);
- priv->regs = (struct rk3288_pwm *)dev_read_addr(dev); + priv->base = dev_read_addr(dev);
return 0; } @@ -89,8 +139,12 @@ static int rk_pwm_probe(struct udevice *dev) debug("%s get clock fail!\n", __func__); return -EINVAL; } + priv->freq = clk_get_rate(&clk); - priv->enable_conf = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE; + priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev); + + if (priv->data->supports_polarity) + priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
return 0; } @@ -101,8 +155,55 @@ static const struct pwm_ops rk_pwm_ops = { .set_enable = rk_pwm_set_enable, };
+static const struct rockchip_pwm_data pwm_data_v1 = { + .regs = { + .duty = 0x04, + .period = 0x08, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 2, + .supports_polarity = false, + .supports_lock = false, + .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN, + .enable_conf_mask = BIT(1) | BIT(3), +}; + +static const struct rockchip_pwm_data pwm_data_v2 = { + .regs = { + .duty = 0x08, + .period = 0x04, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 1, + .supports_polarity = true, + .supports_lock = false, + .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | + PWM_CONTINUOUS, + .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), +}; + +static const struct rockchip_pwm_data pwm_data_v3 = { + .regs = { + .duty = 0x08, + .period = 0x04, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 1, + .supports_polarity = true, + .supports_lock = true, + .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | + PWM_CONTINUOUS, + .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), +}; + static const struct udevice_id rk_pwm_ids[] = { - { .compatible = "rockchip,rk3288-pwm" }, + { .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1}, + { .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2}, + { .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3}, + { .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2}, { } };

Hi David,
On 2019/11/25 下午3:38, David Wu wrote:
The new PWM driver supports PWM polarity, lock and more functions.
Please add a little bit more info about the patch, eg. the difference for pwm v1 vs v2 vs v3.
Thanks,
- Kever
Signed-off-by: David Wu david.wu@rock-chips.com
arch/arm/include/asm/arch-rockchip/pwm.h | 17 ++- drivers/pwm/rk_pwm.c | 139 +++++++++++++++++++---- 2 files changed, 131 insertions(+), 25 deletions(-)
diff --git a/arch/arm/include/asm/arch-rockchip/pwm.h b/arch/arm/include/asm/arch-rockchip/pwm.h index b5178db394..e8594055cd 100644 --- a/arch/arm/include/asm/arch-rockchip/pwm.h +++ b/arch/arm/include/asm/arch-rockchip/pwm.h @@ -7,13 +7,15 @@ #ifndef _ASM_ARCH_PWM_H #define _ASM_ARCH_PWM_H
-struct rk3288_pwm {
- u32 cnt;
- u32 period_hpr;
- u32 duty_lpr;
- u32 ctrl;
+struct rockchip_pwm_regs {
- unsigned long duty;
- unsigned long period;
- unsigned long cntr;
- unsigned long ctrl; };
-check_member(rk3288_pwm, ctrl, 0xc);
+#define PWM_CTRL_TIMER_EN (1 << 0) +#define PWM_CTRL_OUTPUT_EN (1 << 3)
#define RK_PWM_DISABLE (0 << 0) #define RK_PWM_ENABLE (1 << 0) @@ -33,6 +35,9 @@ check_member(rk3288_pwm, ctrl, 0xc); #define PWM_OUTPUT_LEFT (0 << 5) #define PWM_OUTPUT_CENTER (1 << 5)
+#define PWM_LOCK (1 << 6) +#define PWM_UNLOCK (0 << 6)
- #define PWM_LP_ENABLE (1 << 8) #define PWM_LP_DISABLE (0 << 8)
diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c index 88db294cf1..c9d9b7c11b 100644 --- a/drivers/pwm/rk_pwm.c +++ b/drivers/pwm/rk_pwm.c @@ -15,22 +15,38 @@ #include <asm/arch-rockchip/pwm.h> #include <power/regulator.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct rockchip_pwm_data {
- struct rockchip_pwm_regs regs;
- unsigned int prescaler;
- bool supports_polarity;
- bool supports_lock;
- u32 enable_conf;
- u32 enable_conf_mask;
+};
- struct rk_pwm_priv {
- struct rk3288_pwm *regs;
- fdt_addr_t base; ulong freq;
- uint enable_conf;
u32 conf_polarity;
const struct rockchip_pwm_data *data; };
static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity) { struct rk_pwm_priv *priv = dev_get_priv(dev);
if (!priv->data->supports_polarity) {
debug("%s: Do not support polarity\n", __func__);
return 0;
}
debug("%s: polarity=%u\n", __func__, polarity);
- priv->enable_conf &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK); if (polarity)
priv->enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
elsepriv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
priv->enable_conf |= PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
return 0; }
@@ -39,20 +55,44 @@ static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns, uint duty_ns) { struct rk_pwm_priv *priv = dev_get_priv(dev);
- struct rk3288_pwm *regs = priv->regs;
const struct rockchip_pwm_regs *regs = &priv->data->regs; unsigned long period, duty;
u32 ctrl;
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
writel(PWM_SEL_SRC_CLK | PWM_OUTPUT_LEFT | PWM_LP_DISABLE |
PWM_CONTINUOUS | priv->enable_conf |
RK_PWM_DISABLE,
®s->ctrl);
period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 1000000);
duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 1000000);
- ctrl = readl(priv->base + regs->ctrl);
- /*
* Lock the period and duty of previous configuration, then
* change the duty and period, that would not be effective.
*/
- if (priv->data->supports_lock) {
ctrl |= PWM_LOCK;
writel(ctrl, priv->base + regs->ctrl);
- }
- period = lldiv((uint64_t)priv->freq * period_ns,
priv->data->prescaler * 1000000000);
- duty = lldiv((uint64_t)priv->freq * duty_ns,
priv->data->prescaler * 1000000000);
- writel(period, priv->base + regs->period);
- writel(duty, priv->base + regs->duty);
- if (priv->data->supports_polarity) {
ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK);
ctrl |= priv->conf_polarity;
- }
- /*
* Unlock and set polarity at the same time,
* the configuration of duty, period and polarity
* would be effective together at next period.
*/
- if (priv->data->supports_lock)
ctrl &= ~PWM_LOCK;
- writel(ctrl, priv->base + regs->ctrl);
writel(period, ®s->period_hpr);
writel(duty, ®s->duty_lpr); debug("%s: period=%lu, duty=%lu\n", __func__, period, duty);
return 0;
@@ -61,10 +101,20 @@ static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns, static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable) { struct rk_pwm_priv *priv = dev_get_priv(dev);
- struct rk3288_pwm *regs = priv->regs;
const struct rockchip_pwm_regs *regs = &priv->data->regs;
u32 ctrl;
debug("%s: Enable '%s'\n", __func__, dev->name);
- clrsetbits_le32(®s->ctrl, RK_PWM_ENABLE, enable ? RK_PWM_ENABLE : 0);
ctrl = readl(priv->base + regs->ctrl);
ctrl &= ~priv->data->enable_conf_mask;
if (enable)
ctrl |= priv->data->enable_conf;
else
ctrl &= ~priv->data->enable_conf;
writel(ctrl, priv->base + regs->ctrl);
return 0; }
@@ -73,7 +123,7 @@ static int rk_pwm_ofdata_to_platdata(struct udevice *dev) { struct rk_pwm_priv *priv = dev_get_priv(dev);
- priv->regs = (struct rk3288_pwm *)dev_read_addr(dev);
priv->base = dev_read_addr(dev);
return 0; }
@@ -89,8 +139,12 @@ static int rk_pwm_probe(struct udevice *dev) debug("%s get clock fail!\n", __func__); return -EINVAL; }
- priv->freq = clk_get_rate(&clk);
- priv->enable_conf = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev);
if (priv->data->supports_polarity)
priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE;
return 0; }
@@ -101,8 +155,55 @@ static const struct pwm_ops rk_pwm_ops = { .set_enable = rk_pwm_set_enable, };
+static const struct rockchip_pwm_data pwm_data_v1 = {
- .regs = {
.duty = 0x04,
.period = 0x08,
.cntr = 0x00,
.ctrl = 0x0c,
- },
- .prescaler = 2,
- .supports_polarity = false,
- .supports_lock = false,
- .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
- .enable_conf_mask = BIT(1) | BIT(3),
+};
+static const struct rockchip_pwm_data pwm_data_v2 = {
- .regs = {
.duty = 0x08,
.period = 0x04,
.cntr = 0x00,
.ctrl = 0x0c,
- },
- .prescaler = 1,
- .supports_polarity = true,
- .supports_lock = false,
- .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
PWM_CONTINUOUS,
- .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
+};
+static const struct rockchip_pwm_data pwm_data_v3 = {
- .regs = {
.duty = 0x08,
.period = 0x04,
.cntr = 0x00,
.ctrl = 0x0c,
- },
- .prescaler = 1,
- .supports_polarity = true,
- .supports_lock = true,
- .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE |
PWM_CONTINUOUS,
- .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
+};
- static const struct udevice_id rk_pwm_ids[] = {
- { .compatible = "rockchip,rk3288-pwm" },
- { .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1},
- { .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2},
- { .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3},
- { .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2}, { } };
participants (2)
-
David Wu
-
Kever Yang