Blame view

drivers/cpufreq/qcom-cpufreq-hw.c 11.1 KB
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
1
2
3
4
5
6
7
8
  // SPDX-License-Identifier: GPL-2.0
  /*
   * Copyright (c) 2018, The Linux Foundation. All rights reserved.
   */
  
  #include <linux/bitfield.h>
  #include <linux/cpufreq.h>
  #include <linux/init.h>
51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
9
  #include <linux/interconnect.h>
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
10
11
12
13
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/of_address.h>
  #include <linux/of_platform.h>
55538fbc7   Taniya Das   cpufreq: qcom: Re...
14
  #include <linux/pm_opp.h>
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
15
16
17
18
19
20
  #include <linux/slab.h>
  
  #define LUT_MAX_ENTRIES			40U
  #define LUT_SRC				GENMASK(31, 30)
  #define LUT_L_VAL			GENMASK(7, 0)
  #define LUT_CORE_COUNT			GENMASK(18, 16)
55538fbc7   Taniya Das   cpufreq: qcom: Re...
21
  #define LUT_VOLT			GENMASK(11, 0)
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
22
  #define CLK_HW_DIV			2
0eae1e37d   Sibi Sankar   cpufreq: qcom-hw:...
23
  #define LUT_TURBO_IND			1
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
24

dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
25
26
27
28
29
30
31
32
33
34
35
36
  struct qcom_cpufreq_soc_data {
  	u32 reg_enable;
  	u32 reg_freq_lut;
  	u32 reg_volt_lut;
  	u32 reg_perf_state;
  	u8 lut_row_size;
  };
  
  struct qcom_cpufreq_data {
  	void __iomem *base;
  	const struct qcom_cpufreq_soc_data *soc_data;
  };
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
37
38
  
  static unsigned long cpu_hw_rate, xo_rate;
51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  static bool icc_scaling_enabled;
  
  static int qcom_cpufreq_set_bw(struct cpufreq_policy *policy,
  			       unsigned long freq_khz)
  {
  	unsigned long freq_hz = freq_khz * 1000;
  	struct dev_pm_opp *opp;
  	struct device *dev;
  	int ret;
  
  	dev = get_cpu_device(policy->cpu);
  	if (!dev)
  		return -ENODEV;
  
  	opp = dev_pm_opp_find_freq_exact(dev, freq_hz, true);
  	if (IS_ERR(opp))
  		return PTR_ERR(opp);
  
  	ret = dev_pm_opp_set_bw(dev, opp);
  	dev_pm_opp_put(opp);
  	return ret;
  }
  
  static int qcom_cpufreq_update_opp(struct device *cpu_dev,
  				   unsigned long freq_khz,
  				   unsigned long volt)
  {
  	unsigned long freq_hz = freq_khz * 1000;
  	int ret;
  
  	/* Skip voltage update if the opp table is not available */
  	if (!icc_scaling_enabled)
  		return dev_pm_opp_add(cpu_dev, freq_hz, volt);
  
  	ret = dev_pm_opp_adjust_voltage(cpu_dev, freq_hz, volt, volt, volt);
  	if (ret) {
  		dev_err(cpu_dev, "Voltage update failed freq=%ld
  ", freq_khz);
  		return ret;
  	}
  
  	return dev_pm_opp_enable(cpu_dev, freq_hz);
  }
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
82
83
84
85
  
  static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
  					unsigned int index)
  {
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
86
87
  	struct qcom_cpufreq_data *data = policy->driver_data;
  	const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
ada54f35b   Douglas RAILLARD   cpufreq: qcom-hw:...
88
  	unsigned long freq = policy->freq_table[index].frequency;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
89

dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
90
  	writel_relaxed(index, data->base + soc_data->reg_perf_state);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
91

51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
92
93
  	if (icc_scaling_enabled)
  		qcom_cpufreq_set_bw(policy, freq);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
94
95
96
97
98
  	return 0;
  }
  
  static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
  {
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
99
100
  	struct qcom_cpufreq_data *data;
  	const struct qcom_cpufreq_soc_data *soc_data;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
101
102
103
104
105
106
  	struct cpufreq_policy *policy;
  	unsigned int index;
  
  	policy = cpufreq_cpu_get_raw(cpu);
  	if (!policy)
  		return 0;
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
107
108
  	data = policy->driver_data;
  	soc_data = data->soc_data;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
109

dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
110
  	index = readl_relaxed(data->base + soc_data->reg_perf_state);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
111
112
113
114
115
116
117
118
  	index = min(index, LUT_MAX_ENTRIES - 1);
  
  	return policy->freq_table[index].frequency;
  }
  
  static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
  						unsigned int target_freq)
  {
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
119
120
  	struct qcom_cpufreq_data *data = policy->driver_data;
  	const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
292072c38   Viresh Kumar   cpufreq: cached_r...
121
  	unsigned int index;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
122
123
  
  	index = policy->cached_resolved_idx;
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
124
  	writel_relaxed(index, data->base + soc_data->reg_perf_state);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
125

1a0419b0d   Ionela Voinescu   cpufreq: move inv...
126
  	return policy->freq_table[index].frequency;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
127
  }
