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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.8-rc7 191 lines 4.1 kB view raw
1/* 2 * H8/300 16bit Timer driver 3 * 4 * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp> 5 */ 6 7#include <linux/interrupt.h> 8#include <linux/init.h> 9#include <linux/clocksource.h> 10#include <linux/clk.h> 11#include <linux/io.h> 12#include <linux/of.h> 13#include <linux/of_address.h> 14#include <linux/of_irq.h> 15 16#define TSTR 0 17#define TISRC 6 18 19#define TCR 0 20#define TCNT 2 21 22#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a)) 23#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a)) 24 25struct timer16_priv { 26 struct clocksource cs; 27 unsigned long total_cycles; 28 void __iomem *mapbase; 29 void __iomem *mapcommon; 30 unsigned short cs_enabled; 31 unsigned char enb; 32 unsigned char ovf; 33 unsigned char ovie; 34}; 35 36static unsigned long timer16_get_counter(struct timer16_priv *p) 37{ 38 unsigned short v1, v2, v3; 39 unsigned char o1, o2; 40 41 o1 = ioread8(p->mapcommon + TISRC) & p->ovf; 42 43 /* Make sure the timer value is stable. Stolen from acpi_pm.c */ 44 do { 45 o2 = o1; 46 v1 = ioread16be(p->mapbase + TCNT); 47 v2 = ioread16be(p->mapbase + TCNT); 48 v3 = ioread16be(p->mapbase + TCNT); 49 o1 = ioread8(p->mapcommon + TISRC) & p->ovf; 50 } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) 51 || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); 52 53 if (likely(!o1)) 54 return v2; 55 else 56 return v2 + 0x10000; 57} 58 59 60static irqreturn_t timer16_interrupt(int irq, void *dev_id) 61{ 62 struct timer16_priv *p = (struct timer16_priv *)dev_id; 63 64 bclr(p->ovf, p->mapcommon + TISRC); 65 p->total_cycles += 0x10000; 66 67 return IRQ_HANDLED; 68} 69 70static inline struct timer16_priv *cs_to_priv(struct clocksource *cs) 71{ 72 return container_of(cs, struct timer16_priv, cs); 73} 74 75static cycle_t timer16_clocksource_read(struct clocksource *cs) 76{ 77 struct timer16_priv *p = cs_to_priv(cs); 78 unsigned long raw, value; 79 80 value = p->total_cycles; 81 raw = timer16_get_counter(p); 82 83 return value + raw; 84} 85 86static int timer16_enable(struct clocksource *cs) 87{ 88 struct timer16_priv *p = cs_to_priv(cs); 89 90 WARN_ON(p->cs_enabled); 91 92 p->total_cycles = 0; 93 iowrite16be(0x0000, p->mapbase + TCNT); 94 iowrite8(0x83, p->mapbase + TCR); 95 bset(p->ovie, p->mapcommon + TISRC); 96 bset(p->enb, p->mapcommon + TSTR); 97 98 p->cs_enabled = true; 99 return 0; 100} 101 102static void timer16_disable(struct clocksource *cs) 103{ 104 struct timer16_priv *p = cs_to_priv(cs); 105 106 WARN_ON(!p->cs_enabled); 107 108 bclr(p->ovie, p->mapcommon + TISRC); 109 bclr(p->enb, p->mapcommon + TSTR); 110 111 p->cs_enabled = false; 112} 113 114static struct timer16_priv timer16_priv = { 115 .cs = { 116 .name = "h8300_16timer", 117 .rating = 200, 118 .read = timer16_clocksource_read, 119 .enable = timer16_enable, 120 .disable = timer16_disable, 121 .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8), 122 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 123 }, 124}; 125 126#define REG_CH 0 127#define REG_COMM 1 128 129static int __init h8300_16timer_init(struct device_node *node) 130{ 131 void __iomem *base[2]; 132 int ret, irq; 133 unsigned int ch; 134 struct clk *clk; 135 136 clk = of_clk_get(node, 0); 137 if (IS_ERR(clk)) { 138 pr_err("failed to get clock for clocksource\n"); 139 return PTR_ERR(clk); 140 } 141 142 ret = -ENXIO; 143 base[REG_CH] = of_iomap(node, 0); 144 if (!base[REG_CH]) { 145 pr_err("failed to map registers for clocksource\n"); 146 goto free_clk; 147 } 148 149 base[REG_COMM] = of_iomap(node, 1); 150 if (!base[REG_COMM]) { 151 pr_err("failed to map registers for clocksource\n"); 152 goto unmap_ch; 153 } 154 155 ret = -EINVAL; 156 irq = irq_of_parse_and_map(node, 0); 157 if (!irq) { 158 pr_err("failed to get irq for clockevent\n"); 159 goto unmap_comm; 160 } 161 162 of_property_read_u32(node, "renesas,channel", &ch); 163 164 timer16_priv.mapbase = base[REG_CH]; 165 timer16_priv.mapcommon = base[REG_COMM]; 166 timer16_priv.enb = ch; 167 timer16_priv.ovf = ch; 168 timer16_priv.ovie = 4 + ch; 169 170 ret = request_irq(irq, timer16_interrupt, 171 IRQF_TIMER, timer16_priv.cs.name, &timer16_priv); 172 if (ret < 0) { 173 pr_err("failed to request irq %d of clocksource\n", irq); 174 goto unmap_comm; 175 } 176 177 clocksource_register_hz(&timer16_priv.cs, 178 clk_get_rate(clk) / 8); 179 return 0; 180 181unmap_comm: 182 iounmap(base[REG_COMM]); 183unmap_ch: 184 iounmap(base[REG_CH]); 185free_clk: 186 clk_put(clk); 187 return ret; 188} 189 190CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", 191 h8300_16timer_init);