Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/clocksource/clksrc_st_lpc.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Clocksource using the Low Power Timer found in the Low Power Controller (LPC)
4
*
5
* Copyright (C) 2015 STMicroelectronics – All Rights Reserved
6
*
7
* Author(s): Francesco Virlinzi <[email protected]>
8
* Ajit Pal Singh <[email protected]>
9
*/
10
11
#include <linux/clk.h>
12
#include <linux/clocksource.h>
13
#include <linux/init.h>
14
#include <linux/of_address.h>
15
#include <linux/sched_clock.h>
16
#include <linux/slab.h>
17
18
#include <dt-bindings/mfd/st-lpc.h>
19
20
/* Low Power Timer */
21
#define LPC_LPT_LSB_OFF 0x400
22
#define LPC_LPT_MSB_OFF 0x404
23
#define LPC_LPT_START_OFF 0x408
24
25
static struct st_clksrc_ddata {
26
struct clk *clk;
27
void __iomem *base;
28
} ddata;
29
30
static void __init st_clksrc_reset(void)
31
{
32
writel_relaxed(0, ddata.base + LPC_LPT_START_OFF);
33
writel_relaxed(0, ddata.base + LPC_LPT_MSB_OFF);
34
writel_relaxed(0, ddata.base + LPC_LPT_LSB_OFF);
35
writel_relaxed(1, ddata.base + LPC_LPT_START_OFF);
36
}
37
38
static u64 notrace st_clksrc_sched_clock_read(void)
39
{
40
return (u64)readl_relaxed(ddata.base + LPC_LPT_LSB_OFF);
41
}
42
43
static int __init st_clksrc_init(void)
44
{
45
unsigned long rate;
46
int ret;
47
48
st_clksrc_reset();
49
50
rate = clk_get_rate(ddata.clk);
51
52
sched_clock_register(st_clksrc_sched_clock_read, 32, rate);
53
54
ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF,
55
"clksrc-st-lpc", rate, 300, 32,
56
clocksource_mmio_readl_up);
57
if (ret) {
58
pr_err("clksrc-st-lpc: Failed to register clocksource\n");
59
return ret;
60
}
61
62
return 0;
63
}
64
65
static int __init st_clksrc_setup_clk(struct device_node *np)
66
{
67
struct clk *clk;
68
69
clk = of_clk_get(np, 0);
70
if (IS_ERR(clk)) {
71
pr_err("clksrc-st-lpc: Failed to get LPC clock\n");
72
return PTR_ERR(clk);
73
}
74
75
if (clk_prepare_enable(clk)) {
76
pr_err("clksrc-st-lpc: Failed to enable LPC clock\n");
77
return -EINVAL;
78
}
79
80
if (!clk_get_rate(clk)) {
81
pr_err("clksrc-st-lpc: Failed to get LPC clock rate\n");
82
clk_disable_unprepare(clk);
83
return -EINVAL;
84
}
85
86
ddata.clk = clk;
87
88
return 0;
89
}
90
91
static int __init st_clksrc_of_register(struct device_node *np)
92
{
93
int ret;
94
uint32_t mode;
95
96
ret = of_property_read_u32(np, "st,lpc-mode", &mode);
97
if (ret) {
98
pr_err("clksrc-st-lpc: An LPC mode must be provided\n");
99
return ret;
100
}
101
102
/* LPC can either run as a Clocksource or in RTC or WDT mode */
103
if (mode != ST_LPC_MODE_CLKSRC)
104
return 0;
105
106
ddata.base = of_iomap(np, 0);
107
if (!ddata.base) {
108
pr_err("clksrc-st-lpc: Unable to map iomem\n");
109
return -ENXIO;
110
}
111
112
ret = st_clksrc_setup_clk(np);
113
if (ret) {
114
iounmap(ddata.base);
115
return ret;
116
}
117
118
ret = st_clksrc_init();
119
if (ret) {
120
clk_disable_unprepare(ddata.clk);
121
clk_put(ddata.clk);
122
iounmap(ddata.base);
123
return ret;
124
}
125
126
pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n",
127
clk_get_rate(ddata.clk));
128
129
return ret;
130
}
131
TIMER_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register);
132
133