55538fbc7   Taniya Das   cpufreq: qcom: Re...
128
  static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
129
  				    struct cpufreq_policy *policy)
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
130
  {
0eae1e37d   Sibi Sankar   cpufreq: qcom-hw:...
131
  	u32 data, src, lval, i, core_count, prev_freq = 0, freq;
55538fbc7   Taniya Das   cpufreq: qcom: Re...
132
  	u32 volt;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
133
  	struct cpufreq_frequency_table	*table;
51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
134
135
136
  	struct dev_pm_opp *opp;
  	unsigned long rate;
  	int ret;
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
137
138
  	struct qcom_cpufreq_data *drv_data = policy->driver_data;
  	const struct qcom_cpufreq_soc_data *soc_data = drv_data->soc_data;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
139
140
141
142
  
  	table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL);
  	if (!table)
  		return -ENOMEM;
51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  	ret = dev_pm_opp_of_add_table(cpu_dev);
  	if (!ret) {
  		/* Disable all opps and cross-validate against LUT later */
  		icc_scaling_enabled = true;
  		for (rate = 0; ; rate++) {
  			opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
  			if (IS_ERR(opp))
  				break;
  
  			dev_pm_opp_put(opp);
  			dev_pm_opp_disable(cpu_dev, rate);
  		}
  	} else if (ret != -ENODEV) {
  		dev_err(cpu_dev, "Invalid opp table in device tree
  ");
  		return ret;
  	} else {
afdb219ba   Sibi Sankar   cpufreq: qcom: Di...
160
  		policy->fast_switch_possible = true;
51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
161
162
  		icc_scaling_enabled = false;
  	}
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
163
  	for (i = 0; i < LUT_MAX_ENTRIES; i++) {
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
164
165
  		data = readl_relaxed(drv_data->base + soc_data->reg_freq_lut +
  				      i * soc_data->lut_row_size);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
166
167
168
  		src = FIELD_GET(LUT_SRC, data);
  		lval = FIELD_GET(LUT_L_VAL, data);
  		core_count = FIELD_GET(LUT_CORE_COUNT, data);
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
169
170
  		data = readl_relaxed(drv_data->base + soc_data->reg_volt_lut +
  				      i * soc_data->lut_row_size);
55538fbc7   Taniya Das   cpufreq: qcom: Re...
171
  		volt = FIELD_GET(LUT_VOLT, data) * 1000;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
172
173
174
175
  		if (src)
  			freq = xo_rate * lval / 1000;
  		else
  			freq = cpu_hw_rate / 1000;
0eae1e37d   Sibi Sankar   cpufreq: qcom-hw:...
176
  		if (freq != prev_freq && core_count != LUT_TURBO_IND) {
bc9b9c5ab   Matthias Kaehlcke   cpufreq: qcom: Do...
177
178
179
180
  			if (!qcom_cpufreq_update_opp(cpu_dev, freq, volt)) {
  				table[i].frequency = freq;
  				dev_dbg(cpu_dev, "index=%d freq=%d, core_count %d
  ", i,
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
181
  				freq, core_count);
bc9b9c5ab   Matthias Kaehlcke   cpufreq: qcom: Do...
182
183
184
185
186
  			} else {
  				dev_warn(cpu_dev, "failed to update OPP for freq=%d
  ", freq);
  				table[i].frequency = CPUFREQ_ENTRY_INVALID;
  			}
0eae1e37d   Sibi Sankar   cpufreq: qcom-hw:...
187
  		} else if (core_count == LUT_TURBO_IND) {
55538fbc7   Taniya Das   cpufreq: qcom: Re...
188
  			table[i].frequency = CPUFREQ_ENTRY_INVALID;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
189
190
191
192
193
194
  		}
  
  		/*
  		 * Two of the same frequencies with the same core counts means
  		 * end of table
  		 */
0eae1e37d   Sibi Sankar   cpufreq: qcom-hw:...
195
  		if (i > 0 && prev_freq == freq) {
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
196
197
198
199
200
201
  			struct cpufreq_frequency_table *prev = &table[i - 1];
  
  			/*
  			 * Only treat the last frequency that might be a boost
  			 * as the boost frequency
  			 */
0eae1e37d   Sibi Sankar   cpufreq: qcom-hw:...
202
  			if (prev->frequency == CPUFREQ_ENTRY_INVALID) {
bc9b9c5ab   Matthias Kaehlcke   cpufreq: qcom: Do...
203
204
205
206
207
208
209
210
  				if (!qcom_cpufreq_update_opp(cpu_dev, prev_freq, volt)) {
  					prev->frequency = prev_freq;
  					prev->flags = CPUFREQ_BOOST_FREQ;
  				} else {
  					dev_warn(cpu_dev, "failed to update OPP for freq=%d
  ",
  						 freq);
  				}
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
211
212
213
214
  			}
  
  			break;
  		}
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
215
216
217
218
219
  		prev_freq = freq;
  	}
  
  	table[i].frequency = CPUFREQ_TABLE_END;
  	policy->freq_table = table;
55538fbc7   Taniya Das   cpufreq: qcom: Re...
220
  	dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
  
  	return 0;
  }
  
  static void qcom_get_related_cpus(int index, struct cpumask *m)
  {
  	struct device_node *cpu_np;
  	struct of_phandle_args args;
  	int cpu, ret;
  
  	for_each_possible_cpu(cpu) {
  		cpu_np = of_cpu_device_node_get(cpu);
  		if (!cpu_np)
  			continue;
  
  		ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
  						 "#freq-domain-cells", 0,
  						 &args);
  		of_node_put(cpu_np);
  		if (ret < 0)
  			continue;
  
  		if (index == args.args[0])
  			cpumask_set_cpu(cpu, m);
  	}
  }
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
247
248
249
250
251
252
253
  static const struct qcom_cpufreq_soc_data qcom_soc_data = {
  	.reg_enable = 0x0,
  	.reg_freq_lut = 0x110,
  	.reg_volt_lut = 0x114,
  	.reg_perf_state = 0x920,
  	.lut_row_size = 32,
  };
