From patchwork Mon Nov 25 07:38:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Wu X-Patchwork-Id: 1200287 X-Patchwork-Delegate: ykai007@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=rock-chips.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 47LzRX1dStz9sP3 for ; Mon, 25 Nov 2019 18:38:30 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id F0208C21D83; Mon, 25 Nov 2019 07:38:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=RCVD_IN_SORBS_WEB autolearn=no autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id A6D26C21C4A; Mon, 25 Nov 2019 07:38:21 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id E52E1C21C4A; Mon, 25 Nov 2019 07:38:20 +0000 (UTC) Received: from lucky1.263xmail.com (lucky1.263xmail.com [211.157.147.134]) by lists.denx.de (Postfix) with ESMTPS id 766C2C21BE5 for ; Mon, 25 Nov 2019 07:38:19 +0000 (UTC) Received: from localhost (unknown [192.168.167.235]) by lucky1.263xmail.com (Postfix) with ESMTP id 663354AB15; Mon, 25 Nov 2019 15:38:16 +0800 (CST) X-MAIL-GRAY: 0 X-MAIL-DELIVERY: 1 X-ADDR-CHECKED4: 1 X-ANTISPAM-LEVEL: 2 X-ABS-CHECKED: 0 Received: from localhost.localdomain (unknown [58.22.7.114]) by smtp.263.net (postfix) whith ESMTP id P15554T140660950664960S1574667495991819_; Mon, 25 Nov 2019 15:38:17 +0800 (CST) X-IP-DOMAINF: 1 X-UNIQUE-TAG: <51cac70e6b50c2052770df4124163b2d> X-RL-SENDER: david.wu@rock-chips.com X-SENDER: wdc@rock-chips.com X-LOGIN-NAME: david.wu@rock-chips.com X-FST-TO: u-boot@lists.denx.de X-SENDER-IP: 58.22.7.114 X-ATTACHMENT-NUM: 0 X-DNS-TYPE: 0 From: David Wu To: u-boot@lists.denx.de Date: Mon, 25 Nov 2019 15:38:09 +0800 Message-Id: <20191125073809.11576-1-david.wu@rock-chips.com> X-Mailer: git-send-email 2.19.1 MIME-Version: 1.0 Cc: David Wu Subject: [U-Boot] [PATCH] pwm: rk_pwm: Make PWM driver to support all Rockchip Socs X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" The new PWM driver supports PWM polarity, lock and more functions. Signed-off-by: David Wu --- 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 #include +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}, { } };