pwm: add driver for nexell
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 <stefan_b@posteo.net>
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 <mk7.kang@samsung.com>
-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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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 <kyungmin.park@samsung.com>
+ * Minkyu Kang <mk7.kang@samsung.com>
+ */
+
+#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