Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/cpufreq/davinci-cpufreq.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* CPU frequency scaling for DaVinci
4
*
5
* Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/
6
*
7
* Based on linux/arch/arm/plat-omap/cpu-omap.c. Original Copyright follows:
8
*
9
* Copyright (C) 2005 Nokia Corporation
10
* Written by Tony Lindgren <[email protected]>
11
*
12
* Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
13
*
14
* Copyright (C) 2007-2008 Texas Instruments, Inc.
15
* Updated to support OMAP3
16
* Rajendra Nayak <[email protected]>
17
*/
18
#include <linux/types.h>
19
#include <linux/cpufreq.h>
20
#include <linux/init.h>
21
#include <linux/err.h>
22
#include <linux/clk.h>
23
#include <linux/platform_data/davinci-cpufreq.h>
24
#include <linux/platform_device.h>
25
#include <linux/export.h>
26
27
struct davinci_cpufreq {
28
struct device *dev;
29
struct clk *armclk;
30
struct clk *asyncclk;
31
unsigned long asyncrate;
32
};
33
static struct davinci_cpufreq cpufreq;
34
35
static int davinci_target(struct cpufreq_policy *policy, unsigned int idx)
36
{
37
struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
38
struct clk *armclk = cpufreq.armclk;
39
unsigned int old_freq, new_freq;
40
int ret = 0;
41
42
old_freq = policy->cur;
43
new_freq = pdata->freq_table[idx].frequency;
44
45
/* if moving to higher frequency, up the voltage beforehand */
46
if (pdata->set_voltage && new_freq > old_freq) {
47
ret = pdata->set_voltage(idx);
48
if (ret)
49
return ret;
50
}
51
52
ret = clk_set_rate(armclk, new_freq * 1000);
53
if (ret)
54
return ret;
55
56
if (cpufreq.asyncclk) {
57
ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
58
if (ret)
59
return ret;
60
}
61
62
/* if moving to lower freq, lower the voltage after lowering freq */
63
if (pdata->set_voltage && new_freq < old_freq)
64
pdata->set_voltage(idx);
65
66
return 0;
67
}
68
69
static int davinci_cpu_init(struct cpufreq_policy *policy)
70
{
71
int result = 0;
72
struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
73
struct cpufreq_frequency_table *freq_table = pdata->freq_table;
74
75
if (policy->cpu != 0)
76
return -EINVAL;
77
78
/* Finish platform specific initialization */
79
if (pdata->init) {
80
result = pdata->init();
81
if (result)
82
return result;
83
}
84
85
policy->clk = cpufreq.armclk;
86
87
/*
88
* Time measurement across the target() function yields ~1500-1800us
89
* time taken with no drivers on notification list.
90
* Setting the latency to 2000 us to accommodate addition of drivers
91
* to pre/post change notification list.
92
*/
93
cpufreq_generic_init(policy, freq_table, 2000 * 1000);
94
return 0;
95
}
96
97
static struct cpufreq_driver davinci_driver = {
98
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
99
.verify = cpufreq_generic_frequency_table_verify,
100
.target_index = davinci_target,
101
.get = cpufreq_generic_get,
102
.init = davinci_cpu_init,
103
.name = "davinci",
104
};
105
106
static int __init davinci_cpufreq_probe(struct platform_device *pdev)
107
{
108
struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
109
struct clk *asyncclk;
110
111
if (!pdata)
112
return -EINVAL;
113
if (!pdata->freq_table)
114
return -EINVAL;
115
116
cpufreq.dev = &pdev->dev;
117
118
cpufreq.armclk = clk_get(NULL, "arm");
119
if (IS_ERR(cpufreq.armclk)) {
120
dev_err(cpufreq.dev, "Unable to get ARM clock\n");
121
return PTR_ERR(cpufreq.armclk);
122
}
123
124
asyncclk = clk_get(cpufreq.dev, "async");
125
if (!IS_ERR(asyncclk)) {
126
cpufreq.asyncclk = asyncclk;
127
cpufreq.asyncrate = clk_get_rate(asyncclk);
128
}
129
130
return cpufreq_register_driver(&davinci_driver);
131
}
132
133
static void __exit davinci_cpufreq_remove(struct platform_device *pdev)
134
{
135
cpufreq_unregister_driver(&davinci_driver);
136
137
clk_put(cpufreq.armclk);
138
139
if (cpufreq.asyncclk)
140
clk_put(cpufreq.asyncclk);
141
}
142
143
static struct platform_driver davinci_cpufreq_driver = {
144
.driver = {
145
.name = "cpufreq-davinci",
146
},
147
.remove = __exit_p(davinci_cpufreq_remove),
148
};
149
150
int __init davinci_cpufreq_init(void)
151
{
152
return platform_driver_probe(&davinci_cpufreq_driver,
153
davinci_cpufreq_probe);
154
}
155
156
157