static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq, u32 flags) { int err = 0; struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct busfreq_data_int *data = platform_get_drvdata(pdev); struct dev_pm_opp *opp; unsigned long old_freq, freq; unsigned long volt; rcu_read_lock(); opp = devfreq_recommended_opp(dev, _freq, flags); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(dev, "%s: Invalid OPP.\n", __func__); return PTR_ERR(opp); } freq = dev_pm_opp_get_freq(opp); volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); old_freq = data->curr_freq; if (old_freq == freq) return 0; dev_dbg(dev, "targetting %lukHz %luuV\n", freq, volt); mutex_lock(&data->lock); if (data->disabled) goto out; if (freq > exynos5_int_opp_table[0].clk) pm_qos_update_request(&data->int_req, freq * 16 / 1000); else pm_qos_update_request(&data->int_req, -1); if (old_freq < freq) err = exynos5_int_setvolt(data, volt); if (err) goto out; err = clk_set_rate(data->int_clk, freq * 1000); if (err) goto out; if (old_freq > freq) err = exynos5_int_setvolt(data, volt); if (err) goto out; data->curr_freq = freq; out: mutex_unlock(&data->lock); return err; }
static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev)); struct dev_pm_opp *opp; unsigned long old_clk_rate = pfdev->devfreq.cur_freq; unsigned long target_volt, target_rate; int err; opp = devfreq_recommended_opp(dev, freq, flags); if (IS_ERR(opp)) return PTR_ERR(opp); target_rate = dev_pm_opp_get_freq(opp); target_volt = dev_pm_opp_get_voltage(opp); dev_pm_opp_put(opp); if (old_clk_rate == target_rate) return 0; /* * If frequency scaling from low to high, adjust voltage first. * If frequency scaling from high to low, adjust frequency first. */ if (old_clk_rate < target_rate) { err = regulator_set_voltage(pfdev->regulator, target_volt, target_volt); if (err) { dev_err(dev, "Cannot set voltage %lu uV\n", target_volt); return err; } } err = clk_set_rate(pfdev->clock, target_rate); if (err) { dev_err(dev, "Cannot set frequency %lu (%d)\n", target_rate, err); regulator_set_voltage(pfdev->regulator, pfdev->devfreq.cur_volt, pfdev->devfreq.cur_volt); return err; } if (old_clk_rate > target_rate) { err = regulator_set_voltage(pfdev->regulator, target_volt, target_volt); if (err) dev_err(dev, "Cannot set voltage %lu uV\n", target_volt); } pfdev->devfreq.cur_freq = target_rate; pfdev->devfreq.cur_volt = target_volt; return 0; }
static int exynos4_bus_target(struct device *dev, unsigned long *_freq, u32 flags) { int err = 0; struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct busfreq_data *data = platform_get_drvdata(pdev); struct dev_pm_opp *opp; unsigned long freq; unsigned long old_freq = data->curr_oppinfo.rate; struct busfreq_opp_info new_oppinfo; rcu_read_lock(); opp = devfreq_recommended_opp(dev, _freq, flags); if (IS_ERR(opp)) { rcu_read_unlock(); return PTR_ERR(opp); } new_oppinfo.rate = dev_pm_opp_get_freq(opp); new_oppinfo.volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); freq = new_oppinfo.rate; if (old_freq == freq) return 0; dev_dbg(dev, "targeting %lukHz %luuV\n", freq, new_oppinfo.volt); mutex_lock(&data->lock); if (data->disabled) goto out; if (old_freq < freq) err = exynos4_bus_setvolt(data, &new_oppinfo, &data->curr_oppinfo); if (err) goto out; if (old_freq != freq) { switch (data->type) { case TYPE_BUSF_EXYNOS4210: err = exynos4210_set_busclk(data, &new_oppinfo); break; case TYPE_BUSF_EXYNOS4x12: err = exynos4x12_set_busclk(data, &new_oppinfo); break; default: err = -EINVAL; } } if (err) goto out; if (old_freq > freq) err = exynos4_bus_setvolt(data, &new_oppinfo, &data->curr_oppinfo); if (err) goto out; data->curr_oppinfo = new_oppinfo; out: mutex_unlock(&data->lock); return err; }
static int cpufreq_init(struct cpufreq_policy *policy) { struct cpufreq_frequency_table *freq_table; struct private_data *priv; struct device *cpu_dev; struct clk *cpu_clk; struct dev_pm_opp *suspend_opp; unsigned int transition_latency; bool opp_v1 = false; const char *name; int ret; cpu_dev = get_cpu_device(policy->cpu); if (!cpu_dev) { pr_err("failed to get cpu%d device\n", policy->cpu); return -ENODEV; } cpu_clk = clk_get(cpu_dev, NULL); if (IS_ERR(cpu_clk)) { ret = PTR_ERR(cpu_clk); dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret); return ret; } /* Get OPP-sharing information from "operating-points-v2" bindings */ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); if (ret) { /* * operating-points-v2 not supported, fallback to old method of * finding shared-OPPs for backward compatibility. */ if (ret == -ENOENT) opp_v1 = true; else goto out_put_clk; } /* * OPP layer will be taking care of regulators now, but it needs to know * the name of the regulator first. */ name = find_supply_name(cpu_dev); if (name) { ret = dev_pm_opp_set_regulator(cpu_dev, name); if (ret) { dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n", policy->cpu, ret); goto out_put_clk; } } /* * Initialize OPP tables for all policy->cpus. They will be shared by * all CPUs which have marked their CPUs shared with OPP bindings. * * For platforms not using operating-points-v2 bindings, we do this * before updating policy->cpus. Otherwise, we will end up creating * duplicate OPPs for policy->cpus. * * OPPs might be populated at runtime, don't check for error here */ dev_pm_opp_of_cpumask_add_table(policy->cpus); /* * But we need OPP table to function so if it is not there let's * give platform code chance to provide it for us. */ ret = dev_pm_opp_get_opp_count(cpu_dev); if (ret <= 0) { dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); ret = -EPROBE_DEFER; goto out_free_opp; } if (opp_v1) { struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data(); if (!pd || !pd->independent_clocks) cpumask_setall(policy->cpus); /* * OPP tables are initialized only for policy->cpu, do it for * others as well. */ ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); if (ret) dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", __func__, ret); } priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; goto out_free_opp; } priv->reg_name = name; ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); if (ret) { dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); goto out_free_priv; } priv->cpu_dev = cpu_dev; policy->driver_data = priv; policy->clk = cpu_clk; rcu_read_lock(); suspend_opp = dev_pm_opp_get_suspend_opp(cpu_dev); if (suspend_opp) policy->suspend_freq = dev_pm_opp_get_freq(suspend_opp) / 1000; rcu_read_unlock(); ret = cpufreq_table_validate_and_show(policy, freq_table); if (ret) { dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, ret); goto out_free_cpufreq_table; } /* Support turbo/boost mode */ if (policy_has_boost_freq(policy)) { /* This gets disabled by core on driver unregister */ ret = cpufreq_enable_boost_support(); if (ret) goto out_free_cpufreq_table; cpufreq_dt_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs; } transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev); if (!transition_latency) transition_latency = CPUFREQ_ETERNAL; policy->cpuinfo.transition_latency = transition_latency; return 0; out_free_cpufreq_table: dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); out_free_priv: kfree(priv); out_free_opp: dev_pm_opp_of_cpumask_remove_table(policy->cpus); if (name) dev_pm_opp_put_regulator(cpu_dev); out_put_clk: clk_put(cpu_clk); return ret; }
static int exynos8890_devfreq_int_init_freq_table(struct device *dev, struct exynos_devfreq_data *data) { u32 max_freq, min_freq; unsigned long tmp_max, tmp_min; struct dev_pm_opp *target_opp; u32 flags = 0; int i; max_freq = (u32)cal_dfs_get_max_freq(dvfs_int); if (!max_freq) { dev_err(dev, "failed get max frequency\n"); return -EINVAL; } dev_info(dev, "max_freq: %uKhz, get_max_freq: %uKhz\n", data->max_freq, max_freq); if (max_freq < data->max_freq) { rcu_read_lock(); flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; tmp_max = (unsigned long)max_freq; target_opp = devfreq_recommended_opp(dev, &tmp_max, flags); if (IS_ERR(target_opp)) { rcu_read_unlock(); dev_err(dev, "not found valid OPP for max_freq\n"); return PTR_ERR(target_opp); } data->max_freq = dev_pm_opp_get_freq(target_opp); rcu_read_unlock(); } min_freq = (u32)cal_dfs_get_min_freq(dvfs_int); if (!min_freq) { dev_err(dev, "failed get min frequency\n"); return -EINVAL; } dev_info(dev, "min_freq: %uKhz, get_min_freq: %uKhz\n", data->min_freq, min_freq); if (min_freq > data->min_freq) { rcu_read_lock(); flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; tmp_min = (unsigned long)min_freq; target_opp = devfreq_recommended_opp(dev, &tmp_min, flags); if (IS_ERR(target_opp)) { rcu_read_unlock(); dev_err(dev, "not found valid OPP for min_freq\n"); return PTR_ERR(target_opp); } data->min_freq = dev_pm_opp_get_freq(target_opp); rcu_read_unlock(); } dev_info(dev, "min_freq: %uKhz, max_freq: %uKhz\n", data->min_freq, data->max_freq); for (i = 0; i < data->max_state; i++) { if (data->opp_list[i].freq > data->max_freq || data->opp_list[i].freq < data->min_freq) dev_pm_opp_disable(dev, (unsigned long)data->opp_list[i].freq); } return 0; }