Skip to contentSkip to conversation

ARM: S5PV310: Add Timer support

PATCH New Kukjin Kim 3 participants 6 messages Jul 26, 2010 – Jul 27, 2010

Subsystems (3)
lore
Share & tools
lore

Kukjin Kim

author
#0 lore raw

PATCH v4 5/8 ARM: S5PV310: Add Timer support

From: Changhwan Youn <[email protected]>

This patch adds timer support for S5PV310. Until now, all S5P SoCs use CONFIG_ARCH_USES_GETTIMEOFFSET macro as a default configuration. Instead,S5PV310 implements clocksource and clock_event_device to support the high resolution timer and tickless system.

---
Changes since v3:

- Changes clock source from PWM2 to PWM4 because PWM4 cannot be used for other purpose such as external output function through GPIO.

 arch/arm/mach-s5pv310/include/mach/pwm-clock.h |   70 ++++++
 arch/arm/mach-s5pv310/localtimer.c             |   25 ++
 arch/arm/mach-s5pv310/time.c                   |  287 ++++++++++++++++++++++++
 arch/arm/plat-s5p/include/plat/s5pv310.h       |    1 +
 arch/arm/plat-samsung/Makefile                 |    2 +-
 5 files changed, 384 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-s5pv310/include/mach/pwm-clock.h
 create mode 100644 arch/arm/mach-s5pv310/localtimer.c
 create mode 100644 arch/arm/mach-s5pv310/time.c
arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +70 -0
new file mode 100644
index 0000000..7e6da27
@@ -0,0 +1,70 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/pwm-clock.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <[email protected]>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
+ *
+ * S5PV310 - pwm clock and timer support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_PWMCLK_H
+#define __ASM_ARCH_PWMCLK_H __FILE__
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+	return tcfg == S3C64XX_TCFG1_MUX_TCLK;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+	return 1 << tcfg1;
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+	return 1;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+	return ilog2(div);
+}
+
+#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
+
+#endif /* __ASM_ARCH_PWMCLK_H */
arch/arm/mach-s5pv310/localtimer.c new file +25 -0
new file mode 100644
index 0000000..2784036
@@ -0,0 +1,25 @@
+/* linux/arch/arm/mach-s5pv310/localtimer.c
+ *
+ * Cloned from linux/arch/arm/mach-realview/localtimer.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clockchips.h>
+
+#include <asm/irq.h>
+#include <asm/localtimer.h>
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+	evt->irq = IRQ_LOCALTIMER;
+	twd_timer_setup(evt);
+}
arch/arm/mach-s5pv310/time.c new file +287 -0

287 lines not on this page · raw message

arch/arm/plat-s5p/include/plat/s5pv310.h +1 -0
index d2f05e1..769c991 100644
@@ -22,6 +22,7 @@ extern  int s5pv310_init(void);
 extern void s5pv310_init_irq(void);
 extern void s5pv310_map_io(void);
 extern void s5pv310_init_clocks(int xtal);
+extern struct sys_timer s5pv310_timer;
 
 #define s5pv310_init_uarts s5pv310_common_init_uarts
 
arch/arm/plat-samsung/Makefile +1 -1
index b1d82cc..0d5bf8a 100644
@@ -12,7 +12,7 @@ obj-				:=
 # Objects we always build independent of SoC choice
 
 obj-y				+= init.o
-obj-y				+= time.o
+obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET)   += time.o
 obj-y				+= clock.o
 obj-y				+= pwm-clock.o
 obj-y				+= gpio.o
Signature · 1 line
1.6.2.5
#1 lore raw

PATCH v4 5/8 ARM: S5PV310: Add Timer support

Can you confirm that during boot time, change the pwm2 pin to i2c functions and still it's working correctly?

1. pwm2 is used for clock event at first boot.
2. during i2c init, pwm2 pin is changed to i2c functionality.

then where can get the clockevent?

Another possible scenarios is that.
pwm2 pin is changed to i2c function at bootloader to access the i2c chips. Then below code is working?

Thank you,
Kyungmin Park

Quoted 459 lines · Kukjin Kim

From: Changhwan Youn <[email protected]>

This patch adds timer support for S5PV310. ?Until now, all S5P SoCs use CONFIG_ARCH_USES_GETTIMEOFFSET macro as a default configuration. Instead,S5PV310 implements clocksource and clock_event_device to support the high resolution timer and tickless system.

---
Changes since v3:

- Changes clock source from PWM2 to PWM4 because PWM4 cannot be used for ?other purpose such as external output function through GPIO.

?arch/arm/mach-s5pv310/include/mach/pwm-clock.h | ? 70 ++++++
?arch/arm/mach-s5pv310/localtimer.c ? ? ? ? ? ? | ? 25 ++
?arch/arm/mach-s5pv310/time.c ? ? ? ? ? ? ? ? ? | ?287 ++++++++++++++++++++++++
?arch/arm/plat-s5p/include/plat/s5pv310.h ? ? ? | ? ?1 +
?arch/arm/plat-samsung/Makefile ? ? ? ? ? ? ? ? | ? ?2 +-

?5 files changed, 384 insertions(+), 1 deletions(-) ?create mode 100644 arch/arm/mach-s5pv310/include/mach/pwm-clock.h ?create mode 100644 arch/arm/mach-s5pv310/localtimer.c ?create mode 100644 arch/arm/mach-s5pv310/time.c

arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +70 -0
new file mode 100644
index 0000000..7e6da27
@@ -0,0 +1,70 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/pwm-clock.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * ? ? ? ? ? ? http://www.samsung.com/
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * ? ? ?Ben Dooks <[email protected]>
+ * ? ? ?http://armlinux.simtec.co.uk/
+ *
+ * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
+ *
+ * S5PV310 - pwm clock and timer support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_PWMCLK_H
+#define __ASM_ARCH_PWMCLK_H __FILE__
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+ ? ? ? return tcfg == S3C64XX_TCFG1_MUX_TCLK;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+ ? ? ? return 1 << tcfg1;
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+ ? ? ? return 1;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+ ? ? ? return ilog2(div);
+}
+
+#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
+
+#endif /* __ASM_ARCH_PWMCLK_H */
arch/arm/mach-s5pv310/localtimer.c new file +25 -0
new file mode 100644
index 0000000..2784036
@@ -0,0 +1,25 @@
+/* linux/arch/arm/mach-s5pv310/localtimer.c
+ *
+ * Cloned from linux/arch/arm/mach-realview/localtimer.c
+ *
+ * ?Copyright (C) 2002 ARM Ltd.
+ * ?All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clockchips.h>
+
+#include <asm/irq.h>
+#include <asm/localtimer.h>
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+ ? ? ? evt->irq = IRQ_LOCALTIMER;
+ ? ? ? twd_timer_setup(evt);
+}
arch/arm/mach-s5pv310/time.c new file +287 -0
new file mode 100644
index 0000000..01b012a
@@ -0,0 +1,287 @@
+/* linux/arch/arm/mach-s5pv310/time.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * ? ? ? ? ? ? http://www.samsung.com
+ *
+ * S5PV310 (and compatible) HRT support
+ * PWM 2/4 is used for this feature
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+
+#include <asm/smp_twd.h>
+
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <asm/mach/time.h>
+
+static unsigned long clock_count_per_tick;
+
+static struct clk *tin2;
+static struct clk *tin4;
+static struct clk *tdiv2;
+static struct clk *tdiv4;
+static struct clk *timerclk;
+
+static void s5pv310_pwm_stop(unsigned int pwm_id)
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon = __raw_readl(S3C2410_TCON);
+
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2START;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4START;
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+ ? ? ? __raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon = __raw_readl(S3C2410_TCON);
+
+ ? ? ? /* timers reload after counting zero, so reduce the count by 1 */
+ ? ? ? tcnt--;
+
+ ? ? ? /* ensure timer is stopped... */
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon &= ~(0xf<<12);
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2MANUALUPD;
+
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCNTB(2));
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCMPB(2));
+ ? ? ? ? ? ? ? __raw_writel(tcon, S3C2410_TCON);
+
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon &= ~(7<<20);
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4MANUALUPD;
+
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCNTB(4));
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCMPB(4));
+ ? ? ? ? ? ? ? __raw_writel(tcon, S3C2410_TCON);
+
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+}
+
+static inline void s5pv310_pwm_start(unsigned int pwm_id, bool periodic)
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon ?= __raw_readl(S3C2410_TCON);
+
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2START;
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2MANUALUPD;
+
+ ? ? ? ? ? ? ? if (periodic)
+ ? ? ? ? ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2RELOAD;
+ ? ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2RELOAD;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4START;
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4MANUALUPD;
+
+ ? ? ? ? ? ? ? if (periodic)
+ ? ? ? ? ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4RELOAD;
+ ? ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4RELOAD;
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+ ? ? ? __raw_writel(tcon, S3C2410_TCON);
+}
+
+static int s5pv310_pwm_set_next_event(unsigned long cycles,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
+{
+ ? ? ? s5pv310_pwm_init(2, cycles);
+ ? ? ? s5pv310_pwm_start(2, 0);
+ ? ? ? return 0;
+}
+
+static void s5pv310_pwm_set_mode(enum clock_event_mode mode,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
+{
+ ? ? ? s5pv310_pwm_stop(2);
+
+ ? ? ? switch (mode) {
+ ? ? ? case CLOCK_EVT_MODE_PERIODIC:
+ ? ? ? ? ? ? ? s5pv310_pwm_init(2, clock_count_per_tick);
+ ? ? ? ? ? ? ? s5pv310_pwm_start(2, 1);
+ ? ? ? ? ? ? ? break;
+ ? ? ? case CLOCK_EVT_MODE_ONESHOT:
+ ? ? ? ? ? ? ? break;
+ ? ? ? case CLOCK_EVT_MODE_UNUSED:
+ ? ? ? case CLOCK_EVT_MODE_SHUTDOWN:
+ ? ? ? case CLOCK_EVT_MODE_RESUME:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+}
+
+static struct clock_event_device pwm_event_device = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer2",
+ ? ? ? .features ? ? ? = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ ? ? ? .rating ? ? ? ? = 200,
+ ? ? ? .shift ? ? ? ? ?= 32,
+ ? ? ? .set_next_event = s5pv310_pwm_set_next_event,
+ ? ? ? .set_mode ? ? ? = s5pv310_pwm_set_mode,
+};
+
+irqreturn_t s5pv310_clock_event_isr(int irq, void *dev_id)
+{
+ ? ? ? struct clock_event_device *evt = &pwm_event_device;
+
+ ? ? ? evt->event_handler(evt);
+
+ ? ? ? return IRQ_HANDLED;
+}
+
+static struct irqaction s5pv310_clock_event_irq = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer2_irq",
+ ? ? ? .flags ? ? ? ? ?= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ ? ? ? .handler ? ? ? ?= s5pv310_clock_event_isr,
+};
+
+static void __init s5pv310_clockevent_init(void)
+{
+ ? ? ? unsigned long pclk;
+ ? ? ? unsigned long clock_rate;
+ ? ? ? struct clk *tscaler;
+
+ ? ? ? pclk = clk_get_rate(timerclk);
+
+ ? ? ? /* configure clock tick */
+
+ ? ? ? tscaler = clk_get_parent(tdiv2);
+
+ ? ? ? clk_set_rate(tscaler, pclk / 2);
+ ? ? ? clk_set_rate(tdiv2, pclk / 2);
+ ? ? ? clk_set_parent(tin2, tdiv2);
+
+ ? ? ? clock_rate = clk_get_rate(tin2);
+
+ ? ? ? clock_count_per_tick = clock_rate / HZ;
+
+ ? ? ? pwm_event_device.mult =
+ ? ? ? ? ? ? ? div_sc(clock_rate, NSEC_PER_SEC, pwm_event_device.shift);
+ ? ? ? pwm_event_device.max_delta_ns =
+ ? ? ? ? ? ? ? clockevent_delta2ns(-1, &pwm_event_device);
+ ? ? ? pwm_event_device.min_delta_ns =
+ ? ? ? ? ? ? ? clockevent_delta2ns(1, &pwm_event_device);
+
+ ? ? ? pwm_event_device.cpumask = cpumask_of(0);
+ ? ? ? clockevents_register_device(&pwm_event_device);
+
+ ? ? ? setup_irq(IRQ_TIMER2, &s5pv310_clock_event_irq);
+}
+
+static cycle_t s5pv310_pwm4_read(struct clocksource *cs)
+{
+ ? ? ? return (cycle_t) ~__raw_readl(S3C_TIMERREG(0x40));
+}
+
+struct clocksource pwm_clocksource = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer4",
+ ? ? ? .rating ? ? ? ? = 250,
+ ? ? ? .read ? ? ? ? ? = s5pv310_pwm4_read,
+ ? ? ? .mask ? ? ? ? ? = CLOCKSOURCE_MASK(32),
+ ? ? ? .shift ? ? ? ? ?= 20,
+ ? ? ? .flags ? ? ? ? ?= CLOCK_SOURCE_IS_CONTINUOUS ,
+};
+
+static void __init s5pv310_clocksource_init(void)
+{
+ ? ? ? unsigned long pclk;
+ ? ? ? unsigned long clock_rate;
+
+ ? ? ? pclk = clk_get_rate(timerclk);
+
+ ? ? ? clk_set_rate(tdiv4, pclk / 2);
+ ? ? ? clk_set_parent(tin4, tdiv4);
+
+ ? ? ? clock_rate = clk_get_rate(tin4);
+
+ ? ? ? s5pv310_pwm_init(4, ~0);
+ ? ? ? s5pv310_pwm_start(4, 1);
+
+ ? ? ? pwm_clocksource.mult =
+ ? ? ? ? ? ? ? clocksource_khz2mult(clock_rate/1000, pwm_clocksource.shift);
+
+ ? ? ? if (clocksource_register(&pwm_clocksource))
+ ? ? ? ? ? ? ? panic("%s: can't register clocksource\n", pwm_clocksource.name);
+}
+
+static void __init s5pv310_timer_resources(void)
+{
+ ? ? ? struct platform_device tmpdev;
+
+ ? ? ? tmpdev.dev.bus = &platform_bus_type;
+
+ ? ? ? timerclk = clk_get(NULL, "timers");
+ ? ? ? if (IS_ERR(timerclk))
+ ? ? ? ? ? ? ? panic("failed to get timers clock for system timer");
+
+ ? ? ? clk_enable(timerclk);
+
+ ? ? ? tmpdev.id = 2;
+ ? ? ? tin2 = clk_get(&tmpdev.dev, "pwm-tin");
+ ? ? ? if (IS_ERR(tin2))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tin2 clock for system timer");
+
+ ? ? ? tdiv2 = clk_get(&tmpdev.dev, "pwm-tdiv");
+ ? ? ? if (IS_ERR(tdiv2))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tdiv2 clock for system timer");
+ ? ? ? clk_enable(tin2);
+
+ ? ? ? tmpdev.id = 4;
+ ? ? ? tin4 = clk_get(&tmpdev.dev, "pwm-tin");
+ ? ? ? if (IS_ERR(tin4))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tin4 clock for system timer");
+
+ ? ? ? tdiv4 = clk_get(&tmpdev.dev, "pwm-tdiv");
+ ? ? ? if (IS_ERR(tdiv4))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tdiv4 clock for system timer");
+
+ ? ? ? clk_enable(tin4);
+}
+
+static void __init s5pv310_timer_init(void)
+{
+#ifdef CONFIG_LOCAL_TIMERS
+ ? ? ? twd_base = S5P_VA_TWD;
+#endif
+
+ ? ? ? s5pv310_timer_resources();
+ ? ? ? s5pv310_clockevent_init();
+ ? ? ? s5pv310_clocksource_init();
+}
+
+struct sys_timer s5pv310_timer = {
+ ? ? ? .init ? ? ? ? ? = s5pv310_timer_init,
+};
arch/arm/plat-s5p/include/plat/s5pv310.h +1 -0
index d2f05e1..769c991 100644
@@ -22,6 +22,7 @@ extern ?int s5pv310_init(void);
 ?extern void s5pv310_init_irq(void);
 ?extern void s5pv310_map_io(void);
 ?extern void s5pv310_init_clocks(int xtal);
