1b1bc04a2SDmitry Osipenko // SPDX-License-Identifier: GPL-2.0-only 2b1bc04a2SDmitry Osipenko 3b1bc04a2SDmitry Osipenko #include <linux/clk.h> 4b1bc04a2SDmitry Osipenko #include <linux/clk-provider.h> 5*a96cbb14SRob Herring #include <linux/mod_devicetable.h> 6b1bc04a2SDmitry Osipenko #include <linux/mutex.h> 7b1bc04a2SDmitry Osipenko #include <linux/platform_device.h> 8b1bc04a2SDmitry Osipenko #include <linux/pm_domain.h> 9b1bc04a2SDmitry Osipenko #include <linux/pm_opp.h> 10b1bc04a2SDmitry Osipenko #include <linux/pm_runtime.h> 11b1bc04a2SDmitry Osipenko #include <linux/slab.h> 12b1bc04a2SDmitry Osipenko 13b1bc04a2SDmitry Osipenko #include <soc/tegra/common.h> 14b1bc04a2SDmitry Osipenko 15b1bc04a2SDmitry Osipenko #include "clk.h" 16b1bc04a2SDmitry Osipenko 17b1bc04a2SDmitry Osipenko /* 18b1bc04a2SDmitry Osipenko * This driver manages performance state of the core power domain for the 19b1bc04a2SDmitry Osipenko * independent PLLs and system clocks. We created a virtual clock device 20b1bc04a2SDmitry Osipenko * for such clocks, see tegra_clk_dev_register(). 21b1bc04a2SDmitry Osipenko */ 22b1bc04a2SDmitry Osipenko 23b1bc04a2SDmitry Osipenko struct tegra_clk_device { 24b1bc04a2SDmitry Osipenko struct notifier_block clk_nb; 25b1bc04a2SDmitry Osipenko struct device *dev; 26b1bc04a2SDmitry Osipenko struct clk_hw *hw; 27b1bc04a2SDmitry Osipenko struct mutex lock; 28b1bc04a2SDmitry Osipenko }; 29b1bc04a2SDmitry Osipenko 30b1bc04a2SDmitry Osipenko static int tegra_clock_set_pd_state(struct tegra_clk_device *clk_dev, 31b1bc04a2SDmitry Osipenko unsigned long rate) 32b1bc04a2SDmitry Osipenko { 33b1bc04a2SDmitry Osipenko struct device *dev = clk_dev->dev; 34b1bc04a2SDmitry Osipenko struct dev_pm_opp *opp; 35b1bc04a2SDmitry Osipenko unsigned int pstate; 36b1bc04a2SDmitry Osipenko 37b1bc04a2SDmitry Osipenko opp = dev_pm_opp_find_freq_ceil(dev, &rate); 38b1bc04a2SDmitry Osipenko if (opp == ERR_PTR(-ERANGE)) { 39b1bc04a2SDmitry Osipenko /* 40b1bc04a2SDmitry Osipenko * Some clocks may be unused by a particular board and they 41b1bc04a2SDmitry Osipenko * may have uninitiated clock rate that is overly high. In 42b1bc04a2SDmitry Osipenko * this case clock is expected to be disabled, but still we 43b1bc04a2SDmitry Osipenko * need to set up performance state of the power domain and 44b1bc04a2SDmitry Osipenko * not error out clk initialization. A typical example is 45b1bc04a2SDmitry Osipenko * a PCIe clock on Android tablets. 46b1bc04a2SDmitry Osipenko */ 47b1bc04a2SDmitry Osipenko dev_dbg(dev, "failed to find ceil OPP for %luHz\n", rate); 48b1bc04a2SDmitry Osipenko opp = dev_pm_opp_find_freq_floor(dev, &rate); 49b1bc04a2SDmitry Osipenko } 50b1bc04a2SDmitry Osipenko 51b1bc04a2SDmitry Osipenko if (IS_ERR(opp)) { 52b1bc04a2SDmitry Osipenko dev_err(dev, "failed to find OPP for %luHz: %pe\n", rate, opp); 53b1bc04a2SDmitry Osipenko return PTR_ERR(opp); 54b1bc04a2SDmitry Osipenko } 55b1bc04a2SDmitry Osipenko 56b1bc04a2SDmitry Osipenko pstate = dev_pm_opp_get_required_pstate(opp, 0); 57b1bc04a2SDmitry Osipenko dev_pm_opp_put(opp); 58b1bc04a2SDmitry Osipenko 59b1bc04a2SDmitry Osipenko return dev_pm_genpd_set_performance_state(dev, pstate); 60b1bc04a2SDmitry Osipenko } 61b1bc04a2SDmitry Osipenko 62b1bc04a2SDmitry Osipenko static int tegra_clock_change_notify(struct notifier_block *nb, 63b1bc04a2SDmitry Osipenko unsigned long msg, void *data) 64b1bc04a2SDmitry Osipenko { 65b1bc04a2SDmitry Osipenko struct clk_notifier_data *cnd = data; 66b1bc04a2SDmitry Osipenko struct tegra_clk_device *clk_dev; 67b1bc04a2SDmitry Osipenko int err = 0; 68b1bc04a2SDmitry Osipenko 69b1bc04a2SDmitry Osipenko clk_dev = container_of(nb, struct tegra_clk_device, clk_nb); 70b1bc04a2SDmitry Osipenko 71b1bc04a2SDmitry Osipenko mutex_lock(&clk_dev->lock); 72b1bc04a2SDmitry Osipenko switch (msg) { 73b1bc04a2SDmitry Osipenko case PRE_RATE_CHANGE: 74b1bc04a2SDmitry Osipenko if (cnd->new_rate > cnd->old_rate) 75b1bc04a2SDmitry Osipenko err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate); 76b1bc04a2SDmitry Osipenko break; 77b1bc04a2SDmitry Osipenko 78b1bc04a2SDmitry Osipenko case ABORT_RATE_CHANGE: 79b1bc04a2SDmitry Osipenko err = tegra_clock_set_pd_state(clk_dev, cnd->old_rate); 80b1bc04a2SDmitry Osipenko break; 81b1bc04a2SDmitry Osipenko 82b1bc04a2SDmitry Osipenko case POST_RATE_CHANGE: 83b1bc04a2SDmitry Osipenko if (cnd->new_rate < cnd->old_rate) 84b1bc04a2SDmitry Osipenko err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate); 85b1bc04a2SDmitry Osipenko break; 86b1bc04a2SDmitry Osipenko 87b1bc04a2SDmitry Osipenko default: 88b1bc04a2SDmitry Osipenko break; 89b1bc04a2SDmitry Osipenko } 90b1bc04a2SDmitry Osipenko mutex_unlock(&clk_dev->lock); 91b1bc04a2SDmitry Osipenko 92b1bc04a2SDmitry Osipenko return notifier_from_errno(err); 93b1bc04a2SDmitry Osipenko } 94b1bc04a2SDmitry Osipenko 95b1bc04a2SDmitry Osipenko static int tegra_clock_sync_pd_state(struct tegra_clk_device *clk_dev) 96b1bc04a2SDmitry Osipenko { 97b1bc04a2SDmitry Osipenko unsigned long rate; 98b1bc04a2SDmitry Osipenko int ret; 99b1bc04a2SDmitry Osipenko 100b1bc04a2SDmitry Osipenko mutex_lock(&clk_dev->lock); 101b1bc04a2SDmitry Osipenko 102b1bc04a2SDmitry Osipenko rate = clk_hw_get_rate(clk_dev->hw); 103b1bc04a2SDmitry Osipenko ret = tegra_clock_set_pd_state(clk_dev, rate); 104b1bc04a2SDmitry Osipenko 105b1bc04a2SDmitry Osipenko mutex_unlock(&clk_dev->lock); 106b1bc04a2SDmitry Osipenko 107b1bc04a2SDmitry Osipenko return ret; 108b1bc04a2SDmitry Osipenko } 109b1bc04a2SDmitry Osipenko 110b1bc04a2SDmitry Osipenko static int tegra_clock_probe(struct platform_device *pdev) 111b1bc04a2SDmitry Osipenko { 112b1bc04a2SDmitry Osipenko struct tegra_core_opp_params opp_params = {}; 113b1bc04a2SDmitry Osipenko struct tegra_clk_device *clk_dev; 114b1bc04a2SDmitry Osipenko struct device *dev = &pdev->dev; 115b1bc04a2SDmitry Osipenko struct clk *clk; 116b1bc04a2SDmitry Osipenko int err; 117b1bc04a2SDmitry Osipenko 118b1bc04a2SDmitry Osipenko if (!dev->pm_domain) 119b1bc04a2SDmitry Osipenko return -EINVAL; 120b1bc04a2SDmitry Osipenko 121b1bc04a2SDmitry Osipenko clk_dev = devm_kzalloc(dev, sizeof(*clk_dev), GFP_KERNEL); 122b1bc04a2SDmitry Osipenko if (!clk_dev) 123b1bc04a2SDmitry Osipenko return -ENOMEM; 124b1bc04a2SDmitry Osipenko 125b1bc04a2SDmitry Osipenko clk = devm_clk_get(dev, NULL); 126b1bc04a2SDmitry Osipenko if (IS_ERR(clk)) 127b1bc04a2SDmitry Osipenko return PTR_ERR(clk); 128b1bc04a2SDmitry Osipenko 129b1bc04a2SDmitry Osipenko clk_dev->dev = dev; 130b1bc04a2SDmitry Osipenko clk_dev->hw = __clk_get_hw(clk); 131b1bc04a2SDmitry Osipenko clk_dev->clk_nb.notifier_call = tegra_clock_change_notify; 132b1bc04a2SDmitry Osipenko mutex_init(&clk_dev->lock); 133b1bc04a2SDmitry Osipenko 134b1bc04a2SDmitry Osipenko platform_set_drvdata(pdev, clk_dev); 135b1bc04a2SDmitry Osipenko 136b1bc04a2SDmitry Osipenko /* 137b1bc04a2SDmitry Osipenko * Runtime PM was already enabled for this device by the parent clk 138b1bc04a2SDmitry Osipenko * driver and power domain state should be synced under clk_dev lock, 139b1bc04a2SDmitry Osipenko * hence we don't use the common OPP helper that initializes OPP 140b1bc04a2SDmitry Osipenko * state. For some clocks common OPP helper may fail to find ceil 141b1bc04a2SDmitry Osipenko * rate, it's handled by this driver. 142b1bc04a2SDmitry Osipenko */ 143b1bc04a2SDmitry Osipenko err = devm_tegra_core_dev_init_opp_table(dev, &opp_params); 144b1bc04a2SDmitry Osipenko if (err) 145b1bc04a2SDmitry Osipenko return err; 146b1bc04a2SDmitry Osipenko 147b1bc04a2SDmitry Osipenko err = clk_notifier_register(clk, &clk_dev->clk_nb); 148b1bc04a2SDmitry Osipenko if (err) { 149b1bc04a2SDmitry Osipenko dev_err(dev, "failed to register clk notifier: %d\n", err); 150b1bc04a2SDmitry Osipenko return err; 151b1bc04a2SDmitry Osipenko } 152b1bc04a2SDmitry Osipenko 153b1bc04a2SDmitry Osipenko /* 154b1bc04a2SDmitry Osipenko * The driver is attaching to a potentially active/resumed clock, hence 155b1bc04a2SDmitry Osipenko * we need to sync the power domain performance state in a accordance to 156b1bc04a2SDmitry Osipenko * the clock rate if clock is resumed. 157b1bc04a2SDmitry Osipenko */ 158b1bc04a2SDmitry Osipenko err = tegra_clock_sync_pd_state(clk_dev); 159b1bc04a2SDmitry Osipenko if (err) 160b1bc04a2SDmitry Osipenko goto unreg_clk; 161b1bc04a2SDmitry Osipenko 162b1bc04a2SDmitry Osipenko return 0; 163b1bc04a2SDmitry Osipenko 164b1bc04a2SDmitry Osipenko unreg_clk: 165b1bc04a2SDmitry Osipenko clk_notifier_unregister(clk, &clk_dev->clk_nb); 166b1bc04a2SDmitry Osipenko 167b1bc04a2SDmitry Osipenko return err; 168b1bc04a2SDmitry Osipenko } 169b1bc04a2SDmitry Osipenko 170b1bc04a2SDmitry Osipenko /* 171b1bc04a2SDmitry Osipenko * Tegra GENPD driver enables clocks during NOIRQ phase. It can't be done 172b1bc04a2SDmitry Osipenko * for clocks served by this driver because runtime PM is unavailable in 173b1bc04a2SDmitry Osipenko * NOIRQ phase. We will keep clocks resumed during suspend to mitigate this 174b1bc04a2SDmitry Osipenko * problem. In practice this makes no difference from a power management 175b1bc04a2SDmitry Osipenko * perspective since voltage is kept at a nominal level during suspend anyways. 176b1bc04a2SDmitry Osipenko */ 177b1bc04a2SDmitry Osipenko static const struct dev_pm_ops tegra_clock_pm = { 178b1bc04a2SDmitry Osipenko SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_resume_and_get, pm_runtime_put) 179b1bc04a2SDmitry Osipenko }; 180b1bc04a2SDmitry Osipenko 181b1bc04a2SDmitry Osipenko static const struct of_device_id tegra_clock_match[] = { 182b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra20-sclk" }, 183b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra30-sclk" }, 184b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra30-pllc" }, 185b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra30-plle" }, 186b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra30-pllm" }, 187b1bc04a2SDmitry Osipenko { } 188b1bc04a2SDmitry Osipenko }; 189b1bc04a2SDmitry Osipenko 190b1bc04a2SDmitry Osipenko static struct platform_driver tegra_clock_driver = { 191b1bc04a2SDmitry Osipenko .driver = { 192b1bc04a2SDmitry Osipenko .name = "tegra-clock", 193b1bc04a2SDmitry Osipenko .of_match_table = tegra_clock_match, 194b1bc04a2SDmitry Osipenko .pm = &tegra_clock_pm, 195b1bc04a2SDmitry Osipenko .suppress_bind_attrs = true, 196b1bc04a2SDmitry Osipenko }, 197b1bc04a2SDmitry Osipenko .probe = tegra_clock_probe, 198b1bc04a2SDmitry Osipenko }; 199b1bc04a2SDmitry Osipenko builtin_platform_driver(tegra_clock_driver); 200