| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright 2013 Freescale Semiconductor, Inc. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * CPU Frequency Scaling driver for Freescale QorIQ SoCs. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | 6 | */ |
|---|
| 10 | 7 | |
|---|
| 11 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 13 | 10 | #include <linux/clk.h> |
|---|
| 14 | 11 | #include <linux/clk-provider.h> |
|---|
| 15 | 12 | #include <linux/cpufreq.h> |
|---|
| 16 | | -#include <linux/cpu_cooling.h> |
|---|
| 17 | 13 | #include <linux/errno.h> |
|---|
| 18 | 14 | #include <linux/init.h> |
|---|
| 19 | 15 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 22 | 18 | #include <linux/of.h> |
|---|
| 23 | 19 | #include <linux/slab.h> |
|---|
| 24 | 20 | #include <linux/smp.h> |
|---|
| 21 | +#include <linux/platform_device.h> |
|---|
| 25 | 22 | |
|---|
| 26 | 23 | /** |
|---|
| 27 | 24 | * struct cpu_data |
|---|
| .. | .. |
|---|
| 31 | 28 | struct cpu_data { |
|---|
| 32 | 29 | struct clk **pclk; |
|---|
| 33 | 30 | struct cpufreq_frequency_table *table; |
|---|
| 34 | | - struct thermal_cooling_device *cdev; |
|---|
| 35 | 31 | }; |
|---|
| 36 | | - |
|---|
| 37 | | -/* |
|---|
| 38 | | - * Don't use cpufreq on this SoC -- used when the SoC would have otherwise |
|---|
| 39 | | - * matched a more generic compatible. |
|---|
| 40 | | - */ |
|---|
| 41 | | -#define SOC_BLACKLIST 1 |
|---|
| 42 | 32 | |
|---|
| 43 | 33 | /** |
|---|
| 44 | 34 | * struct soc_data - SoC specific data |
|---|
| .. | .. |
|---|
| 239 | 229 | { |
|---|
| 240 | 230 | struct cpu_data *data = policy->driver_data; |
|---|
| 241 | 231 | |
|---|
| 242 | | - cpufreq_cooling_unregister(data->cdev); |
|---|
| 243 | 232 | kfree(data->pclk); |
|---|
| 244 | 233 | kfree(data->table); |
|---|
| 245 | 234 | kfree(data); |
|---|
| .. | .. |
|---|
| 258 | 247 | return clk_set_parent(policy->clk, parent); |
|---|
| 259 | 248 | } |
|---|
| 260 | 249 | |
|---|
| 261 | | - |
|---|
| 262 | | -static void qoriq_cpufreq_ready(struct cpufreq_policy *policy) |
|---|
| 263 | | -{ |
|---|
| 264 | | - struct cpu_data *cpud = policy->driver_data; |
|---|
| 265 | | - |
|---|
| 266 | | - cpud->cdev = of_cpufreq_cooling_register(policy); |
|---|
| 267 | | -} |
|---|
| 268 | | - |
|---|
| 269 | 250 | static struct cpufreq_driver qoriq_cpufreq_driver = { |
|---|
| 270 | 251 | .name = "qoriq_cpufreq", |
|---|
| 271 | | - .flags = CPUFREQ_CONST_LOOPS, |
|---|
| 252 | + .flags = CPUFREQ_CONST_LOOPS | |
|---|
| 253 | + CPUFREQ_IS_COOLING_DEV, |
|---|
| 272 | 254 | .init = qoriq_cpufreq_cpu_init, |
|---|
| 273 | 255 | .exit = qoriq_cpufreq_cpu_exit, |
|---|
| 274 | 256 | .verify = cpufreq_generic_frequency_table_verify, |
|---|
| 275 | 257 | .target_index = qoriq_cpufreq_target, |
|---|
| 276 | 258 | .get = cpufreq_generic_get, |
|---|
| 277 | | - .ready = qoriq_cpufreq_ready, |
|---|
| 278 | 259 | .attr = cpufreq_generic_attr, |
|---|
| 279 | 260 | }; |
|---|
| 280 | 261 | |
|---|
| 281 | | -static const struct soc_data blacklist = { |
|---|
| 282 | | - .flags = SOC_BLACKLIST, |
|---|
| 283 | | -}; |
|---|
| 284 | | - |
|---|
| 285 | | -static const struct of_device_id node_matches[] __initconst = { |
|---|
| 262 | +static const struct of_device_id qoriq_cpufreq_blacklist[] = { |
|---|
| 286 | 263 | /* e6500 cannot use cpufreq due to erratum A-008083 */ |
|---|
| 287 | | - { .compatible = "fsl,b4420-clockgen", &blacklist }, |
|---|
| 288 | | - { .compatible = "fsl,b4860-clockgen", &blacklist }, |
|---|
| 289 | | - { .compatible = "fsl,t2080-clockgen", &blacklist }, |
|---|
| 290 | | - { .compatible = "fsl,t4240-clockgen", &blacklist }, |
|---|
| 291 | | - |
|---|
| 292 | | - { .compatible = "fsl,ls1012a-clockgen", }, |
|---|
| 293 | | - { .compatible = "fsl,ls1021a-clockgen", }, |
|---|
| 294 | | - { .compatible = "fsl,ls1043a-clockgen", }, |
|---|
| 295 | | - { .compatible = "fsl,ls1046a-clockgen", }, |
|---|
| 296 | | - { .compatible = "fsl,ls1088a-clockgen", }, |
|---|
| 297 | | - { .compatible = "fsl,ls2080a-clockgen", }, |
|---|
| 298 | | - { .compatible = "fsl,p4080-clockgen", }, |
|---|
| 299 | | - { .compatible = "fsl,qoriq-clockgen-1.0", }, |
|---|
| 300 | | - { .compatible = "fsl,qoriq-clockgen-2.0", }, |
|---|
| 264 | + { .compatible = "fsl,b4420-clockgen", }, |
|---|
| 265 | + { .compatible = "fsl,b4860-clockgen", }, |
|---|
| 266 | + { .compatible = "fsl,t2080-clockgen", }, |
|---|
| 267 | + { .compatible = "fsl,t4240-clockgen", }, |
|---|
| 301 | 268 | {} |
|---|
| 302 | 269 | }; |
|---|
| 303 | 270 | |
|---|
| 304 | | -static int __init qoriq_cpufreq_init(void) |
|---|
| 271 | +static int qoriq_cpufreq_probe(struct platform_device *pdev) |
|---|
| 305 | 272 | { |
|---|
| 306 | 273 | int ret; |
|---|
| 307 | | - struct device_node *np; |
|---|
| 308 | | - const struct of_device_id *match; |
|---|
| 309 | | - const struct soc_data *data; |
|---|
| 274 | + struct device_node *np; |
|---|
| 310 | 275 | |
|---|
| 311 | | - np = of_find_matching_node(NULL, node_matches); |
|---|
| 312 | | - if (!np) |
|---|
| 276 | + np = of_find_matching_node(NULL, qoriq_cpufreq_blacklist); |
|---|
| 277 | + if (np) { |
|---|
| 278 | + of_node_put(np); |
|---|
| 279 | + dev_info(&pdev->dev, "Disabling due to erratum A-008083"); |
|---|
| 313 | 280 | return -ENODEV; |
|---|
| 314 | | - |
|---|
| 315 | | - match = of_match_node(node_matches, np); |
|---|
| 316 | | - data = match->data; |
|---|
| 317 | | - |
|---|
| 318 | | - of_node_put(np); |
|---|
| 319 | | - |
|---|
| 320 | | - if (data && data->flags & SOC_BLACKLIST) |
|---|
| 321 | | - return -ENODEV; |
|---|
| 281 | + } |
|---|
| 322 | 282 | |
|---|
| 323 | 283 | ret = cpufreq_register_driver(&qoriq_cpufreq_driver); |
|---|
| 324 | | - if (!ret) |
|---|
| 325 | | - pr_info("Freescale QorIQ CPU frequency scaling driver\n"); |
|---|
| 284 | + if (ret) |
|---|
| 285 | + return ret; |
|---|
| 326 | 286 | |
|---|
| 327 | | - return ret; |
|---|
| 287 | + dev_info(&pdev->dev, "Freescale QorIQ CPU frequency scaling driver\n"); |
|---|
| 288 | + return 0; |
|---|
| 328 | 289 | } |
|---|
| 329 | | -module_init(qoriq_cpufreq_init); |
|---|
| 330 | 290 | |
|---|
| 331 | | -static void __exit qoriq_cpufreq_exit(void) |
|---|
| 291 | +static int qoriq_cpufreq_remove(struct platform_device *pdev) |
|---|
| 332 | 292 | { |
|---|
| 333 | 293 | cpufreq_unregister_driver(&qoriq_cpufreq_driver); |
|---|
| 334 | | -} |
|---|
| 335 | | -module_exit(qoriq_cpufreq_exit); |
|---|
| 336 | 294 | |
|---|
| 295 | + return 0; |
|---|
| 296 | +} |
|---|
| 297 | + |
|---|
| 298 | +static struct platform_driver qoriq_cpufreq_platform_driver = { |
|---|
| 299 | + .driver = { |
|---|
| 300 | + .name = "qoriq-cpufreq", |
|---|
| 301 | + }, |
|---|
| 302 | + .probe = qoriq_cpufreq_probe, |
|---|
| 303 | + .remove = qoriq_cpufreq_remove, |
|---|
| 304 | +}; |
|---|
| 305 | +module_platform_driver(qoriq_cpufreq_platform_driver); |
|---|
| 306 | + |
|---|
| 307 | +MODULE_ALIAS("platform:qoriq-cpufreq"); |
|---|
| 337 | 308 | MODULE_LICENSE("GPL"); |
|---|
| 338 | 309 | MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>"); |
|---|
| 339 | 310 | MODULE_DESCRIPTION("cpufreq driver for Freescale QorIQ series SoCs"); |
|---|