[U-Boot] [V2 04/15] S3C64XX: add pwm for s3c64xx support
Zhong Hongbo
bocui107 at gmail.com
Fri Jul 20 00:04:56 CEST 2012
Hi Minkyu,
I notice this patch are delegated to you. But the patchwork miss the
patch 4.
If you need me to do anything, Please let me know.
Thanks,
hongbo
On 07/14/2012 12:11 AM, Zhong Hongbo wrote:
> From: Zhong Hongbo <bocui107 at gmail.com>
>
> Signed-off-by: Zhong Hongbo <bocui107 at gmail.com>
> ---
> Change for V2:
> - Change the type of the return value from unsinged int
> to unsinged long for s3c64xx_get_base_nand function.
> ---
> arch/arm/cpu/arm1176/s3c64xx/Makefile | 1 +
> arch/arm/cpu/arm1176/s3c64xx/pwm.c | 189 +++++++++++++++++++++++++++
> arch/arm/include/asm/arch-s3c64xx/pwm.h | 70 ++++++++++
> arch/arm/include/asm/arch-s3c64xx/s3c6400.h | 56 ++-------
> arch/arm/include/asm/arch-s3c64xx/s3c64x0.h | 59 ---------
> include/configs/smdk6400.h | 3 +
> 6 files changed, 272 insertions(+), 106 deletions(-)
> create mode 100644 arch/arm/cpu/arm1176/s3c64xx/pwm.c
> create mode 100644 arch/arm/include/asm/arch-s3c64xx/pwm.h
> delete mode 100644 arch/arm/include/asm/arch-s3c64xx/s3c64x0.h
>
> diff --git a/arch/arm/cpu/arm1176/s3c64xx/Makefile b/arch/arm/cpu/arm1176/s3c64xx/Makefile
> index 0785b19..966663f 100644
> --- a/arch/arm/cpu/arm1176/s3c64xx/Makefile
> +++ b/arch/arm/cpu/arm1176/s3c64xx/Makefile
> @@ -32,6 +32,7 @@ SOBJS = reset.o
>
> COBJS-$(CONFIG_S3C6400) += cpu_init.o speed.o
> COBJS-y += timer.o
> +COBJS-$(CONFIG_PWM) += pwm.o
>
> OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y))
>
> diff --git a/arch/arm/cpu/arm1176/s3c64xx/pwm.c b/arch/arm/cpu/arm1176/s3c64xx/pwm.c
> new file mode 100644
> index 0000000..d1d70ff
> --- /dev/null
> +++ b/arch/arm/cpu/arm1176/s3c64xx/pwm.c
> @@ -0,0 +1,189 @@
> +/*
> + * Copyright (C) 2012
> + *
> + * Zhong Hongbo <bocui107 at gmail.com>
> + *
> + * based on arch/arm/cpu/armv7/s5p-common/sromc.c
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <pwm.h>
> +#include <asm/io.h>
> +#include <asm/arch/s3c6400.h>
> +#include <asm/arch/pwm.h>
> +
> +int pwm_enable(int pwm_id)
> +{
> + const struct s3c_timer *pwm =
> + (struct s3c_timer *)s3c64xx_get_base_timer();
> + unsigned long tcon;
> +
> + tcon = readl(&pwm->tcon);
> + tcon |= TCON_START(pwm_id);
> +
> + writel(tcon, &pwm->tcon);
> +
> + return 0;
> +}
> +
> +void pwm_disable(int pwm_id)
> +{
> + const struct s3c_timer *pwm =
> + (struct s3c_timer *)s3c64xx_get_base_timer();
> + unsigned long tcon;
> +
> + tcon = readl(&pwm->tcon);
> + tcon &= ~TCON_START(pwm_id);
> +
> + writel(tcon, &pwm->tcon);
> +}
> +
> +static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
> +{
> + unsigned long tin_parent_rate;
> + unsigned int div;
> +
> + tin_parent_rate = get_PCLK();
> +
> + for (div = 2; div <= 16; div *= 2) {
> + if ((tin_parent_rate / (div << 16)) < freq)
> + return tin_parent_rate / div;
> + }
> +
> + return tin_parent_rate / 16;
> +}
> +
> +#define NS_IN_HZ (1000000000UL)
> +
> +int pwm_config(int pwm_id, int duty_ns, int period_ns)
> +{
> + const struct s3c_timer *pwm =
> + (struct s3c_timer *)s3c64xx_get_base_timer();
> + unsigned int offset;
> + unsigned long tin_rate;
> + unsigned long tin_ns;
> + unsigned long period;
> + unsigned long tcon;
> + unsigned long tcnt;
> + unsigned long tcmp;
> +
> + /*
> + * We currently avoid using 64bit arithmetic by using the
> + * fact that anything faster than 1GHz is easily representable
> + * by 32bits.
> + */
> + if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ)
> + return -ERANGE;
> +
> + if (duty_ns > period_ns)
> + return -EINVAL;
> +
> + period = NS_IN_HZ / period_ns;
> +
> + /* Check to see if we are changing the clock rate of the PWM */
> + tin_rate = pwm_calc_tin(pwm_id, period);
> +
> + tin_ns = NS_IN_HZ / tin_rate;
> + tcnt = period_ns / tin_ns;
> +
> + /* Note, counters count down */
> + tcmp = duty_ns / tin_ns;
> + tcmp = tcnt - tcmp;
> +
> + /*
> + * the pwm hw only checks the compare register after a decrement,
> + * so the pin never toggles if tcmp = tcnt
> + */
> + if (tcmp == tcnt)
> + tcmp--;
> +
> + if (tcmp < 0)
> + tcmp = 0;
> +
> + /* Update the PWM register block. */
> + offset = pwm_id * 3;
> + if (pwm_id < 4) {
> + writel(tcnt, &pwm->tcntb0 + offset);
> + writel(tcmp, &pwm->tcmpb0 + offset);
> + }
> +
> + tcon = readl(&pwm->tcon);
> + tcon |= TCON_UPDATE(pwm_id);
> + if (pwm_id < 4)
> + tcon |= TCON_AUTO_RELOAD(pwm_id);
> + else
> + tcon |= TCON4_AUTO_RELOAD;
> + writel(tcon, &pwm->tcon);
> +
> + tcon &= ~TCON_UPDATE(pwm_id);
> + writel(tcon, &pwm->tcon);
> +
> + return 0;
> +}
> +
> +int pwm_init(int pwm_id, int div, int invert)
> +{
> + u32 val;
> + const struct s3c_timer *pwm =
> + (struct s3c_timer *)s3c64xx_get_base_timer();
> + unsigned long timer_rate_hz;
> + unsigned int offset, prescaler;
> +
> + /*
> + * Timer Freq(HZ) =
> + * PWM_CLK / { (prescaler_value + 1) * (divider_value) }
> + */
> +
> + val = readl(&pwm->tcfg0);
> + if (pwm_id < 2) {
> + prescaler = PRESCALER_0;
> + val &= ~0xff;
> + val |= (prescaler & 0xff);
> + } else {
> + prescaler = PRESCALER_1;
> + val &= ~(0xff << 8);
> + val |= (prescaler & 0xff) << 8;
> + }
> + writel(val, &pwm->tcfg0);
> + val = readl(&pwm->tcfg1);
> + val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
> + val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
> + writel(val, &pwm->tcfg1);
> +
> + timer_rate_hz = get_PCLK() / ((prescaler + 1) *
> + (div + 1));
> +
> + timer_rate_hz = timer_rate_hz / CONFIG_SYS_HZ;
> +
> + /* set count value */
> + offset = pwm_id * 3;
> + writel(timer_rate_hz, &pwm->tcntb0 + offset);
> +
> + val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
> + if (invert && (pwm_id < 4))
> + val |= TCON_INVERTER(pwm_id);
> + writel(val, &pwm->tcon);
> +
> + pwm_enable(pwm_id);
> +
> + return 0;
> +}
> diff --git a/arch/arm/include/asm/arch-s3c64xx/pwm.h b/arch/arm/include/asm/arch-s3c64xx/pwm.h
> new file mode 100644
> index 0000000..1e18f8c
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-s3c64xx/pwm.h
> @@ -0,0 +1,70 @@
> +/*
> + * Copyright (C) 2012
> + * Zhong Hongbo <bocui107 at gmail.com>
> + *
> + * based on arch/arm/include/asm/arch-s5pc1xx/pwm.h
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#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)
> +
> +#define TCFG1_DMA(x) (x << 20)
> +
> +#ifndef __ASSEMBLY__
> +struct s3c_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 res1;
> + unsigned int tcnto2;
> + unsigned int tcntb3;
> + unsigned int res2;
> + unsigned int tcnto3;
> + unsigned int tcntb4;
> + unsigned int tcnto4;
> + unsigned int tint_cstat;
> +};
> +#endif
> +#endif
> diff --git a/arch/arm/include/asm/arch-s3c64xx/s3c6400.h b/arch/arm/include/asm/arch-s3c64xx/s3c6400.h
> index 77b9509..b884763 100644
> --- a/arch/arm/include/asm/arch-s3c64xx/s3c6400.h
> +++ b/arch/arm/include/asm/arch-s3c64xx/s3c6400.h
> @@ -31,6 +31,10 @@
> #ifndef __S3C6400_H__
> #define __S3C6400_H__
>
> +#if defined(CONFIG_SYNC_MODE) && defined(CONFIG_S3C6400)
> +#error CONFIG_SYNC_MODE unavailable on S3C6400, please, fix your configuration!
> +#endif
> +
> #define S3C64XX_UART_CHANNELS 3
> #define S3C64XX_SPI_CHANNELS 2
>
> @@ -587,51 +591,6 @@
> */
> #define ELFIN_TIMER_BASE 0x7F006000
>
> -#define TCFG0_REG __REG(0x7F006000)
> -#define TCFG1_REG __REG(0x7F006004)
> -#define TCON_REG __REG(0x7F006008)
> -#define TCNTB0_REG __REG(0x7F00600c)
> -#define TCMPB0_REG __REG(0x7F006010)
> -#define TCNTO0_REG __REG(0x7F006014)
> -#define TCNTB1_REG __REG(0x7F006018)
> -#define TCMPB1_REG __REG(0x7F00601c)
> -#define TCNTO1_REG __REG(0x7F006020)
> -#define TCNTB2_REG __REG(0x7F006024)
> -#define TCMPB2_REG __REG(0x7F006028)
> -#define TCNTO2_REG __REG(0x7F00602c)
> -#define TCNTB3_REG __REG(0x7F006030)
> -#define TCMPB3_REG __REG(0x7F006034)
> -#define TCNTO3_REG __REG(0x7F006038)
> -#define TCNTB4_REG __REG(0x7F00603c)
> -#define TCNTO4_REG __REG(0x7F006040)
> -
> -/* Fields */
> -#define fTCFG0_DZONE Fld(8, 16) /* the dead zone length (=timer 0) */
> -#define fTCFG0_PRE1 Fld(8, 8) /* prescaler value for time 2,3,4 */
> -#define fTCFG0_PRE0 Fld(8, 0) /* prescaler value for time 0,1 */
> -#define fTCFG1_MUX4 Fld(4, 16)
> -/* bits */
> -#define TCFG0_DZONE(x) FInsrt((x), fTCFG0_DZONE)
> -#define TCFG0_PRE1(x) FInsrt((x), fTCFG0_PRE1)
> -#define TCFG0_PRE0(x) FInsrt((x), fTCFG0_PRE0)
> -#define TCON_4_AUTO (1 << 22) /* auto reload on/off for Timer 4 */
> -#define TCON_4_UPDATE (1 << 21) /* manual Update TCNTB4 */
> -#define TCON_4_ONOFF (1 << 20) /* 0: Stop, 1: start Timer 4 */
> -#define COUNT_4_ON (TCON_4_ONOFF * 1)
> -#define COUNT_4_OFF (TCON_4_ONOFF * 0)
> -#define TCON_3_AUTO (1 << 19) /* auto reload on/off for Timer 3 */
> -#define TIMER3_ATLOAD_ON (TCON_3_AUTO * 1)
> -#define TIMER3_ATLAOD_OFF FClrBit(TCON, TCON_3_AUTO)
> -#define TCON_3_INVERT (1 << 18) /* 1: Inverter on for TOUT3 */
> -#define TIMER3_IVT_ON (TCON_3_INVERT * 1)
> -#define TIMER3_IVT_OFF (FClrBit(TCON, TCON_3_INVERT))
> -#define TCON_3_MAN (1 << 17) /* manual Update TCNTB3,TCMPB3 */
> -#define TIMER3_MANUP (TCON_3_MAN*1)
> -#define TIMER3_NOP (FClrBit(TCON, TCON_3_MAN))
> -#define TCON_3_ONOFF (1 << 16) /* 0: Stop, 1: start Timer 3 */
> -#define TIMER3_ON (TCON_3_ONOFF * 1)
> -#define TIMER3_OFF (FClrBit(TCON, TCON_3_ONOFF))
> -
> #if defined(CONFIG_CLK_400_100_50)
> #define STARTUP_AMDIV 400
> #define STARTUP_MDIV 400
> @@ -749,8 +708,6 @@
>
> #ifndef __ASSEMBLY__
>
> -#include "s3c64x0.h"
> -
> static inline unsigned long s3c64xx_get_base_uart(void)
> {
> return ELFIN_UART_BASE;
> @@ -760,6 +717,11 @@ static inline unsigned long s3c64xx_get_base_nand(void)
> {
> return ELFIN_NAND_BASE;
> }
> +
> +static inline unsigned long s3c64xx_get_base_timer(void)
> +{
> + return ELFIN_TIMER_BASE;
> +}
> #endif
>
> #endif /*__S3C6400_H__*/
> diff --git a/arch/arm/include/asm/arch-s3c64xx/s3c64x0.h b/arch/arm/include/asm/arch-s3c64xx/s3c64x0.h
> deleted file mode 100644
> index 7add68c..0000000
> --- a/arch/arm/include/asm/arch-s3c64xx/s3c64x0.h
> +++ /dev/null
> @@ -1,59 +0,0 @@
> -/*
> - * (C) Copyright 2003
> - * David MÃŒller ELSOFT AG Switzerland. d.mueller at elsoft.ch
> - *
> - * (C) Copyright 2008
> - * Guennadi Liakhovetki, DENX Software Engineering, <lg at denx.de>
> - *
> - * See file CREDITS for list of people who contributed to this
> - * project.
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License as
> - * published by the Free Software Foundation; either version 2 of
> - * the License, or (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> - * MA 02111-1307 USA
> - */
> -
> -/************************************************
> - * NAME : S3C64XX.h
> - * Version : 31.3.2003
> - *
> - * common stuff for SAMSUNG S3C64XX SoC
> - ************************************************/
> -
> -#ifndef __S3C64XX_H__
> -#define __S3C64XX_H__
> -
> -#if defined(CONFIG_SYNC_MODE) && defined(CONFIG_S3C6400)
> -#error CONFIG_SYNC_MODE unavailable on S3C6400, please, fix your configuration!
> -#endif
> -
> -#include <asm/types.h>
> -
> -/* PWM TIMER (see manual chapter 10) */
> -typedef struct {
> - volatile u32 TCNTB;
> - volatile u32 TCMPB;
> - volatile u32 TCNTO;
> -} s3c64xx_timer;
> -
> -typedef struct {
> - volatile u32 TCFG0;
> - volatile u32 TCFG1;
> - volatile u32 TCON;
> - s3c64xx_timer ch[4];
> - volatile u32 TCNTB4;
> - volatile u32 TCNTO4;
> -} s3c64xx_timers;
> -
> -#endif /*__S3C64XX_H__*/
> diff --git a/include/configs/smdk6400.h b/include/configs/smdk6400.h
> index 47326d6..3642a5c 100644
> --- a/include/configs/smdk6400.h
> +++ b/include/configs/smdk6400.h
> @@ -141,6 +141,9 @@
>
> #define CONFIG_SYS_HZ 1000
>
> +/* PWM */
> +#define CONFIG_PWM 1
> +
> /*-----------------------------------------------------------------------
> * Stack sizes
> *
>
More information about the U-Boot
mailing list