diff options
Diffstat (limited to 'drivers/clocksource/h8300_tpu.c')
-rw-r--r-- | drivers/clocksource/h8300_tpu.c | 159 |
1 files changed, 55 insertions, 104 deletions
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 @@ | |||
1 | /* | 1 | /* |
2 | * H8/300 TPU Driver | 2 | * H8S TPU Driver |
3 | * | 3 | * |
4 | * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp> | 4 | * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp> |
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/errno.h> | 8 | #include <linux/errno.h> |
9 | #include <linux/sched.h> | ||
10 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/init.h> | 10 | #include <linux/init.h> |
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/clocksource.h> | 11 | #include <linux/clocksource.h> |
16 | #include <linux/module.h> | ||
17 | #include <linux/clk.h> | 12 | #include <linux/clk.h> |
18 | #include <linux/io.h> | 13 | #include <linux/io.h> |
19 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/of_address.h> | ||
16 | #include <linux/of_irq.h> | ||
20 | 17 | ||
21 | #include <asm/irq.h> | 18 | #define TCR 0x0 |
19 | #define TSR 0x5 | ||
20 | #define TCNT 0x6 | ||
22 | 21 | ||
23 | #define TCR 0 | 22 | #define TCFV 0x10 |
24 | #define TMDR 1 | ||
25 | #define TIOR 2 | ||
26 | #define TER 4 | ||
27 | #define TSR 5 | ||
28 | #define TCNT 6 | ||
29 | #define TGRA 8 | ||
30 | #define TGRB 10 | ||
31 | #define TGRC 12 | ||
32 | #define TGRD 14 | ||
33 | 23 | ||
34 | struct tpu_priv { | 24 | struct tpu_priv { |
35 | struct platform_device *pdev; | ||
36 | struct clocksource cs; | 25 | struct clocksource cs; |
37 | struct clk *clk; | 26 | void __iomem *mapbase1; |
38 | unsigned long mapbase1; | 27 | void __iomem *mapbase2; |
39 | unsigned long mapbase2; | ||
40 | raw_spinlock_t lock; | 28 | raw_spinlock_t lock; |
41 | unsigned int cs_enabled; | 29 | unsigned int cs_enabled; |
42 | }; | 30 | }; |
@@ -45,8 +33,8 @@ static inline unsigned long read_tcnt32(struct tpu_priv *p) | |||
45 | { | 33 | { |
46 | unsigned long tcnt; | 34 | unsigned long tcnt; |
47 | 35 | ||
48 | tcnt = ctrl_inw(p->mapbase1 + TCNT) << 16; | 36 | tcnt = ioread16be(p->mapbase1 + TCNT) << 16; |
49 | tcnt |= ctrl_inw(p->mapbase2 + TCNT); | 37 | tcnt |= ioread16be(p->mapbase2 + TCNT); |
50 | return tcnt; | 38 | return tcnt; |
51 | } | 39 | } |
52 | 40 | ||
@@ -55,7 +43,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val) | |||
55 | unsigned long v1, v2, v3; | 43 | unsigned long v1, v2, v3; |
56 | int o1, o2; | 44 | int o1, o2; |
57 | 45 | ||
58 | o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10; | 46 | o1 = ioread8(p->mapbase1 + TSR) & TCFV; |
59 | 47 | ||
60 | /* Make sure the timer value is stable. Stolen from acpi_pm.c */ | 48 | /* Make sure the timer value is stable. Stolen from acpi_pm.c */ |
61 | do { | 49 | do { |
@@ -63,7 +51,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val) | |||
63 | v1 = read_tcnt32(p); | 51 | v1 = read_tcnt32(p); |
64 | v2 = read_tcnt32(p); | 52 | v2 = read_tcnt32(p); |
65 | v3 = read_tcnt32(p); | 53 | v3 = read_tcnt32(p); |
66 | o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10; | 54 | o1 = ioread8(p->mapbase1 + TSR) & TCFV; |
67 | } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) | 55 | } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) |
68 | || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); | 56 | || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); |
69 | 57 | ||
@@ -96,10 +84,10 @@ static int tpu_clocksource_enable(struct clocksource *cs) | |||
96 | 84 | ||
97 | WARN_ON(p->cs_enabled); | 85 | WARN_ON(p->cs_enabled); |
98 | 86 | ||
99 | ctrl_outw(0, p->mapbase1 + TCNT); | 87 | iowrite16be(0, p->mapbase1 + TCNT); |
100 | ctrl_outw(0, p->mapbase2 + TCNT); | 88 | iowrite16be(0, p->mapbase2 + TCNT); |
101 | ctrl_outb(0x0f, p->mapbase1 + TCR); | 89 | iowrite8(0x0f, p->mapbase1 + TCR); |
102 | ctrl_outb(0x03, p->mapbase2 + TCR); | 90 | iowrite8(0x03, p->mapbase2 + TCR); |
103 | 91 | ||
104 | p->cs_enabled = true; | 92 | p->cs_enabled = true; |
105 | return 0; | 93 | return 0; |
@@ -111,96 +99,59 @@ static void tpu_clocksource_disable(struct clocksource *cs) | |||
111 | 99 | ||
112 | WARN_ON(!p->cs_enabled); | 100 | WARN_ON(!p->cs_enabled); |
113 | 101 | ||
114 | ctrl_outb(0, p->mapbase1 + TCR); | 102 | iowrite8(0, p->mapbase1 + TCR); |
115 | ctrl_outb(0, p->mapbase2 + TCR); | 103 | iowrite8(0, p->mapbase2 + TCR); |
116 | p->cs_enabled = false; | 104 | p->cs_enabled = false; |
117 | } | 105 | } |
118 | 106 | ||
107 | static struct tpu_priv tpu_priv = { | ||
108 | .cs = { | ||
109 | .name = "H8S_TPU", | ||
110 | .rating = 200, | ||
111 | .read = tpu_clocksource_read, | ||
112 | .enable = tpu_clocksource_enable, | ||
113 | .disable = tpu_clocksource_disable, | ||
114 | .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8), | ||
115 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
116 | }, | ||
117 | }; | ||
118 | |||
119 | #define CH_L 0 | 119 | #define CH_L 0 |
120 | #define CH_H 1 | 120 | #define CH_H 1 |
121 | 121 | ||
122 | static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev) | 122 | static void __init h8300_tpu_init(struct device_node *node) |
123 | { | 123 | { |
124 | struct resource *res[2]; | 124 | void __iomem *base[2]; |
125 | 125 | struct clk *clk; | |
126 | p->pdev = pdev; | ||
127 | 126 | ||
128 | res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L); | 127 | clk = of_clk_get(node, 0); |
129 | res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H); | 128 | if (IS_ERR(clk)) { |
130 | if (!res[CH_L] || !res[CH_H]) { | 129 | pr_err("failed to get clock for clocksource\n"); |
131 | dev_err(&p->pdev->dev, "failed to get I/O memory\n"); | 130 | return; |
132 | return -ENXIO; | ||
133 | } | 131 | } |
134 | 132 | ||
135 | p->clk = clk_get(&p->pdev->dev, "fck"); | 133 | base[CH_L] = of_iomap(node, CH_L); |
136 | if (IS_ERR(p->clk)) { | 134 | if (!base[CH_L]) { |
137 | dev_err(&p->pdev->dev, "can't get clk\n"); | 135 | pr_err("failed to map registers for clocksource\n"); |
138 | return PTR_ERR(p->clk); | 136 | goto free_clk; |
139 | } | 137 | } |
140 | 138 | base[CH_H] = of_iomap(node, CH_H); | |
141 | p->mapbase1 = res[CH_L]->start; | 139 | if (!base[CH_H]) { |
142 | p->mapbase2 = res[CH_H]->start; | 140 | pr_err("failed to map registers for clocksource\n"); |
143 | 141 | goto unmap_L; | |
144 | p->cs.name = pdev->name; | ||
145 | p->cs.rating = 200; | ||
146 | p->cs.read = tpu_clocksource_read; | ||
147 | p->cs.enable = tpu_clocksource_enable; | ||
148 | p->cs.disable = tpu_clocksource_disable; | ||
149 | p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); | ||
150 | p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
151 | clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 64); | ||
152 | platform_set_drvdata(pdev, p); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int tpu_probe(struct platform_device *pdev) | ||
158 | { | ||
159 | struct tpu_priv *p = platform_get_drvdata(pdev); | ||
160 | |||
161 | if (p) { | ||
162 | dev_info(&pdev->dev, "kept as earlytimer\n"); | ||
163 | return 0; | ||
164 | } | 142 | } |
165 | 143 | ||
166 | p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); | 144 | tpu_priv.mapbase1 = base[CH_L]; |
167 | if (!p) | 145 | tpu_priv.mapbase2 = base[CH_H]; |
168 | return -ENOMEM; | ||
169 | 146 | ||
170 | return tpu_setup(p, pdev); | 147 | clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64); |
171 | } | ||
172 | |||
173 | static int tpu_remove(struct platform_device *pdev) | ||
174 | { | ||
175 | return -EBUSY; | ||
176 | } | ||
177 | |||
178 | static const struct of_device_id tpu_of_table[] = { | ||
179 | { .compatible = "renesas,tpu" }, | ||
180 | { } | ||
181 | }; | ||
182 | 148 | ||
183 | static struct platform_driver tpu_driver = { | 149 | return; |
184 | .probe = tpu_probe, | ||
185 | .remove = tpu_remove, | ||
186 | .driver = { | ||
187 | .name = "h8s-tpu", | ||
188 | .of_match_table = of_match_ptr(tpu_of_table), | ||
189 | } | ||
190 | }; | ||
191 | |||
192 | static int __init tpu_init(void) | ||
193 | { | ||
194 | return platform_driver_register(&tpu_driver); | ||
195 | } | ||
196 | 150 | ||
197 | static void __exit tpu_exit(void) | 151 | unmap_L: |
198 | { | 152 | iounmap(base[CH_H]); |
199 | platform_driver_unregister(&tpu_driver); | 153 | free_clk: |
154 | clk_put(clk); | ||
200 | } | 155 | } |
201 | 156 | ||
202 | subsys_initcall(tpu_init); | 157 | CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); |
203 | module_exit(tpu_exit); | ||
204 | MODULE_AUTHOR("Yoshinori Sato"); | ||
205 | MODULE_DESCRIPTION("H8S Timer Pulse Unit Driver"); | ||
206 | MODULE_LICENSE("GPL v2"); | ||