Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/cpufreq/airoha-cpufreq.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
#include <linux/bitfield.h>
4
#include <linux/cpufreq.h>
5
#include <linux/module.h>
6
#include <linux/platform_device.h>
7
#include <linux/pm_domain.h>
8
#include <linux/pm_runtime.h>
9
#include <linux/slab.h>
10
11
#include "cpufreq-dt.h"
12
13
struct airoha_cpufreq_priv {
14
int opp_token;
15
struct dev_pm_domain_list *pd_list;
16
struct platform_device *cpufreq_dt;
17
};
18
19
static struct platform_device *cpufreq_pdev;
20
21
/* NOP function to disable OPP from setting clock */
22
static int airoha_cpufreq_config_clks_nop(struct device *dev,
23
struct opp_table *opp_table,
24
struct dev_pm_opp *opp,
25
void *data, bool scaling_down)
26
{
27
return 0;
28
}
29
30
static const char * const airoha_cpufreq_clk_names[] = { "cpu", NULL };
31
static const char * const airoha_cpufreq_pd_names[] = { "perf" };
32
33
static int airoha_cpufreq_probe(struct platform_device *pdev)
34
{
35
const struct dev_pm_domain_attach_data attach_data = {
36
.pd_names = airoha_cpufreq_pd_names,
37
.num_pd_names = ARRAY_SIZE(airoha_cpufreq_pd_names),
38
.pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP,
39
};
40
struct dev_pm_opp_config config = {
41
.clk_names = airoha_cpufreq_clk_names,
42
.config_clks = airoha_cpufreq_config_clks_nop,
43
};
44
struct platform_device *cpufreq_dt;
45
struct airoha_cpufreq_priv *priv;
46
struct device *dev = &pdev->dev;
47
struct device *cpu_dev;
48
int ret;
49
50
/* CPUs refer to the same OPP table */
51
cpu_dev = get_cpu_device(0);
52
if (!cpu_dev)
53
return -ENODEV;
54
55
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
56
if (!priv)
57
return -ENOMEM;
58
59
/* Set OPP table conf with NOP config_clks */
60
priv->opp_token = dev_pm_opp_set_config(cpu_dev, &config);
61
if (priv->opp_token < 0)
62
return dev_err_probe(dev, priv->opp_token, "Failed to set OPP config\n");
63
64
/* Attach PM for OPP */
65
ret = dev_pm_domain_attach_list(cpu_dev, &attach_data,
66
&priv->pd_list);
67
if (ret)
68
goto clear_opp_config;
69
70
cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
71
ret = PTR_ERR_OR_ZERO(cpufreq_dt);
72
if (ret) {
73
dev_err(dev, "failed to create cpufreq-dt device: %d\n", ret);
74
goto detach_pm;
75
}
76
77
priv->cpufreq_dt = cpufreq_dt;
78
platform_set_drvdata(pdev, priv);
79
80
return 0;
81
82
detach_pm:
83
dev_pm_domain_detach_list(priv->pd_list);
84
clear_opp_config:
85
dev_pm_opp_clear_config(priv->opp_token);
86
87
return ret;
88
}
89
90
static void airoha_cpufreq_remove(struct platform_device *pdev)
91
{
92
struct airoha_cpufreq_priv *priv = platform_get_drvdata(pdev);
93
94
platform_device_unregister(priv->cpufreq_dt);
95
96
dev_pm_domain_detach_list(priv->pd_list);
97
98
dev_pm_opp_clear_config(priv->opp_token);
99
}
100
101
static struct platform_driver airoha_cpufreq_driver = {
102
.probe = airoha_cpufreq_probe,
103
.remove = airoha_cpufreq_remove,
104
.driver = {
105
.name = "airoha-cpufreq",
106
},
107
};
108
109
static const struct of_device_id airoha_cpufreq_match_list[] __initconst = {
110
{ .compatible = "airoha,en7581" },
111
{},
112
};
113
MODULE_DEVICE_TABLE(of, airoha_cpufreq_match_list);
114
115
static int __init airoha_cpufreq_init(void)
116
{
117
struct device_node *np = of_find_node_by_path("/");
118
const struct of_device_id *match;
119
int ret;
120
121
if (!np)
122
return -ENODEV;
123
124
match = of_match_node(airoha_cpufreq_match_list, np);
125
of_node_put(np);
126
if (!match)
127
return -ENODEV;
128
129
ret = platform_driver_register(&airoha_cpufreq_driver);
130
if (unlikely(ret < 0))
131
return ret;
132
133
cpufreq_pdev = platform_device_register_data(NULL, "airoha-cpufreq",
134
-1, match, sizeof(*match));
135
ret = PTR_ERR_OR_ZERO(cpufreq_pdev);
136
if (ret)
137
platform_driver_unregister(&airoha_cpufreq_driver);
138
139
return ret;
140
}
141
module_init(airoha_cpufreq_init);
142
143
static void __exit airoha_cpufreq_exit(void)
144
{
145
platform_device_unregister(cpufreq_pdev);
146
platform_driver_unregister(&airoha_cpufreq_driver);
147
}
148
module_exit(airoha_cpufreq_exit);
149
150
MODULE_AUTHOR("Christian Marangi <[email protected]>");
151
MODULE_DESCRIPTION("CPUfreq driver for Airoha SoCs");
152
MODULE_LICENSE("GPL");
153
154