From f11899894c0a683c754ca71b45f7c9c3d35a3a1c Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Sat, 20 Apr 2013 23:22:13 +0200 Subject: clocksource: add samsung pwm timer driver This adds a new clocksource driver for the PWM timer that is present in most Samsung SoCs, based on the existing driver in arch/arm/plat-samsung/samsung-time.c and many changes implemented by Tomasz Figa. Originally, the conversion of all Samsung machines to the new driver was planned for 3.10, but that work ended up being too late and too invasive just before the merge window. Unfortunately, other changes in the Exynos platform resulted in some Exynos4 setups, particularly the Universal C210 board to be broken. In order to fix that with minimum risk, so we now leave the existing pwm clocksource driver in place for all older platforms and use the new driver only for device tree enabled boards. This way, we can get the broken machines running again using DT descriptions. All clocksource changes were implemented by Tomasz, while the DT registration was rewritten by Arnd. Signed-off-by: Arnd Bergmann Cc: Tomasz Figa Cc: Kyungmin Park Cc: Kukjin Kim Cc: Ben Dooks Cc: John Stultz Cc: Thomas Gleixner --- include/clocksource/samsung_pwm.h | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 include/clocksource/samsung_pwm.h (limited to 'include/clocksource') diff --git a/include/clocksource/samsung_pwm.h b/include/clocksource/samsung_pwm.h new file mode 100644 index 000000000000..eff8668da252 --- /dev/null +++ b/include/clocksource/samsung_pwm.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * 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. + * + * 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, see . + */ +#ifndef __CLOCKSOURCE_SAMSUNG_PWM_H +#define __CLOCKSOURCE_SAMSUNG_PWM_H + +#include + +#define SAMSUNG_PWM_NUM 5 + +struct platform_device; +struct device_node; + +struct samsung_pwm_variant { + u8 bits; + u8 div_base; + u8 tclk_mask; + u8 output_mask; + bool has_tint_cstat; +}; + +struct samsung_pwm { + struct samsung_pwm_variant variant; + spinlock_t slock; + void __iomem *base; + int irq[SAMSUNG_PWM_NUM]; +}; + +#endif /* __CLOCKSOURCE_SAMSUNG_PWM_H */ -- cgit v1.2.3-58-ga151 From 7aac482e6290ab7ad21809e0c7327be959a2203e Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Apr 2013 17:46:24 +0200 Subject: clocksource: samsung_pwm_timer: Make PWM spinlock global This patch makes the PWM spinlock global and exports it to allow using it in Samsung PWM driver (will be reworked to use proper synchronization in further patches). Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Reviewed-by: Arnd Bergmann Acked-by: Kukjin Kim Signed-off-by: Olof Johansson --- drivers/clocksource/samsung_pwm_timer.c | 24 +++++++++++++----------- include/clocksource/samsung_pwm.h | 2 ++ 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'include/clocksource') diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 1752457a4f76..d9048b843546 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -49,6 +49,9 @@ #define TCON_INVERT(chan) (1 << (4 * (chan) + 2)) #define TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3)) +DEFINE_SPINLOCK(samsung_pwm_lock); +EXPORT_SYMBOL(samsung_pwm_lock); + struct samsung_timer_source { unsigned int event_id; unsigned int source_id; @@ -72,14 +75,14 @@ static void samsung_timer_set_prescale(struct samsung_pwm *pwm, if (channel >= 2) shift = TCFG0_PRESCALER1_SHIFT; - spin_lock_irqsave(&pwm->slock, flags); + spin_lock_irqsave(&samsung_pwm_lock, flags); reg = readl(pwm->base + REG_TCFG0); reg &= ~(TCFG0_PRESCALER_MASK << shift); reg |= (prescale - 1) << shift; writel(reg, pwm->base + REG_TCFG0); - spin_unlock_irqrestore(&pwm->slock, flags); + spin_unlock_irqrestore(&samsung_pwm_lock, flags); } static void samsung_timer_set_divisor(struct samsung_pwm *pwm, @@ -92,14 +95,14 @@ static void samsung_timer_set_divisor(struct samsung_pwm *pwm, bits = (fls(divisor) - 1) - pwm->variant.div_base; - spin_lock_irqsave(&pwm->slock, flags); + spin_lock_irqsave(&samsung_pwm_lock, flags); reg = readl(pwm->base + REG_TCFG1); reg &= ~(TCFG1_MUX_MASK << shift); reg |= bits << shift; writel(reg, pwm->base + REG_TCFG1); - spin_unlock_irqrestore(&pwm->slock, flags); + spin_unlock_irqrestore(&samsung_pwm_lock, flags); } static void samsung_time_stop(unsigned int channel) @@ -110,13 +113,13 @@ static void samsung_time_stop(unsigned int channel) if (channel > 0) ++channel; - spin_lock_irqsave(&pwm->slock, flags); + spin_lock_irqsave(&samsung_pwm_lock, flags); tcon = __raw_readl(pwm->base + REG_TCON); tcon &= ~TCON_START(channel); __raw_writel(tcon, pwm->base + REG_TCON); - spin_unlock_irqrestore(&pwm->slock, flags); + spin_unlock_irqrestore(&samsung_pwm_lock, flags); } static void samsung_time_setup(unsigned int channel, unsigned long tcnt) @@ -128,7 +131,7 @@ static void samsung_time_setup(unsigned int channel, unsigned long tcnt) if (tcon_chan > 0) ++tcon_chan; - spin_lock_irqsave(&pwm->slock, flags); + spin_lock_irqsave(&samsung_pwm_lock, flags); tcon = __raw_readl(pwm->base + REG_TCON); @@ -141,7 +144,7 @@ static void samsung_time_setup(unsigned int channel, unsigned long tcnt) __raw_writel(tcnt, pwm->base + REG_TCMPB(channel)); __raw_writel(tcon, pwm->base + REG_TCON); - spin_unlock_irqrestore(&pwm->slock, flags); + spin_unlock_irqrestore(&samsung_pwm_lock, flags); } static void samsung_time_start(unsigned int channel, bool periodic) @@ -152,7 +155,7 @@ static void samsung_time_start(unsigned int channel, bool periodic) if (channel > 0) ++channel; - spin_lock_irqsave(&pwm->slock, flags); + spin_lock_irqsave(&samsung_pwm_lock, flags); tcon = __raw_readl(pwm->base + REG_TCON); @@ -166,7 +169,7 @@ static void samsung_time_start(unsigned int channel, bool periodic) __raw_writel(tcon, pwm->base + REG_TCON); - spin_unlock_irqrestore(&pwm->slock, flags); + spin_unlock_irqrestore(&samsung_pwm_lock, flags); } static int samsung_set_next_event(unsigned long cycles, @@ -394,7 +397,6 @@ static void __init samsung_pwm_alloc(struct device_node *np, return; } memcpy(&pwm->variant, variant, sizeof(pwm->variant)); - spin_lock_init(&pwm->slock); for (i = 0; i < SAMSUNG_PWM_NUM; ++i) pwm->irq[i] = irq_of_parse_and_map(np, i); diff --git a/include/clocksource/samsung_pwm.h b/include/clocksource/samsung_pwm.h index eff8668da252..399d2414734f 100644 --- a/include/clocksource/samsung_pwm.h +++ b/include/clocksource/samsung_pwm.h @@ -23,6 +23,8 @@ struct platform_device; struct device_node; +extern spinlock_t samsung_pwm_lock; + struct samsung_pwm_variant { u8 bits; u8 div_base; -- cgit v1.2.3-58-ga151 From 09d718a78c79ddc270dccbfa1b1070b20b9a9ae1 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Apr 2013 17:46:26 +0200 Subject: clocksource: samsung_pwm_timer: Drop unused samsung_pwm struct This patch removes the unused samsung_pwm struct from public header. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Reviewed-by: Arnd Bergmann Acked-by: Kukjin Kim Signed-off-by: Olof Johansson --- include/clocksource/samsung_pwm.h | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'include/clocksource') diff --git a/include/clocksource/samsung_pwm.h b/include/clocksource/samsung_pwm.h index 399d2414734f..b1d8fe706f1a 100644 --- a/include/clocksource/samsung_pwm.h +++ b/include/clocksource/samsung_pwm.h @@ -20,9 +20,6 @@ #define SAMSUNG_PWM_NUM 5 -struct platform_device; -struct device_node; - extern spinlock_t samsung_pwm_lock; struct samsung_pwm_variant { @@ -33,11 +30,4 @@ struct samsung_pwm_variant { bool has_tint_cstat; }; -struct samsung_pwm { - struct samsung_pwm_variant variant; - spinlock_t slock; - void __iomem *base; - int irq[SAMSUNG_PWM_NUM]; -}; - #endif /* __CLOCKSOURCE_SAMSUNG_PWM_H */ -- cgit v1.2.3-58-ga151 From f9bb48a2c25a96757d13795ba7cc52687f94446f Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Apr 2013 17:46:27 +0200 Subject: clocksource: samsung_pwm_timer: Add support for non-DT platforms This patch extends the driver to support platforms that still use legacy ATAGS-based boot, without device tree, by providing an exported function that can be used from platform code to initialize the clocksource. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Reviewed-by: Arnd Bergmann Acked-by: Kukjin Kim Signed-off-by: Olof Johansson --- drivers/clocksource/Kconfig | 1 - drivers/clocksource/samsung_pwm_timer.c | 16 ++++++++++++++-- include/clocksource/samsung_pwm.h | 3 +++ 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'include/clocksource') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index ff5b6d87d65a..6d6174978f95 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -70,7 +70,6 @@ config CLKSRC_METAG_GENERIC config CLKSRC_SAMSUNG_PWM bool - depends on OF select CLKSRC_MMIO help This is a new clocksource driver for the PWM timer found in diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index e3257fae04e6..9f4bd6aa2343 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -356,7 +356,7 @@ static void __init samsung_timer_resources(void) /* * PWM master driver */ -static void __init samsung_pwm_clocksource_init(void) +static void __init _samsung_pwm_clocksource_init(void) { u8 mask; int channel; @@ -378,6 +378,17 @@ static void __init samsung_pwm_clocksource_init(void) samsung_clocksource_init(); } +void __init samsung_pwm_clocksource_init(void __iomem *base, + unsigned int *irqs, struct samsung_pwm_variant *variant) +{ + pwm.base = base; + memcpy(&pwm.variant, variant, sizeof(pwm.variant)); + memcpy(pwm.irq, irqs, SAMSUNG_PWM_NUM * sizeof(*irqs)); + + _samsung_pwm_clocksource_init(); +} + +#ifdef CONFIG_CLKSRC_OF static void __init samsung_pwm_alloc(struct device_node *np, const struct samsung_pwm_variant *variant) { @@ -414,7 +425,7 @@ static void __init samsung_pwm_alloc(struct device_node *np, return; } - samsung_pwm_clocksource_init(); + _samsung_pwm_clocksource_init(); } static const struct samsung_pwm_variant s3c24xx_variant = { @@ -468,3 +479,4 @@ static void __init s5p_pwm_clocksource_init(struct device_node *np) samsung_pwm_alloc(np, &s5p_variant); } CLOCKSOURCE_OF_DECLARE(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); +#endif diff --git a/include/clocksource/samsung_pwm.h b/include/clocksource/samsung_pwm.h index b1d8fe706f1a..5c449c8199e9 100644 --- a/include/clocksource/samsung_pwm.h +++ b/include/clocksource/samsung_pwm.h @@ -30,4 +30,7 @@ struct samsung_pwm_variant { bool has_tint_cstat; }; +void samsung_pwm_clocksource_init(void __iomem *base, + unsigned int *irqs, struct samsung_pwm_variant *variant); + #endif /* __CLOCKSOURCE_SAMSUNG_PWM_H */ -- cgit v1.2.3-58-ga151