|
@@ -39,6 +39,7 @@
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/printk.h>
|
|
#include <linux/printk.h>
|
|
|
|
+#include <linux/pm_opp.h>
|
|
#include <linux/scpi_protocol.h>
|
|
#include <linux/scpi_protocol.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/sort.h>
|
|
#include <linux/sort.h>
|
|
@@ -684,6 +685,65 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
|
|
return info;
|
|
return info;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int scpi_dev_domain_id(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ struct of_phandle_args clkspec;
|
|
|
|
+
|
|
|
|
+ if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells",
|
|
|
|
+ 0, &clkspec))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ return clkspec.args[0];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct scpi_dvfs_info *scpi_dvfs_info(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ int domain = scpi_dev_domain_id(dev);
|
|
|
|
+
|
|
|
|
+ if (domain < 0)
|
|
|
|
+ return ERR_PTR(domain);
|
|
|
|
+
|
|
|
|
+ return scpi_dvfs_get_info(domain);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int scpi_dvfs_get_transition_latency(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ struct scpi_dvfs_info *info = scpi_dvfs_info(dev);
|
|
|
|
+
|
|
|
|
+ if (IS_ERR(info))
|
|
|
|
+ return PTR_ERR(info);
|
|
|
|
+
|
|
|
|
+ if (!info->latency)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ return info->latency;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int scpi_dvfs_add_opps_to_device(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ int idx, ret;
|
|
|
|
+ struct scpi_opp *opp;
|
|
|
|
+ struct scpi_dvfs_info *info = scpi_dvfs_info(dev);
|
|
|
|
+
|
|
|
|
+ if (IS_ERR(info))
|
|
|
|
+ return PTR_ERR(info);
|
|
|
|
+
|
|
|
|
+ if (!info->opps)
|
|
|
|
+ return -EIO;
|
|
|
|
+
|
|
|
|
+ for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
|
|
|
|
+ ret = dev_pm_opp_add(dev, opp->freq, opp->m_volt * 1000);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_warn(dev, "failed to add opp %uHz %umV\n",
|
|
|
|
+ opp->freq, opp->m_volt);
|
|
|
|
+ while (idx-- > 0)
|
|
|
|
+ dev_pm_opp_remove(dev, (--opp)->freq);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int scpi_sensor_get_capability(u16 *sensors)
|
|
static int scpi_sensor_get_capability(u16 *sensors)
|
|
{
|
|
{
|
|
struct sensor_capabilities cap_buf;
|
|
struct sensor_capabilities cap_buf;
|
|
@@ -765,6 +825,9 @@ static struct scpi_ops scpi_ops = {
|
|
.dvfs_get_idx = scpi_dvfs_get_idx,
|
|
.dvfs_get_idx = scpi_dvfs_get_idx,
|
|
.dvfs_set_idx = scpi_dvfs_set_idx,
|
|
.dvfs_set_idx = scpi_dvfs_set_idx,
|
|
.dvfs_get_info = scpi_dvfs_get_info,
|
|
.dvfs_get_info = scpi_dvfs_get_info,
|
|
|
|
+ .device_domain_id = scpi_dev_domain_id,
|
|
|
|
+ .get_transition_latency = scpi_dvfs_get_transition_latency,
|
|
|
|
+ .add_opps_to_device = scpi_dvfs_add_opps_to_device,
|
|
.sensor_get_capability = scpi_sensor_get_capability,
|
|
.sensor_get_capability = scpi_sensor_get_capability,
|
|
.sensor_get_info = scpi_sensor_get_info,
|
|
.sensor_get_info = scpi_sensor_get_info,
|
|
.sensor_get_value = scpi_sensor_get_value,
|
|
.sensor_get_value = scpi_sensor_get_value,
|