From patchwork Fri Jul 10 17:07:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Bosch X-Patchwork-Id: 241330 List-Id: U-Boot discussion From: stefan_b at posteo.net (Stefan Bosch) Date: Fri, 10 Jul 2020 19:07:31 +0200 Subject: [PATCH v4 07/14] pwm: add driver for nexell In-Reply-To: <1594400858-3140-1-git-send-email-stefan_b@posteo.net> References: <1594400858-3140-1-git-send-email-stefan_b@posteo.net> Message-ID: <1594400858-3140-8-git-send-email-stefan_b@posteo.net> Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01: - Since drivers/pwm/pwm-nexell.c is an adapted version of s5p-common/pwm.c an appropriately changed version of s5p-common/pwm.c is used instead. Therefore arch/arm/mach-s5pc1xx/include/mach/pwm.h copied to arch/arm/mach-nexell/include/mach and s5p-common/Makefile changed appropriately. - '#ifdef CONFIG...' changed to 'if (IS_ENABLED(CONFIG...))' where possible (and similar). Signed-off-by: Stefan Bosch --- (no changes since v3) Changes in v3: - Handling of Configs for LCD backlight control reworked because (among others) not setting CONFIG_S5P4418_ONEWIRE and/or CONFIG_PWM_NX has caused errors when compiling board/friendlyarm/nanopi2/onewire.c. - pwm.h: () around macro argument x added to avoid precedence issues. - '#ifdef...' changed to 'if (IS_ENABLED(CONFIG...))' where possible because of appropriate warnings of patman. Changes in v2: - commit "i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)" splitted into separate commits for gpio, i2c, mmc, pwm. - Since drivers/pwm/pwm-nexell.c is an adapted version of s5p-common/pwm.c an appropriately changed version of s5p-common/pwm.c is used now. Therefore arch/arm/mach-s5pc1xx/include/mach/pwm.h copied to arch/arm/mach-nexell/include/mach and s5p-common/Makefile changed appropriately. arch/arm/cpu/armv7/s5p-common/Makefile | 13 +++++--- arch/arm/cpu/armv7/s5p-common/pwm.c | 57 ++++++++++++++++++++++++++++++++- arch/arm/mach-nexell/include/mach/pwm.h | 54 +++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mach-nexell/include/mach/pwm.h diff --git a/arch/arm/cpu/armv7/s5p-common/Makefile b/arch/arm/cpu/armv7/s5p-common/Makefile index 12cf804..bfe0238 100644 --- a/arch/arm/cpu/armv7/s5p-common/Makefile +++ b/arch/arm/cpu/armv7/s5p-common/Makefile @@ -3,9 +3,14 @@ # Copyright (C) 2009 Samsung Electronics # Minkyu Kang -obj-y += cpu_info.o +ifdef CONFIG_ARCH_NEXELL +obj-$(CONFIG_PWM_NX) += pwm.o +obj-$(CONFIG_S5P4418_ONEWIRE) += pwm.o +else +obj-y += cpu_info.o ifndef CONFIG_SPL_BUILD -obj-y += timer.o -obj-y += sromc.o -obj-$(CONFIG_PWM) += pwm.o +obj-y += timer.o +obj-y += sromc.o +obj-$(CONFIG_PWM) += pwm.o +endif endif diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 6b9e865..aef2e55 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -15,7 +15,11 @@ int pwm_enable(int pwm_id) { const struct s5p_timer *pwm = +#if defined(CONFIG_ARCH_NEXELL) + (struct s5p_timer *)PHY_BASEADDR_PWM; +#else (struct s5p_timer *)samsung_get_base_timer(); +#endif unsigned long tcon; tcon = readl(&pwm->tcon); @@ -29,7 +33,11 @@ int pwm_enable(int pwm_id) void pwm_disable(int pwm_id) { const struct s5p_timer *pwm = +#if defined(CONFIG_ARCH_NEXELL) + (struct s5p_timer *)PHY_BASEADDR_PWM; +#else (struct s5p_timer *)samsung_get_base_timer(); +#endif unsigned long tcon; tcon = readl(&pwm->tcon); @@ -43,14 +51,43 @@ static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) unsigned long tin_parent_rate; unsigned int div; +#if defined(CONFIG_ARCH_NEXELL) + unsigned int pre_div; + const struct s5p_timer *pwm = + (struct s5p_timer *)PHY_BASEADDR_PWM; + unsigned int val; + struct clk *clk = clk_get(CORECLK_NAME_PCLK); + + tin_parent_rate = clk_get_rate(clk); +#else tin_parent_rate = get_pwm_clk(); +#endif + +#if defined(CONFIG_ARCH_NEXELL) + writel(0, &pwm->tcfg0); + val = readl(&pwm->tcfg0); + + if (pwm_id < 2) + div = ((val >> 0) & 0xff) + 1; + else + div = ((val >> 8) & 0xff) + 1; + writel(0, &pwm->tcfg1); + val = readl(&pwm->tcfg1); + val = (val >> MUX_DIV_SHIFT(pwm_id)) & 0xF; + pre_div = (1UL << val); + + freq = tin_parent_rate / div / pre_div; + + return freq; +#else for (div = 2; div <= 16; div *= 2) { if ((tin_parent_rate / (div << 16)) < freq) return tin_parent_rate / div; } return tin_parent_rate / 16; +#endif } #define NS_IN_SEC 1000000000UL @@ -58,7 +95,11 @@ static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) int pwm_config(int pwm_id, int duty_ns, int period_ns) { const struct s5p_timer *pwm = +#if defined(CONFIG_ARCH_NEXELL) + (struct s5p_timer *)PHY_BASEADDR_PWM; +#else (struct s5p_timer *)samsung_get_base_timer(); +#endif unsigned int offset; unsigned long tin_rate; unsigned long tin_ns; @@ -84,7 +125,12 @@ int pwm_config(int pwm_id, int duty_ns, int period_ns) tin_rate = pwm_calc_tin(pwm_id, frequency); tin_ns = NS_IN_SEC / tin_rate; - tcnt = period_ns / tin_ns; + + if (IS_ENABLED(CONFIG_ARCH_NEXELL)) + /* The counter starts at zero. */ + tcnt = (period_ns / tin_ns) - 1; + else + tcnt = period_ns / tin_ns; /* Note, counters count down */ tcmp = duty_ns / tin_ns; @@ -115,7 +161,11 @@ int pwm_init(int pwm_id, int div, int invert) { u32 val; const struct s5p_timer *pwm = +#if defined(CONFIG_ARCH_NEXELL) + (struct s5p_timer *)PHY_BASEADDR_PWM; +#else (struct s5p_timer *)samsung_get_base_timer(); +#endif unsigned long ticks_per_period; unsigned int offset, prescaler; @@ -148,7 +198,12 @@ int pwm_init(int pwm_id, int div, int invert) ticks_per_period = -1UL; } else { const unsigned long pwm_hz = 1000; +#if defined(CONFIG_ARCH_NEXELL) + struct clk *clk = clk_get(CORECLK_NAME_PCLK); + unsigned long timer_rate_hz = clk_get_rate(clk) / +#else unsigned long timer_rate_hz = get_pwm_clk() / +#endif ((prescaler + 1) * (1 << div)); ticks_per_period = timer_rate_hz / pwm_hz; diff --git a/arch/arm/mach-nexell/include/mach/pwm.h b/arch/arm/mach-nexell/include/mach/pwm.h new file mode 100644 index 0000000..08a287d --- /dev/null +++ b/arch/arm/mach-nexell/include/mach/pwm.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2009 Samsung Electronics + * Kyungmin Park + * Minkyu Kang + */ + +#ifndef __ASM_ARM_ARCH_PWM_H_ +#define __ASM_ARM_ARCH_PWM_H_ + +#define PRESCALER_0 (8 - 1) /* prescaler of timer 0, 1 */ +#define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */ + +/* Divider MUX */ +#define MUX_DIV_1 0 /* 1/1 period */ +#define MUX_DIV_2 1 /* 1/2 period */ +#define MUX_DIV_4 2 /* 1/4 period */ +#define MUX_DIV_8 3 /* 1/8 period */ +#define MUX_DIV_16 4 /* 1/16 period */ + +#define MUX_DIV_SHIFT(x) ((x) * 4) + +#define TCON_OFFSET(x) (((x) + 1) * (!!(x)) << 2) + +#define TCON_START(x) (1 << TCON_OFFSET(x)) +#define TCON_UPDATE(x) (1 << (TCON_OFFSET(x) + 1)) +#define TCON_INVERTER(x) (1 << (TCON_OFFSET(x) + 2)) +#define TCON_AUTO_RELOAD(x) (1 << (TCON_OFFSET(x) + 3)) +#define TCON4_AUTO_RELOAD (1 << 22) + +#ifndef __ASSEMBLY__ +struct s5p_timer { + unsigned int tcfg0; + unsigned int tcfg1; + unsigned int tcon; + unsigned int tcntb0; + unsigned int tcmpb0; + unsigned int tcnto0; + unsigned int tcntb1; + unsigned int tcmpb1; + unsigned int tcnto1; + unsigned int tcntb2; + unsigned int tcmpb2; + unsigned int tcnto2; + unsigned int tcntb3; + unsigned int res1; + unsigned int tcnto3; + unsigned int tcntb4; + unsigned int tcnto4; + unsigned int tintcstat; +}; +#endif /* __ASSEMBLY__ */ + +#endif