+extern struct sys_timer s5pv310_timer;
 

?#define s5pv310_init_uarts s5pv310_common_init_uarts

arch/arm/plat-samsung/Makefile +0 -0
index b1d82cc..0d5bf8a 100644
@@ -12,7 +12,7 @@ obj- ? ? ? ? ? ? ? ? ? ? ? ? ?:=

?# Objects we always build independent of SoC choice

?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= init.o

arch/arm/plat-samsung/Makefile +1 -1
-obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= time.o
+obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) ? += time.o

?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= clock.o
?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= pwm-clock.o
?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= gpio.o
--
1.6.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html

#2 lore raw

PATCH v4 5/8 ARM: S5PV310: Add Timer support

Hi! Kyungmin,

After booting, clock event is generated by 2 arm private timers. What do you mean by 'change the pwm2 pin to i2c functions' ? What do you use for I2C emulation? (TOUT2 or gpio) Could you explain it in detail?

Thanks and regards,
Sangbeom Kim

Quoted 299 lines · Kyungmin Park

Can you confirm that during boot time, change the pwm2 pin to i2c functions and still it's working correctly?

1. pwm2 is used for clock event at first boot.
2. during i2c init, pwm2 pin is changed to i2c functionality.

then where can get the clockevent?

Another possible scenarios is that.
pwm2 pin is changed to i2c function at bootloader to access the i2c chips. Then below code is working?

Thank you,
Kyungmin Park

Quoted 13 lines · Kukjin Kim

From: Changhwan Youn <[email protected]>

This patch adds timer support for S5PV310.  Until now, all S5P SoCs use CONFIG_ARCH_USES_GETTIMEOFFSET macro as a default configuration. Instead,S5PV310 implements clocksource and clock_event_device to support the high resolution timer and tickless system.

---
Changes since v3:

Quoted 6 lines

- Changes clock source from PWM2 to PWM4 because PWM4 cannot be used for other purpose such as external output function through GPIO.

 arch/arm/mach-s5pv310/include/mach/pwm-clock.h |   70 ++++++ arch/arm/mach-s5pv310/localtimer.c             |   25 ++ arch/arm/mach-s5pv310/time.c                   |  287

++++++++++++++++++++++++

Review

Quoted 8 lines

 arch/arm/plat-s5p/include/plat/s5pv310.h       |    1 + arch/arm/plat-samsung/Makefile                 |    2 +-

 5 files changed, 384 insertions(+), 1 deletions(-)

 create mode 100644 arch/arm/mach-s5pv310/include/mach/pwm-clock.h create mode 100644 arch/arm/mach-s5pv310/localtimer.c create mode 100644 arch/arm/mach-s5pv310/time.c

(quoted diff) +0 -0

b/arch/arm/mach-s5pv310/include/mach/pwm-clock.h

arch/arm/mach-

Quoted 76 lines

new file mode 100644
index 0000000..7e6da27

arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +70 -0
@@ -0,0 +1,70 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/pwm-clock.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <[email protected]>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
+ *
+ * S5PV310 - pwm clock and timer support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_PWMCLK_H
+#define __ASM_ARCH_PWMCLK_H __FILE__
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+       return tcfg == S3C64XX_TCFG1_MUX_TCLK;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+       return 1 << tcfg1;
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+       return 1;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+       return ilog2(div);
+}
+
+#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
+
+#endif /* __ASM_ARCH_PWMCLK_H */
arch/arm/mach- renamed from arch/arm/mach-s5pv310/localtimer.c +0 -0

s5pv310/localtimer.c

Quoted 177 lines

new file mode 100644
index 0000000..2784036

