0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/io.h>
0015 #include <linux/init.h>
0016 #include <linux/export.h>
0017 #include <linux/jiffies.h>
0018 #include <linux/spinlock.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/clockchips.h>
0021
0022 #include <asm/time.h>
0023
0024 #include <cs5536/cs5536_mfgpt.h>
0025
0026 static DEFINE_RAW_SPINLOCK(mfgpt_lock);
0027
0028 static u32 mfgpt_base;
0029
0030
0031
0032
0033
0034
0035
0036
0037 void disable_mfgpt0_counter(void)
0038 {
0039 outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
0040 }
0041 EXPORT_SYMBOL(disable_mfgpt0_counter);
0042
0043
0044 void enable_mfgpt0_counter(void)
0045 {
0046 outw(0xe310, MFGPT0_SETUP);
0047 }
0048 EXPORT_SYMBOL(enable_mfgpt0_counter);
0049
0050 static int mfgpt_timer_set_periodic(struct clock_event_device *evt)
0051 {
0052 raw_spin_lock(&mfgpt_lock);
0053
0054 outw(COMPARE, MFGPT0_CMP2);
0055 outw(0, MFGPT0_CNT);
0056 enable_mfgpt0_counter();
0057
0058 raw_spin_unlock(&mfgpt_lock);
0059 return 0;
0060 }
0061
0062 static int mfgpt_timer_shutdown(struct clock_event_device *evt)
0063 {
0064 if (clockevent_state_periodic(evt) || clockevent_state_oneshot(evt)) {
0065 raw_spin_lock(&mfgpt_lock);
0066 disable_mfgpt0_counter();
0067 raw_spin_unlock(&mfgpt_lock);
0068 }
0069
0070 return 0;
0071 }
0072
0073 static struct clock_event_device mfgpt_clockevent = {
0074 .name = "mfgpt",
0075 .features = CLOCK_EVT_FEAT_PERIODIC,
0076
0077
0078 .set_state_shutdown = mfgpt_timer_shutdown,
0079 .set_state_periodic = mfgpt_timer_set_periodic,
0080 .irq = CS5536_MFGPT_INTR,
0081 };
0082
0083 static irqreturn_t timer_interrupt(int irq, void *dev_id)
0084 {
0085 u32 basehi;
0086
0087
0088
0089
0090
0091
0092
0093 _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
0094
0095
0096 outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
0097
0098 mfgpt_clockevent.event_handler(&mfgpt_clockevent);
0099
0100 return IRQ_HANDLED;
0101 }
0102
0103
0104
0105
0106
0107 void __init setup_mfgpt0_timer(void)
0108 {
0109 u32 basehi;
0110 struct clock_event_device *cd = &mfgpt_clockevent;
0111 unsigned int cpu = smp_processor_id();
0112
0113 cd->cpumask = cpumask_of(cpu);
0114 clockevent_set_clock(cd, MFGPT_TICK_RATE);
0115 cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
0116 cd->max_delta_ticks = 0xffff;
0117 cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
0118 cd->min_delta_ticks = 0xf;
0119
0120
0121 _wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
0122
0123
0124 _wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
0125
0126
0127 _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
0128
0129 clockevents_register_device(cd);
0130
0131 if (request_irq(CS5536_MFGPT_INTR, timer_interrupt,
0132 IRQF_NOBALANCING | IRQF_TIMER, "timer", NULL))
0133 pr_err("Failed to register timer interrupt\n");
0134 }
0135
0136
0137
0138
0139
0140
0141 static u64 mfgpt_read(struct clocksource *cs)
0142 {
0143 unsigned long flags;
0144 int count;
0145 u32 jifs;
0146 static int old_count;
0147 static u32 old_jifs;
0148
0149 raw_spin_lock_irqsave(&mfgpt_lock, flags);
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 jifs = jiffies;
0164
0165 count = inw(MFGPT0_CNT);
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177 if (count < old_count && jifs == old_jifs)
0178 count = old_count;
0179
0180 old_count = count;
0181 old_jifs = jifs;
0182
0183 raw_spin_unlock_irqrestore(&mfgpt_lock, flags);
0184
0185 return (u64) (jifs * COMPARE) + count;
0186 }
0187
0188 static struct clocksource clocksource_mfgpt = {
0189 .name = "mfgpt",
0190 .rating = 120,
0191 .read = mfgpt_read,
0192 .mask = CLOCKSOURCE_MASK(32),
0193 };
0194
0195 int __init init_mfgpt_clocksource(void)
0196 {
0197 if (num_possible_cpus() > 1)
0198 return 0;
0199
0200 return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
0201 }
0202
0203 arch_initcall(init_mfgpt_clocksource);