49b59f4c3   Manivannan Sadhasivam   cpufreq: qcom-hw:...
254
255
256
257
258
259
260
  static const struct qcom_cpufreq_soc_data epss_soc_data = {
  	.reg_enable = 0x0,
  	.reg_freq_lut = 0x100,
  	.reg_volt_lut = 0x200,
  	.reg_perf_state = 0x320,
  	.lut_row_size = 4,
  };
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
261
262
  static const struct of_device_id qcom_cpufreq_hw_match[] = {
  	{ .compatible = "qcom,cpufreq-hw", .data = &qcom_soc_data },
49b59f4c3   Manivannan Sadhasivam   cpufreq: qcom-hw:...
263
  	{ .compatible = "qcom,cpufreq-epss", .data = &epss_soc_data },
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
264
265
266
  	{}
  };
  MODULE_DEVICE_TABLE(of, qcom_cpufreq_hw_match);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
267
268
  static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
  {
bd74e286b   Manivannan Sadhasivam   cpufreq: qcom-hw:...
269
270
  	struct platform_device *pdev = cpufreq_get_driver_data();
  	struct device *dev = &pdev->dev;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
271
272
  	struct of_phandle_args args;
  	struct device_node *cpu_np;
55538fbc7   Taniya Das   cpufreq: qcom: Re...
273
  	struct device *cpu_dev;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
274
  	void __iomem *base;
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
275
  	struct qcom_cpufreq_data *data;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
276
  	int ret, index;
55538fbc7   Taniya Das   cpufreq: qcom: Re...
277
278
279
280
281
282
283
  	cpu_dev = get_cpu_device(policy->cpu);
  	if (!cpu_dev) {
  		pr_err("%s: failed to get cpu%d device
  ", __func__,
  		       policy->cpu);
  		return -ENODEV;
  	}
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
284
285
286
287
288
289
290
291
292
293
294
  	cpu_np = of_cpu_device_node_get(policy->cpu);
  	if (!cpu_np)
  		return -EINVAL;
  
  	ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
  					 "#freq-domain-cells", 0, &args);
  	of_node_put(cpu_np);
  	if (ret)
  		return ret;
  
  	index = args.args[0];