arch/arm/mach-s5pv310/localtimer.c new file +25 -0
@@ -0,0 +1,25 @@
+/* linux/arch/arm/mach-s5pv310/localtimer.c
+ *
+ * Cloned from linux/arch/arm/mach-realview/localtimer.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clockchips.h>
+
+#include <asm/irq.h>
+#include <asm/localtimer.h>
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+       evt->irq = IRQ_LOCALTIMER;
+       twd_timer_setup(evt);
+}
arch/arm/mach-s5pv310/time.c new file +141 -0
new file mode 100644
index 0000000..01b012a
@@ -0,0 +1,287 @@
+/* linux/arch/arm/mach-s5pv310/time.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5PV310 (and compatible) HRT support
+ * PWM 2/4 is used for this feature
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+
+#include <asm/smp_twd.h>
+
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <asm/mach/time.h>
+
+static unsigned long clock_count_per_tick;
+
+static struct clk *tin2;
+static struct clk *tin4;
+static struct clk *tdiv2;
+static struct clk *tdiv4;
+static struct clk *timerclk;
+
+static void s5pv310_pwm_stop(unsigned int pwm_id)
+{
+       unsigned long tcon;
+
+       tcon = __raw_readl(S3C2410_TCON);
+
+       switch (pwm_id) {
+       case 2:
+               tcon &= ~S3C2410_TCON_T2START;
+               break;
+       case 4:
+               tcon &= ~S3C2410_TCON_T4START;
+               break;
+       default:
+               break;
+       }
+       __raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
+{
+       unsigned long tcon;
+
+       tcon = __raw_readl(S3C2410_TCON);
+
+       /* timers reload after counting zero, so reduce the count by 1 */
+       tcnt--;
+
+       /* ensure timer is stopped... */
+       switch (pwm_id) {
+       case 2:
+               tcon &= ~(0xf<<12);
+               tcon |= S3C2410_TCON_T2MANUALUPD;
+
+               __raw_writel(tcnt, S3C2410_TCNTB(2));
+               __raw_writel(tcnt, S3C2410_TCMPB(2));
+               __raw_writel(tcon, S3C2410_TCON);
+
+               break;
+       case 4:
+               tcon &= ~(7<<20);
+               tcon |= S3C2410_TCON_T4MANUALUPD;
+
+               __raw_writel(tcnt, S3C2410_TCNTB(4));
+               __raw_writel(tcnt, S3C2410_TCMPB(4));
+               __raw_writel(tcon, S3C2410_TCON);
+
+               break;
+       default:
+               break;
+       }
+}
+
+static inline void s5pv310_pwm_start(unsigned int pwm_id, bool periodic)
+{
+       unsigned long tcon;
+
+       tcon  = __raw_readl(S3C2410_TCON);
+
+       switch (pwm_id) {
+       case 2:
+               tcon |= S3C2410_TCON_T2START;
+               tcon &= ~S3C2410_TCON_T2MANUALUPD;
+
+               if (periodic)
+                       tcon |= S3C2410_TCON_T2RELOAD;
+               else
+                       tcon &= ~S3C2410_TCON_T2RELOAD;
+               break;
+       case 4:
+               tcon |= S3C2410_TCON_T4START;
+               tcon &= ~S3C2410_TCON_T4MANUALUPD;
+
+               if (periodic)
+                       tcon |= S3C2410_TCON_T4RELOAD;
+               else
+                       tcon &= ~S3C2410_TCON_T4RELOAD;
+               break;
+       default:
+               break;
+       }
+       __raw_writel(tcon, S3C2410_TCON);
+}
+
+static int s5pv310_pwm_set_next_event(unsigned long cycles,
+                                       struct clock_event_device *evt)
+{
+       s5pv310_pwm_init(2, cycles);
+       s5pv310_pwm_start(2, 0);
+       return 0;
+}
+
+static void s5pv310_pwm_set_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt)
+{
+       s5pv310_pwm_stop(2);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               s5pv310_pwm_init(2, clock_count_per_tick);
+               s5pv310_pwm_start(2, 1);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static struct clock_event_device pwm_event_device = {
+       .name           = "pwm_timer2",
+       .features       = CLOCK_EVT_FEAT_PERIODIC |

CLOCK_EVT_FEAT_ONESHOT,

Quoted 181 lines
Quoted 75 lines
arch/arm/mach-s5pv310/time.c new file +75 -0
+       .rating         = 200,
+       .shift          = 32,
+       .set_next_event = s5pv310_pwm_set_next_event,
+       .set_mode       = s5pv310_pwm_set_mode,
+};
+
+irqreturn_t s5pv310_clock_event_isr(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &pwm_event_device;
+
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction s5pv310_clock_event_irq = {
+       .name           = "pwm_timer2_irq",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = s5pv310_clock_event_isr,
+};
+
+static void __init s5pv310_clockevent_init(void)
+{
+       unsigned long pclk;
+       unsigned long clock_rate;
+       struct clk *tscaler;
+
+       pclk = clk_get_rate(timerclk);
+
+       /* configure clock tick */
+
+       tscaler = clk_get_parent(tdiv2);
+
+       clk_set_rate(tscaler, pclk / 2);
+       clk_set_rate(tdiv2, pclk / 2);
+       clk_set_parent(tin2, tdiv2);
+
+       clock_rate = clk_get_rate(tin2);
+
+       clock_count_per_tick = clock_rate / HZ;
+
+       pwm_event_device.mult =
+               div_sc(clock_rate, NSEC_PER_SEC, pwm_event_device.shift);
+       pwm_event_device.max_delta_ns =
+               clockevent_delta2ns(-1, &pwm_event_device);
+       pwm_event_device.min_delta_ns =
+               clockevent_delta2ns(1, &pwm_event_device);
+
+       pwm_event_device.cpumask = cpumask_of(0);
+       clockevents_register_device(&pwm_event_device);
+
+       setup_irq(IRQ_TIMER2, &s5pv310_clock_event_irq);
+}
+
+static cycle_t s5pv310_pwm4_read(struct clocksource *cs)
+{
+       return (cycle_t) ~__raw_readl(S3C_TIMERREG(0x40));
+}
+
+struct clocksource pwm_clocksource = {
+       .name           = "pwm_timer4",
+       .rating         = 250,
+       .read           = s5pv310_pwm4_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 20,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS ,
+};
+
+static void __init s5pv310_clocksource_init(void)
+{
+       unsigned long pclk;
+       unsigned long clock_rate;
+
+       pclk = clk_get_rate(timerclk);
+

arch/arm/mach-s5pv310/time.c

Quoted 10 lines
arch/arm/mach-s5pv310/time.c new file +10 -0
+       clk_set_rate(tdiv4, pclk / 2);
+       clk_set_parent(tin4, tdiv4);
+
+       clock_rate = clk_get_rate(tin4);
+
+       s5pv310_pwm_init(4, ~0);
+       s5pv310_pwm_start(4, 1);
+
+       pwm_clocksource.mult =
+               clocksource_khz2mult(clock_rate/1000,

pwm_clocksource.shift);

arch/arm/mach-s5pv310/time.c

Quoted 3 lines
arch/arm/mach-s5pv310/time.c new file +3 -0
+
+       if (clocksource_register(&pwm_clocksource))
+               panic("%s: can't register clocksource\n",

pwm_clocksource.name);

arch/arm/plat-

Quoted 51 lines
arch/arm/mach-s5pv310/time.c new file +50 -0
+}
+
+static void __init s5pv310_timer_resources(void)
+{
+       struct platform_device tmpdev;
+
+       tmpdev.dev.bus = &platform_bus_type;
+
+       timerclk = clk_get(NULL, "timers");
+       if (IS_ERR(timerclk))
+               panic("failed to get timers clock for system timer");
+
+       clk_enable(timerclk);
+
+       tmpdev.id = 2;
+       tin2 = clk_get(&tmpdev.dev, "pwm-tin");
+       if (IS_ERR(tin2))
+               panic("failed to get pwm-tin2 clock for system timer");
+
+       tdiv2 = clk_get(&tmpdev.dev, "pwm-tdiv");
+       if (IS_ERR(tdiv2))
+               panic("failed to get pwm-tdiv2 clock for system timer");
+       clk_enable(tin2);
+
+       tmpdev.id = 4;
+       tin4 = clk_get(&tmpdev.dev, "pwm-tin");
+       if (IS_ERR(tin4))
+               panic("failed to get pwm-tin4 clock for system timer");
+
+       tdiv4 = clk_get(&tmpdev.dev, "pwm-tdiv");
+       if (IS_ERR(tdiv4))
+               panic("failed to get pwm-tdiv4 clock for system timer");
+
+       clk_enable(tin4);
+}
+
+static void __init s5pv310_timer_init(void)
+{
+#ifdef CONFIG_LOCAL_TIMERS
+       twd_base = S5P_VA_TWD;
+#endif
+
+       s5pv310_timer_resources();
+       s5pv310_clockevent_init();
+       s5pv310_clocksource_init();
+}
+
+struct sys_timer s5pv310_timer = {
+       .init           = s5pv310_timer_init,
+};
arch/arm/plat- renamed from arch/arm/plat-s5p/include/plat/s5pv310.h +0 -0

s5p/include/plat/s5pv310.h

arch/arm/plat-

Quoted 12 lines

index d2f05e1..769c991 100644

arch/arm/plat-s5p/include/plat/s5pv310.h +1 -0
@@ -22,6 +22,7 @@ extern  int s5pv310_init(void);
  extern void s5pv310_init_irq(void);
  extern void s5pv310_map_io(void);
  extern void s5pv310_init_clocks(int xtal);
+extern struct sys_timer s5pv310_timer;
 
  #define s5pv310_init_uarts s5pv310_common_init_uarts
 
arch/arm/plat- renamed from arch/arm/plat-samsung/Makefile +0 -0

samsung/Makefile

Quoted 15 lines

index b1d82cc..0d5bf8a 100644

arch/arm/plat-samsung/Makefile +0 -0
@@ -12,7 +12,7 @@ obj-                          :=
  # Objects we always build independent of SoC choice
 

 obj-y                          += init.o

arch/arm/plat-samsung/Makefile +1 -1
-obj-y                          += time.o
+obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET)   += time.o

 obj-y                          += clock.o
 obj-y                          += pwm-clock.o
 obj-y                          += gpio.o
--
1.6.2.5

Quoted 2 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-

soc" in

Quoted 3 lines

the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#3 lore raw

PATCH v4 5/8 ARM: S5PV310: Add Timer support

Quoted 6 lines · Sangbeom Kim

Hi! Kyungmin,

After booting, clock event is generated by 2 arm private timers. What do you mean by 'change the pwm2 pin to i2c functions' ? What do you use for I2C emulation? (TOUT2 or gpio) Could you explain it in detail?

In the spec, PWM2 is muxed with I2C_7. I muxed it I2C pin to use i2c chip.

Thank you,
Kyungmin Park

Quoted 501 lines

Thanks and regards,
Sangbeom Kim

Quoted 299 lines · Kyungmin Park

Can you confirm that during boot time, change the pwm2 pin to i2c functions and still it's working correctly?

1. pwm2 is used for clock event at first boot.
2. during i2c init, pwm2 pin is changed to i2c functionality.

then where can get the clockevent?

Another possible scenarios is that.
pwm2 pin is changed to i2c function at bootloader to access the i2c chips. Then below code is working?

Thank you,
Kyungmin Park

Quoted 13 lines · Kukjin Kim

From: Changhwan Youn <[email protected]>

This patch adds timer support for S5PV310. ?Until now, all S5P SoCs use CONFIG_ARCH_USES_GETTIMEOFFSET macro as a default configuration. Instead,S5PV310 implements clocksource and clock_event_device to support the high resolution timer and tickless system.

---
Changes since v3:

Quoted 6 lines

- Changes clock source from PWM2 to PWM4 because PWM4 cannot be used for ?other purpose such as external output function through GPIO.

?arch/arm/mach-s5pv310/include/mach/pwm-clock.h | ? 70 ++++++
?arch/arm/mach-s5pv310/localtimer.c ? ? ? ? ? ? | ? 25 ++
?arch/arm/mach-s5pv310/time.c ? ? ? ? ? ? ? ? ? | ?287

++++++++++++++++++++++++

Review

Quoted 8 lines

?arch/arm/plat-s5p/include/plat/s5pv310.h ? ? ? | ? ?1 + ?arch/arm/plat-samsung/Makefile ? ? ? ? ? ? ? ? | ? ?2 +- ?5 files changed, 384 insertions(+), 1 deletions(-) ?create mode 100644 arch/arm/mach-s5pv310/include/mach/pwm-clock.h ?create mode 100644 arch/arm/mach-s5pv310/localtimer.c ?create mode 100644 arch/arm/mach-s5pv310/time.c

(quoted diff) +0 -0

b/arch/arm/mach-s5pv310/include/mach/pwm-clock.h

arch/arm/mach-

Quoted 76 lines

new file mode 100644
index 0000000..7e6da27

arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +70 -0
@@ -0,0 +1,70 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/pwm-clock.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * ? ? ? ? ? ? http://www.samsung.com/
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * ? ? ?Ben Dooks <[email protected]>
+ * ? ? ?http://armlinux.simtec.co.uk/
+ *
+ * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
+ *
+ * S5PV310 - pwm clock and timer support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_PWMCLK_H
+#define __ASM_ARCH_PWMCLK_H __FILE__
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+ ? ? ? return tcfg == S3C64XX_TCFG1_MUX_TCLK;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+ ? ? ? return 1 << tcfg1;
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+ ? ? ? return 1;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+ ? ? ? return ilog2(div);
+}
+
+#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
+
+#endif /* __ASM_ARCH_PWMCLK_H */
arch/arm/mach- renamed from arch/arm/mach-s5pv310/localtimer.c +0 -0

