12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Raspberry Pi cpufreq driver
- *
- * Copyright (C) 2019, Nicolas Saenz Julienne <[email protected]>
- */
- #include <linux/clk.h>
- #include <linux/cpu.h>
- #include <linux/cpufreq.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/pm_opp.h>
- #define RASPBERRYPI_FREQ_INTERVAL 100000000
- static struct platform_device *cpufreq_dt;
- static int raspberrypi_cpufreq_probe(struct platform_device *pdev)
- {
- struct device *cpu_dev;
- unsigned long min, max;
- unsigned long rate;
- struct clk *clk;
- int ret;
- cpu_dev = get_cpu_device(0);
- if (!cpu_dev) {
- pr_err("Cannot get CPU for cpufreq driver\n");
- return -ENODEV;
- }
- clk = clk_get(cpu_dev, NULL);
- if (IS_ERR(clk)) {
- dev_err(cpu_dev, "Cannot get clock for CPU0\n");
- return PTR_ERR(clk);
- }
- /*
- * The max and min frequencies are configurable in the Raspberry Pi
- * firmware, so we query them at runtime.
- */
- min = roundup(clk_round_rate(clk, 0), RASPBERRYPI_FREQ_INTERVAL);
- max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
- clk_put(clk);
- for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
- ret = dev_pm_opp_add(cpu_dev, rate, 0);
- if (ret)
- goto remove_opp;
- }
- cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
- ret = PTR_ERR_OR_ZERO(cpufreq_dt);
- if (ret) {
- dev_err(cpu_dev, "Failed to create platform device, %d\n", ret);
- goto remove_opp;
- }
- return 0;
- remove_opp:
- dev_pm_opp_remove_all_dynamic(cpu_dev);
- return ret;
- }
- static int raspberrypi_cpufreq_remove(struct platform_device *pdev)
- {
- struct device *cpu_dev;
- cpu_dev = get_cpu_device(0);
- if (cpu_dev)
- dev_pm_opp_remove_all_dynamic(cpu_dev);
- platform_device_unregister(cpufreq_dt);
- return 0;
- }
- /*
- * Since the driver depends on clk-raspberrypi, which may return EPROBE_DEFER,
- * all the activity is performed in the probe, which may be defered as well.
- */
- static struct platform_driver raspberrypi_cpufreq_driver = {
- .driver = {
- .name = "raspberrypi-cpufreq",
- },
- .probe = raspberrypi_cpufreq_probe,
- .remove = raspberrypi_cpufreq_remove,
- };
- module_platform_driver(raspberrypi_cpufreq_driver);
- MODULE_AUTHOR("Nicolas Saenz Julienne <[email protected]");
- MODULE_DESCRIPTION("Raspberry Pi cpufreq driver");
- MODULE_LICENSE("GPL");
- MODULE_ALIAS("platform:raspberrypi-cpufreq");
|