pwm: add driver for nexell
authorStefan Bosch <stefan_b@posteo.net>
Fri, 10 Jul 2020 17:07:31 +0000 (19:07 +0200)
committerTom Rini <trini@konsulko.com>
Wed, 29 Jul 2020 12:43:40 +0000 (08:43 -0400)
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>
arch/arm/cpu/armv7/s5p-common/Makefile
arch/arm/cpu/armv7/s5p-common/pwm.c
arch/arm/mach-nexell/include/mach/pwm.h [new file with mode: 0644]

index 12cf804..bfe0238 100644 (file)
@@ -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
index 6b9e865..aef2e55 100644 (file)
 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 (file)
index 0000000..08a287d
--- /dev/null
@@ -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