s5pv310/localtimer.c

Quoted 177 lines

new file mode 100644
index 0000000..2784036

arch/arm/mach-s5pv310/localtimer.c new file +25 -0
@@ -0,0 +1,25 @@
+/* linux/arch/arm/mach-s5pv310/localtimer.c
+ *
+ * Cloned from linux/arch/arm/mach-realview/localtimer.c
+ *
+ * ?Copyright (C) 2002 ARM Ltd.
+ * ?All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clockchips.h>
+
+#include <asm/irq.h>
+#include <asm/localtimer.h>
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+ ? ? ? evt->irq = IRQ_LOCALTIMER;
+ ? ? ? twd_timer_setup(evt);
+}
arch/arm/mach-s5pv310/time.c new file +141 -0
new file mode 100644
index 0000000..01b012a
@@ -0,0 +1,287 @@
+/* linux/arch/arm/mach-s5pv310/time.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * ? ? ? ? ? ? http://www.samsung.com
+ *
+ * S5PV310 (and compatible) HRT support
+ * PWM 2/4 is used for this feature
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+
+#include <asm/smp_twd.h>
+
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <asm/mach/time.h>
+
+static unsigned long clock_count_per_tick;
+
+static struct clk *tin2;
+static struct clk *tin4;
+static struct clk *tdiv2;
+static struct clk *tdiv4;
+static struct clk *timerclk;
+
+static void s5pv310_pwm_stop(unsigned int pwm_id)
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon = __raw_readl(S3C2410_TCON);
+
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2START;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4START;
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+ ? ? ? __raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon = __raw_readl(S3C2410_TCON);
+
+ ? ? ? /* timers reload after counting zero, so reduce the count by 1 */
+ ? ? ? tcnt--;
+
+ ? ? ? /* ensure timer is stopped... */
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon &= ~(0xf<<12);
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2MANUALUPD;
+
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCNTB(2));
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCMPB(2));
+ ? ? ? ? ? ? ? __raw_writel(tcon, S3C2410_TCON);
+
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon &= ~(7<<20);
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4MANUALUPD;
+
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCNTB(4));
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCMPB(4));
+ ? ? ? ? ? ? ? __raw_writel(tcon, S3C2410_TCON);
+
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+}
+
+static inline void s5pv310_pwm_start(unsigned int pwm_id, bool periodic)
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon ?= __raw_readl(S3C2410_TCON);
+
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2START;
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2MANUALUPD;
+
+ ? ? ? ? ? ? ? if (periodic)
+ ? ? ? ? ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2RELOAD;
+ ? ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2RELOAD;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4START;
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4MANUALUPD;
+
+ ? ? ? ? ? ? ? if (periodic)
+ ? ? ? ? ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4RELOAD;
+ ? ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4RELOAD;
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+ ? ? ? __raw_writel(tcon, S3C2410_TCON);
+}
+
+static int s5pv310_pwm_set_next_event(unsigned long cycles,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
+{
+ ? ? ? s5pv310_pwm_init(2, cycles);
+ ? ? ? s5pv310_pwm_start(2, 0);
+ ? ? ? return 0;
+}
+
+static void s5pv310_pwm_set_mode(enum clock_event_mode mode,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
+{
+ ? ? ? s5pv310_pwm_stop(2);
+
+ ? ? ? switch (mode) {
+ ? ? ? case CLOCK_EVT_MODE_PERIODIC:
+ ? ? ? ? ? ? ? s5pv310_pwm_init(2, clock_count_per_tick);
+ ? ? ? ? ? ? ? s5pv310_pwm_start(2, 1);
+ ? ? ? ? ? ? ? break;
+ ? ? ? case CLOCK_EVT_MODE_ONESHOT:
+ ? ? ? ? ? ? ? break;
+ ? ? ? case CLOCK_EVT_MODE_UNUSED:
+ ? ? ? case CLOCK_EVT_MODE_SHUTDOWN:
Quoted 8 lines

arch/arm/mach-s5pv310/time.c line 149

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+ ? ? ? case CLOCK_EVT_MODE_RESUME:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+}
+
+static struct clock_event_device pwm_event_device = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer2",
+ ? ? ? .features ? ? ? = CLOCK_EVT_FEAT_PERIODIC |

CLOCK_EVT_FEAT_ONESHOT,

Quoted 173 lines
Quoted 75 lines
arch/arm/mach-s5pv310/time.c new file +75 -0
+ ? ? ? .rating ? ? ? ? = 200,
+ ? ? ? .shift ? ? ? ? ?= 32,
+ ? ? ? .set_next_event = s5pv310_pwm_set_next_event,
+ ? ? ? .set_mode ? ? ? = s5pv310_pwm_set_mode,
+};
+
+irqreturn_t s5pv310_clock_event_isr(int irq, void *dev_id)
+{
+ ? ? ? struct clock_event_device *evt = &pwm_event_device;
+
+ ? ? ? evt->event_handler(evt);
+
+ ? ? ? return IRQ_HANDLED;
+}
+
+static struct irqaction s5pv310_clock_event_irq = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer2_irq",
+ ? ? ? .flags ? ? ? ? ?= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ ? ? ? .handler ? ? ? ?= s5pv310_clock_event_isr,
+};
+
+static void __init s5pv310_clockevent_init(void)
+{
+ ? ? ? unsigned long pclk;
+ ? ? ? unsigned long clock_rate;
+ ? ? ? struct clk *tscaler;
+
+ ? ? ? pclk = clk_get_rate(timerclk);
+
+ ? ? ? /* configure clock tick */
+
+ ? ? ? tscaler = clk_get_parent(tdiv2);
+
+ ? ? ? clk_set_rate(tscaler, pclk / 2);
+ ? ? ? clk_set_rate(tdiv2, pclk / 2);
+ ? ? ? clk_set_parent(tin2, tdiv2);
+
+ ? ? ? clock_rate = clk_get_rate(tin2);
+
+ ? ? ? clock_count_per_tick = clock_rate / HZ;
+
+ ? ? ? pwm_event_device.mult =
+ ? ? ? ? ? ? ? div_sc(clock_rate, NSEC_PER_SEC, pwm_event_device.shift);
+ ? ? ? pwm_event_device.max_delta_ns =
+ ? ? ? ? ? ? ? clockevent_delta2ns(-1, &pwm_event_device);
+ ? ? ? pwm_event_device.min_delta_ns =
+ ? ? ? ? ? ? ? clockevent_delta2ns(1, &pwm_event_device);
+
+ ? ? ? pwm_event_device.cpumask = cpumask_of(0);
+ ? ? ? clockevents_register_device(&pwm_event_device);
+
+ ? ? ? setup_irq(IRQ_TIMER2, &s5pv310_clock_event_irq);
+}
+
+static cycle_t s5pv310_pwm4_read(struct clocksource *cs)
+{
+ ? ? ? return (cycle_t) ~__raw_readl(S3C_TIMERREG(0x40));
+}
+
+struct clocksource pwm_clocksource = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer4",
+ ? ? ? .rating ? ? ? ? = 250,
+ ? ? ? .read ? ? ? ? ? = s5pv310_pwm4_read,
+ ? ? ? .mask ? ? ? ? ? = CLOCKSOURCE_MASK(32),
+ ? ? ? .shift ? ? ? ? ?= 20,
+ ? ? ? .flags ? ? ? ? ?= CLOCK_SOURCE_IS_CONTINUOUS ,
+};
+
+static void __init s5pv310_clocksource_init(void)
+{
+ ? ? ? unsigned long pclk;
+ ? ? ? unsigned long clock_rate;
+
+ ? ? ? pclk = clk_get_rate(timerclk);
+

arch/arm/mach-s5pv310/time.c line 234

Quoted 10 lines
arch/arm/mach-s5pv310/time.c new file +10 -0
+ ? ? ? clk_set_rate(tdiv4, pclk / 2);
+ ? ? ? clk_set_parent(tin4, tdiv4);
+
+ ? ? ? clock_rate = clk_get_rate(tin4);
+
+ ? ? ? s5pv310_pwm_init(4, ~0);
+ ? ? ? s5pv310_pwm_start(4, 1);
+
+ ? ? ? pwm_clocksource.mult =
+ ? ? ? ? ? ? ? clocksource_khz2mult(clock_rate/1000,

pwm_clocksource.shift);

arch/arm/mach-s5pv310/time.c line 237

Quoted 3 lines
arch/arm/mach-s5pv310/time.c new file +3 -0
+
+ ? ? ? if (clocksource_register(&pwm_clocksource))
+ ? ? ? ? ? ? ? panic("%s: can't register clocksource\n",

pwm_clocksource.name);

arch/arm/plat-

Quoted 51 lines
arch/arm/mach-s5pv310/time.c new file +50 -0
+}
+
+static void __init s5pv310_timer_resources(void)
+{
+ ? ? ? struct platform_device tmpdev;
+
+ ? ? ? tmpdev.dev.bus = &platform_bus_type;
+
+ ? ? ? timerclk = clk_get(NULL, "timers");
+ ? ? ? if (IS_ERR(timerclk))
+ ? ? ? ? ? ? ? panic("failed to get timers clock for system timer");
+
+ ? ? ? clk_enable(timerclk);
+
+ ? ? ? tmpdev.id = 2;
+ ? ? ? tin2 = clk_get(&tmpdev.dev, "pwm-tin");
+ ? ? ? if (IS_ERR(tin2))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tin2 clock for system timer");
+
+ ? ? ? tdiv2 = clk_get(&tmpdev.dev, "pwm-tdiv");
+ ? ? ? if (IS_ERR(tdiv2))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tdiv2 clock for system timer");
+ ? ? ? clk_enable(tin2);
+
+ ? ? ? tmpdev.id = 4;
+ ? ? ? tin4 = clk_get(&tmpdev.dev, "pwm-tin");
+ ? ? ? if (IS_ERR(tin4))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tin4 clock for system timer");
+
+ ? ? ? tdiv4 = clk_get(&tmpdev.dev, "pwm-tdiv");
+ ? ? ? if (IS_ERR(tdiv4))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tdiv4 clock for system timer");
+
+ ? ? ? clk_enable(tin4);
+}
+
+static void __init s5pv310_timer_init(void)
+{
+#ifdef CONFIG_LOCAL_TIMERS
+ ? ? ? twd_base = S5P_VA_TWD;
+#endif
+
+ ? ? ? s5pv310_timer_resources();
+ ? ? ? s5pv310_clockevent_init();
+ ? ? ? s5pv310_clocksource_init();
+}
+
+struct sys_timer s5pv310_timer = {
+ ? ? ? .init ? ? ? ? ? = s5pv310_timer_init,
+};
arch/arm/plat- renamed from arch/arm/plat-s5p/include/plat/s5pv310.h +0 -0

