summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorAjay Singh Parmar <aparmar@codeaurora.org>2016-06-22 17:31:46 -0700
committerDhaval Patel <pdhaval@codeaurora.org>2016-08-01 11:58:07 -0700
commita8872e7407238eebd1a69cbe087c4ce5e4000660 (patch)
tree0dd4557e5ac7ee1f575253e0c0a56acac01fb337 /drivers/gpu
parent989b6c672e98c8c9c217bcc88ac291f7c6c7f2b0 (diff)
drm/msm/dsi-staging: add clock and power utilities
Add clock and power utilities for DSI driver components. Read the clocks, regulators, gpios etc from device tree and make them available for use. Change-Id: Id3b08bac976da6834e636cbd79d05b3ba4b91557 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_clk_pwr.c673
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_clk_pwr.h214
2 files changed, 887 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_pwr.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_pwr.c
new file mode 100644
index 000000000000..b10c80286a97
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_pwr.c
@@ -0,0 +1,673 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk/msm-clk.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "dsi_clk_pwr.h"
+
+#define INC_REFCOUNT(s, start_func) \
+ ({ \
+ int rc = 0; \
+ if ((s)->refcount == 0) { \
+ rc = start_func(s); \
+ if (rc) \
+ pr_err("failed to enable, rc = %d\n", rc); \
+ } \
+ (s)->refcount++; \
+ rc; \
+ })
+
+#define DEC_REFCOUNT(s, stop_func) \
+ ({ \
+ int rc = 0; \
+ if ((s)->refcount == 0) { \
+ pr_err("unbalanced refcount\n"); \
+ } else { \
+ (s)->refcount--; \
+ if ((s)->refcount == 0) { \
+ rc = stop_func(s); \
+ if (rc) \
+ pr_err("disable failed, rc=%d\n", rc); \
+ } \
+ } \
+ rc; \
+ })
+
+static int dsi_core_clk_start(struct dsi_core_clk_info *clks)
+{
+ int rc = 0;
+
+ rc = clk_prepare_enable(clks->mdp_core_clk);
+ if (rc) {
+ pr_err("failed to enable mdp_core_clk, rc=%d\n", rc);
+ goto error;
+ }
+
+ rc = clk_prepare_enable(clks->iface_clk);
+ if (rc) {
+ pr_err("failed to enable iface_clk, rc=%d\n", rc);
+ goto error_disable_core_clk;
+ }
+
+ rc = clk_prepare_enable(clks->bus_clk);
+ if (rc) {
+ pr_err("failed to enable bus_clk, rc=%d\n", rc);
+ goto error_disable_iface_clk;
+ }
+
+ rc = clk_prepare_enable(clks->core_mmss_clk);
+ if (rc) {
+ pr_err("failed to enable core_mmss_clk, rc=%d\n", rc);
+ goto error_disable_bus_clk;
+ }
+
+ return rc;
+
+error_disable_bus_clk:
+ clk_disable_unprepare(clks->bus_clk);
+error_disable_iface_clk:
+ clk_disable_unprepare(clks->iface_clk);
+error_disable_core_clk:
+ clk_disable_unprepare(clks->mdp_core_clk);
+error:
+ return rc;
+}
+
+static int dsi_core_clk_stop(struct dsi_core_clk_info *clks)
+{
+ clk_disable_unprepare(clks->core_mmss_clk);
+ clk_disable_unprepare(clks->bus_clk);
+ clk_disable_unprepare(clks->iface_clk);
+ clk_disable_unprepare(clks->mdp_core_clk);
+
+ return 0;
+}
+
+static int dsi_link_clk_set_rate(struct dsi_link_clk_info *l_clks)
+{
+ int rc = 0;
+
+ rc = clk_set_rate(l_clks->esc_clk, l_clks->esc_clk_rate);
+ if (rc) {
+ pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
+ goto error;
+ }
+
+ rc = clk_set_rate(l_clks->byte_clk, l_clks->byte_clk_rate);
+ if (rc) {
+ pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc);
+ goto error;
+ }
+
+ rc = clk_set_rate(l_clks->pixel_clk, l_clks->pixel_clk_rate);
+ if (rc) {
+ pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc);
+ goto error;
+ }
+error:
+ return rc;
+}
+
+static int dsi_link_clk_prepare(struct dsi_link_clk_info *l_clks)
+{
+ int rc = 0;
+
+ rc = clk_prepare(l_clks->esc_clk);
+ if (rc) {
+ pr_err("Failed to prepare dsi esc clk, rc=%d\n", rc);
+ goto esc_clk_err;
+ }
+
+ rc = clk_prepare(l_clks->byte_clk);
+ if (rc) {
+ pr_err("Failed to prepare dsi byte clk, rc=%d\n", rc);
+ goto byte_clk_err;
+ }
+
+ rc = clk_prepare(l_clks->pixel_clk);
+ if (rc) {
+ pr_err("Failed to prepare dsi pixel clk, rc=%d\n", rc);
+ goto pixel_clk_err;
+ }
+
+ return rc;
+
+pixel_clk_err:
+ clk_unprepare(l_clks->byte_clk);
+byte_clk_err:
+ clk_unprepare(l_clks->esc_clk);
+esc_clk_err:
+ return rc;
+}
+
+static void dsi_link_clk_unprepare(struct dsi_link_clk_info *l_clks)
+{
+ clk_unprepare(l_clks->pixel_clk);
+ clk_unprepare(l_clks->byte_clk);
+ clk_unprepare(l_clks->esc_clk);
+}
+
+static int dsi_link_clk_enable(struct dsi_link_clk_info *l_clks)
+{
+ int rc = 0;
+
+ rc = clk_enable(l_clks->esc_clk);
+ if (rc) {
+ pr_err("Failed to enable dsi esc clk, rc=%d\n", rc);
+ goto esc_clk_err;
+ }
+
+ rc = clk_enable(l_clks->byte_clk);
+ if (rc) {
+ pr_err("Failed to enable dsi byte clk, rc=%d\n", rc);
+ goto byte_clk_err;
+ }
+
+ rc = clk_enable(l_clks->pixel_clk);
+ if (rc) {
+ pr_err("Failed to enable dsi pixel clk, rc=%d\n", rc);
+ goto pixel_clk_err;
+ }
+
+ return rc;
+
+pixel_clk_err:
+ clk_disable(l_clks->byte_clk);
+byte_clk_err:
+ clk_disable(l_clks->esc_clk);
+esc_clk_err:
+ return rc;
+}
+
+static void dsi_link_clk_disable(struct dsi_link_clk_info *l_clks)
+{
+ clk_disable(l_clks->esc_clk);
+ clk_disable(l_clks->pixel_clk);
+ clk_disable(l_clks->byte_clk);
+}
+
+/**
+ * dsi_link_clk_start() - enable dsi link clocks
+ */
+static int dsi_link_clk_start(struct dsi_link_clk_info *clks)
+{
+ int rc = 0;
+
+ if (clks->set_new_rate) {
+ rc = dsi_link_clk_set_rate(clks);
+ if (rc) {
+ pr_err("failed to set clk rates, rc = %d\n", rc);
+ goto error;
+ } else {
+ clks->set_new_rate = false;
+ }
+ }
+
+ rc = dsi_link_clk_prepare(clks);
+ if (rc) {
+ pr_err("failed to prepare link clks, rc = %d\n", rc);
+ goto error;
+ }
+
+ rc = dsi_link_clk_enable(clks);
+ if (rc) {
+ pr_err("failed to enable link clks, rc = %d\n", rc);
+ goto error_unprepare;
+ }
+
+ pr_debug("Link clocks are enabled\n");
+ return rc;
+error_unprepare:
+ dsi_link_clk_unprepare(clks);
+error:
+ return rc;
+}
+
+/**
+ * dsi_link_clk_stop() - Stop DSI link clocks.
+ */
+static int dsi_link_clk_stop(struct dsi_link_clk_info *clks)
+{
+ dsi_link_clk_disable(clks);
+ dsi_link_clk_unprepare(clks);
+
+ pr_debug("Link clocks disabled\n");
+
+ return 0;
+}
+
+/*
+ * dsi_pwr_parse_supply_node() - parse power supply node from root device node
+ */
+static int dsi_pwr_parse_supply_node(struct device_node *root,
+ struct dsi_regulator_info *regs)
+{
+ int rc = 0;
+ int i = 0;
+ u32 tmp = 0;
+ struct device_node *node = NULL;
+
+ for_each_child_of_node(root, node) {
+ const char *st = NULL;
+
+ rc = of_property_read_string(node, "qcom,supply-name", &st);
+ if (rc) {
+ pr_err("failed to read name, rc = %d\n", rc);
+ goto error;
+ }
+
+ snprintf(regs->vregs[i].vreg_name,
+ strlen(regs->vregs[i].vreg_name),
+ "%s", st);
+
+ rc = of_property_read_u32(node, "qcom,supply-min-voltage",
+ &tmp);
+ if (rc) {
+ pr_err("failed to read min voltage, rc = %d\n", rc);
+ goto error;
+ }
+ regs->vregs[i].min_voltage = tmp;
+
+ rc = of_property_read_u32(node, "qcom,supply-max-voltage",
+ &tmp);
+ if (rc) {
+ pr_err("failed to read max voltage, rc = %d\n", rc);
+ goto error;
+ }
+ regs->vregs[i].max_voltage = tmp;
+
+ rc = of_property_read_u32(node, "qcom,supply-enable-load",
+ &tmp);
+ if (rc) {
+ pr_err("failed to read enable load, rc = %d\n", rc);
+ goto error;
+ }
+ regs->vregs[i].enable_load = tmp;
+
+ rc = of_property_read_u32(node, "qcom,supply-disable-load",
+ &tmp);
+ if (rc) {
+ pr_err("failed to read disable load, rc = %d\n", rc);
+ goto error;
+ }
+ regs->vregs[i].disable_load = tmp;
+
+ /* Optional values */
+ rc = of_property_read_u32(node, "qcom,supply-pre-on-sleep",
+ &tmp);
+ if (rc) {
+ pr_debug("pre-on-sleep not specified\n");
+ rc = 0;
+ } else {
+ regs->vregs[i].pre_on_sleep = tmp;
+ }
+
+ rc = of_property_read_u32(node, "qcom,supply-pre-off-sleep",
+ &tmp);
+ if (rc) {
+ pr_debug("pre-off-sleep not specified\n");
+ rc = 0;
+ } else {
+ regs->vregs[i].pre_off_sleep = tmp;
+ }
+
+ rc = of_property_read_u32(node, "qcom,supply-post-on-sleep",
+ &tmp);
+ if (rc) {
+ pr_debug("post-on-sleep not specified\n");
+ rc = 0;
+ } else {
+ regs->vregs[i].post_on_sleep = tmp;
+ }
+
+ rc = of_property_read_u32(node, "qcom,supply-post-off-sleep",
+ &tmp);
+ if (rc) {
+ pr_debug("post-off-sleep not specified\n");
+ rc = 0;
+ } else {
+ regs->vregs[i].post_off_sleep = tmp;
+ }
+
+ ++i;
+ pr_debug("[%s] minv=%d maxv=%d, en_load=%d, dis_load=%d\n",
+ regs->vregs[i].vreg_name,
+ regs->vregs[i].min_voltage,
+ regs->vregs[i].max_voltage,
+ regs->vregs[i].enable_load,
+ regs->vregs[i].disable_load);
+ }
+
+error:
+ return rc;
+}
+
+/**
+ * dsi_pwr_enable_vregs() - enable/disable regulators
+ */
+static int dsi_pwr_enable_vregs(struct dsi_regulator_info *regs, bool enable)
+{
+ int rc = 0, i = 0;
+ struct dsi_vreg *vreg;
+ int num_of_v = 0;
+
+ if (enable) {
+ for (i = 0; i < regs->count; i++) {
+ vreg = &regs->vregs[i];
+ if (vreg->pre_on_sleep)
+ msleep(vreg->pre_on_sleep);
+
+ rc = regulator_set_load(vreg->vreg,
+ vreg->enable_load);
+ if (rc < 0) {
+ pr_err("Setting optimum mode failed for %s\n",
+ vreg->vreg_name);
+ goto error;
+ }
+ num_of_v = regulator_count_voltages(vreg->vreg);
+ if (num_of_v > 0) {
+ rc = regulator_set_voltage(vreg->vreg,
+ vreg->min_voltage,
+ vreg->max_voltage);
+ if (rc) {
+ pr_err("Set voltage(%s) fail, rc=%d\n",
+ vreg->vreg_name, rc);
+ goto error_disable_opt_mode;
+ }
+ }
+
+ rc = regulator_enable(vreg->vreg);
+ if (rc) {
+ pr_err("enable failed for %s, rc=%d\n",
+ vreg->vreg_name, rc);
+ goto error_disable_voltage;
+ }
+
+ if (vreg->post_on_sleep)
+ msleep(vreg->post_on_sleep);
+ }
+ } else {
+ for (i = (regs->count - 1); i >= 0; i--) {
+ if (regs->vregs[i].pre_off_sleep)
+ msleep(regs->vregs[i].pre_off_sleep);
+
+ (void)regulator_set_load(regs->vregs[i].vreg,
+ regs->vregs[i].disable_load);
+ (void)regulator_disable(regs->vregs[i].vreg);
+
+ if (regs->vregs[i].post_off_sleep)
+ msleep(regs->vregs[i].post_off_sleep);
+ }
+ }
+
+ return 0;
+error_disable_opt_mode:
+ (void)regulator_set_load(regs->vregs[i].vreg,
+ regs->vregs[i].disable_load);
+
+error_disable_voltage:
+ if (num_of_v > 0)
+ (void)regulator_set_voltage(regs->vregs[i].vreg,
+ 0, regs->vregs[i].max_voltage);
+error:
+ for (i--; i >= 0; i--) {
+ if (regs->vregs[i].pre_off_sleep)
+ msleep(regs->vregs[i].pre_off_sleep);
+
+ (void)regulator_set_load(regs->vregs[i].vreg,
+ regs->vregs[i].disable_load);
+
+ num_of_v = regulator_count_voltages(regs->vregs[i].vreg);
+ if (num_of_v > 0)
+ (void)regulator_set_voltage(regs->vregs[i].vreg,
+ 0, regs->vregs[i].max_voltage);
+
+ (void)regulator_disable(regs->vregs[i].vreg);
+
+ if (regs->vregs[i].post_off_sleep)
+ msleep(regs->vregs[i].post_off_sleep);
+ }
+
+ return rc;
+}
+
+/**
+ * dsi_clk_pwr_get_dt_vreg_data - parse regulator supply information
+ * @dev: Device whose of_node needs to be parsed.
+ * @regs: Pointer where regulator information will be copied to.
+ * @supply_name: Name of the supply node.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_pwr_get_dt_vreg_data(struct device *dev,
+ struct dsi_regulator_info *regs,
+ char *supply_name)
+{
+ int rc = 0;
+ struct device_node *of_node = NULL;
+ struct device_node *supply_node = NULL;
+ struct device_node *supply_root_node = NULL;
+
+ if (!dev || !regs) {
+ pr_err("Bad params\n");
+ return -EINVAL;
+ }
+
+ of_node = dev->of_node;
+ regs->count = 0;
+ supply_root_node = of_get_child_by_name(of_node, supply_name);
+ if (!supply_root_node) {
+ supply_root_node = of_parse_phandle(of_node, supply_name, 0);
+ if (!supply_root_node) {
+ pr_err("No supply entry present for %s\n", supply_name);
+ return -EINVAL;
+ }
+ }
+
+ for_each_child_of_node(supply_root_node, supply_node)
+ regs->count++;
+
+ if (regs->count == 0) {
+ pr_err("No vregs defined for %s\n", supply_name);
+ return -EINVAL;
+ }
+
+ regs->vregs = devm_kcalloc(dev, regs->count, sizeof(*regs->vregs),
+ GFP_KERNEL);
+ if (!regs->vregs) {
+ regs->count = 0;
+ return -ENOMEM;
+ }
+
+ rc = dsi_pwr_parse_supply_node(supply_root_node, regs);
+ if (rc) {
+ pr_err("failed to parse supply node for %s, rc = %d\n",
+ supply_name, rc);
+ devm_kfree(dev, regs->vregs);
+ regs->vregs = NULL;
+ regs->count = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * dsi_pwr_enable_regulator() - enable a set of regulators
+ * @regs: Pointer to set of regulators to enable or disable.
+ * @enable: Enable/Disable regulators.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_pwr_enable_regulator(struct dsi_regulator_info *regs, bool enable)
+{
+ int rc = 0;
+
+ if (enable) {
+ if (regs->refcount == 0) {
+ rc = dsi_pwr_enable_vregs(regs, true);
+ if (rc)
+ pr_err("failed to enable regulators\n");
+ }
+ regs->refcount++;
+ } else {
+ if (regs->refcount == 0) {
+ pr_err("Unbalanced regulator off\n");
+ } else {
+ regs->refcount--;
+ if (regs->refcount == 0) {
+ rc = dsi_pwr_enable_vregs(regs, false);
+ if (rc)
+ pr_err("failed to disable vregs\n");
+ }
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * dsi_clk_enable_core_clks() - enable DSI core clocks
+ * @clks: DSI core clock information.
+ * @enable: enable/disable DSI core clocks.
+ *
+ * A ref count is maintained, so caller should make sure disable and enable
+ * calls are balanced.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_enable_core_clks(struct dsi_core_clk_info *clks, bool enable)
+{
+ int rc = 0;
+
+ if (enable)
+ rc = INC_REFCOUNT(clks, dsi_core_clk_start);
+ else
+ rc = DEC_REFCOUNT(clks, dsi_core_clk_stop);
+
+ return rc;
+}
+
+/**
+ * dsi_clk_enable_link_clks() - enable DSI link clocks
+ * @clks: DSI link clock information.
+ * @enable: enable/disable DSI link clocks.
+ *
+ * A ref count is maintained, so caller should make sure disable and enable
+ * calls are balanced.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_enable_link_clks(struct dsi_link_clk_info *clks, bool enable)
+{
+ int rc = 0;
+
+ if (enable)
+ rc = INC_REFCOUNT(clks, dsi_link_clk_start);
+ else
+ rc = DEC_REFCOUNT(clks, dsi_link_clk_stop);
+
+ return rc;
+}
+
+/**
+ * dsi_clk_set_link_frequencies() - set frequencies for link clks
+ * @clks: Link clock information
+ * @pixel_clk: pixel clock frequency in KHz.
+ * @byte_clk: Byte clock frequency in KHz.
+ * @esc_clk: Escape clock frequency in KHz.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_set_link_frequencies(struct dsi_link_clk_info *clks,
+ u64 pixel_clk,
+ u64 byte_clk,
+ u64 esc_clk)
+{
+ int rc = 0;
+
+ clks->pixel_clk_rate = pixel_clk;
+ clks->byte_clk_rate = byte_clk;
+ clks->esc_clk_rate = esc_clk;
+ clks->set_new_rate = true;
+
+ return rc;
+}
+
+/**
+ * dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock
+ * @clks: DSI link clock information.
+ * @pixel_clk: Pixel clock rate in KHz.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_set_pixel_clk_rate(struct dsi_link_clk_info *clks, u64 pixel_clk)
+{
+ int rc = 0;
+
+ rc = clk_set_rate(clks->pixel_clk, pixel_clk);
+ if (rc)
+ pr_err("failed to set clk rate for pixel clk, rc=%d\n", rc);
+ else
+ clks->pixel_clk_rate = pixel_clk;
+
+ return rc;
+}
+
+/**
+ * dsi_clk_set_byte_clk_rate() - set frequency for byte clock
+ * @clks: DSI link clock information.
+ * @byte_clk: Byte clock rate in KHz.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_set_byte_clk_rate(struct dsi_link_clk_info *clks, u64 byte_clk)
+{
+ int rc = 0;
+
+ rc = clk_set_rate(clks->byte_clk, byte_clk);
+ if (rc)
+ pr_err("failed to set clk rate for byte clk, rc=%d\n", rc);
+ else
+ clks->byte_clk_rate = byte_clk;
+
+ return rc;
+}
+
+/**
+ * dsi_clk_update_parent() - update parent clocks for specified clock
+ * @parent: link clock pair which are set as parent.
+ * @child: link clock pair whose parent has to be set.
+ */
+int dsi_clk_update_parent(struct dsi_clk_link_set *parent,
+ struct dsi_clk_link_set *child)
+{
+ int rc = 0;
+
+ rc = clk_set_parent(child->byte_clk, parent->byte_clk);
+ if (rc) {
+ pr_err("failed to set byte clk parent\n");
+ goto error;
+ }
+
+ rc = clk_set_parent(child->pixel_clk, parent->pixel_clk);
+ if (rc) {
+ pr_err("failed to set pixel clk parent\n");
+ goto error;
+ }
+error:
+ return rc;
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_pwr.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_pwr.h
new file mode 100644
index 000000000000..223ca4ec4290
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_pwr.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _DSI_CLK_PWR_H_
+#define _DSI_CLK_PWR_H_
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+
+/**
+ * struct dsi_vreg - regulator information for DSI regulators
+ * @vreg: Handle to the regulator.
+ * @vreg_name: Regulator name.
+ * @min_voltage: Minimum voltage in uV.
+ * @max_voltage: Maximum voltage in uV.
+ * @enable_load: Load, in uA, when enabled.
+ * @disable_load: Load, in uA, when disabled.
+ * @pre_on_sleep: Sleep, in ms, before enabling the regulator.
+ * @post_on_sleep: Sleep, in ms, after enabling the regulator.
+ * @pre_off_sleep: Sleep, in ms, before disabling the regulator.
+ * @post_off_sleep: Sleep, in ms, after disabling the regulator.
+ */
+struct dsi_vreg {
+ struct regulator *vreg;
+ char vreg_name[32];
+ u32 min_voltage;
+ u32 max_voltage;
+ u32 enable_load;
+ u32 disable_load;
+ u32 pre_on_sleep;
+ u32 post_on_sleep;
+ u32 pre_off_sleep;
+ u32 post_off_sleep;
+};
+
+/**
+ * struct dsi_regulator_info - set of vregs that are turned on/off together.
+ * @vregs: Array of dsi_vreg structures.
+ * @count: Number of vregs.
+ * @refcount: Reference counting for enabling.
+ */
+struct dsi_regulator_info {
+ struct dsi_vreg *vregs;
+ u32 count;
+ u32 refcount;
+};
+
+/**
+ * struct dsi_core_clk_info - Core clock information for DSI hardware
+ * @mdp_core_clk: Handle to MDP core clock.
+ * @iface_clk: Handle to MDP interface clock.
+ * @core_mmss_clk: Handle to MMSS core clock.
+ * @bus_clk: Handle to bus clock.
+ * @refcount: Reference count for core clocks.
+ * @clk_state: Current clock state.
+ */
+struct dsi_core_clk_info {
+ struct clk *mdp_core_clk;
+ struct clk *iface_clk;
+ struct clk *core_mmss_clk;
+ struct clk *bus_clk;
+
+ u32 refcount;
+ u32 clk_state;
+};
+
+/**
+ * struct dsi_link_clk_info - Link clock information for DSI hardware.
+ * @byte_clk: Handle to DSI byte clock.
+ * @byte_clk_rate: Frequency of DSI byte clock in KHz.
+ * @pixel_clk: Handle to DSI pixel clock.
+ * @pixel_clk_rate: Frequency of DSI pixel clock in KHz.
+ * @esc_clk: Handle to DSI escape clock.
+ * @esc_clk_rate: Frequency of DSI escape clock in KHz.
+ * @refcount: Reference count for link clocks.
+ * @clk_state: Current clock state.
+ * @set_new_rate: private flag used by clock utility.
+ */
+struct dsi_link_clk_info {
+ struct clk *byte_clk;
+ u64 byte_clk_rate;
+
+ struct clk *pixel_clk;
+ u64 pixel_clk_rate;
+
+ struct clk *esc_clk;
+ u64 esc_clk_rate;
+
+ u32 refcount;
+ u32 clk_state;
+ bool set_new_rate;
+};
+
+/**
+ * struct dsi_clk_link_set - Pair of clock handles to describe link clocks
+ * @byte_clk: Handle to DSi byte clock.
+ * @pixel_clk: Handle to DSI pixel clock.
+ */
+struct dsi_clk_link_set {
+ struct clk *byte_clk;
+ struct clk *pixel_clk;
+};
+
+/**
+ * dsi_clk_pwr_of_get_vreg_data - parse regulator supply information
+ * @of_node: Device of node to parse for supply information.
+ * @regs: Pointer where regulator information will be copied to.
+ * @supply_name: Name of the supply node.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_pwr_of_get_vreg_data(struct device_node *of_node,
+ struct dsi_regulator_info *regs,
+ char *supply_name);
+
+/**
+ * dsi_clk_pwr_get_dt_vreg_data - parse regulator supply information
+ * @dev: Device whose of_node needs to be parsed.
+ * @regs: Pointer where regulator information will be copied to.
+ * @supply_name: Name of the supply node.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_pwr_get_dt_vreg_data(struct device *dev,
+ struct dsi_regulator_info *regs,
+ char *supply_name);
+
+/**
+ * dsi_pwr_enable_regulator() - enable a set of regulators
+ * @regs: Pointer to set of regulators to enable or disable.
+ * @enable: Enable/Disable regulators.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_pwr_enable_regulator(struct dsi_regulator_info *regs, bool enable);
+
+/**
+ * dsi_clk_enable_core_clks() - enable DSI core clocks
+ * @clks: DSI core clock information.
+ * @enable: enable/disable DSI core clocks.
+ *
+ * A ref count is maintained, so caller should make sure disable and enable
+ * calls are balanced.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_enable_core_clks(struct dsi_core_clk_info *clks, bool enable);
+
+/**
+ * dsi_clk_enable_link_clks() - enable DSI link clocks
+ * @clks: DSI link clock information.
+ * @enable: enable/disable DSI link clocks.
+ *
+ * A ref count is maintained, so caller should make sure disable and enable
+ * calls are balanced.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_enable_link_clks(struct dsi_link_clk_info *clks, bool enable);
+
+/**
+ * dsi_clk_set_link_frequencies() - set frequencies for link clks
+ * @clks: Link clock information
+ * @pixel_clk: pixel clock frequency in KHz.
+ * @byte_clk: Byte clock frequency in KHz.
+ * @esc_clk: Escape clock frequency in KHz.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_set_link_frequencies(struct dsi_link_clk_info *clks,
+ u64 pixel_clk,
+ u64 byte_clk,
+ u64 esc_clk);
+
+/**
+ * dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock
+ * @clks: DSI link clock information.
+ * @pixel_clk: Pixel clock rate in KHz.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_set_pixel_clk_rate(struct dsi_link_clk_info *clks, u64 pixel_clk);
+
+/**
+ * dsi_clk_set_byte_clk_rate() - set frequency for byte clock
+ * @clks: DSI link clock information.
+ * @byte_clk: Byte clock rate in KHz.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+int dsi_clk_set_byte_clk_rate(struct dsi_link_clk_info *clks, u64 byte_clk);
+
+/**
+ * dsi_clk_update_parent() - update parent clocks for specified clock
+ * @parent: link clock pair which are set as parent.
+ * @child: link clock pair whose parent has to be set.
+ */
+int dsi_clk_update_parent(struct dsi_clk_link_set *parent,
+ struct dsi_clk_link_set *child);
+#endif /* _DSI_CLK_PWR_H_ */