diff mbox series

[RFC,v2,06/13] pwm: add driver for nexell

Message ID 1585388636-5404-7-git-send-email-stefan_b@posteo.net
State Accepted
Commit 18284c1d56bfe2b51484561881377489ffa86c3b
Headers show
Series arm: add support for SoC S5P4418 | expand

Commit Message

Stefan Bosch March 28, 2020, 9:43 a.m. UTC
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.

Signed-off-by: Stefan Bosch <stefan_b at posteo.net>
---

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  |  4 +++
 arch/arm/cpu/armv7/s5p-common/pwm.c     | 56 +++++++++++++++++++++++++++++++++
 arch/arm/mach-nexell/include/mach/pwm.h | 54 +++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)
 create mode 100644 arch/arm/mach-nexell/include/mach/pwm.h
diff mbox series

Patch

diff --git a/arch/arm/cpu/armv7/s5p-common/Makefile b/arch/arm/cpu/armv7/s5p-common/Makefile
index 12cf804..3d4649b 100644
--- a/arch/arm/cpu/armv7/s5p-common/Makefile
+++ b/arch/arm/cpu/armv7/s5p-common/Makefile
@@ -3,9 +3,13 @@ 
 # Copyright (C) 2009 Samsung Electronics
 # Minkyu Kang <mk7.kang at samsung.com>
 
+ifdef CONFIG_ARCH_NEXELL
+obj-$(CONFIG_PWM_NX)	+= 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
 endif
+endif
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c
index 6b9e865..c4915af 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,13 @@  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;
+
+#if defined(CONFIG_ARCH_NEXELL)
+	/* The counter starts at zero. */
+	tcnt = (period_ns / tin_ns) - 1;
+#else
 	tcnt = period_ns / tin_ns;
+#endif
 
 	/* Note, counters count down */
 	tcmp = duty_ns / tin_ns;
@@ -115,7 +162,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 +199,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..1a531be
--- /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 at samsung.com>
+ * Minkyu Kang <mk7.kang at 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