Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/ralink/timer.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Ralink RT2880 timer
4
* Author: John Crispin
5
*
6
* Copyright (C) 2013 John Crispin <[email protected]>
7
*/
8
9
#include <linux/bits.h>
10
#include <linux/clk.h>
11
#include <linux/device.h>
12
#include <linux/err.h>
13
#include <linux/interrupt.h>
14
#include <linux/io.h>
15
#include <linux/mod_devicetable.h>
16
#include <linux/platform_device.h>
17
#include <linux/timer.h>
18
#include <linux/types.h>
19
20
#include <asm/mach-ralink/ralink_regs.h>
21
22
#define TIMER_REG_TMRSTAT 0x00
23
#define TIMER_REG_TMR0LOAD 0x10
24
#define TIMER_REG_TMR0CTL 0x18
25
26
#define TMRSTAT_TMR0INT BIT(0)
27
28
#define TMR0CTL_ENABLE BIT(7)
29
#define TMR0CTL_MODE_PERIODIC BIT(4)
30
#define TMR0CTL_PRESCALER 1
31
#define TMR0CTL_PRESCALE_VAL (0xf - TMR0CTL_PRESCALER)
32
#define TMR0CTL_PRESCALE_DIV (65536 / BIT(TMR0CTL_PRESCALER))
33
34
struct rt_timer {
35
struct device *dev;
36
void __iomem *membase;
37
int irq;
38
unsigned long timer_freq;
39
unsigned long timer_div;
40
};
41
42
static inline void rt_timer_w32(struct rt_timer *rt, u8 reg, u32 val)
43
{
44
__raw_writel(val, rt->membase + reg);
45
}
46
47
static inline u32 rt_timer_r32(struct rt_timer *rt, u8 reg)
48
{
49
return __raw_readl(rt->membase + reg);
50
}
51
52
static irqreturn_t rt_timer_irq(int irq, void *_rt)
53
{
54
struct rt_timer *rt = (struct rt_timer *) _rt;
55
56
rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
57
rt_timer_w32(rt, TIMER_REG_TMRSTAT, TMRSTAT_TMR0INT);
58
59
return IRQ_HANDLED;
60
}
61
62
63
static int rt_timer_request(struct rt_timer *rt)
64
{
65
int err = request_irq(rt->irq, rt_timer_irq, 0,
66
dev_name(rt->dev), rt);
67
if (err) {
68
dev_err(rt->dev, "failed to request irq\n");
69
} else {
70
u32 t = TMR0CTL_MODE_PERIODIC | TMR0CTL_PRESCALE_VAL;
71
rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
72
}
73
return err;
74
}
75
76
static int rt_timer_config(struct rt_timer *rt, unsigned long divisor)
77
{
78
if (rt->timer_freq < divisor)
79
rt->timer_div = rt->timer_freq;
80
else
81
rt->timer_div = divisor;
82
83
rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
84
85
return 0;
86
}
87
88
static int rt_timer_enable(struct rt_timer *rt)
89
{
90
u32 t;
91
92
rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
93
94
t = rt_timer_r32(rt, TIMER_REG_TMR0CTL);
95
t |= TMR0CTL_ENABLE;
96
rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
97
98
return 0;
99
}
100
101
static int rt_timer_probe(struct platform_device *pdev)
102
{
103
struct rt_timer *rt;
104
struct clk *clk;
105
106
rt = devm_kzalloc(&pdev->dev, sizeof(*rt), GFP_KERNEL);
107
if (!rt) {
108
dev_err(&pdev->dev, "failed to allocate memory\n");
109
return -ENOMEM;
110
}
111
112
rt->irq = platform_get_irq(pdev, 0);
113
if (rt->irq < 0)
114
return rt->irq;
115
116
rt->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
117
if (IS_ERR(rt->membase))
118
return PTR_ERR(rt->membase);
119
120
clk = devm_clk_get(&pdev->dev, NULL);
121
if (IS_ERR(clk)) {
122
dev_err(&pdev->dev, "failed get clock rate\n");
123
return PTR_ERR(clk);
124
}
125
126
rt->timer_freq = clk_get_rate(clk) / TMR0CTL_PRESCALE_DIV;
127
if (!rt->timer_freq)
128
return -EINVAL;
129
130
rt->dev = &pdev->dev;
131
platform_set_drvdata(pdev, rt);
132
133
rt_timer_request(rt);
134
rt_timer_config(rt, 2);
135
rt_timer_enable(rt);
136
137
dev_info(&pdev->dev, "maximum frequency is %luHz\n", rt->timer_freq);
138
139
return 0;
140
}
141
142
static const struct of_device_id rt_timer_match[] = {
143
{ .compatible = "ralink,rt2880-timer" },
144
{},
145
};
146
147
static struct platform_driver rt_timer_driver = {
148
.probe = rt_timer_probe,
149
.driver = {
150
.name = "rt-timer",
151
.of_match_table = rt_timer_match,
152
.suppress_bind_attrs = true,
153
},
154
};
155
builtin_platform_driver(rt_timer_driver);
156
157