s5p/include/plat/s5pv310.h

arch/arm/plat-

Quoted 12 lines

index d2f05e1..769c991 100644

arch/arm/plat-s5p/include/plat/s5pv310.h +1 -0
@@ -22,6 +22,7 @@ extern ?int s5pv310_init(void);
 ?extern void s5pv310_init_irq(void);
 ?extern void s5pv310_map_io(void);
 ?extern void s5pv310_init_clocks(int xtal);
+extern struct sys_timer s5pv310_timer;
 

?#define s5pv310_init_uarts s5pv310_common_init_uarts

arch/arm/plat- renamed from arch/arm/plat-samsung/Makefile +0 -0

samsung/Makefile

Quoted 15 lines

index b1d82cc..0d5bf8a 100644

arch/arm/plat-samsung/Makefile +0 -0
@@ -12,7 +12,7 @@ obj- ? ? ? ? ? ? ? ? ? ? ? ? ?:=

?# Objects we always build independent of SoC choice

?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= init.o

arch/arm/plat-samsung/Makefile +1 -1
-obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= time.o
+obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) ? += time.o

?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= clock.o
?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= pwm-clock.o
?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= gpio.o
--
1.6.2.5

Quoted 2 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-

soc" in

Quoted 8 lines
Quoted 3 lines

the body of a message to majordomo at vger.kernel.org More majordomo info at ?http://vger.kernel.org/majordomo-info.html

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html

#4 lore raw

PATCH v4 5/8 ARM: S5PV310: Add Timer support

Thanks for your answer,
If you want use to GPD0[2] as I2C_7, you can use it as I2C port. Because We don't use PWM2 Tout.
We only use pwm timer2 for internal operation.
Thanks,

Quoted 8 lines · Kyungmin Park
Quoted 6 lines · Sangbeom Kim

Hi! Kyungmin,

After booting, clock event is generated by 2 arm private timers. What do you mean by 'change the pwm2 pin to i2c functions' ? What do you use for I2C emulation? (TOUT2 or gpio) Could you explain it in detail?

Quoted 20 lines

In the spec, PWM2 is muxed with I2C_7. I muxed it I2C pin to use i2c chip.

Thank you,
Kyungmin Park

Quoted 16 lines

Thanks and regards,
Sangbeom Kim

Quoted 10 lines · Kyungmin Park

Can you confirm that during boot time, change the pwm2 pin to i2c functions and still it's working correctly?

1. pwm2 is used for clock event at first boot.
2. during i2c init, pwm2 pin is changed to i2c functionality.

then where can get the clockevent?

Another possible scenarios is that.
pwm2 pin is changed to i2c function at bootloader to access the i2c

chips.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Then below code is working?

Thank you,
Kyungmin Park

On Mon, Jul 26, 2010 at 9:42 PM, Kukjin Kim <[email protected]>

Quoted 335 lines · wrote:
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

From: Changhwan Youn <[email protected]>

This patch adds timer support for S5PV310.  Until now, all S5P SoCs use CONFIG_ARCH_USES_GETTIMEOFFSET macro as a default configuration. Instead,S5PV310 implements clocksource and clock_event_device to support the high resolution timer and tickless system.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

---
Changes since v3:

- Changes clock source from PWM2 to PWM4 because PWM4 cannot be used

for

Quoted 27 lines
Quoted 27 lines
Quoted 5 lines

 other purpose such as external output function through GPIO.

 arch/arm/mach-s5pv310/include/mach/pwm-clock.h |   70 ++++++ arch/arm/mach-s5pv310/localtimer.c             |   25 ++ arch/arm/mach-s5pv310/time.c                   |  287

++++++++++++++++++++++++

Review

Quoted 8 lines

 arch/arm/plat-s5p/include/plat/s5pv310.h       |    1 + arch/arm/plat-samsung/Makefile                 |    2 +-

 5 files changed, 384 insertions(+), 1 deletions(-)

 create mode 100644 arch/arm/mach-s5pv310/include/mach/pwm-clock.h create mode 100644 arch/arm/mach-s5pv310/localtimer.c create mode 100644 arch/arm/mach-s5pv310/time.c

(quoted diff) +0 -0

b/arch/arm/mach-s5pv310/include/mach/pwm-clock.h

Quoted 12 lines

new file mode 100644
index 0000000..7e6da27

arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +7 -0
@@ -0,0 +1,70 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/pwm-clock.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/include/mach/pwm-clock.h

Quoted 8 lines
arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +8 -0
+ *      Ben Dooks <[email protected]>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
+ *
+ * S5PV310 - pwm clock and timer support
+ *
+ * This program is free software; you can redistribute it and/or

modify

Quoted 9 lines
Quoted 9 lines

arch/arm/mach-s5pv310/include/mach/pwm-clock.h

Quoted 9 lines
arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +9 -0
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_PWMCLK_H
+#define __ASM_ARCH_PWMCLK_H __FILE__
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a

tclk

Quoted 48 lines
Quoted 48 lines

arch/arm/mach-

Quoted 47 lines
arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +46 -0
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+       return tcfg == S3C64XX_TCFG1_MUX_TCLK;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+       return 1 << tcfg1;
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+       return 1;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+       return ilog2(div);
+}
+
+#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
+
+#endif /* __ASM_ARCH_PWMCLK_H */
arch/arm/mach- renamed from arch/arm/mach-s5pv310/localtimer.c +0 -0

s5pv310/localtimer.c

Quoted 13 lines
Quoted 5 lines
Quoted 5 lines

new file mode 100644
index 0000000..2784036

arch/arm/mach-s5pv310/localtimer.c new file +0 -0
@@ -0,0 +1,25 @@
Quoted 8 lines

arch/arm/mach-s5pv310/localtimer.c

