diff options
Diffstat (limited to 'drivers/clocksource')
-rw-r--r-- | drivers/clocksource/Kconfig | 135 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 2 | ||||
-rw-r--r-- | drivers/clocksource/acpi_pm.c | 27 | ||||
-rw-r--r-- | drivers/clocksource/arm_global_timer.c | 21 | ||||
-rw-r--r-- | drivers/clocksource/dw_apb_timer.c | 46 | ||||
-rw-r--r-- | drivers/clocksource/dw_apb_timer_of.c | 16 | ||||
-rw-r--r-- | drivers/clocksource/h8300_timer16.c | 222 | ||||
-rw-r--r-- | drivers/clocksource/h8300_timer8.c | 264 | ||||
-rw-r--r-- | drivers/clocksource/h8300_tpu.c | 159 | ||||
-rw-r--r-- | drivers/clocksource/mmio.c | 2 | ||||
-rw-r--r-- | drivers/clocksource/mtk_timer.c | 20 | ||||
-rw-r--r-- | drivers/clocksource/rockchip_timer.c | 23 | ||||
-rw-r--r-- | drivers/clocksource/tango_xtal.c | 18 | ||||
-rw-r--r-- | drivers/clocksource/tegra20_timer.c | 3 | ||||
-rw-r--r-- | drivers/clocksource/time-lpc32xx.c | 4 | ||||
-rw-r--r-- | drivers/clocksource/time-pistachio.c | 2 | ||||
-rw-r--r-- | drivers/clocksource/timer-sun5i.c | 16 | ||||
-rw-r--r-- | drivers/clocksource/vt8500_timer.c | 7 |
18 files changed, 425 insertions, 562 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 2eb5f0efae90..56777f04d2d9 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -28,10 +28,16 @@ config CLKSRC_MMIO bool config DIGICOLOR_TIMER - bool + bool "Digicolor timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + help + Enables the support for the digicolor timer driver. config DW_APB_TIMER - bool + bool "DW APB timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + help + Enables the support for the dw_apb timer. config DW_APB_TIMER_OF bool @@ -39,47 +45,77 @@ config DW_APB_TIMER_OF select CLKSRC_OF config ROCKCHIP_TIMER - bool + bool "Rockchip timer driver" if COMPILE_TEST + depends on ARM || ARM64 select CLKSRC_OF + help + Enables the support for the rockchip timer driver. config ARMADA_370_XP_TIMER - bool + bool "Armada 370 and XP timer driver" if COMPILE_TEST + depends on ARM select CLKSRC_OF + help + Enables the support for the Armada 370 and XP timer driver. config MESON6_TIMER - bool + bool "Meson6 timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS select CLKSRC_MMIO + help + Enables the support for the Meson6 timer driver. config ORION_TIMER + bool "Orion timer driver" if COMPILE_TEST + depends on ARM select CLKSRC_OF select CLKSRC_MMIO - bool + help + Enables the support for the Orion timer driver config SUN4I_TIMER + bool "Sun4i timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS select CLKSRC_MMIO - bool + help + Enables support for the Sun4i timer. config SUN5I_HSTIMER + bool "Sun5i timer driver" if COMPILE_TEST select CLKSRC_MMIO - bool + depends on COMMON_CLK + help + Enables support the Sun5i timer. config TEGRA_TIMER - bool + bool "Tegra timer driver" if COMPILE_TEST + depends on ARM + help + Enables support for the Tegra driver. config VT8500_TIMER - bool + bool "VT8500 timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + help + Enables support for the VT8500 driver. config CADENCE_TTC_TIMER - bool + bool "Cadence TTC timer driver" if COMPILE_TEST + depends on COMMON_CLK + help + Enables support for the cadence ttc driver. config ASM9260_TIMER - bool + bool "ASM9260 timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS select CLKSRC_MMIO select CLKSRC_OF + help + Enables support for the ASM9260 timer. config CLKSRC_NOMADIK_MTU - bool - depends on (ARCH_NOMADIK || ARCH_U8500) + bool "Nomakdik clocksource driver" if COMPILE_TEST + depends on ARM select CLKSRC_MMIO help Support for Multi Timer Unit. MTU provides access @@ -93,9 +129,8 @@ config CLKSRC_NOMADIK_MTU_SCHED_CLOCK Use the Multi Timer Unit as the sched_clock. config CLKSRC_DBX500_PRCMU - bool "Clocksource PRCMU Timer" - depends on UX500_SOC_DB8500 - default y + bool "Clocksource PRCMU Timer" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS help Use the always on PRCMU Timer as clocksource @@ -116,13 +151,19 @@ config CLKSRC_EFM32 event device. config CLKSRC_LPC32XX - bool + bool "Clocksource for LPC32XX" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS && HAS_IOMEM select CLKSRC_MMIO select CLKSRC_OF + help + Support for the LPC32XX clocksource. config CLKSRC_PISTACHIO - bool + bool "Clocksource for Pistachio SoC" if COMPILE_TEST + depends on HAS_IOMEM select CLKSRC_OF + help + Enables the clocksource for the Pistachio SoC. config CLKSRC_TI_32K bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST @@ -199,13 +240,14 @@ config CLKSRC_METAG_GENERIC This option enables support for the Meta per-thread timers. config CLKSRC_EXYNOS_MCT - def_bool y if ARCH_EXYNOS - depends on !ARM64 + bool "Exynos multi core timer driver" if COMPILE_TEST + depends on ARM help Support for Multi Core Timer controller on Exynos SoCs. config CLKSRC_SAMSUNG_PWM - bool + bool "PWM timer drvier for Samsung S3C, S5P" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS help This is a new clocksource driver for the PWM timer found in Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver @@ -213,7 +255,9 @@ config CLKSRC_SAMSUNG_PWM needed only on systems that do not have the Exynos MCT available. config FSL_FTM_TIMER - bool + bool "Freescale FlexTimer Module driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO help Support for Freescale FlexTimer Module (FTM) timer. @@ -226,9 +270,12 @@ config SYS_SUPPORTS_SH_CMT bool config MTK_TIMER + bool "Mediatek timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS && HAS_IOMEM select CLKSRC_OF select CLKSRC_MMIO - bool + help + Support for Mediatek timer driver. config SYS_SUPPORTS_SH_MTU2 bool @@ -279,7 +326,12 @@ config EM_TIMER_STI such as EMEV2 from former NEC Electronics. config CLKSRC_QCOM - bool + bool "Qualcomm MSM timer" if COMPILE_TEST + depends on ARM + select CLKSRC_OF + help + This enables the clocksource and the per CPU clockevent driver for the + Qualcomm SoCs. config CLKSRC_VERSATILE bool "ARM Versatile (Express) reference platforms clock source" @@ -298,21 +350,40 @@ config CLKSRC_MIPS_GIC select CLKSRC_OF config CLKSRC_TANGO_XTAL - bool + bool "Clocksource for Tango SoC" if COMPILE_TEST + depends on ARM select CLKSRC_OF + select CLKSRC_MMIO + help + This enables the clocksource for Tango SoC config CLKSRC_PXA - def_bool y if ARCH_PXA || ARCH_SA1100 - select CLKSRC_OF if OF + bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO help This enables OST0 support available on PXA and SA-11x0 platforms. +config H8300_TMR8 + bool "Clockevent timer for the H8300 platform" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS && HAS_IOMEM + help + This enables the 8 bits timer for the H8300 platform. + config H8300_TMR16 - bool + bool "Clockevent timer for the H83069 platform" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS && HAS_IOMEM + help + This enables the 16 bits timer for the H8300 platform with the + H83069 cpu. config H8300_TPU - bool + bool "Clocksource for the H8300 platform" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS && HAS_IOMEM + help + This enables the clocksource for the H8300 platform with the + H8S2678 cpu. config CLKSRC_IMX_GPT bool "Clocksource using i.MX GPT" if COMPILE_TEST @@ -320,9 +391,9 @@ config CLKSRC_IMX_GPT select CLKSRC_MMIO config CLKSRC_ST_LPC - bool - depends on ARCH_STI + bool "Low power clocksource found in the LPC" if COMPILE_TEST select CLKSRC_OF if OF + depends on HAS_IOMEM help Enable this option to use the Low Power controller timer as clocksource. diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 56bd16e77ae3..dc2b8997f6e6 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -60,7 +60,7 @@ obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o -obj-$(CONFIG_H8300) += h8300_timer8.o +obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o obj-$(CONFIG_H8300_TPU) += h8300_tpu.o obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 6eab88985670..28037d0b8dcd 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -109,10 +109,8 @@ static void acpi_pm_check_blacklist(struct pci_dev *dev) /* the bug has been fixed in PIIX4M */ if (dev->revision < 3) { - printk(KERN_WARNING "* Found PM-Timer Bug on the chipset." - " Due to workarounds for a bug,\n" - "* this clock source is slow. Consider trying" - " other clock sources\n"); + pr_warn("* Found PM-Timer Bug on the chipset. Due to workarounds for a bug,\n" + "* this clock source is slow. Consider trying other clock sources\n"); acpi_pm_need_workaround(); } @@ -125,12 +123,9 @@ static void acpi_pm_check_graylist(struct pci_dev *dev) if (acpi_pm_good) return; - printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to" - " workarounds for a bug,\n" - "* this clock source is slow. If you are sure your timer" - " does not have\n" - "* this bug, please use \"acpi_pm_good\" to disable the" - " workaround\n"); + pr_warn("* The chipset may have PM-Timer Bug. Due to workarounds for a bug,\n" + "* this clock source is slow. If you are sure your timer does not have\n" + "* this bug, please use \"acpi_pm_good\" to disable the workaround\n"); acpi_pm_need_workaround(); } @@ -162,8 +157,7 @@ static int verify_pmtmr_rate(void) /* Check that the PMTMR delta is within 5% of what we expect */ if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 || delta > (PMTMR_EXPECTED_RATE * 21) / 20) { - printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% " - "of normal - aborting.\n", + pr_info("PM-Timer running at invalid rate: %lu%% of normal - aborting.\n", 100UL * delta / PMTMR_EXPECTED_RATE); return -1; } @@ -199,15 +193,14 @@ static int __init init_acpi_pm_clocksource(void) break; if ((value2 < value1) && ((value2) < 0xFFF)) break; - printk(KERN_INFO "PM-Timer had inconsistent results:" - " %#llx, %#llx - aborting.\n", - value1, value2); + pr_info("PM-Timer had inconsistent results: %#llx, %#llx - aborting.\n", + value1, value2); pmtmr_ioport = 0; return -EINVAL; } if (i == ACPI_PM_READ_CHECKS) { - printk(KERN_INFO "PM-Timer failed consistency check " - " (%#llx) - aborting.\n", value1); + pr_info("PM-Timer failed consistency check (%#llx) - aborting.\n", + value1); pmtmr_ioport = 0; return -ENODEV; } diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index a2cb6fae9295..d189d8cb69f7 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -99,17 +99,17 @@ static void gt_compare_set(unsigned long delta, int periodic) counter += delta; ctrl = GT_CONTROL_TIMER_ENABLE; - writel(ctrl, gt_base + GT_CONTROL); - writel(lower_32_bits(counter), gt_base + GT_COMP0); - writel(upper_32_bits(counter), gt_base + GT_COMP1); + writel_relaxed(ctrl, gt_base + GT_CONTROL); + writel_relaxed(lower_32_bits(counter), gt_base + GT_COMP0); + writel_relaxed(upper_32_bits(counter), gt_base + GT_COMP1); if (periodic) { - writel(delta, gt_base + GT_AUTO_INC); + writel_relaxed(delta, gt_base + GT_AUTO_INC); ctrl |= GT_CONTROL_AUTO_INC; } ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE; - writel(ctrl, gt_base + GT_CONTROL); + writel_relaxed(ctrl, gt_base + GT_CONTROL); } static int gt_clockevent_shutdown(struct clock_event_device *evt) @@ -195,12 +195,23 @@ static cycle_t gt_clocksource_read(struct clocksource *cs) return gt_counter_read(); } +static void gt_resume(struct clocksource *cs) +{ + unsigned long ctrl; + + ctrl = readl(gt_base + GT_CONTROL); + if (!(ctrl & GT_CONTROL_TIMER_ENABLE)) + /* re-enable timer on resume */ + writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL); +} + static struct clocksource gt_clocksource = { .name = "arm_global_timer", .rating = 300, .read = gt_clocksource_read, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .resume = gt_resume, }; #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index c76c75006ea6..63345260244d 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -49,20 +49,31 @@ clocksource_to_dw_apb_clocksource(struct clocksource *cs) return container_of(cs, struct dw_apb_clocksource, cs); } -static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs) +static inline u32 apbt_readl(struct dw_apb_timer *timer, unsigned long offs) { return readl(timer->base + offs); } -static void apbt_writel(struct dw_apb_timer *timer, unsigned long val, - unsigned long offs) +static inline void apbt_writel(struct dw_apb_timer *timer, u32 val, + unsigned long offs) { writel(val, timer->base + offs); } +static inline u32 apbt_readl_relaxed(struct dw_apb_timer *timer, unsigned long offs) +{ + return readl_relaxed(timer->base + offs); +} + +static inline void apbt_writel_relaxed(struct dw_apb_timer *timer, u32 val, + unsigned long offs) +{ + writel_relaxed(val, timer->base + offs); +} + static void apbt_disable_int(struct dw_apb_timer *timer) { - unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); + u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL); ctrl |= APBTMR_CONTROL_INT; apbt_writel(timer, ctrl, APBTMR_N_CONTROL); @@ -81,7 +92,7 @@ void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced) static void apbt_eoi(struct dw_apb_timer *timer) { - apbt_readl(timer, APBTMR_N_EOI); + apbt_readl_relaxed(timer, APBTMR_N_EOI); } static irqreturn_t dw_apb_clockevent_irq(int irq, void *data) @@ -103,7 +114,7 @@ static irqreturn_t dw_apb_clockevent_irq(int irq, void *data) static void apbt_enable_int(struct dw_apb_timer *timer) { - unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); + u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL); /* clear pending intr */ apbt_readl(timer, APBTMR_N_EOI); ctrl &= ~APBTMR_CONTROL_INT; @@ -113,7 +124,7 @@ static void apbt_enable_int(struct dw_apb_timer *timer) static int apbt_shutdown(struct clock_event_device *evt) { struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); - unsigned long ctrl; + u32 ctrl; pr_debug("%s CPU %d state=shutdown\n", __func__, cpumask_first(evt->cpumask)); @@ -127,7 +138,7 @@ static int apbt_shutdown(struct clock_event_device *evt) static int apbt_set_oneshot(struct clock_event_device *evt) { struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); - unsigned long ctrl; + u32 ctrl; pr_debug("%s CPU %d state=oneshot\n", __func__, cpumask_first(evt->cpumask)); @@ -160,7 +171,7 @@ static int apbt_set_periodic(struct clock_event_device *evt) { struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); - unsigned long ctrl; + u32 ctrl; pr_debug("%s CPU %d state=periodic\n", __func__, cpumask_first(evt->cpumask)); @@ -196,17 +207,17 @@ static int apbt_resume(struct clock_event_device *evt) static int apbt_next_event(unsigned long delta, struct clock_event_device *evt) { - unsigned long ctrl; + u32 ctrl; struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); /* Disable timer */ - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); + ctrl = apbt_readl_relaxed(&dw_ced->timer, APBTMR_N_CONTROL); ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); /* write new count */ - apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT); + apbt_writel_relaxed(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT); ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); return 0; } @@ -323,7 +334,7 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs) * start count down from 0xffff_ffff. this is done by toggling the * enable bit then load initial load count to ~0. */ - unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL); + u32 ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL); ctrl &= ~APBTMR_CONTROL_ENABLE; apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); @@ -338,11 +349,12 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs) static cycle_t __apbt_read_clocksource(struct clocksource *cs) { - unsigned long current_count; + u32 current_count; struct dw_apb_clocksource *dw_cs = clocksource_to_dw_apb_clocksource(cs); - current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); + current_count = apbt_readl_relaxed(&dw_cs->timer, + APBTMR_N_CURRENT_VALUE); return (cycle_t)~current_count; } diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index a19a3f619cc7..860843cef572 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/delay.h> #include <linux/dw_apb_timer.h> #include <linux/of.h> #include <linux/of_address.h> @@ -130,6 +131,17 @@ static void __init init_sched_clock(void) sched_clock_register(read_sched_clock, 32, sched_rate); } +#ifdef CONFIG_ARM +static unsigned long dw_apb_delay_timer_read(void) +{ + return ~readl_relaxed(sched_io_base); +} + +static struct delay_timer dw_apb_delay_timer = { + .read_current_timer = dw_apb_delay_timer_read, +}; +#endif + static int num_called; static void __init dw_apb_timer_init(struct device_node *timer) { @@ -142,6 +154,10 @@ static void __init dw_apb_timer_init(struct device_node *timer) pr_debug("%s: found clocksource timer\n", __func__); add_clocksource(timer); init_sched_clock(); +#ifdef CONFIG_ARM + dw_apb_delay_timer.freq = sched_rate; + register_current_timer_delay(&dw_apb_delay_timer); +#endif break; default: break; diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c index 0e076c6fc006..75c44079b345 100644 --- a/drivers/clocksource/h8300_timer16.c +++ b/drivers/clocksource/h8300_timer16.c @@ -4,85 +4,56 @@ * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp> */ -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <linux/platform_device.h> #include <linux/clocksource.h> -#include <linux/module.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/of.h> - -#include <asm/segment.h> -#include <asm/irq.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #define TSTR 0 -#define TSNC 1 -#define TMDR 2 -#define TOLR 3 -#define TISRA 4 -#define TISRB 5 #define TISRC 6 #define TCR 0 -#define TIOR 1 #define TCNT 2 -#define GRA 4 -#define GRB 6 - -#define FLAG_REPROGRAM (1 << 0) -#define FLAG_SKIPEVENT (1 << 1) -#define FLAG_IRQCONTEXT (1 << 2) -#define FLAG_STARTED (1 << 3) -#define ONESHOT 0 -#define PERIODIC 1 - -#define RELATIVE 0 -#define ABSOLUTE 1 +#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a)) +#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a)) struct timer16_priv { - struct platform_device *pdev; struct clocksource cs; - struct irqaction irqaction; unsigned long total_cycles; - unsigned long mapbase; - unsigned long mapcommon; - unsigned long flags; - unsigned short gra; + void __iomem *mapbase; + void __iomem *mapcommon; unsigned short cs_enabled; unsigned char enb; - unsigned char imfa; - unsigned char imiea; unsigned char ovf; - raw_spinlock_t lock; - struct clk *clk; + unsigned char ovie; }; static unsigned long timer16_get_counter(struct timer16_priv *p) { - unsigned long v1, v2, v3; - int o1, o2; + unsigned short v1, v2, v3; + unsigned char o1, o2; - o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf; + o1 = ioread8(p->mapcommon + TISRC) & p->ovf; /* Make sure the timer value is stable. Stolen from acpi_pm.c */ do { o2 = o1; - v1 = ctrl_inw(p->mapbase + TCNT); - v2 = ctrl_inw(p->mapbase + TCNT); - v3 = ctrl_inw(p->mapbase + TCNT); - o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf; + v1 = ioread16be(p->mapbase + TCNT); + v2 = ioread16be(p->mapbase + TCNT); + v3 = ioread16be(p->mapbase + TCNT); + o1 = ioread8(p->mapcommon + TISRC) & p->ovf; } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); - v2 |= 0x10000; - return v2; + if (likely(!o1)) + return v2; + else + return v2 + 0x10000; } @@ -90,8 +61,7 @@ static irqreturn_t timer16_interrupt(int irq, void *dev_id) { struct timer16_priv *p = (struct timer16_priv *)dev_id; - ctrl_outb(ctrl_inb(p->mapcommon + TISRA) & ~p->imfa, - p->mapcommon + TISRA); + bclr(p->ovf, p->mapcommon + TISRC); p->total_cycles += 0x10000; return IRQ_HANDLED; @@ -105,13 +75,10 @@ static inline struct timer16_priv *cs_to_priv(struct clocksource *cs) static cycle_t timer16_clocksource_read(struct clocksource *cs) { struct timer16_priv *p = cs_to_priv(cs); - unsigned long flags, raw; - unsigned long value; + unsigned long raw, value; - raw_spin_lock_irqsave(&p->lock, flags); value = p->total_cycles; raw = timer16_get_counter(p); - raw_spin_unlock_irqrestore(&p->lock, flags); return value + raw; } @@ -123,10 +90,10 @@ static int timer16_enable(struct clocksource *cs) WARN_ON(p->cs_enabled); p->total_cycles = 0; - ctrl_outw(0x0000, p->mapbase + TCNT); - ctrl_outb(0x83, p->mapbase + TCR); - ctrl_outb(ctrl_inb(p->mapcommon + TSTR) | p->enb, - p->mapcommon + TSTR); + iowrite16be(0x0000, p->mapbase + TCNT); + iowrite8(0x83, p->mapbase + TCR); + bset(p->ovie, p->mapcommon + TISRC); + bset(p->enb, p->mapcommon + TSTR); p->cs_enabled = true; return 0; @@ -138,116 +105,83 @@ static void timer16_disable(struct clocksource *cs) WARN_ON(!p->cs_enabled); - ctrl_outb(ctrl_inb(p->mapcommon + TSTR) & ~p->enb, - p->mapcommon + TSTR); + bclr(p->ovie, p->mapcommon + TISRC); + bclr(p->enb, p->mapcommon + TSTR); p->cs_enabled = false; } +static struct timer16_priv timer16_priv = { + .cs = { + .name = "h8300_16timer", + .rating = 200, + .read = timer16_clocksource_read, + .enable = timer16_enable, + .disable = timer16_disable, + .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }, +}; + #define REG_CH 0 #define REG_COMM 1 -static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev) +static void __init h8300_16timer_init(struct device_node *node) { - struct resource *res[2]; + void __iomem *base[2]; int ret, irq; unsigned int ch; + struct clk *clk; - p->pdev = pdev; - - res[REG_CH] = platform_get_resource(p->pdev, - IORESOURCE_MEM, REG_CH); - res[REG_COMM] = platform_get_resource(p->pdev, - IORESOURCE_MEM, REG_COMM); - if (!res[REG_CH] || !res[REG_COMM]) { - dev_err(&p->pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; - } - irq = platform_get_irq(p->pdev, 0); - if (irq < 0) { - dev_err(&p->pdev->dev, "failed to get irq\n"); - return irq; + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("failed to get clock for clocksource\n"); + return; } - p->clk = clk_get(&p->pdev->dev, "fck"); - if (IS_ERR(p->clk)) { - dev_err(&p->pdev->dev, "can't get clk\n"); - return PTR_ERR(p->clk); + base[REG_CH] = of_iomap(node, 0); + if (!base[REG_CH]) { + pr_err("failed to map registers for clocksource\n"); + goto free_clk; } - of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch); - - p->pdev = pdev; - p->mapbase = res[REG_CH]->start; - p->mapcommon = res[REG_COMM]->start; - p->enb = 1 << ch; - p->imfa = 1 << ch; - p->imiea = 1 << (4 + ch); - p->cs.name = pdev->name; - p->cs.rating = 200; - p->cs.read = timer16_clocksource_read; - p->cs.enable = timer16_enable; - p->cs.disable = timer16_disable; - p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); - p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; - ret = request_irq(irq, timer16_interrupt, - IRQF_TIMER, pdev->name, p); - if (ret < 0) { - dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); - return ret; + base[REG_COMM] = of_iomap(node, 1); + if (!base[REG_COMM]) { + pr_err("failed to map registers for clocksource\n"); + goto unmap_ch; } - clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8); - - return 0; -} - -static int timer16_probe(struct platform_device *pdev) -{ - struct timer16_priv *p = platform_get_drvdata(pdev); - - if (p) { - dev_info(&pdev->dev, "kept as earlytimer\n"); - return 0; + irq = irq_of_parse_and_map(node, 0); + if (!irq) { + pr_err("failed to get irq for clockevent\n"); + goto unmap_comm; } - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; + of_property_read_u32(node, "renesas,channel", &ch); - return timer16_setup(p, pdev); -} - -static int timer16_remove(struct platform_device *pdev) -{ - return -EBUSY; -} + timer16_priv.mapbase = base[REG_CH]; + timer16_priv.mapcommon = base[REG_COMM]; + timer16_priv.enb = ch; + timer16_priv.ovf = ch; + timer16_priv.ovie = 4 + ch; -static const struct of_device_id timer16_of_table[] = { - { .compatible = "renesas,16bit-timer" }, - { } -}; -static struct platform_driver timer16_driver = { - .probe = timer16_probe, - .remove = timer16_remove, - .driver = { - .name = "h8300h-16timer", - .of_match_table = of_match_ptr(timer16_of_table), + ret = request_irq(irq, timer16_interrupt, + IRQF_TIMER, timer16_priv.cs.name, &timer16_priv); + if (ret < 0) { + pr_err("failed to request irq %d of clocksource\n", irq); + goto unmap_comm; } -}; -static int __init timer16_init(void) -{ - return platform_driver_register(&timer16_driver); -} + clocksource_register_hz(&timer16_priv.cs, + clk_get_rate(clk) / 8); + return; -static void __exit timer16_exit(void) -{ - platform_driver_unregister(&timer16_driver); +unmap_comm: + iounmap(base[REG_COMM]); +unmap_ch: + iounmap(base[REG_CH]); +free_clk: + clk_put(clk); } -subsys_initcall(timer16_init); -module_exit(timer16_exit); -MODULE_AUTHOR("Yoshinori Sato"); -MODULE_DESCRIPTION("H8/300H 16bit Timer Driver"); -MODULE_LICENSE("GPL v2"); +CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init); diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index 44375d8b9bc4..c151941e1956 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -8,19 +8,15 @@ */ #include <linux/errno.h> -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/slab.h> #include <linux/clockchips.h> -#include <linux/module.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/of.h> - -#include <asm/irq.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #define _8TCR 0 #define _8TCSR 2 @@ -28,126 +24,74 @@ #define TCORB 6 #define _8TCNT 8 -#define FLAG_REPROGRAM (1 << 0) -#define FLAG_SKIPEVENT (1 << 1) -#define FLAG_IRQCONTEXT (1 << 2) +#define CMIEA 6 +#define CMFA 6 + #define FLAG_STARTED (1 << 3) -#define ONESHOT 0 -#define PERIODIC 1 +#define SCALE 64 -#define RELATIVE 0 -#define ABSOLUTE 1 +#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a)) +#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a)) struct timer8_priv { - struct platform_device *pdev; struct clock_event_device ced; - struct irqaction irqaction; - unsigned long mapbase; - raw_spinlock_t lock; + void __iomem *mapbase; unsigned long flags; unsigned int rate; - unsigned int tcora; - struct clk *pclk; }; -static unsigned long timer8_get_counter(struct timer8_priv *p) -{ - unsigned long v1, v2, v3; - int o1, o2; - - o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20; - - /* Make sure the timer value is stable. Stolen from acpi_pm.c */ - do { - o2 = o1; - v1 = ctrl_inw(p->mapbase + _8TCNT); - v2 = ctrl_inw(p->mapbase + _8TCNT); - v3 = ctrl_inw(p->mapbase + _8TCNT); - o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20; - } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) - || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); - - v2 |= o1 << 10; - return v2; -} - static irqreturn_t timer8_interrupt(int irq, void *dev_id) { struct timer8_priv *p = dev_id; - ctrl_outb(ctrl_inb(p->mapbase + _8TCSR) & ~0x40, - p->mapbase + _8TCSR); - p->flags |= FLAG_IRQCONTEXT; - ctrl_outw(p->tcora, p->mapbase + TCORA); - if (!(p->flags & FLAG_SKIPEVENT)) { - if (clockevent_state_oneshot(&p->ced)) - ctrl_outw(0x0000, p->mapbase + _8TCR); - p->ced.event_handler(&p->ced); - } - p->flags &= ~(FLAG_SKIPEVENT | FLAG_IRQCONTEXT); + if (clockevent_state_oneshot(&p->ced)) + iowrite16be(0x0000, p->mapbase + _8TCR); + + p->ced.event_handler(&p->ced); + + bclr(CMFA, p->mapbase + _8TCSR); return IRQ_HANDLED; } static void timer8_set_next(struct timer8_priv *p, unsigned long delta) { - unsigned long flags; - unsigned long now; - - raw_spin_lock_irqsave(&p->lock, flags); if (delta >= 0x10000) - dev_warn(&p->pdev->dev, "delta out of range\n"); - now = timer8_get_counter(p); - p->tcora = delta; - ctrl_outb(ctrl_inb(p->mapbase + _8TCR) | 0x40, p->mapbase + _8TCR); - if (delta > now) - ctrl_outw(delta, p->mapbase + TCORA); - else - ctrl_outw(now + 1, p->mapbase + TCORA); - - raw_spin_unlock_irqrestore(&p->lock, flags); + pr_warn("delta out of range\n"); + bclr(CMIEA, p->mapbase + _8TCR); + iowrite16be(delta, p->mapbase + TCORA); + iowrite16be(0x0000, p->mapbase + _8TCNT); + bclr(CMFA, p->mapbase + _8TCSR); + bset(CMIEA, p->mapbase + _8TCR); } static int timer8_enable(struct timer8_priv *p) { - p->rate = clk_get_rate(p->pclk) / 64; - ctrl_outw(0xffff, p->mapbase + TCORA); - ctrl_outw(0x0000, p->mapbase + _8TCNT); - ctrl_outw(0x0c02, p->mapbase + _8TCR); + iowrite16be(0xffff, p->mapbase + TCORA); + iowrite16be(0x0000, p->mapbase + _8TCNT); + iowrite16be(0x0c02, p->mapbase + _8TCR); return 0; } static int timer8_start(struct timer8_priv *p) { - int ret = 0; - unsigned long flags; - - raw_spin_lock_irqsave(&p->lock, flags); - - if (!(p->flags & FLAG_STARTED)) - ret = timer8_enable(p); + int ret; - if (ret) - goto out; - p->flags |= FLAG_STARTED; + if ((p->flags & FLAG_STARTED)) + return 0; - out: - raw_spin_unlock_irqrestore(&p->lock, flags); + ret = timer8_enable(p); + if (!ret) + p->flags |= FLAG_STARTED; return ret; } static void timer8_stop(struct timer8_priv *p) { - unsigned long flags; - - raw_spin_lock_irqsave(&p->lock, flags); - - ctrl_outw(0x0000, p->mapbase + _8TCR); - - raw_spin_unlock_irqrestore(&p->lock, flags); + iowrite16be(0x0000, p->mapbase + _8TCR); } static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced) @@ -155,7 +99,7 @@ static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced) return container_of(ced, struct timer8_priv, ced); } -static void timer8_clock_event_start(struct timer8_priv *p, int periodic) +static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta) { struct clock_event_device *ced = &p->ced; @@ -166,7 +110,7 @@ static void timer8_clock_event_start(struct timer8_priv *p, int periodic) ced->max_delta_ns = clockevent_delta2ns(0xffff, ced); ced->min_delta_ns = clockevent_delta2ns(0x0001, ced); - timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000); + timer8_set_next(p, delta); } static int timer8_clock_event_shutdown(struct clock_event_device *ced) @@ -179,9 +123,9 @@ static int timer8_clock_event_periodic(struct clock_event_device *ced) { struct timer8_priv *p = ced_to_priv(ced); - dev_info(&p->pdev->dev, "used for periodic clock events\n"); + pr_info("%s: used for periodic clock events\n", ced->name); timer8_stop(p); - timer8_clock_event_start(p, PERIODIC); + timer8_clock_event_start(p, (p->rate + HZ/2) / HZ); return 0; } @@ -190,9 +134,9 @@ static int timer8_clock_event_oneshot(struct clock_event_device *ced) { struct timer8_priv *p = ced_to_priv(ced); - dev_info(&p->pdev->dev, "used for oneshot clock events\n"); + pr_info("%s: used for oneshot clock events\n", ced->name); timer8_stop(p); - timer8_clock_event_start(p, ONESHOT); + timer8_clock_event_start(p, 0x10000); return 0; } @@ -208,110 +152,64 @@ static int timer8_clock_event_next(unsigned long delta, return 0; } -static int timer8_setup(struct timer8_priv *p, - struct platform_device *pdev) +static struct timer8_priv timer8_priv = { + .ced = { + .name = "h8300_8timer", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = timer8_clock_event_next, + .set_state_shutdown = timer8_clock_event_shutdown, + .set_state_periodic = timer8_clock_event_periodic, + .set_state_oneshot = timer8_clock_event_oneshot, + }, +}; + +static void __init h8300_8timer_init(struct device_node *node) { - struct resource *res; + void __iomem *base; int irq; - int ret; + struct clk *clk; - p->pdev = pdev; - - res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&p->pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("failed to get clock for clockevent\n"); + return; } - irq = platform_get_irq(p->pdev, 0); - if (irq < 0) { - dev_err(&p->pdev->dev, "failed to get irq\n"); - return -ENXIO; + base = of_iomap(node, 0); + if (!base) { + pr_err("failed to map registers for clockevent\n"); + goto free_clk; } - p->mapbase = res->start; - - p->irqaction.name = dev_name(&p->pdev->dev); - p->irqaction.handler = timer8_interrupt; - p->irqaction.dev_id = p; - p->irqaction.flags = IRQF_TIMER; - - p->pclk = clk_get(&p->pdev->dev, "fck"); - if (IS_ERR(p->pclk)) { - dev_err(&p->pdev->dev, "can't get clk\n"); - return PTR_ERR(p->pclk); + irq = irq_of_parse_and_map(node, 0); + if (!irq) { + pr_err("failed to get irq for clockevent\n"); + goto unmap_reg; } - p->ced.name = pdev->name; - p->ced.features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT; - p->ced.rating = 200; - p->ced.cpumask = cpumask_of(0); - p->ced.set_next_event = timer8_clock_event_next; - p->ced.set_state_shutdown = timer8_clock_event_shutdown; - p->ced.set_state_periodic = timer8_clock_event_periodic; - p->ced.set_state_oneshot = timer8_clock_event_oneshot; - - ret = setup_irq(irq, &p->irqaction); - if (ret < 0) { - dev_err(&p->pdev->dev, - "failed to request irq %d\n", irq); - return ret; - } - clockevents_register_device(&p->ced); - platform_set_drvdata(pdev, p); + timer8_priv.mapbase = base; - return 0; -} - -static int timer8_probe(struct platform_device *pdev) -{ - struct timer8_priv *p = platform_get_drvdata(pdev); - - if (p) { - dev_info(&pdev->dev, "kept as earlytimer\n"); - return 0; + timer8_priv.rate = clk_get_rate(clk) / SCALE; + if (!timer8_priv.rate) { + pr_err("Failed to get rate for the clocksource\n"); + goto unmap_reg; } - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - return timer8_setup(p, pdev); -} - -static int timer8_remove(struct platform_device *pdev) -{ - return -EBUSY; -} - -static const struct of_device_id timer8_of_table[] __maybe_unused = { - { .compatible = "renesas,8bit-timer" }, - { } -}; - -MODULE_DEVICE_TABLE(of, timer8_of_table); -static struct platform_driver timer8_driver = { - .probe = timer8_probe, - .remove = timer8_remove, - .driver = { - .name = "h8300-8timer", - .of_match_table = of_match_ptr(timer8_of_table), + if (request_irq(irq, timer8_interrupt, IRQF_TIMER, + timer8_priv.ced.name, &timer8_priv) < 0) { + pr_err("failed to request irq %d for clockevent\n", irq); + goto unmap_reg; } -}; -static int __init timer8_init(void) -{ - return platform_driver_register(&timer8_driver); -} + clockevents_config_and_register(&timer8_priv.ced, + timer8_priv.rate, 1, 0x0000ffff); -static void __exit timer8_exit(void) -{ - platform_driver_unregister(&timer8_driver); + return; +unmap_reg: + iounmap(base); +free_clk: + clk_put(clk); } -subsys_initcall(timer8_init); -module_exit(timer8_exit); -MODULE_AUTHOR("Yoshinori Sato"); -MODULE_DESCRIPTION("H8/300 8bit Timer Driver"); -MODULE_LICENSE("GPL v2"); +CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c index 5487410bfabb..d4c1a287c262 100644 --- a/drivers/clocksource/h8300_tpu.c +++ b/drivers/clocksource/h8300_tpu.c @@ -1,42 +1,30 @@ /* - * H8/300 TPU Driver + * H8S TPU Driver * * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp> * */ #include <linux/errno.h> -#include <linux/sched.h> #include <linux/kernel.h> -#include <linux/interrupt.h> #include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/slab.h> #include <linux/clocksource.h> -#include <linux/module.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> -#include <asm/irq.h> +#define TCR 0x0 +#define TSR 0x5 +#define TCNT 0x6 -#define TCR 0 -#define TMDR 1 -#define TIOR 2 -#define TER 4 -#define TSR 5 -#define TCNT 6 -#define TGRA 8 -#define TGRB 10 -#define TGRC 12 -#define TGRD 14 +#define TCFV 0x10 struct tpu_priv { - struct platform_device *pdev; struct clocksource cs; - struct clk *clk; - unsigned long mapbase1; - unsigned long mapbase2; + void __iomem *mapbase1; + void __iomem *mapbase2; raw_spinlock_t lock; unsigned int cs_enabled; }; @@ -45,8 +33,8 @@ static inline unsigned long read_tcnt32(struct tpu_priv *p) { unsigned long tcnt; - tcnt = ctrl_inw(p->mapbase1 + TCNT) << 16; - tcnt |= ctrl_inw(p->mapbase2 + TCNT); + tcnt = ioread16be(p->mapbase1 + TCNT) << 16; + tcnt |= ioread16be(p->mapbase2 + TCNT); return tcnt; } @@ -55,7 +43,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val) unsigned long v1, v2, v3; int o1, o2; - o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10; + o1 = ioread8(p->mapbase1 + TSR) & TCFV; /* Make sure the timer value is stable. Stolen from acpi_pm.c */ do { @@ -63,7 +51,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val) v1 = read_tcnt32(p); v2 = read_tcnt32(p); v3 = read_tcnt32(p); - o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10; + o1 = ioread8(p->mapbase1 + TSR) & TCFV; } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); @@ -96,10 +84,10 @@ static int tpu_clocksource_enable(struct clocksource *cs) WARN_ON(p->cs_enabled); - ctrl_outw(0, p->mapbase1 + TCNT); - ctrl_outw(0, p->mapbase2 + TCNT); - ctrl_outb(0x0f, p->mapbase1 + TCR); - ctrl_outb(0x03, p->mapbase2 + TCR); + iowrite16be(0, p->mapbase1 + TCNT); + iowrite16be(0, p->mapbase2 + TCNT); + iowrite8(0x0f, p->mapbase1 + TCR); + iowrite8(0x03, p->mapbase2 + TCR); p->cs_enabled = true; return 0; @@ -111,96 +99,59 @@ static void tpu_clocksource_disable(struct clocksource *cs) WARN_ON(!p->cs_enabled); - ctrl_outb(0, p->mapbase1 + TCR); - ctrl_outb(0, p->mapbase2 + TCR); + iowrite8(0, p->mapbase1 + TCR); + iowrite8(0, p->mapbase2 + TCR); p->cs_enabled = false; } +static struct tpu_priv tpu_priv = { + .cs = { + .name = "H8S_TPU", + .rating = 200, + .read = tpu_clocksource_read, + .enable = tpu_clocksource_enable, + .disable = tpu_clocksource_disable, + .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }, +}; + #define CH_L 0 #define CH_H 1 -static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev) +static void __init h8300_tpu_init(struct device_node *node) { - struct resource *res[2]; - - p->pdev = pdev; + void __iomem *base[2]; + struct clk *clk; - res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L); - res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H); - if (!res[CH_L] || !res[CH_H]) { - dev_err(&p->pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("failed to get clock for clocksource\n"); + return; } - p->clk = clk_get(&p->pdev->dev, "fck"); - if (IS_ERR(p->clk)) { - dev_err(&p->pdev->dev, "can't get clk\n"); - return PTR_ERR(p->clk); + base[CH_L] = of_iomap(node, CH_L); + if (!base[CH_L]) { + pr_err("failed to map registers for clocksource\n"); + goto free_clk; } - - p->mapbase1 = res[CH_L]->start; - p->mapbase2 = res[CH_H]->start; - - p->cs.name = pdev->name; - p->cs.rating = 200; - p->cs.read = tpu_clocksource_read; - p->cs.enable = tpu_clocksource_enable; - p->cs.disable = tpu_clocksource_disable; - p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); - p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; - clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 64); - platform_set_drvdata(pdev, p); - - return 0; -} - -static int tpu_probe(struct platform_device *pdev) -{ - struct tpu_priv *p = platform_get_drvdata(pdev); - - if (p) { - dev_info(&pdev->dev, "kept as earlytimer\n"); - return 0; + base[CH_H] = of_iomap(node, CH_H); + if (!base[CH_H]) { + pr_err("failed to map registers for clocksource\n"); + goto unmap_L; } - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; + tpu_priv.mapbase1 = base[CH_L]; + tpu_priv.mapbase2 = base[CH_H]; - return tpu_setup(p, pdev); -} - -static int tpu_remove(struct platform_device *pdev) -{ - return -EBUSY; -} - -static const struct of_device_id tpu_of_table[] = { - { .compatible = "renesas,tpu" }, - { } -}; + clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64); -static struct platform_driver tpu_driver = { - .probe = tpu_probe, - .remove = tpu_remove, - .driver = { - .name = "h8s-tpu", - .of_match_table = of_match_ptr(tpu_of_table), - } -}; - -static int __init tpu_init(void) -{ - return platform_driver_register(&tpu_driver); -} + return; -static void __exit tpu_exit(void) -{ - platform_driver_unregister(&tpu_driver); +unmap_L: + iounmap(base[CH_H]); +free_clk: + clk_put(clk); } -subsys_initcall(tpu_init); -module_exit(tpu_exit); -MODULE_AUTHOR("Yoshinori Sato"); -MODULE_DESCRIPTION("H8S Timer Pulse Unit Driver"); -MODULE_LICENSE("GPL v2"); +CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c index 1593ade2a815..c4f7d7a9b689 100644 --- a/drivers/clocksource/mmio.c +++ b/drivers/clocksource/mmio.c @@ -55,7 +55,7 @@ int __init clocksource_mmio_init(void __iomem *base, const char *name, { struct clocksource_mmio *cs; - if (bits > 32 || bits < 16) + if (bits > 64 || bits < 16) return -EINVAL; cs = kzalloc(sizeof(struct clocksource_mmio), GFP_KERNEL); diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index fbfc74685e6a..d67bc356488f 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -16,6 +16,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/clk.h> #include <linux/clockchips.h> #include <linux/interrupt.h> @@ -187,10 +189,8 @@ static void __init mtk_timer_init(struct device_node *node) struct clk *clk; evt = kzalloc(sizeof(*evt), GFP_KERNEL); - if (!evt) { - pr_warn("Can't allocate mtk clock event driver struct"); + if (!evt) return; - } evt->dev.name = "mtk_tick"; evt->dev.rating = 300; @@ -204,31 +204,31 @@ static void __init mtk_timer_init(struct device_node *node) evt->gpt_base = of_io_request_and_map(node, 0, "mtk-timer"); if (IS_ERR(evt->gpt_base)) { - pr_warn("Can't get resource\n"); - return; + pr_err("Can't get resource\n"); + goto err_kzalloc; } evt->dev.irq = irq_of_parse_and_map(node, 0); if (evt->dev.irq <= 0) { - pr_warn("Can't parse IRQ"); + pr_err("Can't parse IRQ\n"); goto err_mem; } clk = of_clk_get(node, 0); if (IS_ERR(clk)) { - pr_warn("Can't get timer clock"); + pr_err("Can't get timer clock\n"); goto err_irq; } if (clk_prepare_enable(clk)) { - pr_warn("Can't prepare clock"); + pr_err("Can't prepare clock\n"); goto err_clk_put; } rate = clk_get_rate(clk); if (request_irq(evt->dev.irq, mtk_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) { - pr_warn("failed to setup irq %d\n", evt->dev.irq); + pr_err("failed to setup irq %d\n", evt->dev.irq); goto err_clk_disable; } @@ -260,5 +260,7 @@ err_mem: iounmap(evt->gpt_base); of_address_to_resource(node, 0, &res); release_mem_region(res.start, resource_size(&res)); +err_kzalloc: + kfree(evt); } CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index d3c1742ded1a..8c77a529d0d4 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -17,16 +17,16 @@ #define TIMER_NAME "rk_timer" -#define TIMER_LOAD_COUNT0 0x00 -#define TIMER_LOAD_COUNT1 0x04 -#define TIMER_CONTROL_REG 0x10 -#define TIMER_INT_STATUS 0x18 +#define TIMER_LOAD_COUNT0 0x00 +#define TIMER_LOAD_COUNT1 0x04 +#define TIMER_CONTROL_REG 0x10 +#define TIMER_INT_STATUS 0x18 -#define TIMER_DISABLE 0x0 -#define TIMER_ENABLE 0x1 -#define TIMER_MODE_FREE_RUNNING (0 << 1) -#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1) -#define TIMER_INT_UNMASK (1 << 2) +#define TIMER_DISABLE 0x0 +#define TIMER_ENABLE 0x1 +#define TIMER_MODE_FREE_RUNNING (0 << 1) +#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1) +#define TIMER_INT_UNMASK (1 << 2) struct bc_timer { struct clock_event_device ce; @@ -49,14 +49,12 @@ static inline void __iomem *rk_base(struct clock_event_device *ce) static inline void rk_timer_disable(struct clock_event_device *ce) { writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG); - dsb(); } static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags) { writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags, rk_base(ce) + TIMER_CONTROL_REG); - dsb(); } static void rk_timer_update_counter(unsigned long cycles, @@ -64,13 +62,11 @@ static void rk_timer_update_counter(unsigned long cycles, { writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0); writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1); - dsb(); } static void rk_timer_interrupt_clear(struct clock_event_device *ce) { writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS); - dsb(); } static inline int rk_timer_set_next_event(unsigned long cycles, @@ -173,4 +169,5 @@ static void __init rk_timer_init(struct device_node *np) clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX); } + CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init); diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c index d297b30d2bc0..2bcecafdeaea 100644 --- a/drivers/clocksource/tango_xtal.c +++ b/drivers/clocksource/tango_xtal.c @@ -19,19 +19,6 @@ static u64 notrace read_sched_clock(void) return read_xtal_counter(); } -static cycle_t read_clocksource(struct clocksource *cs) -{ - return read_xtal_counter(); -} - -static struct clocksource tango_xtal = { - .name = "tango-xtal", - .rating = 350, - .read = read_clocksource, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - static void __init tango_clocksource_init(struct device_node *np) { struct clk *clk; @@ -53,8 +40,9 @@ static void __init tango_clocksource_init(struct device_node *np) delay_timer.freq = xtal_freq; delay_timer.read_current_timer = read_xtal_counter; - ret = clocksource_register_hz(&tango_xtal, xtal_freq); - if (ret != 0) { + ret = clocksource_mmio_init(xtal_in_cnt, "tango-xtal", xtal_freq, 350, + 32, clocksource_mmio_readl_up); + if (!ret) { pr_err("%s: registration failed\n", np->full_name); return; } diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 6ebda1177e79..38333aba3055 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -96,7 +96,8 @@ static struct clock_event_device tegra_clockevent = { .name = "timer0", .rating = 300, .features = CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_PERIODIC, + CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_DYNIRQ, .set_next_event = tegra_timer_set_next_event, .set_state_shutdown = tegra_timer_shutdown, .set_state_periodic = tegra_timer_set_periodic, diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c index a1c06a2bc77c..1316876b487a 100644 --- a/drivers/clocksource/time-lpc32xx.c +++ b/drivers/clocksource/time-lpc32xx.c @@ -125,7 +125,7 @@ static int __init lpc32xx_clocksource_init(struct device_node *np) clk = of_clk_get_by_name(np, "timerclk"); if (IS_ERR(clk)) { - pr_err("clock get failed (%lu)\n", PTR_ERR(clk)); + pr_err("clock get failed (%ld)\n", PTR_ERR(clk)); return PTR_ERR(clk); } @@ -184,7 +184,7 @@ static int __init lpc32xx_clockevent_init(struct device_node *np) clk = of_clk_get_by_name(np, "timerclk"); if (IS_ERR(clk)) { - pr_err("clock get failed (%lu)\n", PTR_ERR(clk)); + pr_err("clock get failed (%ld)\n", PTR_ERR(clk)); return PTR_ERR(clk); } diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c index bba679900054..3269d9ef7a18 100644 --- a/drivers/clocksource/time-pistachio.c +++ b/drivers/clocksource/time-pistachio.c @@ -84,7 +84,7 @@ pistachio_clocksource_read_cycles(struct clocksource *cs) counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0); raw_spin_unlock_irqrestore(&pcs->lock, flags); - return ~(cycle_t)counter; + return (cycle_t)~counter; } static u64 notrace pistachio_read_sched_clock(void) diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index bca9573e036a..24c83f9efd87 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -152,13 +152,6 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static cycle_t sun5i_clksrc_read(struct clocksource *clksrc) -{ - struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc); - - return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1)); -} - static int sun5i_rate_cb_clksrc(struct notifier_block *nb, unsigned long event, void *data) { @@ -217,13 +210,8 @@ static int __init sun5i_setup_clocksource(struct device_node *node, writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, base + TIMER_CTL_REG(1)); - cs->clksrc.name = node->name; - cs->clksrc.rating = 340; - cs->clksrc.read = sun5i_clksrc_read; - cs->clksrc.mask = CLOCKSOURCE_MASK(32); - cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; - - ret = clocksource_register_hz(&cs->clksrc, rate); + ret = clocksource_mmio_init(base + TIMER_CNTVAL_LO_REG(1), node->name, + rate, 340, 32, clocksource_mmio_readl_down); if (ret) { pr_err("Couldn't register clock source.\n"); goto err_remove_notifier; diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index a92e94b40b5b..ddb409274f45 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -30,7 +30,6 @@ #include <linux/clocksource.h> #include <linux/clockchips.h> #include <linux/delay.h> -#include <asm/mach/time.h> #include <linux/of.h> #include <linux/of_address.h> @@ -50,6 +49,8 @@ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) +#define MIN_OSCR_DELTA 16 + static void __iomem *regbase; static cycle_t vt8500_timer_read(struct clocksource *cs) @@ -80,7 +81,7 @@ static int vt8500_timer_set_next_event(unsigned long cycles, cpu_relax(); writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL); - if ((signed)(alarm - clocksource.read(&clocksource)) <= 16) + if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA) return -ETIME; writel(1, regbase + TIMER_IER_VAL); @@ -151,7 +152,7 @@ static void __init vt8500_timer_init(struct device_node *np) pr_err("%s: setup_irq failed for %s\n", __func__, clockevent.name); clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ, - 4, 0xf0000000); + MIN_OSCR_DELTA * 2, 0xf0000000); } CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); |