1/* 2 * linux/arch/h8300/kernel/cpu/timer/timer8.c 3 * 4 * Yoshinori Sato <ysato@users.sourcefoge.jp> 5 * 6 * 8bit Timer driver 7 * 8 */ 9 10#include <linux/errno.h> 11#include <linux/sched.h> 12#include <linux/kernel.h> 13#include <linux/interrupt.h> 14#include <linux/init.h> 15#include <linux/platform_device.h> 16#include <linux/slab.h> 17#include <linux/clockchips.h> 18#include <linux/module.h> 19#include <linux/clk.h> 20#include <linux/io.h> 21#include <linux/of.h> 22 23#include <asm/irq.h> 24 25#define _8TCR 0 26#define _8TCSR 2 27#define TCORA 4 28#define TCORB 6 29#define _8TCNT 8 30 31#define FLAG_REPROGRAM (1 << 0) 32#define FLAG_SKIPEVENT (1 << 1) 33#define FLAG_IRQCONTEXT (1 << 2) 34#define FLAG_STARTED (1 << 3) 35 36#define ONESHOT 0 37#define PERIODIC 1 38 39#define RELATIVE 0 40#define ABSOLUTE 1 41 42struct timer8_priv { 43 struct platform_device *pdev; 44 struct clock_event_device ced; 45 struct irqaction irqaction; 46 unsigned long mapbase; 47 raw_spinlock_t lock; 48 unsigned long flags; 49 unsigned int rate; 50 unsigned int tcora; 51 struct clk *pclk; 52}; 53 54static unsigned long timer8_get_counter(struct timer8_priv *p) 55{ 56 unsigned long v1, v2, v3; 57 int o1, o2; 58 59 o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20; 60 61 /* Make sure the timer value is stable. Stolen from acpi_pm.c */ 62 do { 63 o2 = o1; 64 v1 = ctrl_inw(p->mapbase + _8TCNT); 65 v2 = ctrl_inw(p->mapbase + _8TCNT); 66 v3 = ctrl_inw(p->mapbase + _8TCNT); 67 o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20; 68 } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) 69 || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); 70 71 v2 |= o1 << 10; 72 return v2; 73} 74 75static irqreturn_t timer8_interrupt(int irq, void *dev_id) 76{ 77 struct timer8_priv *p = dev_id; 78 79 ctrl_outb(ctrl_inb(p->mapbase + _8TCSR) & ~0x40, 80 p->mapbase + _8TCSR); 81 p->flags |= FLAG_IRQCONTEXT; 82 ctrl_outw(p->tcora, p->mapbase + TCORA); 83 if (!(p->flags & FLAG_SKIPEVENT)) { 84 if (clockevent_state_oneshot(&p->ced)) 85 ctrl_outw(0x0000, p->mapbase + _8TCR); 86 p->ced.event_handler(&p->ced); 87 } 88 p->flags &= ~(FLAG_SKIPEVENT | FLAG_IRQCONTEXT); 89 90 return IRQ_HANDLED; 91} 92 93static void timer8_set_next(struct timer8_priv *p, unsigned long delta) 94{ 95 unsigned long flags; 96 unsigned long now; 97 98 raw_spin_lock_irqsave(&p->lock, flags); 99 if (delta >= 0x10000) 100 dev_warn(&p->pdev->dev, "delta out of range\n"); 101 now = timer8_get_counter(p); 102 p->tcora = delta; 103 ctrl_outb(ctrl_inb(p->mapbase + _8TCR) | 0x40, p->mapbase + _8TCR); 104 if (delta > now) 105 ctrl_outw(delta, p->mapbase + TCORA); 106 else 107 ctrl_outw(now + 1, p->mapbase + TCORA); 108 109 raw_spin_unlock_irqrestore(&p->lock, flags); 110} 111 112static int timer8_enable(struct timer8_priv *p) 113{ 114 p->rate = clk_get_rate(p->pclk) / 64; 115 ctrl_outw(0xffff, p->mapbase + TCORA); 116 ctrl_outw(0x0000, p->mapbase + _8TCNT); 117 ctrl_outw(0x0c02, p->mapbase + _8TCR); 118 119 return 0; 120} 121 122static int timer8_start(struct timer8_priv *p) 123{ 124 int ret = 0; 125 unsigned long flags; 126 127 raw_spin_lock_irqsave(&p->lock, flags); 128 129 if (!(p->flags & FLAG_STARTED)) 130 ret = timer8_enable(p); 131 132 if (ret) 133 goto out; 134 p->flags |= FLAG_STARTED; 135 136 out: 137 raw_spin_unlock_irqrestore(&p->lock, flags); 138 139 return ret; 140} 141 142static void timer8_stop(struct timer8_priv *p) 143{ 144 unsigned long flags; 145 146 raw_spin_lock_irqsave(&p->lock, flags); 147 148 ctrl_outw(0x0000, p->mapbase + _8TCR); 149 150 raw_spin_unlock_irqrestore(&p->lock, flags); 151} 152 153static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced) 154{ 155 return container_of(ced, struct timer8_priv, ced); 156} 157 158static void timer8_clock_event_start(struct timer8_priv *p, int periodic) 159{ 160 struct clock_event_device *ced = &p->ced; 161 162 timer8_start(p); 163 164 ced->shift = 32; 165 ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift); 166 ced->max_delta_ns = clockevent_delta2ns(0xffff, ced); 167 ced->min_delta_ns = clockevent_delta2ns(0x0001, ced); 168 169 timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000); 170} 171 172static int timer8_clock_event_shutdown(struct clock_event_device *ced) 173{ 174 timer8_stop(ced_to_priv(ced)); 175 return 0; 176} 177 178static int timer8_clock_event_periodic(struct clock_event_device *ced) 179{ 180 struct timer8_priv *p = ced_to_priv(ced); 181 182 dev_info(&p->pdev->dev, "used for periodic clock events\n"); 183 timer8_stop(p); 184 timer8_clock_event_start(p, PERIODIC); 185 186 return 0; 187} 188 189static int timer8_clock_event_oneshot(struct clock_event_device *ced) 190{ 191 struct timer8_priv *p = ced_to_priv(ced); 192 193 dev_info(&p->pdev->dev, "used for oneshot clock events\n"); 194 timer8_stop(p); 195 timer8_clock_event_start(p, ONESHOT); 196 197 return 0; 198} 199 200static int timer8_clock_event_next(unsigned long delta, 201 struct clock_event_device *ced) 202{ 203 struct timer8_priv *p = ced_to_priv(ced); 204 205 BUG_ON(!clockevent_state_oneshot(ced)); 206 timer8_set_next(p, delta - 1); 207 208 return 0; 209} 210 211static int timer8_setup(struct timer8_priv *p, 212 struct platform_device *pdev) 213{ 214 struct resource *res; 215 int irq; 216 int ret; 217 218 p->pdev = pdev; 219 220 res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); 221 if (!res) { 222 dev_err(&p->pdev->dev, "failed to get I/O memory\n"); 223 return -ENXIO; 224 } 225 226 irq = platform_get_irq(p->pdev, 0); 227 if (irq < 0) { 228 dev_err(&p->pdev->dev, "failed to get irq\n"); 229 return -ENXIO; 230 } 231 232 p->mapbase = res->start; 233 234 p->irqaction.name = dev_name(&p->pdev->dev); 235 p->irqaction.handler = timer8_interrupt; 236 p->irqaction.dev_id = p; 237 p->irqaction.flags = IRQF_TIMER; 238 239 p->pclk = clk_get(&p->pdev->dev, "fck"); 240 if (IS_ERR(p->pclk)) { 241 dev_err(&p->pdev->dev, "can't get clk\n"); 242 return PTR_ERR(p->pclk); 243 } 244 245 p->ced.name = pdev->name; 246 p->ced.features = CLOCK_EVT_FEAT_PERIODIC | 247 CLOCK_EVT_FEAT_ONESHOT; 248 p->ced.rating = 200; 249 p->ced.cpumask = cpumask_of(0); 250 p->ced.set_next_event = timer8_clock_event_next; 251 p->ced.set_state_shutdown = timer8_clock_event_shutdown; 252 p->ced.set_state_periodic = timer8_clock_event_periodic; 253 p->ced.set_state_oneshot = timer8_clock_event_oneshot; 254 255 ret = setup_irq(irq, &p->irqaction); 256 if (ret < 0) { 257 dev_err(&p->pdev->dev, 258 "failed to request irq %d\n", irq); 259 return ret; 260 } 261 clockevents_register_device(&p->ced); 262 platform_set_drvdata(pdev, p); 263 264 return 0; 265} 266 267static int timer8_probe(struct platform_device *pdev) 268{ 269 struct timer8_priv *p = platform_get_drvdata(pdev); 270 271 if (p) { 272 dev_info(&pdev->dev, "kept as earlytimer\n"); 273 return 0; 274 } 275 276 p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); 277 if (!p) 278 return -ENOMEM; 279 280 return timer8_setup(p, pdev); 281} 282 283static int timer8_remove(struct platform_device *pdev) 284{ 285 return -EBUSY; 286} 287 288static const struct of_device_id timer8_of_table[] __maybe_unused = { 289 { .compatible = "renesas,8bit-timer" }, 290 { } 291}; 292 293MODULE_DEVICE_TABLE(of, timer8_of_table); 294static struct platform_driver timer8_driver = { 295 .probe = timer8_probe, 296 .remove = timer8_remove, 297 .driver = { 298 .name = "h8300-8timer", 299 .of_match_table = of_match_ptr(timer8_of_table), 300 } 301}; 302 303static int __init timer8_init(void) 304{ 305 return platform_driver_register(&timer8_driver); 306} 307 308static void __exit timer8_exit(void) 309{ 310 platform_driver_unregister(&timer8_driver); 311} 312 313subsys_initcall(timer8_init); 314module_exit(timer8_exit); 315MODULE_AUTHOR("Yoshinori Sato"); 316MODULE_DESCRIPTION("H8/300 8bit Timer Driver"); 317MODULE_LICENSE("GPL v2"); 318