Quoted 8 lines
arch/arm/mach-s5pv310/localtimer.c new file +8 -0
+/* linux/arch/arm/mach-s5pv310/localtimer.c
+ *
+ * Cloned from linux/arch/arm/mach-realview/localtimer.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or

modify

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
arch/arm/mach-s5pv310/localtimer.c new file +10 -0
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clockchips.h>
+
+#include <asm/irq.h>
+#include <asm/localtimer.h>
+
+/*
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-

Quoted 8 lines
arch/arm/mach-s5pv310/localtimer.c new file +7 -0
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+       evt->irq = IRQ_LOCALTIMER;
+       twd_timer_setup(evt);
+}
arch/arm/mach- renamed from arch/arm/mach-s5pv310/time.c +0 -0

s5pv310/time.c

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

new file mode 100644
index 0000000..01b012a

arch/arm/mach-s5pv310/time.c new file +1 -0
@@ -0,0 +1,287 @@
+/* linux/arch/arm/mach-s5pv310/time.c
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5PV310 (and compatible) HRT support
+ * PWM 2/4 is used for this feature
+ *
+ * This program is free software; you can redistribute it and/or

modify

Quoted 44 lines
Quoted 44 lines
Quoted 44 lines
arch/arm/mach-s5pv310/time.c new file +44 -0
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+
+#include <asm/smp_twd.h>
+
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <asm/mach/time.h>
+
+static unsigned long clock_count_per_tick;
+
+static struct clk *tin2;
+static struct clk *tin4;
+static struct clk *tdiv2;
+static struct clk *tdiv4;
+static struct clk *timerclk;
+
+static void s5pv310_pwm_stop(unsigned int pwm_id)
+{
+       unsigned long tcon;
+
+       tcon = __raw_readl(S3C2410_TCON);
+
+       switch (pwm_id) {
+       case 2:
+               tcon &= ~S3C2410_TCON_T2START;
+               break;
+       case 4:
+               tcon &= ~S3C2410_TCON_T4START;
+               break;
+       default:
+               break;
+       }
+       __raw_writel(tcon, S3C2410_TCON);
+}
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+
+static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
+{
+       unsigned long tcon;
+
+       tcon = __raw_readl(S3C2410_TCON);
+
+       /* timers reload after counting zero, so reduce the count by 1

*/

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
arch/arm/mach-s5pv310/time.c new file +20 -0
+       tcnt--;
+
+       /* ensure timer is stopped... */
+       switch (pwm_id) {
+       case 2:
+               tcon &= ~(0xf<<12);
+               tcon |= S3C2410_TCON_T2MANUALUPD;
+
+               __raw_writel(tcnt, S3C2410_TCNTB(2));
+               __raw_writel(tcnt, S3C2410_TCMPB(2));
+               __raw_writel(tcon, S3C2410_TCON);
+
+               break;
+       case 4:
+               tcon &= ~(7<<20);
+               tcon |= S3C2410_TCON_T4MANUALUPD;
+
+               __raw_writel(tcnt, S3C2410_TCNTB(4));
+               __raw_writel(tcnt, S3C2410_TCMPB(4));
+               __raw_writel(tcon, S3C2410_TCON);
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+
+               break;
+       default:
+               break;
+       }
+}
+
+static inline void s5pv310_pwm_start(unsigned int pwm_id, bool

periodic)