f17b3e443   Manivannan Sadhasivam   cpufreq: qcom-hw:...
295
296
297
  	base = devm_platform_ioremap_resource(pdev, index);
  	if (IS_ERR(base))
  		return PTR_ERR(base);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
298

dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
299
300
301
302
303
304
305
306
  	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  	if (!data) {
  		ret = -ENOMEM;
  		goto error;
  	}
  
  	data->soc_data = of_device_get_match_data(&pdev->dev);
  	data->base = base;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
307
308
  
  	/* HW should be in enabled state to proceed */
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
309
  	if (!(readl_relaxed(base + data->soc_data->reg_enable) & 0x1)) {
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
310
311
312
313
314
315
316
317
318
319
320
321
322
  		dev_err(dev, "Domain-%d cpufreq hardware not enabled
  ", index);
  		ret = -ENODEV;
  		goto error;
  	}
  
  	qcom_get_related_cpus(index, policy->cpus);
  	if (!cpumask_weight(policy->cpus)) {
  		dev_err(dev, "Domain-%d failed to get related CPUs
  ", index);
  		ret = -ENOENT;
  		goto error;
  	}
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
323
  	policy->driver_data = data;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
324

dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
325
  	ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
326
327
328
329
330
  	if (ret) {
  		dev_err(dev, "Domain-%d failed to read LUT
  ", index);
  		goto error;
  	}
55538fbc7   Taniya Das   cpufreq: qcom: Re...
331
332
333
334
335
336
337
  	ret = dev_pm_opp_get_opp_count(cpu_dev);
  	if (ret <= 0) {
  		dev_err(cpu_dev, "Failed to add OPPs
  ");
  		ret = -ENODEV;
  		goto error;
  	}
0e0ffa855   Lukasz Luba   OPP: refactor dev...
338
  	dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
dab535052   Matthias Kaehlcke   cpufreq: qcom-hw:...
339

2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
340
341
342
343
344
345
346
347
  	return 0;
  error:
  	devm_iounmap(dev, base);
  	return ret;
  }
  
  static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
  {
55538fbc7   Taniya Das   cpufreq: qcom: Re...
348
  	struct device *cpu_dev = get_cpu_device(policy->cpu);
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
349
  	struct qcom_cpufreq_data *data = policy->driver_data;
bd74e286b   Manivannan Sadhasivam   cpufreq: qcom-hw:...
350
  	struct platform_device *pdev = cpufreq_get_driver_data();
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
351

55538fbc7   Taniya Das   cpufreq: qcom: Re...
352
  	dev_pm_opp_remove_all_dynamic(cpu_dev);
51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
353
  	dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
354
  	kfree(policy->freq_table);
dcd1fd724   Manivannan Sadhasivam   cpufreq: qcom-hw:...
355
  	devm_iounmap(&pdev->dev, data->base);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
356
357
358
359
360
361
362
363
364
365
366
367
  
  	return 0;
  }
  
  static struct freq_attr *qcom_cpufreq_hw_attr[] = {
  	&cpufreq_freq_attr_scaling_available_freqs,
  	&cpufreq_freq_attr_scaling_boost_freqs,
  	NULL
  };
  
  static struct cpufreq_driver cpufreq_qcom_hw_driver = {
  	.flags		= CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
4c5ff1c83   Amit Kucheria   cpufreq: qcom-hw:...
368
369
  			  CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
  			  CPUFREQ_IS_COOLING_DEV,
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
370
371
372
373
374
375
376
377
378
379
380
381
  	.verify		= cpufreq_generic_frequency_table_verify,
  	.target_index	= qcom_cpufreq_hw_target_index,
  	.get		= qcom_cpufreq_hw_get,
  	.init		= qcom_cpufreq_hw_cpu_init,
  	.exit		= qcom_cpufreq_hw_cpu_exit,
  	.fast_switch    = qcom_cpufreq_hw_fast_switch,
  	.name		= "qcom-cpufreq-hw",
  	.attr		= qcom_cpufreq_hw_attr,
  };
  
  static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
  {
51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
382
  	struct device *cpu_dev;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  	struct clk *clk;
  	int ret;
  
  	clk = clk_get(&pdev->dev, "xo");
  	if (IS_ERR(clk))
  		return PTR_ERR(clk);
  
  	xo_rate = clk_get_rate(clk);
  	clk_put(clk);
  
  	clk = clk_get(&pdev->dev, "alternate");
  	if (IS_ERR(clk))
  		return PTR_ERR(clk);
  
  	cpu_hw_rate = clk_get_rate(clk) / CLK_HW_DIV;
  	clk_put(clk);
bd74e286b   Manivannan Sadhasivam   cpufreq: qcom-hw:...
399
  	cpufreq_qcom_hw_driver.driver_data = pdev;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
400

51c843cf7   Sibi Sankar   cpufreq: qcom: Up...
401
402
403
404
405
406
407
408
  	/* Check for optional interconnect paths on CPU0 */
  	cpu_dev = get_cpu_device(0);
  	if (!cpu_dev)
  		return -EPROBE_DEFER;
  
  	ret = dev_pm_opp_of_find_icc_paths(cpu_dev, NULL);
  	if (ret)
  		return ret;
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  	ret = cpufreq_register_driver(&cpufreq_qcom_hw_driver);
  	if (ret)
  		dev_err(&pdev->dev, "CPUFreq HW driver failed to register
  ");
  	else
  		dev_dbg(&pdev->dev, "QCOM CPUFreq HW driver initialized
  ");
  
  	return ret;
  }
  
  static int qcom_cpufreq_hw_driver_remove(struct platform_device *pdev)
  {
  	return cpufreq_unregister_driver(&cpufreq_qcom_hw_driver);
  }
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
424
425
426
427
428
429
430
431
432
433
434
435
436
  static struct platform_driver qcom_cpufreq_hw_driver = {
  	.probe = qcom_cpufreq_hw_driver_probe,
  	.remove = qcom_cpufreq_hw_driver_remove,
  	.driver = {
  		.name = "qcom-cpufreq-hw",
  		.of_match_table = qcom_cpufreq_hw_match,
  	},
  };
  
  static int __init qcom_cpufreq_hw_init(void)
  {
  	return platform_driver_register(&qcom_cpufreq_hw_driver);
  }
11ff4bdd1   Amit Kucheria   cpufreq: qcom-hw:...
437
  postcore_initcall(qcom_cpufreq_hw_init);
2849dd8bc   Taniya Das   cpufreq: qcom-hw:...
438
439
440
441
442
443
444
445
446
  
  static void __exit qcom_cpufreq_hw_exit(void)
  {
  	platform_driver_unregister(&qcom_cpufreq_hw_driver);
  }
  module_exit(qcom_cpufreq_hw_exit);
  
  MODULE_DESCRIPTION("QCOM CPUFREQ HW Driver");
  MODULE_LICENSE("GPL v2");