0001
0002
0003 #include <linux/clk.h>
0004 #include <linux/clk-provider.h>
0005 #include <linux/mutex.h>
0006 #include <linux/of_device.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/pm_domain.h>
0009 #include <linux/pm_opp.h>
0010 #include <linux/pm_runtime.h>
0011 #include <linux/slab.h>
0012
0013 #include <soc/tegra/common.h>
0014
0015 #include "clk.h"
0016
0017
0018
0019
0020
0021
0022
0023 struct tegra_clk_device {
0024 struct notifier_block clk_nb;
0025 struct device *dev;
0026 struct clk_hw *hw;
0027 struct mutex lock;
0028 };
0029
0030 static int tegra_clock_set_pd_state(struct tegra_clk_device *clk_dev,
0031 unsigned long rate)
0032 {
0033 struct device *dev = clk_dev->dev;
0034 struct dev_pm_opp *opp;
0035 unsigned int pstate;
0036
0037 opp = dev_pm_opp_find_freq_ceil(dev, &rate);
0038 if (opp == ERR_PTR(-ERANGE)) {
0039
0040
0041
0042
0043
0044
0045
0046
0047 dev_dbg(dev, "failed to find ceil OPP for %luHz\n", rate);
0048 opp = dev_pm_opp_find_freq_floor(dev, &rate);
0049 }
0050
0051 if (IS_ERR(opp)) {
0052 dev_err(dev, "failed to find OPP for %luHz: %pe\n", rate, opp);
0053 return PTR_ERR(opp);
0054 }
0055
0056 pstate = dev_pm_opp_get_required_pstate(opp, 0);
0057 dev_pm_opp_put(opp);
0058
0059 return dev_pm_genpd_set_performance_state(dev, pstate);
0060 }
0061
0062 static int tegra_clock_change_notify(struct notifier_block *nb,
0063 unsigned long msg, void *data)
0064 {
0065 struct clk_notifier_data *cnd = data;
0066 struct tegra_clk_device *clk_dev;
0067 int err = 0;
0068
0069 clk_dev = container_of(nb, struct tegra_clk_device, clk_nb);
0070
0071 mutex_lock(&clk_dev->lock);
0072 switch (msg) {
0073 case PRE_RATE_CHANGE:
0074 if (cnd->new_rate > cnd->old_rate)
0075 err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate);
0076 break;
0077
0078 case ABORT_RATE_CHANGE:
0079 err = tegra_clock_set_pd_state(clk_dev, cnd->old_rate);
0080 break;
0081
0082 case POST_RATE_CHANGE:
0083 if (cnd->new_rate < cnd->old_rate)
0084 err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate);
0085 break;
0086
0087 default:
0088 break;
0089 }
0090 mutex_unlock(&clk_dev->lock);
0091
0092 return notifier_from_errno(err);
0093 }
0094
0095 static int tegra_clock_sync_pd_state(struct tegra_clk_device *clk_dev)
0096 {
0097 unsigned long rate;
0098 int ret;
0099
0100 mutex_lock(&clk_dev->lock);
0101
0102 rate = clk_hw_get_rate(clk_dev->hw);
0103 ret = tegra_clock_set_pd_state(clk_dev, rate);
0104
0105 mutex_unlock(&clk_dev->lock);
0106
0107 return ret;
0108 }
0109
0110 static int tegra_clock_probe(struct platform_device *pdev)
0111 {
0112 struct tegra_core_opp_params opp_params = {};
0113 struct tegra_clk_device *clk_dev;
0114 struct device *dev = &pdev->dev;
0115 struct clk *clk;
0116 int err;
0117
0118 if (!dev->pm_domain)
0119 return -EINVAL;
0120
0121 clk_dev = devm_kzalloc(dev, sizeof(*clk_dev), GFP_KERNEL);
0122 if (!clk_dev)
0123 return -ENOMEM;
0124
0125 clk = devm_clk_get(dev, NULL);
0126 if (IS_ERR(clk))
0127 return PTR_ERR(clk);
0128
0129 clk_dev->dev = dev;
0130 clk_dev->hw = __clk_get_hw(clk);
0131 clk_dev->clk_nb.notifier_call = tegra_clock_change_notify;
0132 mutex_init(&clk_dev->lock);
0133
0134 platform_set_drvdata(pdev, clk_dev);
0135
0136
0137
0138
0139
0140
0141
0142
0143 err = devm_tegra_core_dev_init_opp_table(dev, &opp_params);
0144 if (err)
0145 return err;
0146
0147 err = clk_notifier_register(clk, &clk_dev->clk_nb);
0148 if (err) {
0149 dev_err(dev, "failed to register clk notifier: %d\n", err);
0150 return err;
0151 }
0152
0153
0154
0155
0156
0157
0158 err = tegra_clock_sync_pd_state(clk_dev);
0159 if (err)
0160 goto unreg_clk;
0161
0162 return 0;
0163
0164 unreg_clk:
0165 clk_notifier_unregister(clk, &clk_dev->clk_nb);
0166
0167 return err;
0168 }
0169
0170
0171
0172
0173
0174
0175
0176
0177 static const struct dev_pm_ops tegra_clock_pm = {
0178 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_resume_and_get, pm_runtime_put)
0179 };
0180
0181 static const struct of_device_id tegra_clock_match[] = {
0182 { .compatible = "nvidia,tegra20-sclk" },
0183 { .compatible = "nvidia,tegra30-sclk" },
0184 { .compatible = "nvidia,tegra30-pllc" },
0185 { .compatible = "nvidia,tegra30-plle" },
0186 { .compatible = "nvidia,tegra30-pllm" },
0187 { }
0188 };
0189
0190 static struct platform_driver tegra_clock_driver = {
0191 .driver = {
0192 .name = "tegra-clock",
0193 .of_match_table = tegra_clock_match,
0194 .pm = &tegra_clock_pm,
0195 .suppress_bind_attrs = true,
0196 },
0197 .probe = tegra_clock_probe,
0198 };
0199 builtin_platform_driver(tegra_clock_driver);