Quoted 96 lines
Quoted 52 lines
Quoted 52 lines
arch/arm/mach-s5pv310/time.c new file +52 -0
+{
+       unsigned long tcon;
+
+       tcon  = __raw_readl(S3C2410_TCON);
+
+       switch (pwm_id) {
+       case 2:
+               tcon |= S3C2410_TCON_T2START;
+               tcon &= ~S3C2410_TCON_T2MANUALUPD;
+
+               if (periodic)
+                       tcon |= S3C2410_TCON_T2RELOAD;
+               else
+                       tcon &= ~S3C2410_TCON_T2RELOAD;
+               break;
+       case 4:
+               tcon |= S3C2410_TCON_T4START;
+               tcon &= ~S3C2410_TCON_T4MANUALUPD;
+
+               if (periodic)
+                       tcon |= S3C2410_TCON_T4RELOAD;
+               else
+                       tcon &= ~S3C2410_TCON_T4RELOAD;
+               break;
+       default:
+               break;
+       }
+       __raw_writel(tcon, S3C2410_TCON);
+}
+
+static int s5pv310_pwm_set_next_event(unsigned long cycles,
+                                       struct clock_event_device *evt)
+{
+       s5pv310_pwm_init(2, cycles);
+       s5pv310_pwm_start(2, 0);
+       return 0;
+}
+
+static void s5pv310_pwm_set_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt)
+{
+       s5pv310_pwm_stop(2);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               s5pv310_pwm_init(2, clock_count_per_tick);
+               s5pv310_pwm_start(2, 1);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static struct clock_event_device pwm_event_device = {
+       .name           = "pwm_timer2",
+       .features       = CLOCK_EVT_FEAT_PERIODIC |

CLOCK_EVT_FEAT_ONESHOT,

Quoted 35 lines
Quoted 35 lines
arch/arm/mach-s5pv310/time.c new file +35 -0
+       .rating         = 200,
+       .shift          = 32,
+       .set_next_event = s5pv310_pwm_set_next_event,
+       .set_mode       = s5pv310_pwm_set_mode,
+};
+
+irqreturn_t s5pv310_clock_event_isr(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &pwm_event_device;
+
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction s5pv310_clock_event_irq = {
+       .name           = "pwm_timer2_irq",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = s5pv310_clock_event_isr,
+};
+
+static void __init s5pv310_clockevent_init(void)
+{
+       unsigned long pclk;
+       unsigned long clock_rate;
+       struct clk *tscaler;
+
+       pclk = clk_get_rate(timerclk);
+
+       /* configure clock tick */
+
+       tscaler = clk_get_parent(tdiv2);
+
+       clk_set_rate(tscaler, pclk / 2);
+       clk_set_rate(tdiv2, pclk / 2);
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+       clk_set_parent(tin2, tdiv2);
+
+       clock_rate = clk_get_rate(tin2);
+
+       clock_count_per_tick = clock_rate / HZ;
+
+       pwm_event_device.mult =
+               div_sc(clock_rate, NSEC_PER_SEC,

pwm_event_device.shift);

Quoted 61 lines
Quoted 61 lines
Quoted 61 lines
Quoted 32 lines
arch/arm/mach-s5pv310/time.c new file +32 -0
+       pwm_event_device.max_delta_ns =
+               clockevent_delta2ns(-1, &pwm_event_device);
+       pwm_event_device.min_delta_ns =
+               clockevent_delta2ns(1, &pwm_event_device);
+
+       pwm_event_device.cpumask = cpumask_of(0);
+       clockevents_register_device(&pwm_event_device);
+
+       setup_irq(IRQ_TIMER2, &s5pv310_clock_event_irq);
+}
+
+static cycle_t s5pv310_pwm4_read(struct clocksource *cs)
+{
+       return (cycle_t) ~__raw_readl(S3C_TIMERREG(0x40));
+}
+
+struct clocksource pwm_clocksource = {
+       .name           = "pwm_timer4",
+       .rating         = 250,
+       .read           = s5pv310_pwm4_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 20,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS ,
+};
+
+static void __init s5pv310_clocksource_init(void)
+{
+       unsigned long pclk;
+       unsigned long clock_rate;
+
+       pclk = clk_get_rate(timerclk);
+

arch/arm/mach-s5pv310/time.c

Quoted 10 lines
arch/arm/mach-s5pv310/time.c new file +10 -0
+       clk_set_rate(tdiv4, pclk / 2);
+       clk_set_parent(tin4, tdiv4);
+
+       clock_rate = clk_get_rate(tin4);
+
+       s5pv310_pwm_init(4, ~0);
+       s5pv310_pwm_start(4, 1);
+
+       pwm_clocksource.mult =
+               clocksource_khz2mult(clock_rate/1000,

pwm_clocksource.shift);

arch/arm/mach-s5pv310/time.c

Quoted 3 lines
arch/arm/mach-s5pv310/time.c new file +3 -0
+
+       if (clocksource_register(&pwm_clocksource))
+               panic("%s: can't register clocksource\n",

pwm_clocksource.name);

Quoted 14 lines
arch/arm/mach-s5pv310/time.c new file +14 -0
+}
+
+static void __init s5pv310_timer_resources(void)
+{
+       struct platform_device tmpdev;
+
+       tmpdev.dev.bus = &platform_bus_type;
+
+       timerclk = clk_get(NULL, "timers");
+       if (IS_ERR(timerclk))
+               panic("failed to get timers clock for system timer");
+
+       clk_enable(timerclk);
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+       tmpdev.id = 2;
+       tin2 = clk_get(&tmpdev.dev, "pwm-tin");
+       if (IS_ERR(tin2))
+               panic("failed to get pwm-tin2 clock for system timer");
+
+       tdiv2 = clk_get(&tmpdev.dev, "pwm-tdiv");
+       if (IS_ERR(tdiv2))
+               panic("failed to get pwm-tdiv2 clock for system

timer");

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

arch/arm/mach-s5pv310/time.c

Quoted 10 lines
arch/arm/mach-s5pv310/time.c new file +10 -0
+       clk_enable(tin2);
+
+       tmpdev.id = 4;
+       tin4 = clk_get(&tmpdev.dev, "pwm-tin");
+       if (IS_ERR(tin4))
+               panic("failed to get pwm-tin4 clock for system timer");
+
+       tdiv4 = clk_get(&tmpdev.dev, "pwm-tdiv");
+       if (IS_ERR(tdiv4))
+               panic("failed to get pwm-tdiv4 clock for system

timer");

Quoted 72 lines
Quoted 48 lines
Quoted 48 lines

arch/arm/plat-

Quoted 19 lines
arch/arm/mach-s5pv310/time.c new file +18 -0
+
+       clk_enable(tin4);
+}
+
+static void __init s5pv310_timer_init(void)
+{
+#ifdef CONFIG_LOCAL_TIMERS
+       twd_base = S5P_VA_TWD;
+#endif
+
+       s5pv310_timer_resources();
+       s5pv310_clockevent_init();
+       s5pv310_clocksource_init();
+}
+
+struct sys_timer s5pv310_timer = {
+       .init           = s5pv310_timer_init,
+};
arch/arm/plat- renamed from arch/arm/plat-s5p/include/plat/s5pv310.h +0 -0

s5p/include/plat/s5pv310.h

arch/arm/plat-

Quoted 12 lines

index d2f05e1..769c991 100644

arch/arm/plat-s5p/include/plat/s5pv310.h +1 -0
@@ -22,6 +22,7 @@ extern  int s5pv310_init(void);
  extern void s5pv310_init_irq(void);
  extern void s5pv310_map_io(void);
  extern void s5pv310_init_clocks(int xtal);
+extern struct sys_timer s5pv310_timer;
 
  #define s5pv310_init_uarts s5pv310_common_init_uarts
 
arch/arm/plat- renamed from arch/arm/plat-samsung/Makefile +0 -0

samsung/Makefile

Quoted 15 lines

index b1d82cc..0d5bf8a 100644

arch/arm/plat-samsung/Makefile +0 -0
@@ -12,7 +12,7 @@ obj-                          :=
  # Objects we always build independent of SoC choice
 

 obj-y                          += init.o

arch/arm/plat-samsung/Makefile +1 -1
-obj-y                          += time.o
+obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET)   += time.o

 obj-y                          += clock.o
 obj-y                          += pwm-clock.o
 obj-y                          += gpio.o
--
1.6.2.5

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-

samsung-

Quoted 5 lines
Quoted 5 lines

soc" in

Quoted 3 lines

the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Quoted 7 lines
Quoted 4 lines

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-

soc" in

Quoted 3 lines

the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung- soc" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#5 lore raw

PATCH v4 5/8 ARM: S5PV310: Add Timer support

You mean we can use pwm2 and I2c simultaneously since we don't use the Tout.

Do you also consider low power audio case? In the previous time to this reason, HRT uses the RTC and systimer.

anyway thank you for clarification.

Thank you,
Kyungmin Park

Quoted 546 lines · Sangbeom Kim

Thanks for your answer,
If you want use to GPD0[2] as I2C_7, you can use it as I2C port. Because We don't use PWM2 Tout.
We only use pwm timer2 for internal operation.
Thanks,

Quoted 8 lines · Kyungmin Park
Quoted 6 lines · Sangbeom Kim

Hi! Kyungmin,

After booting, clock event is generated by 2 arm private timers. What do you mean by 'change the pwm2 pin to i2c functions' ? What do you use for I2C emulation? (TOUT2 or gpio) Could you explain it in detail?

Quoted 20 lines

In the spec, PWM2 is muxed with I2C_7. I muxed it I2C pin to use i2c chip.

Thank you,
Kyungmin Park

Quoted 16 lines

Thanks and regards,
Sangbeom Kim

Quoted 10 lines · Kyungmin Park

Can you confirm that during boot time, change the pwm2 pin to i2c functions and still it's working correctly?

1. pwm2 is used for clock event at first boot.
2. during i2c init, pwm2 pin is changed to i2c functionality.

then where can get the clockevent?

Another possible scenarios is that.
pwm2 pin is changed to i2c function at bootloader to access the i2c

chips.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Then below code is working?

Thank you,
Kyungmin Park

On Mon, Jul 26, 2010 at 9:42 PM, Kukjin Kim <[email protected]>

Quoted 335 lines · wrote:
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

From: Changhwan Youn <[email protected]>

This patch adds timer support for S5PV310. ?Until now, all S5P SoCs use CONFIG_ARCH_USES_GETTIMEOFFSET macro as a default configuration. Instead,S5PV310 implements clocksource and clock_event_device to support the high resolution timer and tickless system.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

---
Changes since v3:

- Changes clock source from PWM2 to PWM4 because PWM4 cannot be used

for

Quoted 27 lines
Quoted 27 lines
Quoted 5 lines

?other purpose such as external output function through GPIO.

?arch/arm/mach-s5pv310/include/mach/pwm-clock.h | ? 70 ++++++
?arch/arm/mach-s5pv310/localtimer.c ? ? ? ? ? ? | ? 25 ++
?arch/arm/mach-s5pv310/time.c ? ? ? ? ? ? ? ? ? | ?287

++++++++++++++++++++++++

Review

Quoted 8 lines

?arch/arm/plat-s5p/include/plat/s5pv310.h ? ? ? | ? ?1 + ?arch/arm/plat-samsung/Makefile ? ? ? ? ? ? ? ? | ? ?2 +- ?5 files changed, 384 insertions(+), 1 deletions(-) ?create mode 100644 arch/arm/mach-s5pv310/include/mach/pwm-clock.h ?create mode 100644 arch/arm/mach-s5pv310/localtimer.c ?create mode 100644 arch/arm/mach-s5pv310/time.c

(quoted diff) +0 -0

b/arch/arm/mach-s5pv310/include/mach/pwm-clock.h

Quoted 12 lines

new file mode 100644
index 0000000..7e6da27

arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +7 -0
@@ -0,0 +1,70 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/pwm-clock.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * ? ? ? ? ? ? http://www.samsung.com/
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/include/mach/pwm-clock.h

Quoted 8 lines
arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +8 -0
+ * ? ? ?Ben Dooks <[email protected]>
+ * ? ? ?http://armlinux.simtec.co.uk/
+ *
+ * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
+ *
+ * S5PV310 - pwm clock and timer support
+ *
+ * This program is free software; you can redistribute it and/or

modify

Quoted 9 lines
Quoted 9 lines

arch/arm/mach-s5pv310/include/mach/pwm-clock.h

Quoted 9 lines
arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +9 -0
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_PWMCLK_H
+#define __ASM_ARCH_PWMCLK_H __FILE__
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a

tclk

Quoted 48 lines
Quoted 48 lines

arch/arm/mach-

Quoted 47 lines
arch/arm/mach-s5pv310/include/mach/pwm-clock.h new file +46 -0
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+ ? ? ? return tcfg == S3C64XX_TCFG1_MUX_TCLK;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+ ? ? ? return 1 << tcfg1;
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+ ? ? ? return 1;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+ ? ? ? return ilog2(div);
+}
+
+#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
+
+#endif /* __ASM_ARCH_PWMCLK_H */
arch/arm/mach- renamed from arch/arm/mach-s5pv310/localtimer.c +0 -0

s5pv310/localtimer.c

Quoted 13 lines
Quoted 5 lines
Quoted 5 lines

new file mode 100644
index 0000000..2784036

arch/arm/mach-s5pv310/localtimer.c new file +0 -0
@@ -0,0 +1,25 @@
Quoted 8 lines

arch/arm/mach-s5pv310/localtimer.c

Quoted 8 lines
arch/arm/mach-s5pv310/localtimer.c new file +8 -0
+/* linux/arch/arm/mach-s5pv310/localtimer.c
+ *
+ * Cloned from linux/arch/arm/mach-realview/localtimer.c
+ *
+ * ?Copyright (C) 2002 ARM Ltd.
+ * ?All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or

modify

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
arch/arm/mach-s5pv310/localtimer.c new file +10 -0
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clockchips.h>
+
+#include <asm/irq.h>
+#include <asm/localtimer.h>
+
+/*
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-

Quoted 8 lines
arch/arm/mach-s5pv310/localtimer.c new file +7 -0
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+ ? ? ? evt->irq = IRQ_LOCALTIMER;
+ ? ? ? twd_timer_setup(evt);
+}
arch/arm/mach- renamed from arch/arm/mach-s5pv310/time.c +0 -0

s5pv310/time.c

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

new file mode 100644
index 0000000..01b012a

arch/arm/mach-s5pv310/time.c new file +1 -0
@@ -0,0 +1,287 @@
+/* linux/arch/arm/mach-s5pv310/time.c
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * ? ? ? ? ? ? http://www.samsung.com
+ *
+ * S5PV310 (and compatible) HRT support
+ * PWM 2/4 is used for this feature
+ *
+ * This program is free software; you can redistribute it and/or

modify

Quoted 44 lines
Quoted 44 lines
Quoted 44 lines
arch/arm/mach-s5pv310/time.c new file +44 -0
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+
+#include <asm/smp_twd.h>
+
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <asm/mach/time.h>
+
+static unsigned long clock_count_per_tick;
+
+static struct clk *tin2;
+static struct clk *tin4;
+static struct clk *tdiv2;
+static struct clk *tdiv4;
+static struct clk *timerclk;
+
+static void s5pv310_pwm_stop(unsigned int pwm_id)
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon = __raw_readl(S3C2410_TCON);
+
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2START;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4START;
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+ ? ? ? __raw_writel(tcon, S3C2410_TCON);
+}
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+
+static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon = __raw_readl(S3C2410_TCON);
+
+ ? ? ? /* timers reload after counting zero, so reduce the count by 1

*/

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
arch/arm/mach-s5pv310/time.c new file +20 -0
+ ? ? ? tcnt--;
+
+ ? ? ? /* ensure timer is stopped... */
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon &= ~(0xf<<12);
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2MANUALUPD;
+
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCNTB(2));
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCMPB(2));
+ ? ? ? ? ? ? ? __raw_writel(tcon, S3C2410_TCON);
+
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon &= ~(7<<20);
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4MANUALUPD;
+
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCNTB(4));
+ ? ? ? ? ? ? ? __raw_writel(tcnt, S3C2410_TCMPB(4));
+ ? ? ? ? ? ? ? __raw_writel(tcon, S3C2410_TCON);
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c line 89

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+}
+
+static inline void s5pv310_pwm_start(unsigned int pwm_id, bool

periodic)

