Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clocksource: clps711x: Add CLPS711X clocksource driver

This adds the clocksource driver for Cirrus Logic CLPS711X series SoCs.
Designed primarily for migration CLPS711X subarch for multiplatform & DT,
for this as the "OF" and "non-OF" calls implemented.

Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

authored by

Alexander Shiyan and committed by
Daniel Lezcano
f0b7fabe 38941522

+132
+1
drivers/clocksource/Makefile
··· 16 16 obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o 17 17 obj-$(CONFIG_ORION_TIMER) += time-orion.o 18 18 obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o 19 + obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o 19 20 obj-$(CONFIG_ARCH_MARCO) += timer-marco.o 20 21 obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o 21 22 obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
+131
drivers/clocksource/clps711x-timer.c
··· 1 + /* 2 + * Cirrus Logic CLPS711X clocksource driver 3 + * 4 + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + */ 11 + 12 + #include <linux/clk.h> 13 + #include <linux/clockchips.h> 14 + #include <linux/clocksource.h> 15 + #include <linux/interrupt.h> 16 + #include <linux/io.h> 17 + #include <linux/of_address.h> 18 + #include <linux/of_irq.h> 19 + #include <linux/sched_clock.h> 20 + #include <linux/slab.h> 21 + 22 + enum { 23 + CLPS711X_CLKSRC_CLOCKSOURCE, 24 + CLPS711X_CLKSRC_CLOCKEVENT, 25 + }; 26 + 27 + static void __iomem *tcd; 28 + 29 + static u64 notrace clps711x_sched_clock_read(void) 30 + { 31 + return ~readw(tcd); 32 + } 33 + 34 + static int __init _clps711x_clksrc_init(struct clk *clock, void __iomem *base) 35 + { 36 + unsigned long rate; 37 + 38 + if (!base) 39 + return -ENOMEM; 40 + if (IS_ERR(clock)) 41 + return PTR_ERR(clock); 42 + 43 + rate = clk_get_rate(clock); 44 + 45 + tcd = base; 46 + 47 + clocksource_mmio_init(tcd, "clps711x-clocksource", rate, 300, 16, 48 + clocksource_mmio_readw_down); 49 + 50 + sched_clock_register(clps711x_sched_clock_read, 16, rate); 51 + 52 + return 0; 53 + } 54 + 55 + static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) 56 + { 57 + struct clock_event_device *evt = dev_id; 58 + 59 + evt->event_handler(evt); 60 + 61 + return IRQ_HANDLED; 62 + } 63 + 64 + static void clps711x_clockevent_set_mode(enum clock_event_mode mode, 65 + struct clock_event_device *evt) 66 + { 67 + } 68 + 69 + static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, 70 + unsigned int irq) 71 + { 72 + struct clock_event_device *clkevt; 73 + unsigned long rate; 74 + 75 + if (!irq) 76 + return -EINVAL; 77 + if (!base) 78 + return -ENOMEM; 79 + if (IS_ERR(clock)) 80 + return PTR_ERR(clock); 81 + 82 + clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); 83 + if (!clkevt) 84 + return -ENOMEM; 85 + 86 + rate = clk_get_rate(clock); 87 + 88 + /* Set Timer prescaler */ 89 + writew(DIV_ROUND_CLOSEST(rate, HZ), base); 90 + 91 + clkevt->name = "clps711x-clockevent"; 92 + clkevt->rating = 300; 93 + clkevt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_C3STOP; 94 + clkevt->set_mode = clps711x_clockevent_set_mode; 95 + clkevt->cpumask = cpumask_of(0); 96 + clockevents_config_and_register(clkevt, HZ, 0, 0); 97 + 98 + return request_irq(irq, clps711x_timer_interrupt, IRQF_TIMER, 99 + "clps711x-timer", clkevt); 100 + } 101 + 102 + void __init clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base, 103 + unsigned int irq) 104 + { 105 + struct clk *tc1 = clk_get_sys("clps711x-timer.0", NULL); 106 + struct clk *tc2 = clk_get_sys("clps711x-timer.1", NULL); 107 + 108 + BUG_ON(_clps711x_clksrc_init(tc1, tc1_base)); 109 + BUG_ON(_clps711x_clkevt_init(tc2, tc2_base, irq)); 110 + } 111 + 112 + #ifdef CONFIG_CLKSRC_OF 113 + static void __init clps711x_timer_init(struct device_node *np) 114 + { 115 + unsigned int irq = irq_of_parse_and_map(np, 0); 116 + struct clk *clock = of_clk_get(np, 0); 117 + void __iomem *base = of_iomap(np, 0); 118 + 119 + switch (of_alias_get_id(np, "timer")) { 120 + case CLPS711X_CLKSRC_CLOCKSOURCE: 121 + BUG_ON(_clps711x_clksrc_init(clock, base)); 122 + break; 123 + case CLPS711X_CLKSRC_CLOCKEVENT: 124 + BUG_ON(_clps711x_clkevt_init(clock, base, irq)); 125 + break; 126 + default: 127 + break; 128 + } 129 + } 130 + CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); 131 + #endif