1/* 2 * Copyright 2012-2013 Freescale Semiconductor, Inc. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 */ 9 10#include <linux/interrupt.h> 11#include <linux/clockchips.h> 12#include <linux/clk.h> 13#include <linux/of_address.h> 14#include <linux/of_irq.h> 15#include <linux/sched_clock.h> 16 17/* 18 * Each pit takes 0x10 Bytes register space 19 */ 20#define PITMCR 0x00 21#define PIT0_OFFSET 0x100 22#define PITn_OFFSET(n) (PIT0_OFFSET + 0x10 * (n)) 23#define PITLDVAL 0x00 24#define PITCVAL 0x04 25#define PITTCTRL 0x08 26#define PITTFLG 0x0c 27 28#define PITMCR_MDIS (0x1 << 1) 29 30#define PITTCTRL_TEN (0x1 << 0) 31#define PITTCTRL_TIE (0x1 << 1) 32#define PITCTRL_CHN (0x1 << 2) 33 34#define PITTFLG_TIF 0x1 35 36static void __iomem *clksrc_base; 37static void __iomem *clkevt_base; 38static unsigned long cycle_per_jiffy; 39 40static inline void pit_timer_enable(void) 41{ 42 __raw_writel(PITTCTRL_TEN | PITTCTRL_TIE, clkevt_base + PITTCTRL); 43} 44 45static inline void pit_timer_disable(void) 46{ 47 __raw_writel(0, clkevt_base + PITTCTRL); 48} 49 50static inline void pit_irq_acknowledge(void) 51{ 52 __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); 53} 54 55static u64 pit_read_sched_clock(void) 56{ 57 return ~__raw_readl(clksrc_base + PITCVAL); 58} 59 60static int __init pit_clocksource_init(unsigned long rate) 61{ 62 /* set the max load value and start the clock source counter */ 63 __raw_writel(0, clksrc_base + PITTCTRL); 64 __raw_writel(~0UL, clksrc_base + PITLDVAL); 65 __raw_writel(PITTCTRL_TEN, clksrc_base + PITTCTRL); 66 67 sched_clock_register(pit_read_sched_clock, 32, rate); 68 return clocksource_mmio_init(clksrc_base + PITCVAL, "vf-pit", rate, 69 300, 32, clocksource_mmio_readl_down); 70} 71 72static int pit_set_next_event(unsigned long delta, 73 struct clock_event_device *unused) 74{ 75 /* 76 * set a new value to PITLDVAL register will not restart the timer, 77 * to abort the current cycle and start a timer period with the new 78 * value, the timer must be disabled and enabled again. 79 * and the PITLAVAL should be set to delta minus one according to pit 80 * hardware requirement. 81 */ 82 pit_timer_disable(); 83 __raw_writel(delta - 1, clkevt_base + PITLDVAL); 84 pit_timer_enable(); 85 86 return 0; 87} 88 89static void pit_set_mode(enum clock_event_mode mode, 90 struct clock_event_device *evt) 91{ 92 switch (mode) { 93 case CLOCK_EVT_MODE_PERIODIC: 94 pit_set_next_event(cycle_per_jiffy, evt); 95 break; 96 case CLOCK_EVT_MODE_SHUTDOWN: 97 case CLOCK_EVT_MODE_UNUSED: 98 pit_timer_disable(); 99 break; 100 default: 101 break; 102 } 103} 104 105static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) 106{ 107 struct clock_event_device *evt = dev_id; 108 109 pit_irq_acknowledge(); 110 111 /* 112 * pit hardware doesn't support oneshot, it will generate an interrupt 113 * and reload the counter value from PITLDVAL when PITCVAL reach zero, 114 * and start the counter again. So software need to disable the timer 115 * to stop the counter loop in ONESHOT mode. 116 */ 117 if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) 118 pit_timer_disable(); 119 120 evt->event_handler(evt); 121 122 return IRQ_HANDLED; 123} 124 125static struct clock_event_device clockevent_pit = { 126 .name = "VF pit timer", 127 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 128 .set_mode = pit_set_mode, 129 .set_next_event = pit_set_next_event, 130 .rating = 300, 131}; 132 133static struct irqaction pit_timer_irq = { 134 .name = "VF pit timer", 135 .flags = IRQF_TIMER | IRQF_IRQPOLL, 136 .handler = pit_timer_interrupt, 137 .dev_id = &clockevent_pit, 138}; 139 140static int __init pit_clockevent_init(unsigned long rate, int irq) 141{ 142 __raw_writel(0, clkevt_base + PITTCTRL); 143 __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); 144 145 BUG_ON(setup_irq(irq, &pit_timer_irq)); 146 147 clockevent_pit.cpumask = cpumask_of(0); 148 clockevent_pit.irq = irq; 149 /* 150 * The value for the LDVAL register trigger is calculated as: 151 * LDVAL trigger = (period / clock period) - 1 152 * The pit is a 32-bit down count timer, when the conter value 153 * reaches 0, it will generate an interrupt, thus the minimal 154 * LDVAL trigger value is 1. And then the min_delta is 155 * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit. 156 */ 157 clockevents_config_and_register(&clockevent_pit, rate, 2, 0xffffffff); 158 159 return 0; 160} 161 162static void __init pit_timer_init(struct device_node *np) 163{ 164 struct clk *pit_clk; 165 void __iomem *timer_base; 166 unsigned long clk_rate; 167 int irq; 168 169 timer_base = of_iomap(np, 0); 170 BUG_ON(!timer_base); 171 172 /* 173 * PIT0 and PIT1 can be chained to build a 64-bit timer, 174 * so choose PIT2 as clocksource, PIT3 as clockevent device, 175 * and leave PIT0 and PIT1 unused for anyone else who needs them. 176 */ 177 clksrc_base = timer_base + PITn_OFFSET(2); 178 clkevt_base = timer_base + PITn_OFFSET(3); 179 180 irq = irq_of_parse_and_map(np, 0); 181 BUG_ON(irq <= 0); 182 183 pit_clk = of_clk_get(np, 0); 184 BUG_ON(IS_ERR(pit_clk)); 185 186 BUG_ON(clk_prepare_enable(pit_clk)); 187 188 clk_rate = clk_get_rate(pit_clk); 189 cycle_per_jiffy = clk_rate / (HZ); 190 191 /* enable the pit module */ 192 __raw_writel(~PITMCR_MDIS, timer_base + PITMCR); 193 194 BUG_ON(pit_clocksource_init(clk_rate)); 195 196 pit_clockevent_init(clk_rate, irq); 197} 198CLOCKSOURCE_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); 199