Quoted 96 lines
Quoted 52 lines
Quoted 52 lines
arch/arm/mach-s5pv310/time.c new file +52 -0
+{
+ ? ? ? unsigned long tcon;
+
+ ? ? ? tcon ?= __raw_readl(S3C2410_TCON);
+
+ ? ? ? switch (pwm_id) {
+ ? ? ? case 2:
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2START;
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2MANUALUPD;
+
+ ? ? ? ? ? ? ? if (periodic)
+ ? ? ? ? ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T2RELOAD;
+ ? ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T2RELOAD;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case 4:
+ ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4START;
+ ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4MANUALUPD;
+
+ ? ? ? ? ? ? ? if (periodic)
+ ? ? ? ? ? ? ? ? ? ? ? tcon |= S3C2410_TCON_T4RELOAD;
+ ? ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? ? tcon &= ~S3C2410_TCON_T4RELOAD;
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+ ? ? ? __raw_writel(tcon, S3C2410_TCON);
+}
+
+static int s5pv310_pwm_set_next_event(unsigned long cycles,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
+{
+ ? ? ? s5pv310_pwm_init(2, cycles);
+ ? ? ? s5pv310_pwm_start(2, 0);
+ ? ? ? return 0;
+}
+
+static void s5pv310_pwm_set_mode(enum clock_event_mode mode,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
+{
+ ? ? ? s5pv310_pwm_stop(2);
+
+ ? ? ? switch (mode) {
+ ? ? ? case CLOCK_EVT_MODE_PERIODIC:
+ ? ? ? ? ? ? ? s5pv310_pwm_init(2, clock_count_per_tick);
+ ? ? ? ? ? ? ? s5pv310_pwm_start(2, 1);
+ ? ? ? ? ? ? ? break;
+ ? ? ? case CLOCK_EVT_MODE_ONESHOT:
+ ? ? ? ? ? ? ? break;
+ ? ? ? case CLOCK_EVT_MODE_UNUSED:
+ ? ? ? case CLOCK_EVT_MODE_SHUTDOWN:
Quoted 8 lines

arch/arm/mach-s5pv310/time.c line 149

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+ ? ? ? case CLOCK_EVT_MODE_RESUME:
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+}
+
+static struct clock_event_device pwm_event_device = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer2",
+ ? ? ? .features ? ? ? = CLOCK_EVT_FEAT_PERIODIC |

CLOCK_EVT_FEAT_ONESHOT,

Quoted 35 lines
Quoted 35 lines
arch/arm/mach-s5pv310/time.c new file +35 -0
+ ? ? ? .rating ? ? ? ? = 200,
+ ? ? ? .shift ? ? ? ? ?= 32,
+ ? ? ? .set_next_event = s5pv310_pwm_set_next_event,
+ ? ? ? .set_mode ? ? ? = s5pv310_pwm_set_mode,
+};
+
+irqreturn_t s5pv310_clock_event_isr(int irq, void *dev_id)
+{
+ ? ? ? struct clock_event_device *evt = &pwm_event_device;
+
+ ? ? ? evt->event_handler(evt);
+
+ ? ? ? return IRQ_HANDLED;
+}
+
+static struct irqaction s5pv310_clock_event_irq = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer2_irq",
+ ? ? ? .flags ? ? ? ? ?= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ ? ? ? .handler ? ? ? ?= s5pv310_clock_event_isr,
+};
+
+static void __init s5pv310_clockevent_init(void)
+{
+ ? ? ? unsigned long pclk;
+ ? ? ? unsigned long clock_rate;
+ ? ? ? struct clk *tscaler;
+
+ ? ? ? pclk = clk_get_rate(timerclk);
+
+ ? ? ? /* configure clock tick */
+
+ ? ? ? tscaler = clk_get_parent(tdiv2);
+
+ ? ? ? clk_set_rate(tscaler, pclk / 2);
+ ? ? ? clk_set_rate(tdiv2, pclk / 2);
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c line 192

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+ ? ? ? clk_set_parent(tin2, tdiv2);
+
+ ? ? ? clock_rate = clk_get_rate(tin2);
+
+ ? ? ? clock_count_per_tick = clock_rate / HZ;
+
+ ? ? ? pwm_event_device.mult =
+ ? ? ? ? ? ? ? div_sc(clock_rate, NSEC_PER_SEC,

pwm_event_device.shift);

Quoted 61 lines
Quoted 61 lines
Quoted 61 lines
Quoted 32 lines
arch/arm/mach-s5pv310/time.c new file +32 -0
+ ? ? ? pwm_event_device.max_delta_ns =
+ ? ? ? ? ? ? ? clockevent_delta2ns(-1, &pwm_event_device);
+ ? ? ? pwm_event_device.min_delta_ns =
+ ? ? ? ? ? ? ? clockevent_delta2ns(1, &pwm_event_device);
+
+ ? ? ? pwm_event_device.cpumask = cpumask_of(0);
+ ? ? ? clockevents_register_device(&pwm_event_device);
+
+ ? ? ? setup_irq(IRQ_TIMER2, &s5pv310_clock_event_irq);
+}
+
+static cycle_t s5pv310_pwm4_read(struct clocksource *cs)
+{
+ ? ? ? return (cycle_t) ~__raw_readl(S3C_TIMERREG(0x40));
+}
+
+struct clocksource pwm_clocksource = {
+ ? ? ? .name ? ? ? ? ? = "pwm_timer4",
+ ? ? ? .rating ? ? ? ? = 250,
+ ? ? ? .read ? ? ? ? ? = s5pv310_pwm4_read,
+ ? ? ? .mask ? ? ? ? ? = CLOCKSOURCE_MASK(32),
+ ? ? ? .shift ? ? ? ? ?= 20,
+ ? ? ? .flags ? ? ? ? ?= CLOCK_SOURCE_IS_CONTINUOUS ,
+};
+
+static void __init s5pv310_clocksource_init(void)
+{
+ ? ? ? unsigned long pclk;
+ ? ? ? unsigned long clock_rate;
+
+ ? ? ? pclk = clk_get_rate(timerclk);
+

arch/arm/mach-s5pv310/time.c line 234

Quoted 10 lines
arch/arm/mach-s5pv310/time.c new file +10 -0
+ ? ? ? clk_set_rate(tdiv4, pclk / 2);
+ ? ? ? clk_set_parent(tin4, tdiv4);
+
+ ? ? ? clock_rate = clk_get_rate(tin4);
+
+ ? ? ? s5pv310_pwm_init(4, ~0);
+ ? ? ? s5pv310_pwm_start(4, 1);
+
+ ? ? ? pwm_clocksource.mult =
+ ? ? ? ? ? ? ? clocksource_khz2mult(clock_rate/1000,

pwm_clocksource.shift);

arch/arm/mach-s5pv310/time.c line 237

Quoted 3 lines
arch/arm/mach-s5pv310/time.c new file +3 -0
+
+ ? ? ? if (clocksource_register(&pwm_clocksource))
+ ? ? ? ? ? ? ? panic("%s: can't register clocksource\n",

pwm_clocksource.name);

Quoted 14 lines
arch/arm/mach-s5pv310/time.c new file +14 -0
+}
+
+static void __init s5pv310_timer_resources(void)
+{
+ ? ? ? struct platform_device tmpdev;
+
+ ? ? ? tmpdev.dev.bus = &platform_bus_type;
+
+ ? ? ? timerclk = clk_get(NULL, "timers");
+ ? ? ? if (IS_ERR(timerclk))
+ ? ? ? ? ? ? ? panic("failed to get timers clock for system timer");
+
+ ? ? ? clk_enable(timerclk);
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-s5pv310/time.c line 259

Quoted 8 lines
arch/arm/mach-s5pv310/time.c new file +8 -0
+ ? ? ? tmpdev.id = 2;
+ ? ? ? tin2 = clk_get(&tmpdev.dev, "pwm-tin");
+ ? ? ? if (IS_ERR(tin2))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tin2 clock for system timer");
+
+ ? ? ? tdiv2 = clk_get(&tmpdev.dev, "pwm-tdiv");
+ ? ? ? if (IS_ERR(tdiv2))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tdiv2 clock for system

timer");

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

arch/arm/mach-s5pv310/time.c line 269

Quoted 10 lines
arch/arm/mach-s5pv310/time.c new file +10 -0
+ ? ? ? clk_enable(tin2);
+
+ ? ? ? tmpdev.id = 4;
+ ? ? ? tin4 = clk_get(&tmpdev.dev, "pwm-tin");
+ ? ? ? if (IS_ERR(tin4))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tin4 clock for system timer");
+
+ ? ? ? tdiv4 = clk_get(&tmpdev.dev, "pwm-tdiv");
+ ? ? ? if (IS_ERR(tdiv4))
+ ? ? ? ? ? ? ? panic("failed to get pwm-tdiv4 clock for system

timer");

Quoted 64 lines
Quoted 48 lines
Quoted 48 lines

arch/arm/plat-

Quoted 19 lines
arch/arm/mach-s5pv310/time.c new file +18 -0
+
+ ? ? ? clk_enable(tin4);
+}
+
+static void __init s5pv310_timer_init(void)
+{
+#ifdef CONFIG_LOCAL_TIMERS
+ ? ? ? twd_base = S5P_VA_TWD;
+#endif
+
+ ? ? ? s5pv310_timer_resources();
+ ? ? ? s5pv310_clockevent_init();
+ ? ? ? s5pv310_clocksource_init();
+}
+
+struct sys_timer s5pv310_timer = {
+ ? ? ? .init ? ? ? ? ? = s5pv310_timer_init,
+};
arch/arm/plat- renamed from arch/arm/plat-s5p/include/plat/s5pv310.h +0 -0

s5p/include/plat/s5pv310.h

arch/arm/plat-

Quoted 12 lines

index d2f05e1..769c991 100644

arch/arm/plat-s5p/include/plat/s5pv310.h +1 -0
@@ -22,6 +22,7 @@ extern ?int s5pv310_init(void);
 ?extern void s5pv310_init_irq(void);
 ?extern void s5pv310_map_io(void);
 ?extern void s5pv310_init_clocks(int xtal);
+extern struct sys_timer s5pv310_timer;
 

?#define s5pv310_init_uarts s5pv310_common_init_uarts

arch/arm/plat- renamed from arch/arm/plat-samsung/Makefile +0 -0

samsung/Makefile

Quoted 15 lines

index b1d82cc..0d5bf8a 100644

arch/arm/plat-samsung/Makefile +0 -0
@@ -12,7 +12,7 @@ obj- ? ? ? ? ? ? ? ? ? ? ? ? ?:=

?# Objects we always build independent of SoC choice

?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= init.o

arch/arm/plat-samsung/Makefile +1 -1
-obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= time.o
+obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) ? += time.o

?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= clock.o
?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= pwm-clock.o
?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= gpio.o
--
1.6.2.5

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-

samsung-

Quoted 5 lines
Quoted 5 lines

soc" in

Quoted 3 lines

the body of a message to majordomo at vger.kernel.org More majordomo info at ?http://vger.kernel.org/majordomo-info.html

Quoted 7 lines
Quoted 4 lines

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-

soc" in

Quoted 8 lines
Quoted 3 lines

the body of a message to majordomo at vger.kernel.org More majordomo info at ?http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung- soc" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html