* [RFC/PATCH 0/3] 32k timer patches
@ 2010-03-31 11:13 Felipe Balbi
2010-03-31 11:13 ` [RFC/PATCH 1/3] omap: fix clocksource_32k to start from zero Felipe Balbi
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Felipe Balbi @ 2010-03-31 11:13 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi
The following patches convert 32k-sync timer into a platform_driver
and also remove dead code from timer32k.c
If anyone has a good idea on how to fix-up timer-gp.c, I'll be
glad to hear. Currently I can't move it to platform_driver
because it's used the system timer during machine start so I can't
find a proper location to register the platform_device. If we don't
register a system timer, we will loop forever trying to calibrate
the delay loop.
The patches were boot tested on rx51 and compile tested with
omap_h2_1610_defconfig.
Aaro Koskinen (1):
omap: fix clocksource_32k to start from zero
Felipe Balbi (2):
arm: omap1: remove dead code from timer32k.c
arm: omap1/2/3/4: convert clocksource to a platform_driver
arch/arm/mach-omap1/devices.c | 24 ++++
arch/arm/mach-omap1/timer32k.c | 15 --
arch/arm/mach-omap2/clock2420_data.c | 2 +-
arch/arm/mach-omap2/clock2430_data.c | 2 +-
arch/arm/mach-omap2/clock3xxx_data.c | 2 +-
arch/arm/mach-omap2/devices.c | 38 +++++
arch/arm/plat-omap/Makefile | 4 +-
arch/arm/plat-omap/common.c | 149 --------------------
arch/arm/plat-omap/timer-32k-sync.c | 250 ++++++++++++++++++++++++++++++++++
9 files changed, 317 insertions(+), 169 deletions(-)
create mode 100644 arch/arm/plat-omap/timer-32k-sync.c
^ permalink raw reply [flat|nested] 16+ messages in thread* [RFC/PATCH 1/3] omap: fix clocksource_32k to start from zero 2010-03-31 11:13 [RFC/PATCH 0/3] 32k timer patches Felipe Balbi @ 2010-03-31 11:13 ` Felipe Balbi 2010-03-31 11:13 ` [RFC/PATCH 2/3] arm: omap1: remove dead code from timer32k.c Felipe Balbi 2010-03-31 11:13 ` [RFC/PATCH 3/3] arm: omap1/2/3/4: convert clocksource to a platform_driver Felipe Balbi 2 siblings, 0 replies; 16+ messages in thread From: Felipe Balbi @ 2010-03-31 11:13 UTC (permalink / raw) To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Aaro Koskinen From: Aaro Koskinen <aaro.koskinen@nokia.com> When the 32k sync timer is used for sched_clock(), it should count time from the kernel boot (clocksource init) instead of the last HW reset. Otherwise printk.time values will jump suddenly during the boot: [ 0.000000] calling omap2_clk_arch_init+0x0/0x138 @ 1 [ 0.000000] initcall omap2_clk_arch_init+0x0/0x138 returned -22 after 0 usecs [ 0.000000] initcall omap2_clk_arch_init+0x0/0x138 returned with error code -22 [ 0.000000] calling omap_init_clocksource_32k+0x0/0x98 @ 1 [ 508.697937] initcall omap_init_clocksource_32k+0x0/0x98 returned 0 after 0 usecs [ 508.697967] calling omap_init_devices+0x0/0x38 @ 1 [ 508.698425] initcall omap_init_devices+0x0/0x38 returned 0 after 0 usecs This will confuse tools such as scripts/bootgraph.pl. Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> Acked-by: Kevin Hilman <khilman@deeprootsystems.com> --- arch/arm/plat-omap/common.c | 19 ++++++++++++++----- 1 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index 088c1a0..01cbb48 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c @@ -100,10 +100,17 @@ EXPORT_SYMBOL(omap_get_var_config); #include <linux/clocksource.h> +/* + * offset_32k holds the init time counter value. It is then subtracted + * from every counter read to achieve a counter that counts time from the + * kernel boot (needed for sched_clock()). + */ +static u32 offset_32k __read_mostly; + #ifdef CONFIG_ARCH_OMAP16XX static cycle_t omap16xx_32k_read(struct clocksource *cs) { - return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED); + return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k; } #else #define omap16xx_32k_read NULL @@ -112,7 +119,7 @@ static cycle_t omap16xx_32k_read(struct clocksource *cs) #ifdef CONFIG_ARCH_OMAP2420 static cycle_t omap2420_32k_read(struct clocksource *cs) { - return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10); + return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k; } #else #define omap2420_32k_read NULL @@ -121,7 +128,7 @@ static cycle_t omap2420_32k_read(struct clocksource *cs) #ifdef CONFIG_ARCH_OMAP2430 static cycle_t omap2430_32k_read(struct clocksource *cs) { - return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10); + return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k; } #else #define omap2430_32k_read NULL @@ -130,7 +137,7 @@ static cycle_t omap2430_32k_read(struct clocksource *cs) #ifdef CONFIG_ARCH_OMAP3 static cycle_t omap34xx_32k_read(struct clocksource *cs) { - return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10); + return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k; } #else #define omap34xx_32k_read NULL @@ -139,7 +146,7 @@ static cycle_t omap34xx_32k_read(struct clocksource *cs) #ifdef CONFIG_ARCH_OMAP4 static cycle_t omap44xx_32k_read(struct clocksource *cs) { - return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10); + return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k; } #else #define omap44xx_32k_read NULL @@ -227,6 +234,8 @@ static int __init omap_init_clocksource_32k(void) clocksource_32k.mult = clocksource_hz2mult(32768, clocksource_32k.shift); + offset_32k = clocksource_32k.read(&clocksource_32k); + if (clocksource_register(&clocksource_32k)) printk(err, clocksource_32k.name); } -- 1.7.0.rc0.33.g7c3932 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC/PATCH 2/3] arm: omap1: remove dead code from timer32k.c 2010-03-31 11:13 [RFC/PATCH 0/3] 32k timer patches Felipe Balbi 2010-03-31 11:13 ` [RFC/PATCH 1/3] omap: fix clocksource_32k to start from zero Felipe Balbi @ 2010-03-31 11:13 ` Felipe Balbi 2010-04-06 21:30 ` Kevin Hilman 2010-03-31 11:13 ` [RFC/PATCH 3/3] arm: omap1/2/3/4: convert clocksource to a platform_driver Felipe Balbi 2 siblings, 1 reply; 16+ messages in thread From: Felipe Balbi @ 2010-03-31 11:13 UTC (permalink / raw) To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi Trivial patch, no functional changes Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- arch/arm/mach-omap1/timer32k.c | 15 --------------- 1 files changed, 0 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c index 9ad1185..20cfbcc 100644 --- a/arch/arm/mach-omap1/timer32k.c +++ b/arch/arm/mach-omap1/timer32k.c @@ -68,12 +68,6 @@ struct sys_timer omap_timer; * --------------------------------------------------------------------------- */ -#if defined(CONFIG_ARCH_OMAP16XX) -#define TIMER_32K_SYNCHRONIZED 0xfffbc410 -#else -#error OMAP 32KHz timer does not currently work on 15XX! -#endif - /* 16xx specific defines */ #define OMAP1_32K_TIMER_BASE 0xfffb9000 #define OMAP1_32K_TIMER_CR 0x08 @@ -150,15 +144,6 @@ static struct clock_event_device clockevent_32k_timer = { .set_mode = omap_32k_timer_set_mode, }; -/* - * The 32KHz synchronized timer is an additional timer on 16xx. - * It is always running. - */ -static inline unsigned long omap_32k_sync_timer_read(void) -{ - return omap_readl(TIMER_32K_SYNCHRONIZED); -} - static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = &clockevent_32k_timer; -- 1.7.0.rc0.33.g7c3932 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [RFC/PATCH 2/3] arm: omap1: remove dead code from timer32k.c 2010-03-31 11:13 ` [RFC/PATCH 2/3] arm: omap1: remove dead code from timer32k.c Felipe Balbi @ 2010-04-06 21:30 ` Kevin Hilman 0 siblings, 0 replies; 16+ messages in thread From: Kevin Hilman @ 2010-04-06 21:30 UTC (permalink / raw) To: Felipe Balbi; +Cc: Tony Lindgren, Linux OMAP Mailing List Felipe Balbi <felipe.balbi@nokia.com> writes: > Trivial patch, no functional changes > > Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> Acked-by: Kevin Hilman <khilman@deeprootsystems.com> > --- > arch/arm/mach-omap1/timer32k.c | 15 --------------- > 1 files changed, 0 insertions(+), 15 deletions(-) > > diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c > index 9ad1185..20cfbcc 100644 > --- a/arch/arm/mach-omap1/timer32k.c > +++ b/arch/arm/mach-omap1/timer32k.c > @@ -68,12 +68,6 @@ struct sys_timer omap_timer; > * --------------------------------------------------------------------------- > */ > > -#if defined(CONFIG_ARCH_OMAP16XX) > -#define TIMER_32K_SYNCHRONIZED 0xfffbc410 > -#else > -#error OMAP 32KHz timer does not currently work on 15XX! > -#endif > - > /* 16xx specific defines */ > #define OMAP1_32K_TIMER_BASE 0xfffb9000 > #define OMAP1_32K_TIMER_CR 0x08 > @@ -150,15 +144,6 @@ static struct clock_event_device clockevent_32k_timer = { > .set_mode = omap_32k_timer_set_mode, > }; > > -/* > - * The 32KHz synchronized timer is an additional timer on 16xx. > - * It is always running. > - */ > -static inline unsigned long omap_32k_sync_timer_read(void) > -{ > - return omap_readl(TIMER_32K_SYNCHRONIZED); > -} > - > static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id) > { > struct clock_event_device *evt = &clockevent_32k_timer; > -- > 1.7.0.rc0.33.g7c3932 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
* [RFC/PATCH 3/3] arm: omap1/2/3/4: convert clocksource to a platform_driver 2010-03-31 11:13 [RFC/PATCH 0/3] 32k timer patches Felipe Balbi 2010-03-31 11:13 ` [RFC/PATCH 1/3] omap: fix clocksource_32k to start from zero Felipe Balbi 2010-03-31 11:13 ` [RFC/PATCH 2/3] arm: omap1: remove dead code from timer32k.c Felipe Balbi @ 2010-03-31 11:13 ` Felipe Balbi 2010-04-06 21:37 ` Kevin Hilman 2 siblings, 1 reply; 16+ messages in thread From: Felipe Balbi @ 2010-03-31 11:13 UTC (permalink / raw) To: Tony Lindgren; +Cc: Linux OMAP Mailing List, Felipe Balbi Convert the omap32k clocksource driver into a platform_driver and while at that, also remove the ifdeferry around the code. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- arch/arm/mach-omap1/devices.c | 24 ++++ arch/arm/mach-omap2/clock2420_data.c | 2 +- arch/arm/mach-omap2/clock2430_data.c | 2 +- arch/arm/mach-omap2/clock3xxx_data.c | 2 +- arch/arm/mach-omap2/devices.c | 38 +++++ arch/arm/plat-omap/Makefile | 4 +- arch/arm/plat-omap/common.c | 158 --------------------- arch/arm/plat-omap/timer-32k-sync.c | 250 ++++++++++++++++++++++++++++++++++ 8 files changed, 317 insertions(+), 163 deletions(-) create mode 100644 arch/arm/plat-omap/timer-32k-sync.c diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index 379100c..2e7dbdc 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -28,6 +28,29 @@ /*-------------------------------------------------------------------------*/ +#define OMAP16XX_TIMER_32K_BASE 0xfffbc400 + +static struct resource omap_32k_resources[] = { + { + .start = OMAP16XX_TIMER_32K_BASE, + .end = SZ_4K, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device omap_32k_device = { + .name = "omap-32k-sync-timer", + .id = -1, + .num_resources = ARRAY_SIZE(omap_32k_resources), + .resource = omap_32k_resources, +}; + +static void omap_init_32k(void) +{ + if (cpu_is_omap16xx()) + (void) platform_device_register(&omap_32k_device); +}; + #if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE) #define OMAP_RTC_BASE 0xfffb4800 @@ -295,6 +318,7 @@ static int __init omap1_init_devices(void) * in alphabetical order so they're easier to sort through. */ + omap_init_32k(); omap_init_mbox(); omap_init_rtc(); omap_init_spi100k(); diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c index d932b14..1f6e89d 100644 --- a/arch/arm/mach-omap2/clock2420_data.c +++ b/arch/arm/mach-omap2/clock2420_data.c @@ -1806,7 +1806,7 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "gpios_fck", &gpios_fck, CK_242X), CLK("omap_wdt", "ick", &mpu_wdt_ick, CK_242X), CLK("omap_wdt", "fck", &mpu_wdt_fck, CK_242X), - CLK(NULL, "sync_32k_ick", &sync_32k_ick, CK_242X), + CLK("omap-32k-sync-timer", "ick", &sync_32k_ick, CK_242X), CLK(NULL, "wdt1_ick", &wdt1_ick, CK_242X), CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_242X), CLK("omap24xxcam", "fck", &cam_fck, CK_242X), diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c index 0438b6e..59ac891 100644 --- a/arch/arm/mach-omap2/clock2430_data.c +++ b/arch/arm/mach-omap2/clock2430_data.c @@ -1900,7 +1900,7 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "gpios_fck", &gpios_fck, CK_243X), CLK("omap_wdt", "ick", &mpu_wdt_ick, CK_243X), CLK("omap_wdt", "fck", &mpu_wdt_fck, CK_243X), - CLK(NULL, "sync_32k_ick", &sync_32k_ick, CK_243X), + CLK("omap-32k-sync-timer", "ick", &sync_32k_ick, CK_243X), CLK(NULL, "wdt1_ick", &wdt1_ick, CK_243X), CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_243X), CLK(NULL, "icr_ick", &icr_ick, CK_243X), diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c index d5153b6..785c732 100644 --- a/arch/arm/mach-omap2/clock3xxx_data.c +++ b/arch/arm/mach-omap2/clock3xxx_data.c @@ -3414,7 +3414,7 @@ static struct omap_clk omap3xxx_clks[] = { CLK("omap_wdt", "ick", &wdt2_ick, CK_3XXX), CLK(NULL, "wdt1_ick", &wdt1_ick, CK_3XXX), CLK(NULL, "gpio1_ick", &gpio1_ick, CK_3XXX), - CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick, CK_3XXX), + CLK("omap-32k-sync-timer", "ick", &omap_32ksync_ick, CK_3XXX), CLK(NULL, "gpt12_ick", &gpt12_ick, CK_3XXX), CLK(NULL, "gpt1_ick", &gpt1_ick, CK_3XXX), CLK(NULL, "per_96m_fck", &per_96m_fck, CK_3XXX), diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 23e4d77..2c4ff31 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -29,6 +29,43 @@ #include "mux.h" +static struct resource omap_32k_resources[] = { + { + .start = -EINVAL, /* gets changed later */ + .end = -EINVAL, /* gets changed later */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device omap_32k_device = { + .name = "omap-32k-sync-timer", + .id = -1, + .num_resources = ARRAY_SIZE(omap_32k_resources), + .resource = omap_32k_resources, +}; + +static void omap_init_32k(void) +{ + if (cpu_is_omap2420()) { + omap_32k_resources[0].start = OMAP2420_32KSYNCT_BASE; + omap_32k_resources[0].end = OMAP2420_32KSYNCT_BASE + SZ_4K; + } else if (cpu_is_omap2430()) { + omap_32k_resources[0].start = OMAP2430_32KSYNCT_BASE; + omap_32k_resources[0].end = OMAP2430_32KSYNCT_BASE + SZ_4K; + } else if (cpu_is_omap34xx()) { + omap_32k_resources[0].start = OMAP3430_32KSYNCT_BASE; + omap_32k_resources[0].end = OMAP3430_32KSYNCT_BASE + SZ_4K; + } else if (cpu_is_omap44xx()) { + omap_32k_resources[0].start = OMAP4430_32KSYNCT_BASE; + omap_32k_resources[0].end = OMAP4430_32KSYNCT_BASE + SZ_4K; + } else { /* not supported */ + return; + } + + + (void) platform_device_register(&omap_32k_device); +}; + #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE) static struct resource cam_resources[] = { @@ -794,6 +831,7 @@ static int __init omap2_init_devices(void) * in alphabetical order so they're easier to sort through. */ omap_hsmmc_reset(); + omap_init_32k(); omap_init_camera(); omap_init_mbox(); omap_init_mcspi(); diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 98f0191..9c9cf31 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -4,7 +4,7 @@ # Common support obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \ - usb.o fb.o io.o + usb.o fb.o io.o timer-32k-sync.o obj-m := obj-n := obj- := @@ -30,4 +30,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y) # OMAP mailbox framework obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o -obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o \ No newline at end of file +obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index 01cbb48..4be635a 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c @@ -87,164 +87,6 @@ const void *omap_get_var_config(u16 tag, size_t *len) } EXPORT_SYMBOL(omap_get_var_config); -/* - * 32KHz clocksource ... always available, on pretty most chips except - * OMAP 730 and 1510. Other timers could be used as clocksources, with - * higher resolution in free-running counter modes (e.g. 12 MHz xtal), - * but systems won't necessarily want to spend resources that way. - */ - -#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 - -#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) - -#include <linux/clocksource.h> - -/* - * offset_32k holds the init time counter value. It is then subtracted - * from every counter read to achieve a counter that counts time from the - * kernel boot (needed for sched_clock()). - */ -static u32 offset_32k __read_mostly; - -#ifdef CONFIG_ARCH_OMAP16XX -static cycle_t omap16xx_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k; -} -#else -#define omap16xx_32k_read NULL -#endif - -#ifdef CONFIG_ARCH_OMAP2420 -static cycle_t omap2420_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k; -} -#else -#define omap2420_32k_read NULL -#endif - -#ifdef CONFIG_ARCH_OMAP2430 -static cycle_t omap2430_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k; -} -#else -#define omap2430_32k_read NULL -#endif - -#ifdef CONFIG_ARCH_OMAP3 -static cycle_t omap34xx_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k; -} -#else -#define omap34xx_32k_read NULL -#endif - -#ifdef CONFIG_ARCH_OMAP4 -static cycle_t omap44xx_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k; -} -#else -#define omap44xx_32k_read NULL -#endif - -/* - * Kernel assumes that sched_clock can be called early but may not have - * things ready yet. - */ -static cycle_t omap_32k_read_dummy(struct clocksource *cs) -{ - return 0; -} - -static struct clocksource clocksource_32k = { - .name = "32k_counter", - .rating = 250, - .read = omap_32k_read_dummy, - .mask = CLOCKSOURCE_MASK(32), - .shift = 10, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -/* - * Returns current time from boot in nsecs. It's OK for this to wrap - * around for now, as it's just a relative time stamp. - */ -unsigned long long sched_clock(void) -{ - return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k), - clocksource_32k.mult, clocksource_32k.shift); -} - -/** - * read_persistent_clock - Return time from a persistent clock. - * - * Reads the time from a source which isn't disabled during PM, the - * 32k sync timer. Convert the cycles elapsed since last read into - * nsecs and adds to a monotonically increasing timespec. - */ -static struct timespec persistent_ts; -static cycles_t cycles, last_cycles; -void read_persistent_clock(struct timespec *ts) -{ - unsigned long long nsecs; - cycles_t delta; - struct timespec *tsp = &persistent_ts; - - last_cycles = cycles; - cycles = clocksource_32k.read(&clocksource_32k); - delta = cycles - last_cycles; - - nsecs = clocksource_cyc2ns(delta, - clocksource_32k.mult, clocksource_32k.shift); - - timespec_add_ns(tsp, nsecs); - *ts = *tsp; -} - -static int __init omap_init_clocksource_32k(void) -{ - static char err[] __initdata = KERN_ERR - "%s: can't register clocksource!\n"; - - if (cpu_is_omap16xx() || cpu_class_is_omap2()) { - struct clk *sync_32k_ick; - - if (cpu_is_omap16xx()) - clocksource_32k.read = omap16xx_32k_read; - else if (cpu_is_omap2420()) - clocksource_32k.read = omap2420_32k_read; - else if (cpu_is_omap2430()) - clocksource_32k.read = omap2430_32k_read; - else if (cpu_is_omap34xx()) - clocksource_32k.read = omap34xx_32k_read; - else if (cpu_is_omap44xx()) - clocksource_32k.read = omap44xx_32k_read; - else - return -ENODEV; - - sync_32k_ick = clk_get(NULL, "omap_32ksync_ick"); - if (sync_32k_ick) - clk_enable(sync_32k_ick); - - clocksource_32k.mult = clocksource_hz2mult(32768, - clocksource_32k.shift); - - offset_32k = clocksource_32k.read(&clocksource_32k); - - if (clocksource_register(&clocksource_32k)) - printk(err, clocksource_32k.name); - } - return 0; -} -arch_initcall(omap_init_clocksource_32k); - -#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */ - /* Global address base setup code */ #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) diff --git a/arch/arm/plat-omap/timer-32k-sync.c b/arch/arm/plat-omap/timer-32k-sync.c new file mode 100644 index 0000000..33e1f82 --- /dev/null +++ b/arch/arm/plat-omap/timer-32k-sync.c @@ -0,0 +1,250 @@ +/* + * timer-32k-sync.c -- OMAP 32k Sync Timer Clocksource Driver + * + * Copyright (C) 2005-2010 Tony Lindgren <tony@atomide.com> + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2010 Felipe Balbi <me@felipebalbi.com> + * Copyright (C) 2009 Texas Instruments + * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * 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 <linux/kernel.h> +#include <linux/time.h> +#include <linux/clocksource.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/err.h> + +struct omap_32k_sync_device { + struct timespec persistent_ts; + struct clocksource cs; + cycles_t cycles; + cycles_t last_cycles; + + struct device *dev; + struct clk *ick; + void __iomem *base; + + /* + * offset_32k holds the init time counter value. It is then subtracted + * from every counter read to achieve a counter that counts time from the + * kernel boot (needed for sched_clock()). + */ + u32 offset_32k __read_mostly; +}; + +#define to_omap_32k(cs) (container_of(cs, struct omap_32k_sync_device, cs)) + +static struct omap_32k_sync_device *thecs; + +static inline u32 omap_32k_sync_readl(const void __iomem *base, unsigned offset) +{ + return __raw_readl(base + offset); +} + +static cycle_t omap_32k_sync_32k_read(struct clocksource *cs) +{ + struct omap_32k_sync_device *omap = to_omap_32k(cs); + + return omap_32k_sync_readl(omap->base, 0x10) - omap->offset_32k; +} + +/* + * Returns current time from boot in nsecs. It's OK for this to wrap + * around for now, as it's just a relative time stamp. + */ +unsigned long long sched_clock(void) +{ + struct omap_32k_sync_device *omap = thecs; + + if (!omap) + return 0; + + return clocksource_cyc2ns(omap->cs.read(&omap->cs), + omap->cs.mult, omap->cs.shift); +} + +/** + * read_persistent_clock - Return time from a persistent clock. + * + * Reads the time from a source which isn't disabled during PM, the + * 32k sync timer. Convert the cycles elapsed since last read into + * nsecs and adds to a monotonically increasing timespec. + */ +void read_persistent_clock(struct timespec *ts) +{ + struct omap_32k_sync_device *omap = thecs; + unsigned long long nsecs; + cycles_t delta; + struct timespec *tsp; + + if (!omap) { + ts->tv_sec = 0; + ts->tv_nsec = 0; + return; + } + + tsp = &omap->persistent_ts; + + omap->last_cycles = omap->cycles; + omap->cycles = omap->cs.read(&omap->cs); + delta = omap->cycles - omap->last_cycles; + + nsecs = clocksource_cyc2ns(delta, + omap->cs.mult, omap->cs.shift); + + timespec_add_ns(tsp, nsecs); + *ts = *tsp; +} + +static int __init omap_32k_sync_probe(struct platform_device *pdev) +{ + struct omap_32k_sync_device *omap; + struct resource *res; + struct clk *ick; + + int ret; + + void __iomem *base; + + omap = kzalloc(sizeof(*omap), GFP_KERNEL); + if (!omap) { + dev_dbg(&pdev->dev, "unable to allocate memory\n"); + ret = -ENOMEM; + goto err0; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_dbg(&pdev->dev, "couldn't get resource\n"); + ret = -ENODEV; + goto err1; + } + + base = ioremap(res->start, resource_size(res)); + if (!base) { + dev_dbg(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + ick = clk_get(&pdev->dev, "ick"); + if (IS_ERR(ick)) { + dev_dbg(&pdev->dev, "couldn't get clock\n"); + ret = PTR_ERR(ick); + goto err3; + } + + ret = clk_enable(ick); + if (ret) { + dev_dbg(&pdev->dev, "couldn't enable clock\n"); + goto err4; + } + + omap->base = base; + omap->dev = &pdev->dev; + omap->ick = ick; + + omap->cs.name = "timer-32k"; + omap->cs.rating = 250; + omap->cs.read = omap_32k_sync_32k_read; + omap->cs.mask = CLOCKSOURCE_MASK(32); + omap->cs.shift = 10; + omap->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; + omap->cs.mult = clocksource_hz2mult(32768, omap->cs.shift); + + platform_set_drvdata(pdev, omap); + + ret = clocksource_register(&omap->cs); + if (ret) { + dev_dbg(&pdev->dev, "failed to register clocksource\n"); + goto err5; + } + + /* initialize our offset */ + omap->offset_32k = omap_32k_sync_32k_read(&omap->cs); + + /* + * REVISIT for now we need to keep a global static pointer + * to this clocksource instance. Would it make any sense + * to provide a get_clocksource() to fetch the clocksource + * we just registered ? + */ + thecs = omap; + + return 0; + +err5: + clk_disable(ick); + +err4: + clk_put(ick); + +err3: + iounmap(base); + +err2: +err1: + kfree(omap); + +err0: + return ret; +} + +static int __exit omap_32k_sync_remove(struct platform_device *pdev) +{ + struct omap_32k_sync_device *omap = platform_get_drvdata(pdev); + + clocksource_unregister(&omap->cs); + clk_disable(omap->ick); + clk_put(omap->ick); + iounmap(omap->base); + kfree(omap); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void omap_32k_sync_shutdown(struct platform_device *pdev) +{ + struct omap_32k_sync_device *omap = platform_get_drvdata(pdev); + + clk_disable(omap->ick); +} + +static struct platform_driver omap_32k_sync_driver = { + .remove = __exit_p(omap_32k_sync_remove), + .shutdown = omap_32k_sync_shutdown, + .driver = { + .name = "omap-32k-sync-timer", + }, +}; + +static int __init omap_32k_sync_init(void) +{ + return platform_driver_probe(&omap_32k_sync_driver, omap_32k_sync_probe); +} +arch_initcall(omap_32k_sync_init); + +static void __exit omap_32k_sync_exit(void) +{ + platform_driver_unregister(&omap_32k_sync_driver); +} +module_exit(omap_32k_sync_exit); + +MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>"); +MODULE_LICENSE("GPL v2"); -- 1.7.0.rc0.33.g7c3932 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [RFC/PATCH 3/3] arm: omap1/2/3/4: convert clocksource to a platform_driver 2010-03-31 11:13 ` [RFC/PATCH 3/3] arm: omap1/2/3/4: convert clocksource to a platform_driver Felipe Balbi @ 2010-04-06 21:37 ` Kevin Hilman 2010-04-07 7:21 ` Felipe Balbi 0 siblings, 1 reply; 16+ messages in thread From: Kevin Hilman @ 2010-04-06 21:37 UTC (permalink / raw) To: Felipe Balbi, Benoit Cousson; +Cc: Tony Lindgren, Linux OMAP Mailing List Felipe Balbi <felipe.balbi@nokia.com> writes: > Convert the omap32k clocksource driver into a platform_driver > and while at that, also remove the ifdeferry around the code. > > Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> This looks mostly good to me. One cosmetic request. There is some standardized naming happening for devices based on Benoits work of auto-generating hwmod data. As part of this, this device will now be called counter_32k instead of '32k sync timer' since it's just a simple counter and nobody really knew what the 'sync' was intended to mean. To that end, renaming things to use counter_32k instead of sync timer would be helpful. [...] > > +static struct resource omap_32k_resources[] = { > + { > + .start = -EINVAL, /* gets changed later */ > + .end = -EINVAL, /* gets changed later */ It's more common to just not assign these and leave them as zero. > + .flags = IORESOURCE_MEM, > + }, > +}; Kevin ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC/PATCH 3/3] arm: omap1/2/3/4: convert clocksource to a platform_driver 2010-04-06 21:37 ` Kevin Hilman @ 2010-04-07 7:21 ` Felipe Balbi 2010-04-07 9:57 ` [PATCH 1/3] omap: fix clocksource_32k to start from zero felipe.balbi ` (2 more replies) 0 siblings, 3 replies; 16+ messages in thread From: Felipe Balbi @ 2010-04-07 7:21 UTC (permalink / raw) To: ext Kevin Hilman Cc: Balbi Felipe (Nokia-D/Helsinki), Benoit Cousson, Tony Lindgren, Linux OMAP Mailing List On Tue, Apr 06, 2010 at 11:37:08PM +0200, ext Kevin Hilman wrote: >There is some standardized naming happening for devices based on >Benoits work of auto-generating hwmod data. As part of this, this >device will now be called counter_32k instead of '32k sync timer' >since it's just a simple counter and nobody really knew what the 'sync' >was intended to mean. To that end, renaming things to use counter_32k >instead of sync timer would be helpful. I'll do that soon. >It's more common to just not assign these and leave them as zero. will fix this too. -- balbi ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/3] omap: fix clocksource_32k to start from zero 2010-04-07 7:21 ` Felipe Balbi @ 2010-04-07 9:57 ` felipe.balbi 2010-04-07 10:02 ` Felipe Balbi 2010-04-22 23:49 ` [APPLIED] " Tony Lindgren 2010-04-07 9:57 ` [PATCH 2/3] arm: omap1: remove dead code from timer32k.c felipe.balbi 2010-04-07 9:57 ` [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver felipe.balbi 2 siblings, 2 replies; 16+ messages in thread From: felipe.balbi @ 2010-04-07 9:57 UTC (permalink / raw) To: Kevin Hilman; +Cc: Linux OMAP Mailing List, Aaro Koskinen From: Aaro Koskinen <aaro.koskinen@nokia.com> When the 32k sync timer is used for sched_clock(), it should count time from the kernel boot (clocksource init) instead of the last HW reset. Otherwise printk.time values will jump suddenly during the boot: [ 0.000000] calling omap2_clk_arch_init+0x0/0x138 @ 1 [ 0.000000] initcall omap2_clk_arch_init+0x0/0x138 returned -22 after 0 usecs [ 0.000000] initcall omap2_clk_arch_init+0x0/0x138 returned with error code -22 [ 0.000000] calling omap_init_clocksource_32k+0x0/0x98 @ 1 [ 508.697937] initcall omap_init_clocksource_32k+0x0/0x98 returned 0 after 0 usecs [ 508.697967] calling omap_init_devices+0x0/0x38 @ 1 [ 508.698425] initcall omap_init_devices+0x0/0x38 returned 0 after 0 usecs This will confuse tools such as scripts/bootgraph.pl. Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> Acked-by: Kevin Hilman <khilman@deeprootsystems.com> --- arch/arm/plat-omap/common.c | 19 ++++++++++++++----- 1 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index 088c1a0..01cbb48 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c @@ -100,10 +100,17 @@ EXPORT_SYMBOL(omap_get_var_config); #include <linux/clocksource.h> +/* + * offset_32k holds the init time counter value. It is then subtracted + * from every counter read to achieve a counter that counts time from the + * kernel boot (needed for sched_clock()). + */ +static u32 offset_32k __read_mostly; + #ifdef CONFIG_ARCH_OMAP16XX static cycle_t omap16xx_32k_read(struct clocksource *cs) { - return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED); + return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k; } #else #define omap16xx_32k_read NULL @@ -112,7 +119,7 @@ static cycle_t omap16xx_32k_read(struct clocksource *cs) #ifdef CONFIG_ARCH_OMAP2420 static cycle_t omap2420_32k_read(struct clocksource *cs) { - return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10); + return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k; } #else #define omap2420_32k_read NULL @@ -121,7 +128,7 @@ static cycle_t omap2420_32k_read(struct clocksource *cs) #ifdef CONFIG_ARCH_OMAP2430 static cycle_t omap2430_32k_read(struct clocksource *cs) { - return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10); + return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k; } #else #define omap2430_32k_read NULL @@ -130,7 +137,7 @@ static cycle_t omap2430_32k_read(struct clocksource *cs) #ifdef CONFIG_ARCH_OMAP3 static cycle_t omap34xx_32k_read(struct clocksource *cs) { - return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10); + return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k; } #else #define omap34xx_32k_read NULL @@ -139,7 +146,7 @@ static cycle_t omap34xx_32k_read(struct clocksource *cs) #ifdef CONFIG_ARCH_OMAP4 static cycle_t omap44xx_32k_read(struct clocksource *cs) { - return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10); + return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k; } #else #define omap44xx_32k_read NULL @@ -227,6 +234,8 @@ static int __init omap_init_clocksource_32k(void) clocksource_32k.mult = clocksource_hz2mult(32768, clocksource_32k.shift); + offset_32k = clocksource_32k.read(&clocksource_32k); + if (clocksource_register(&clocksource_32k)) printk(err, clocksource_32k.name); } -- 1.7.0.rc0.33.g7c3932 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/3] omap: fix clocksource_32k to start from zero 2010-04-07 9:57 ` [PATCH 1/3] omap: fix clocksource_32k to start from zero felipe.balbi @ 2010-04-07 10:02 ` Felipe Balbi 2010-04-22 23:49 ` [APPLIED] " Tony Lindgren 1 sibling, 0 replies; 16+ messages in thread From: Felipe Balbi @ 2010-04-07 10:02 UTC (permalink / raw) To: Balbi Felipe (Nokia-D/Helsinki) Cc: Kevin Hilman, Linux OMAP Mailing List, Koskinen Aaro (Nokia-D/Helsinki) Hi, On Wed, Apr 07, 2010 at 11:57:22AM +0200, Balbi Felipe (Nokia-D/Helsinki) wrote: >From: Aaro Koskinen <aaro.koskinen@nokia.com> > >When the 32k sync timer is used for sched_clock(), it should count >time from the kernel boot (clocksource init) instead of the last HW >reset. Otherwise printk.time values will jump suddenly during the boot: > > [ 0.000000] calling omap2_clk_arch_init+0x0/0x138 @ 1 > [ 0.000000] initcall omap2_clk_arch_init+0x0/0x138 returned -22 after 0 usecs > [ 0.000000] initcall omap2_clk_arch_init+0x0/0x138 returned with error code -22 > [ 0.000000] calling omap_init_clocksource_32k+0x0/0x98 @ 1 > [ 508.697937] initcall omap_init_clocksource_32k+0x0/0x98 returned 0 after 0 usecs > [ 508.697967] calling omap_init_devices+0x0/0x38 @ 1 > [ 508.698425] initcall omap_init_devices+0x0/0x38 returned 0 after 0 usecs > >This will confuse tools such as scripts/bootgraph.pl. > >Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com> >Acked-by: Kevin Hilman <khilman@deeprootsystems.com> these 3 patches are also available at: http://gitorious.org/usb/usb/commits/clksource to pull in the patches use: git pull git://gitorious.org/usb/usb.git clksource -- balbi ^ permalink raw reply [flat|nested] 16+ messages in thread
* [APPLIED] [PATCH 1/3] omap: fix clocksource_32k to start from zero 2010-04-07 9:57 ` [PATCH 1/3] omap: fix clocksource_32k to start from zero felipe.balbi 2010-04-07 10:02 ` Felipe Balbi @ 2010-04-22 23:49 ` Tony Lindgren 1 sibling, 0 replies; 16+ messages in thread From: Tony Lindgren @ 2010-04-22 23:49 UTC (permalink / raw) To: linux-omap This patch has been applied to the linux-omap by youw fwiendly patch wobot. Branch in linux-omap: omap-fixes Initial commit ID (Likely to change): 135a57fa43f4f345eb281157d0d4e107b3c74d16 PatchWorks http://patchwork.kernel.org/patch/90994/ Git (Likely to change, and takes a while to get mirrored) http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git;a=commit;h=135a57fa43f4f345eb281157d0d4e107b3c74d16 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 2/3] arm: omap1: remove dead code from timer32k.c 2010-04-07 7:21 ` Felipe Balbi 2010-04-07 9:57 ` [PATCH 1/3] omap: fix clocksource_32k to start from zero felipe.balbi @ 2010-04-07 9:57 ` felipe.balbi 2010-04-22 23:49 ` [APPLIED] " Tony Lindgren 2010-04-07 9:57 ` [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver felipe.balbi 2 siblings, 1 reply; 16+ messages in thread From: felipe.balbi @ 2010-04-07 9:57 UTC (permalink / raw) To: Kevin Hilman; +Cc: Linux OMAP Mailing List, Felipe Balbi From: Felipe Balbi <felipe.balbi@nokia.com> Trivial patch, no functional changes Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- arch/arm/mach-omap1/timer32k.c | 15 --------------- 1 files changed, 0 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c index 9ad1185..20cfbcc 100644 --- a/arch/arm/mach-omap1/timer32k.c +++ b/arch/arm/mach-omap1/timer32k.c @@ -68,12 +68,6 @@ struct sys_timer omap_timer; * --------------------------------------------------------------------------- */ -#if defined(CONFIG_ARCH_OMAP16XX) -#define TIMER_32K_SYNCHRONIZED 0xfffbc410 -#else -#error OMAP 32KHz timer does not currently work on 15XX! -#endif - /* 16xx specific defines */ #define OMAP1_32K_TIMER_BASE 0xfffb9000 #define OMAP1_32K_TIMER_CR 0x08 @@ -150,15 +144,6 @@ static struct clock_event_device clockevent_32k_timer = { .set_mode = omap_32k_timer_set_mode, }; -/* - * The 32KHz synchronized timer is an additional timer on 16xx. - * It is always running. - */ -static inline unsigned long omap_32k_sync_timer_read(void) -{ - return omap_readl(TIMER_32K_SYNCHRONIZED); -} - static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = &clockevent_32k_timer; -- 1.7.0.rc0.33.g7c3932 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [APPLIED] [PATCH 2/3] arm: omap1: remove dead code from timer32k.c 2010-04-07 9:57 ` [PATCH 2/3] arm: omap1: remove dead code from timer32k.c felipe.balbi @ 2010-04-22 23:49 ` Tony Lindgren 0 siblings, 0 replies; 16+ messages in thread From: Tony Lindgren @ 2010-04-22 23:49 UTC (permalink / raw) To: linux-omap This patch has been applied to the linux-omap by youw fwiendly patch wobot. Branch in linux-omap: omap-fixes Initial commit ID (Likely to change): cb7085ea28c95bd7b55e5c37a7e6d3017dcdcc90 PatchWorks http://patchwork.kernel.org/patch/90993/ Git (Likely to change, and takes a while to get mirrored) http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git;a=commit;h=cb7085ea28c95bd7b55e5c37a7e6d3017dcdcc90 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver 2010-04-07 7:21 ` Felipe Balbi 2010-04-07 9:57 ` [PATCH 1/3] omap: fix clocksource_32k to start from zero felipe.balbi 2010-04-07 9:57 ` [PATCH 2/3] arm: omap1: remove dead code from timer32k.c felipe.balbi @ 2010-04-07 9:57 ` felipe.balbi 2010-04-07 16:08 ` Kevin Hilman 2 siblings, 1 reply; 16+ messages in thread From: felipe.balbi @ 2010-04-07 9:57 UTC (permalink / raw) To: Kevin Hilman; +Cc: Linux OMAP Mailing List, Felipe Balbi From: Felipe Balbi <felipe.balbi@nokia.com> Convert the omap32k clocksource driver into a platform_driver and while at that, also remove the ifdeferry around the code. Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> --- arch/arm/mach-omap1/devices.c | 24 ++++ arch/arm/mach-omap2/clock2420_data.c | 2 +- arch/arm/mach-omap2/clock2430_data.c | 2 +- arch/arm/mach-omap2/clock3xxx_data.c | 2 +- arch/arm/mach-omap2/devices.c | 35 +++++ arch/arm/plat-omap/Makefile | 4 +- arch/arm/plat-omap/common.c | 158 --------------------- arch/arm/plat-omap/counter-32k.c | 250 ++++++++++++++++++++++++++++++++++ 8 files changed, 314 insertions(+), 163 deletions(-) create mode 100644 arch/arm/plat-omap/counter-32k.c diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index 379100c..4393b45 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -28,6 +28,29 @@ /*-------------------------------------------------------------------------*/ +#define OMAP16XX_TIMER_32K_BASE 0xfffbc400 + +static struct resource omap_32k_resources[] = { + { + .start = OMAP16XX_TIMER_32K_BASE, + .end = SZ_4K, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device omap_32k_device = { + .name = "omap-counter-32k", + .id = -1, + .num_resources = ARRAY_SIZE(omap_32k_resources), + .resource = omap_32k_resources, +}; + +static void omap_init_32k(void) +{ + if (cpu_is_omap16xx()) + (void) platform_device_register(&omap_32k_device); +}; + #if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE) #define OMAP_RTC_BASE 0xfffb4800 @@ -295,6 +318,7 @@ static int __init omap1_init_devices(void) * in alphabetical order so they're easier to sort through. */ + omap_init_32k(); omap_init_mbox(); omap_init_rtc(); omap_init_spi100k(); diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c index d932b14..a4747ad 100644 --- a/arch/arm/mach-omap2/clock2420_data.c +++ b/arch/arm/mach-omap2/clock2420_data.c @@ -1806,7 +1806,7 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "gpios_fck", &gpios_fck, CK_242X), CLK("omap_wdt", "ick", &mpu_wdt_ick, CK_242X), CLK("omap_wdt", "fck", &mpu_wdt_fck, CK_242X), - CLK(NULL, "sync_32k_ick", &sync_32k_ick, CK_242X), + CLK("omap-counter-32k", "ick", &sync_32k_ick, CK_242X), CLK(NULL, "wdt1_ick", &wdt1_ick, CK_242X), CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_242X), CLK("omap24xxcam", "fck", &cam_fck, CK_242X), diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c index 0438b6e..479ab53 100644 --- a/arch/arm/mach-omap2/clock2430_data.c +++ b/arch/arm/mach-omap2/clock2430_data.c @@ -1900,7 +1900,7 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "gpios_fck", &gpios_fck, CK_243X), CLK("omap_wdt", "ick", &mpu_wdt_ick, CK_243X), CLK("omap_wdt", "fck", &mpu_wdt_fck, CK_243X), - CLK(NULL, "sync_32k_ick", &sync_32k_ick, CK_243X), + CLK("omap-counter-32k", "ick", &sync_32k_ick, CK_243X), CLK(NULL, "wdt1_ick", &wdt1_ick, CK_243X), CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_243X), CLK(NULL, "icr_ick", &icr_ick, CK_243X), diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c index d5153b6..5d6f00d 100644 --- a/arch/arm/mach-omap2/clock3xxx_data.c +++ b/arch/arm/mach-omap2/clock3xxx_data.c @@ -3414,7 +3414,7 @@ static struct omap_clk omap3xxx_clks[] = { CLK("omap_wdt", "ick", &wdt2_ick, CK_3XXX), CLK(NULL, "wdt1_ick", &wdt1_ick, CK_3XXX), CLK(NULL, "gpio1_ick", &gpio1_ick, CK_3XXX), - CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick, CK_3XXX), + CLK("omap-counter-32k", "ick", &omap_32ksync_ick, CK_3XXX), CLK(NULL, "gpt12_ick", &gpt12_ick, CK_3XXX), CLK(NULL, "gpt1_ick", &gpt1_ick, CK_3XXX), CLK(NULL, "per_96m_fck", &per_96m_fck, CK_3XXX), diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 23e4d77..a403041 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -29,6 +29,40 @@ #include "mux.h" +static struct resource omap_32k_resources[] = { + { + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device omap_32k_device = { + .name = "omap-counter-32k", + .id = -1, + .num_resources = ARRAY_SIZE(omap_32k_resources), + .resource = omap_32k_resources, +}; + +static void omap_init_32k(void) +{ + if (cpu_is_omap2420()) { + omap_32k_resources[0].start = OMAP2420_32KSYNCT_BASE; + omap_32k_resources[0].end = OMAP2420_32KSYNCT_BASE + SZ_4K; + } else if (cpu_is_omap2430()) { + omap_32k_resources[0].start = OMAP2430_32KSYNCT_BASE; + omap_32k_resources[0].end = OMAP2430_32KSYNCT_BASE + SZ_4K; + } else if (cpu_is_omap34xx()) { + omap_32k_resources[0].start = OMAP3430_32KSYNCT_BASE; + omap_32k_resources[0].end = OMAP3430_32KSYNCT_BASE + SZ_4K; + } else if (cpu_is_omap44xx()) { + omap_32k_resources[0].start = OMAP4430_32KSYNCT_BASE; + omap_32k_resources[0].end = OMAP4430_32KSYNCT_BASE + SZ_4K; + } else { /* not supported */ + return; + } + + (void) platform_device_register(&omap_32k_device); +}; + #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE) static struct resource cam_resources[] = { @@ -794,6 +828,7 @@ static int __init omap2_init_devices(void) * in alphabetical order so they're easier to sort through. */ omap_hsmmc_reset(); + omap_init_32k(); omap_init_camera(); omap_init_mbox(); omap_init_mcspi(); diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 98f0191..11dfcf0 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -4,7 +4,7 @@ # Common support obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \ - usb.o fb.o io.o + usb.o fb.o io.o counter-32k.o obj-m := obj-n := obj- := @@ -30,4 +30,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y) # OMAP mailbox framework obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o -obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o \ No newline at end of file +obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index 01cbb48..4be635a 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c @@ -87,164 +87,6 @@ const void *omap_get_var_config(u16 tag, size_t *len) } EXPORT_SYMBOL(omap_get_var_config); -/* - * 32KHz clocksource ... always available, on pretty most chips except - * OMAP 730 and 1510. Other timers could be used as clocksources, with - * higher resolution in free-running counter modes (e.g. 12 MHz xtal), - * but systems won't necessarily want to spend resources that way. - */ - -#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 - -#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) - -#include <linux/clocksource.h> - -/* - * offset_32k holds the init time counter value. It is then subtracted - * from every counter read to achieve a counter that counts time from the - * kernel boot (needed for sched_clock()). - */ -static u32 offset_32k __read_mostly; - -#ifdef CONFIG_ARCH_OMAP16XX -static cycle_t omap16xx_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k; -} -#else -#define omap16xx_32k_read NULL -#endif - -#ifdef CONFIG_ARCH_OMAP2420 -static cycle_t omap2420_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k; -} -#else -#define omap2420_32k_read NULL -#endif - -#ifdef CONFIG_ARCH_OMAP2430 -static cycle_t omap2430_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k; -} -#else -#define omap2430_32k_read NULL -#endif - -#ifdef CONFIG_ARCH_OMAP3 -static cycle_t omap34xx_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k; -} -#else -#define omap34xx_32k_read NULL -#endif - -#ifdef CONFIG_ARCH_OMAP4 -static cycle_t omap44xx_32k_read(struct clocksource *cs) -{ - return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k; -} -#else -#define omap44xx_32k_read NULL -#endif - -/* - * Kernel assumes that sched_clock can be called early but may not have - * things ready yet. - */ -static cycle_t omap_32k_read_dummy(struct clocksource *cs) -{ - return 0; -} - -static struct clocksource clocksource_32k = { - .name = "32k_counter", - .rating = 250, - .read = omap_32k_read_dummy, - .mask = CLOCKSOURCE_MASK(32), - .shift = 10, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -/* - * Returns current time from boot in nsecs. It's OK for this to wrap - * around for now, as it's just a relative time stamp. - */ -unsigned long long sched_clock(void) -{ - return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k), - clocksource_32k.mult, clocksource_32k.shift); -} - -/** - * read_persistent_clock - Return time from a persistent clock. - * - * Reads the time from a source which isn't disabled during PM, the - * 32k sync timer. Convert the cycles elapsed since last read into - * nsecs and adds to a monotonically increasing timespec. - */ -static struct timespec persistent_ts; -static cycles_t cycles, last_cycles; -void read_persistent_clock(struct timespec *ts) -{ - unsigned long long nsecs; - cycles_t delta; - struct timespec *tsp = &persistent_ts; - - last_cycles = cycles; - cycles = clocksource_32k.read(&clocksource_32k); - delta = cycles - last_cycles; - - nsecs = clocksource_cyc2ns(delta, - clocksource_32k.mult, clocksource_32k.shift); - - timespec_add_ns(tsp, nsecs); - *ts = *tsp; -} - -static int __init omap_init_clocksource_32k(void) -{ - static char err[] __initdata = KERN_ERR - "%s: can't register clocksource!\n"; - - if (cpu_is_omap16xx() || cpu_class_is_omap2()) { - struct clk *sync_32k_ick; - - if (cpu_is_omap16xx()) - clocksource_32k.read = omap16xx_32k_read; - else if (cpu_is_omap2420()) - clocksource_32k.read = omap2420_32k_read; - else if (cpu_is_omap2430()) - clocksource_32k.read = omap2430_32k_read; - else if (cpu_is_omap34xx()) - clocksource_32k.read = omap34xx_32k_read; - else if (cpu_is_omap44xx()) - clocksource_32k.read = omap44xx_32k_read; - else - return -ENODEV; - - sync_32k_ick = clk_get(NULL, "omap_32ksync_ick"); - if (sync_32k_ick) - clk_enable(sync_32k_ick); - - clocksource_32k.mult = clocksource_hz2mult(32768, - clocksource_32k.shift); - - offset_32k = clocksource_32k.read(&clocksource_32k); - - if (clocksource_register(&clocksource_32k)) - printk(err, clocksource_32k.name); - } - return 0; -} -arch_initcall(omap_init_clocksource_32k); - -#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */ - /* Global address base setup code */ #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) diff --git a/arch/arm/plat-omap/counter-32k.c b/arch/arm/plat-omap/counter-32k.c new file mode 100644 index 0000000..fdb8a85 --- /dev/null +++ b/arch/arm/plat-omap/counter-32k.c @@ -0,0 +1,250 @@ +/* + * counter-32k.c -- OMAP 32k Sync Timer Clocksource Driver + * + * Copyright (C) 2005-2010 Tony Lindgren <tony@atomide.com> + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2010 Felipe Balbi <me@felipebalbi.com> + * Copyright (C) 2009 Texas Instruments + * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * 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 <linux/kernel.h> +#include <linux/time.h> +#include <linux/clocksource.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/err.h> + +struct omap_counter_32k_device { + struct timespec persistent_ts; + struct clocksource cs; + cycles_t cycles; + cycles_t last_cycles; + + struct device *dev; + struct clk *ick; + void __iomem *base; + + /* + * offset_32k holds the init time counter value. It is then subtracted + * from every counter read to achieve a counter that counts time from the + * kernel boot (needed for sched_clock()). + */ + u32 offset_32k __read_mostly; +}; + +#define to_omap_32k(cs) (container_of(cs, struct omap_counter_32k_device, cs)) + +static struct omap_counter_32k_device *thecs; + +static inline u32 omap_counter_32k_readl(const void __iomem *base, unsigned offset) +{ + return __raw_readl(base + offset); +} + +static cycle_t omap_counter_32k_32k_read(struct clocksource *cs) +{ + struct omap_counter_32k_device *omap = to_omap_32k(cs); + + return omap_counter_32k_readl(omap->base, 0x10) - omap->offset_32k; +} + +/* + * Returns current time from boot in nsecs. It's OK for this to wrap + * around for now, as it's just a relative time stamp. + */ +unsigned long long sched_clock(void) +{ + struct omap_counter_32k_device *omap = thecs; + + if (!omap) + return 0; + + return clocksource_cyc2ns(omap->cs.read(&omap->cs), + omap->cs.mult, omap->cs.shift); +} + +/** + * read_persistent_clock - Return time from a persistent clock. + * + * Reads the time from a source which isn't disabled during PM, the + * 32k sync timer. Convert the cycles elapsed since last read into + * nsecs and adds to a monotonically increasing timespec. + */ +void read_persistent_clock(struct timespec *ts) +{ + struct omap_counter_32k_device *omap = thecs; + unsigned long long nsecs; + cycles_t delta; + struct timespec *tsp; + + if (!omap) { + ts->tv_sec = 0; + ts->tv_nsec = 0; + return; + } + + tsp = &omap->persistent_ts; + + omap->last_cycles = omap->cycles; + omap->cycles = omap->cs.read(&omap->cs); + delta = omap->cycles - omap->last_cycles; + + nsecs = clocksource_cyc2ns(delta, + omap->cs.mult, omap->cs.shift); + + timespec_add_ns(tsp, nsecs); + *ts = *tsp; +} + +static int __init omap_counter_32k_probe(struct platform_device *pdev) +{ + struct omap_counter_32k_device *omap; + struct resource *res; + struct clk *ick; + + int ret; + + void __iomem *base; + + omap = kzalloc(sizeof(*omap), GFP_KERNEL); + if (!omap) { + dev_dbg(&pdev->dev, "unable to allocate memory\n"); + ret = -ENOMEM; + goto err0; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_dbg(&pdev->dev, "couldn't get resource\n"); + ret = -ENODEV; + goto err1; + } + + base = ioremap(res->start, resource_size(res)); + if (!base) { + dev_dbg(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + ick = clk_get(&pdev->dev, "ick"); + if (IS_ERR(ick)) { + dev_dbg(&pdev->dev, "couldn't get clock\n"); + ret = PTR_ERR(ick); + goto err3; + } + + ret = clk_enable(ick); + if (ret) { + dev_dbg(&pdev->dev, "couldn't enable clock\n"); + goto err4; + } + + omap->base = base; + omap->dev = &pdev->dev; + omap->ick = ick; + + omap->cs.name = "counter-32k"; + omap->cs.rating = 250; + omap->cs.read = omap_counter_32k_32k_read; + omap->cs.mask = CLOCKSOURCE_MASK(32); + omap->cs.shift = 10; + omap->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; + omap->cs.mult = clocksource_hz2mult(32768, omap->cs.shift); + + platform_set_drvdata(pdev, omap); + + ret = clocksource_register(&omap->cs); + if (ret) { + dev_dbg(&pdev->dev, "failed to register clocksource\n"); + goto err5; + } + + /* initialize our offset */ + omap->offset_32k = omap_counter_32k_32k_read(&omap->cs); + + /* + * REVISIT for now we need to keep a global static pointer + * to this clocksource instance. Would it make any sense + * to provide a get_clocksource() to fetch the clocksource + * we just registered ? + */ + thecs = omap; + + return 0; + +err5: + clk_disable(ick); + +err4: + clk_put(ick); + +err3: + iounmap(base); + +err2: +err1: + kfree(omap); + +err0: + return ret; +} + +static int __exit omap_counter_32k_remove(struct platform_device *pdev) +{ + struct omap_counter_32k_device *omap = platform_get_drvdata(pdev); + + clocksource_unregister(&omap->cs); + clk_disable(omap->ick); + clk_put(omap->ick); + iounmap(omap->base); + kfree(omap); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void omap_counter_32k_shutdown(struct platform_device *pdev) +{ + struct omap_counter_32k_device *omap = platform_get_drvdata(pdev); + + clk_disable(omap->ick); +} + +static struct platform_driver omap_counter_32k_driver = { + .remove = __exit_p(omap_counter_32k_remove), + .shutdown = omap_counter_32k_shutdown, + .driver = { + .name = "omap-counter-32k", + }, +}; + +static int __init omap_counter_32k_init(void) +{ + return platform_driver_probe(&omap_counter_32k_driver, omap_counter_32k_probe); +} +arch_initcall(omap_counter_32k_init); + +static void __exit omap_counter_32k_exit(void) +{ + platform_driver_unregister(&omap_counter_32k_driver); +} +module_exit(omap_counter_32k_exit); + +MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>"); +MODULE_LICENSE("GPL v2"); -- 1.7.0.rc0.33.g7c3932 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver 2010-04-07 9:57 ` [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver felipe.balbi @ 2010-04-07 16:08 ` Kevin Hilman 2010-04-07 17:34 ` Felipe Balbi 0 siblings, 1 reply; 16+ messages in thread From: Kevin Hilman @ 2010-04-07 16:08 UTC (permalink / raw) To: felipe.balbi; +Cc: Linux OMAP Mailing List felipe.balbi@nokia.com writes: > From: Felipe Balbi <felipe.balbi@nokia.com> > > Convert the omap32k clocksource driver into a platform_driver > and while at that, also remove the ifdeferry around the code. > > Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> I'm OK with this for now. Ideally, this would be further converted to use hwmod + omap_device to automatcially created the platform_devices for you. Kevin > --- > arch/arm/mach-omap1/devices.c | 24 ++++ > arch/arm/mach-omap2/clock2420_data.c | 2 +- > arch/arm/mach-omap2/clock2430_data.c | 2 +- > arch/arm/mach-omap2/clock3xxx_data.c | 2 +- > arch/arm/mach-omap2/devices.c | 35 +++++ > arch/arm/plat-omap/Makefile | 4 +- > arch/arm/plat-omap/common.c | 158 --------------------- > arch/arm/plat-omap/counter-32k.c | 250 ++++++++++++++++++++++++++++++++++ > 8 files changed, 314 insertions(+), 163 deletions(-) > create mode 100644 arch/arm/plat-omap/counter-32k.c > > diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c > index 379100c..4393b45 100644 > --- a/arch/arm/mach-omap1/devices.c > +++ b/arch/arm/mach-omap1/devices.c > @@ -28,6 +28,29 @@ > > /*-------------------------------------------------------------------------*/ > > +#define OMAP16XX_TIMER_32K_BASE 0xfffbc400 > + > +static struct resource omap_32k_resources[] = { > + { > + .start = OMAP16XX_TIMER_32K_BASE, > + .end = SZ_4K, > + .flags = IORESOURCE_MEM, > + }, > +}; > + > +static struct platform_device omap_32k_device = { > + .name = "omap-counter-32k", > + .id = -1, > + .num_resources = ARRAY_SIZE(omap_32k_resources), > + .resource = omap_32k_resources, > +}; > + > +static void omap_init_32k(void) > +{ > + if (cpu_is_omap16xx()) > + (void) platform_device_register(&omap_32k_device); > +}; > + > #if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE) > > #define OMAP_RTC_BASE 0xfffb4800 > @@ -295,6 +318,7 @@ static int __init omap1_init_devices(void) > * in alphabetical order so they're easier to sort through. > */ > > + omap_init_32k(); > omap_init_mbox(); > omap_init_rtc(); > omap_init_spi100k(); > diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c > index d932b14..a4747ad 100644 > --- a/arch/arm/mach-omap2/clock2420_data.c > +++ b/arch/arm/mach-omap2/clock2420_data.c > @@ -1806,7 +1806,7 @@ static struct omap_clk omap2420_clks[] = { > CLK(NULL, "gpios_fck", &gpios_fck, CK_242X), > CLK("omap_wdt", "ick", &mpu_wdt_ick, CK_242X), > CLK("omap_wdt", "fck", &mpu_wdt_fck, CK_242X), > - CLK(NULL, "sync_32k_ick", &sync_32k_ick, CK_242X), > + CLK("omap-counter-32k", "ick", &sync_32k_ick, CK_242X), > CLK(NULL, "wdt1_ick", &wdt1_ick, CK_242X), > CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_242X), > CLK("omap24xxcam", "fck", &cam_fck, CK_242X), > diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c > index 0438b6e..479ab53 100644 > --- a/arch/arm/mach-omap2/clock2430_data.c > +++ b/arch/arm/mach-omap2/clock2430_data.c > @@ -1900,7 +1900,7 @@ static struct omap_clk omap2430_clks[] = { > CLK(NULL, "gpios_fck", &gpios_fck, CK_243X), > CLK("omap_wdt", "ick", &mpu_wdt_ick, CK_243X), > CLK("omap_wdt", "fck", &mpu_wdt_fck, CK_243X), > - CLK(NULL, "sync_32k_ick", &sync_32k_ick, CK_243X), > + CLK("omap-counter-32k", "ick", &sync_32k_ick, CK_243X), > CLK(NULL, "wdt1_ick", &wdt1_ick, CK_243X), > CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_243X), > CLK(NULL, "icr_ick", &icr_ick, CK_243X), > diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c > index d5153b6..5d6f00d 100644 > --- a/arch/arm/mach-omap2/clock3xxx_data.c > +++ b/arch/arm/mach-omap2/clock3xxx_data.c > @@ -3414,7 +3414,7 @@ static struct omap_clk omap3xxx_clks[] = { > CLK("omap_wdt", "ick", &wdt2_ick, CK_3XXX), > CLK(NULL, "wdt1_ick", &wdt1_ick, CK_3XXX), > CLK(NULL, "gpio1_ick", &gpio1_ick, CK_3XXX), > - CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick, CK_3XXX), > + CLK("omap-counter-32k", "ick", &omap_32ksync_ick, CK_3XXX), > CLK(NULL, "gpt12_ick", &gpt12_ick, CK_3XXX), > CLK(NULL, "gpt1_ick", &gpt1_ick, CK_3XXX), > CLK(NULL, "per_96m_fck", &per_96m_fck, CK_3XXX), > diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c > index 23e4d77..a403041 100644 > --- a/arch/arm/mach-omap2/devices.c > +++ b/arch/arm/mach-omap2/devices.c > @@ -29,6 +29,40 @@ > > #include "mux.h" > > +static struct resource omap_32k_resources[] = { > + { > + .flags = IORESOURCE_MEM, > + }, > +}; > + > +static struct platform_device omap_32k_device = { > + .name = "omap-counter-32k", > + .id = -1, > + .num_resources = ARRAY_SIZE(omap_32k_resources), > + .resource = omap_32k_resources, > +}; > + > +static void omap_init_32k(void) > +{ > + if (cpu_is_omap2420()) { > + omap_32k_resources[0].start = OMAP2420_32KSYNCT_BASE; > + omap_32k_resources[0].end = OMAP2420_32KSYNCT_BASE + SZ_4K; > + } else if (cpu_is_omap2430()) { > + omap_32k_resources[0].start = OMAP2430_32KSYNCT_BASE; > + omap_32k_resources[0].end = OMAP2430_32KSYNCT_BASE + SZ_4K; > + } else if (cpu_is_omap34xx()) { > + omap_32k_resources[0].start = OMAP3430_32KSYNCT_BASE; > + omap_32k_resources[0].end = OMAP3430_32KSYNCT_BASE + SZ_4K; > + } else if (cpu_is_omap44xx()) { > + omap_32k_resources[0].start = OMAP4430_32KSYNCT_BASE; > + omap_32k_resources[0].end = OMAP4430_32KSYNCT_BASE + SZ_4K; > + } else { /* not supported */ > + return; > + } > + > + (void) platform_device_register(&omap_32k_device); > +}; > + > #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE) > > static struct resource cam_resources[] = { > @@ -794,6 +828,7 @@ static int __init omap2_init_devices(void) > * in alphabetical order so they're easier to sort through. > */ > omap_hsmmc_reset(); > + omap_init_32k(); > omap_init_camera(); > omap_init_mbox(); > omap_init_mcspi(); > diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile > index 98f0191..11dfcf0 100644 > --- a/arch/arm/plat-omap/Makefile > +++ b/arch/arm/plat-omap/Makefile > @@ -4,7 +4,7 @@ > > # Common support > obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \ > - usb.o fb.o io.o > + usb.o fb.o io.o counter-32k.o > obj-m := > obj-n := > obj- := > @@ -30,4 +30,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y) > # OMAP mailbox framework > obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o > > -obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o > \ No newline at end of file > +obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o > diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c > index 01cbb48..4be635a 100644 > --- a/arch/arm/plat-omap/common.c > +++ b/arch/arm/plat-omap/common.c > @@ -87,164 +87,6 @@ const void *omap_get_var_config(u16 tag, size_t *len) > } > EXPORT_SYMBOL(omap_get_var_config); > > -/* > - * 32KHz clocksource ... always available, on pretty most chips except > - * OMAP 730 and 1510. Other timers could be used as clocksources, with > - * higher resolution in free-running counter modes (e.g. 12 MHz xtal), > - * but systems won't necessarily want to spend resources that way. > - */ > - > -#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 > - > -#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) > - > -#include <linux/clocksource.h> > - > -/* > - * offset_32k holds the init time counter value. It is then subtracted > - * from every counter read to achieve a counter that counts time from the > - * kernel boot (needed for sched_clock()). > - */ > -static u32 offset_32k __read_mostly; > - > -#ifdef CONFIG_ARCH_OMAP16XX > -static cycle_t omap16xx_32k_read(struct clocksource *cs) > -{ > - return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k; > -} > -#else > -#define omap16xx_32k_read NULL > -#endif > - > -#ifdef CONFIG_ARCH_OMAP2420 > -static cycle_t omap2420_32k_read(struct clocksource *cs) > -{ > - return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k; > -} > -#else > -#define omap2420_32k_read NULL > -#endif > - > -#ifdef CONFIG_ARCH_OMAP2430 > -static cycle_t omap2430_32k_read(struct clocksource *cs) > -{ > - return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k; > -} > -#else > -#define omap2430_32k_read NULL > -#endif > - > -#ifdef CONFIG_ARCH_OMAP3 > -static cycle_t omap34xx_32k_read(struct clocksource *cs) > -{ > - return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k; > -} > -#else > -#define omap34xx_32k_read NULL > -#endif > - > -#ifdef CONFIG_ARCH_OMAP4 > -static cycle_t omap44xx_32k_read(struct clocksource *cs) > -{ > - return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k; > -} > -#else > -#define omap44xx_32k_read NULL > -#endif > - > -/* > - * Kernel assumes that sched_clock can be called early but may not have > - * things ready yet. > - */ > -static cycle_t omap_32k_read_dummy(struct clocksource *cs) > -{ > - return 0; > -} > - > -static struct clocksource clocksource_32k = { > - .name = "32k_counter", > - .rating = 250, > - .read = omap_32k_read_dummy, > - .mask = CLOCKSOURCE_MASK(32), > - .shift = 10, > - .flags = CLOCK_SOURCE_IS_CONTINUOUS, > -}; > - > -/* > - * Returns current time from boot in nsecs. It's OK for this to wrap > - * around for now, as it's just a relative time stamp. > - */ > -unsigned long long sched_clock(void) > -{ > - return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k), > - clocksource_32k.mult, clocksource_32k.shift); > -} > - > -/** > - * read_persistent_clock - Return time from a persistent clock. > - * > - * Reads the time from a source which isn't disabled during PM, the > - * 32k sync timer. Convert the cycles elapsed since last read into > - * nsecs and adds to a monotonically increasing timespec. > - */ > -static struct timespec persistent_ts; > -static cycles_t cycles, last_cycles; > -void read_persistent_clock(struct timespec *ts) > -{ > - unsigned long long nsecs; > - cycles_t delta; > - struct timespec *tsp = &persistent_ts; > - > - last_cycles = cycles; > - cycles = clocksource_32k.read(&clocksource_32k); > - delta = cycles - last_cycles; > - > - nsecs = clocksource_cyc2ns(delta, > - clocksource_32k.mult, clocksource_32k.shift); > - > - timespec_add_ns(tsp, nsecs); > - *ts = *tsp; > -} > - > -static int __init omap_init_clocksource_32k(void) > -{ > - static char err[] __initdata = KERN_ERR > - "%s: can't register clocksource!\n"; > - > - if (cpu_is_omap16xx() || cpu_class_is_omap2()) { > - struct clk *sync_32k_ick; > - > - if (cpu_is_omap16xx()) > - clocksource_32k.read = omap16xx_32k_read; > - else if (cpu_is_omap2420()) > - clocksource_32k.read = omap2420_32k_read; > - else if (cpu_is_omap2430()) > - clocksource_32k.read = omap2430_32k_read; > - else if (cpu_is_omap34xx()) > - clocksource_32k.read = omap34xx_32k_read; > - else if (cpu_is_omap44xx()) > - clocksource_32k.read = omap44xx_32k_read; > - else > - return -ENODEV; > - > - sync_32k_ick = clk_get(NULL, "omap_32ksync_ick"); > - if (sync_32k_ick) > - clk_enable(sync_32k_ick); > - > - clocksource_32k.mult = clocksource_hz2mult(32768, > - clocksource_32k.shift); > - > - offset_32k = clocksource_32k.read(&clocksource_32k); > - > - if (clocksource_register(&clocksource_32k)) > - printk(err, clocksource_32k.name); > - } > - return 0; > -} > -arch_initcall(omap_init_clocksource_32k); > - > -#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */ > - > /* Global address base setup code */ > > #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) > diff --git a/arch/arm/plat-omap/counter-32k.c b/arch/arm/plat-omap/counter-32k.c > new file mode 100644 > index 0000000..fdb8a85 > --- /dev/null > +++ b/arch/arm/plat-omap/counter-32k.c > @@ -0,0 +1,250 @@ > +/* > + * counter-32k.c -- OMAP 32k Sync Timer Clocksource Driver > + * > + * Copyright (C) 2005-2010 Tony Lindgren <tony@atomide.com> > + * Copyright (C) 2010 Nokia Corporation > + * Copyright (C) 2010 Felipe Balbi <me@felipebalbi.com> > + * Copyright (C) 2009 Texas Instruments > + * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> > + * > + * 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 <linux/kernel.h> > +#include <linux/time.h> > +#include <linux/clocksource.h> > +#include <linux/platform_device.h> > +#include <linux/clk.h> > +#include <linux/err.h> > + > +struct omap_counter_32k_device { > + struct timespec persistent_ts; > + struct clocksource cs; > + cycles_t cycles; > + cycles_t last_cycles; > + > + struct device *dev; > + struct clk *ick; > + void __iomem *base; > + > + /* > + * offset_32k holds the init time counter value. It is then subtracted > + * from every counter read to achieve a counter that counts time from the > + * kernel boot (needed for sched_clock()). > + */ > + u32 offset_32k __read_mostly; > +}; > + > +#define to_omap_32k(cs) (container_of(cs, struct omap_counter_32k_device, cs)) > + > +static struct omap_counter_32k_device *thecs; > + > +static inline u32 omap_counter_32k_readl(const void __iomem *base, unsigned offset) > +{ > + return __raw_readl(base + offset); > +} > + > +static cycle_t omap_counter_32k_32k_read(struct clocksource *cs) > +{ > + struct omap_counter_32k_device *omap = to_omap_32k(cs); > + > + return omap_counter_32k_readl(omap->base, 0x10) - omap->offset_32k; > +} > + > +/* > + * Returns current time from boot in nsecs. It's OK for this to wrap > + * around for now, as it's just a relative time stamp. > + */ > +unsigned long long sched_clock(void) > +{ > + struct omap_counter_32k_device *omap = thecs; > + > + if (!omap) > + return 0; > + > + return clocksource_cyc2ns(omap->cs.read(&omap->cs), > + omap->cs.mult, omap->cs.shift); > +} > + > +/** > + * read_persistent_clock - Return time from a persistent clock. > + * > + * Reads the time from a source which isn't disabled during PM, the > + * 32k sync timer. Convert the cycles elapsed since last read into > + * nsecs and adds to a monotonically increasing timespec. > + */ > +void read_persistent_clock(struct timespec *ts) > +{ > + struct omap_counter_32k_device *omap = thecs; > + unsigned long long nsecs; > + cycles_t delta; > + struct timespec *tsp; > + > + if (!omap) { > + ts->tv_sec = 0; > + ts->tv_nsec = 0; > + return; > + } > + > + tsp = &omap->persistent_ts; > + > + omap->last_cycles = omap->cycles; > + omap->cycles = omap->cs.read(&omap->cs); > + delta = omap->cycles - omap->last_cycles; > + > + nsecs = clocksource_cyc2ns(delta, > + omap->cs.mult, omap->cs.shift); > + > + timespec_add_ns(tsp, nsecs); > + *ts = *tsp; > +} > + > +static int __init omap_counter_32k_probe(struct platform_device *pdev) > +{ > + struct omap_counter_32k_device *omap; > + struct resource *res; > + struct clk *ick; > + > + int ret; > + > + void __iomem *base; > + > + omap = kzalloc(sizeof(*omap), GFP_KERNEL); > + if (!omap) { > + dev_dbg(&pdev->dev, "unable to allocate memory\n"); > + ret = -ENOMEM; > + goto err0; > + } > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_dbg(&pdev->dev, "couldn't get resource\n"); > + ret = -ENODEV; > + goto err1; > + } > + > + base = ioremap(res->start, resource_size(res)); > + if (!base) { > + dev_dbg(&pdev->dev, "ioremap failed\n"); > + ret = -ENOMEM; > + goto err2; > + } > + > + ick = clk_get(&pdev->dev, "ick"); > + if (IS_ERR(ick)) { > + dev_dbg(&pdev->dev, "couldn't get clock\n"); > + ret = PTR_ERR(ick); > + goto err3; > + } > + > + ret = clk_enable(ick); > + if (ret) { > + dev_dbg(&pdev->dev, "couldn't enable clock\n"); > + goto err4; > + } > + > + omap->base = base; > + omap->dev = &pdev->dev; > + omap->ick = ick; > + > + omap->cs.name = "counter-32k"; > + omap->cs.rating = 250; > + omap->cs.read = omap_counter_32k_32k_read; > + omap->cs.mask = CLOCKSOURCE_MASK(32); > + omap->cs.shift = 10; > + omap->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; > + omap->cs.mult = clocksource_hz2mult(32768, omap->cs.shift); > + > + platform_set_drvdata(pdev, omap); > + > + ret = clocksource_register(&omap->cs); > + if (ret) { > + dev_dbg(&pdev->dev, "failed to register clocksource\n"); > + goto err5; > + } > + > + /* initialize our offset */ > + omap->offset_32k = omap_counter_32k_32k_read(&omap->cs); > + > + /* > + * REVISIT for now we need to keep a global static pointer > + * to this clocksource instance. Would it make any sense > + * to provide a get_clocksource() to fetch the clocksource > + * we just registered ? > + */ > + thecs = omap; > + > + return 0; > + > +err5: > + clk_disable(ick); > + > +err4: > + clk_put(ick); > + > +err3: > + iounmap(base); > + > +err2: > +err1: > + kfree(omap); > + > +err0: > + return ret; > +} > + > +static int __exit omap_counter_32k_remove(struct platform_device *pdev) > +{ > + struct omap_counter_32k_device *omap = platform_get_drvdata(pdev); > + > + clocksource_unregister(&omap->cs); > + clk_disable(omap->ick); > + clk_put(omap->ick); > + iounmap(omap->base); > + kfree(omap); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +static void omap_counter_32k_shutdown(struct platform_device *pdev) > +{ > + struct omap_counter_32k_device *omap = platform_get_drvdata(pdev); > + > + clk_disable(omap->ick); > +} > + > +static struct platform_driver omap_counter_32k_driver = { > + .remove = __exit_p(omap_counter_32k_remove), > + .shutdown = omap_counter_32k_shutdown, > + .driver = { > + .name = "omap-counter-32k", > + }, > +}; > + > +static int __init omap_counter_32k_init(void) > +{ > + return platform_driver_probe(&omap_counter_32k_driver, omap_counter_32k_probe); > +} > +arch_initcall(omap_counter_32k_init); > + > +static void __exit omap_counter_32k_exit(void) > +{ > + platform_driver_unregister(&omap_counter_32k_driver); > +} > +module_exit(omap_counter_32k_exit); > + > +MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>"); > +MODULE_LICENSE("GPL v2"); > -- > 1.7.0.rc0.33.g7c3932 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver 2010-04-07 16:08 ` Kevin Hilman @ 2010-04-07 17:34 ` Felipe Balbi 2010-06-11 15:24 ` Shilimkar, Santosh 0 siblings, 1 reply; 16+ messages in thread From: Felipe Balbi @ 2010-04-07 17:34 UTC (permalink / raw) To: ext Kevin Hilman; +Cc: Balbi Felipe (Nokia-D/Helsinki), Linux OMAP Mailing List On Wed, Apr 07, 2010 at 06:08:13PM +0200, ext Kevin Hilman wrote: >felipe.balbi@nokia.com writes: > >> From: Felipe Balbi <felipe.balbi@nokia.com> >> >> Convert the omap32k clocksource driver into a platform_driver >> and while at that, also remove the ifdeferry around the code. >> >> Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> > >I'm OK with this for now. Ideally, this would be further converted to >use hwmod + omap_device to automatcially created the platform_devices >for you. Yeah. I was asking Paul about it today. I can send as a follow up patch on next week. -- balbi ^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver 2010-04-07 17:34 ` Felipe Balbi @ 2010-06-11 15:24 ` Shilimkar, Santosh 0 siblings, 0 replies; 16+ messages in thread From: Shilimkar, Santosh @ 2010-06-11 15:24 UTC (permalink / raw) To: felipe.balbi@nokia.com, ext Kevin Hilman; +Cc: Linux OMAP Mailing List Felipe, > -----Original Message----- > From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of Felipe > Balbi > Sent: Wednesday, April 07, 2010 11:04 PM > To: ext Kevin Hilman > Cc: Balbi Felipe (Nokia-D/Helsinki); Linux OMAP Mailing List > Subject: Re: [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver > > On Wed, Apr 07, 2010 at 06:08:13PM +0200, ext Kevin Hilman wrote: > >felipe.balbi@nokia.com writes: > > > >> From: Felipe Balbi <felipe.balbi@nokia.com> > >> > >> Convert the omap32k clocksource driver into a platform_driver > >> and while at that, also remove the ifdeferry around the code. > >> > >> Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> > > > >I'm OK with this for now. Ideally, this would be further converted to > >use hwmod + omap_device to automatcially created the platform_devices > >for you. > > Yeah. I was asking Paul about it today. I can send as a follow up patch > on next week. > Is there a newer version of this series already available/posted?? Sorry I missed it. Regards Santosh ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2010-06-11 15:24 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-03-31 11:13 [RFC/PATCH 0/3] 32k timer patches Felipe Balbi 2010-03-31 11:13 ` [RFC/PATCH 1/3] omap: fix clocksource_32k to start from zero Felipe Balbi 2010-03-31 11:13 ` [RFC/PATCH 2/3] arm: omap1: remove dead code from timer32k.c Felipe Balbi 2010-04-06 21:30 ` Kevin Hilman 2010-03-31 11:13 ` [RFC/PATCH 3/3] arm: omap1/2/3/4: convert clocksource to a platform_driver Felipe Balbi 2010-04-06 21:37 ` Kevin Hilman 2010-04-07 7:21 ` Felipe Balbi 2010-04-07 9:57 ` [PATCH 1/3] omap: fix clocksource_32k to start from zero felipe.balbi 2010-04-07 10:02 ` Felipe Balbi 2010-04-22 23:49 ` [APPLIED] " Tony Lindgren 2010-04-07 9:57 ` [PATCH 2/3] arm: omap1: remove dead code from timer32k.c felipe.balbi 2010-04-22 23:49 ` [APPLIED] " Tony Lindgren 2010-04-07 9:57 ` [PATCH 3/3] arm: omap1/2/3/4: convert 32k-sync driver to a platform_driver felipe.balbi 2010-04-07 16:08 ` Kevin Hilman 2010-04-07 17:34 ` Felipe Balbi 2010-06-11 15:24 ` Shilimkar, Santosh
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).