#include <linux/device.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm_opp.h>
#include "tegra-emc-common.h"
void tegra_emc_rate_requests_init(struct tegra_emc_rate_requests *reqs,
struct device *dev)
{
unsigned int i;
mutex_init(&reqs->rate_lock);
reqs->dev = dev;
for (i = 0; i < TEGRA_EMC_RATE_TYPE_MAX; i++) {
reqs->requested_rate[i].min_rate = 0;
reqs->requested_rate[i].max_rate = ULONG_MAX;
}
}
EXPORT_SYMBOL_GPL(tegra_emc_rate_requests_init);
static int tegra_emc_request_rate(struct tegra_emc_rate_requests *reqs,
unsigned long new_min_rate,
unsigned long new_max_rate,
enum tegra_emc_rate_request_type type)
{
struct tegra_emc_rate_request *req = reqs->requested_rate;
unsigned long min_rate = 0, max_rate = ULONG_MAX;
unsigned int i;
int err;
lockdep_assert_held(&reqs->rate_lock);
for (i = 0; i < TEGRA_EMC_RATE_TYPE_MAX; i++, req++) {
if (i == type) {
min_rate = max(new_min_rate, min_rate);
max_rate = min(new_max_rate, max_rate);
} else {
min_rate = max(req->min_rate, min_rate);
max_rate = min(req->max_rate, max_rate);
}
}
if (min_rate > max_rate) {
dev_err_ratelimited(reqs->dev, "%s: type %u: out of range: %lu %lu\n",
__func__, type, min_rate, max_rate);
return -ERANGE;
}
err = dev_pm_opp_set_rate(reqs->dev, min_rate);
if (err)
return err;
reqs->requested_rate[type].min_rate = new_min_rate;
reqs->requested_rate[type].max_rate = new_max_rate;
return 0;
}
int tegra_emc_set_min_rate(struct tegra_emc_rate_requests *reqs,
unsigned long rate,
enum tegra_emc_rate_request_type type)
{
struct tegra_emc_rate_request *req = &reqs->requested_rate[type];
int ret;
mutex_lock(&reqs->rate_lock);
ret = tegra_emc_request_rate(reqs, rate, req->max_rate, type);
mutex_unlock(&reqs->rate_lock);
return ret;
}
EXPORT_SYMBOL_GPL(tegra_emc_set_min_rate);
int tegra_emc_set_max_rate(struct tegra_emc_rate_requests *reqs,
unsigned long rate,
enum tegra_emc_rate_request_type type)
{
struct tegra_emc_rate_request *req = &reqs->requested_rate[type];
int ret;
mutex_lock(&reqs->rate_lock);
ret = tegra_emc_request_rate(reqs, req->min_rate, rate, type);
mutex_unlock(&reqs->rate_lock);
return ret;
}
EXPORT_SYMBOL_GPL(tegra_emc_set_max_rate);
MODULE_DESCRIPTION("NVIDIA Tegra EMC common code");
MODULE_LICENSE("GPL");