Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 064883d8 authored by Tingwei Zhang's avatar Tingwei Zhang
Browse files

coresight: Add regulator and clock vote for coreisht components



Some coresight components are driven by external regulators and
clocks. Add regulator and clock support in coresight driver so
proper regulators and clocks are voted when components are enabled.

Change-Id: Ida626be977d377c6bfcd3f63c1d6f46cccd4f67c
Signed-off-by: default avatarTingwei Zhang <tingwei@codeaurora.org>
parent f5f31790
Loading
Loading
Loading
Loading
+66 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>

#include "coresight-priv.h"

@@ -111,6 +112,53 @@ static void coresight_reset_all_sink(void)
	bus_for_each_dev(&coresight_bustype, NULL, NULL, coresight_reset_sink);
}

void coresight_enable_reg_clk(struct coresight_device *csdev)
{
	struct coresight_reg_clk *reg_clk = csdev->reg_clk;
	int ret;
	int i, j;

	if (IS_ERR_OR_NULL(reg_clk))
		return;

	for (i = 0; i < reg_clk->nr_reg; i++) {
		ret = regulator_enable(reg_clk->reg[i]);
		if (ret)
			goto err_regs;
	}

	for (j = 0; j < reg_clk->nr_clk; j++) {
		ret = clk_prepare_enable(reg_clk->clk[j]);
		if (ret)
			goto err_clks;
	}

	return;

err_clks:
	for (j--; j >= 0; j--)
		clk_disable_unprepare(reg_clk->clk[j]);
err_regs:
	for (i--; i >= 0; i--)
		regulator_disable(reg_clk->reg[i]);
}
EXPORT_SYMBOL(coresight_enable_reg_clk);

void coresight_disable_reg_clk(struct coresight_device *csdev)
{
	struct coresight_reg_clk *reg_clk = csdev->reg_clk;
	int i;

	if (IS_ERR_OR_NULL(reg_clk))
		return;

	for (i = 0; i < reg_clk->nr_clk; i++)
		clk_disable_unprepare(reg_clk->clk[i]);
	for (i = 0; i < reg_clk->nr_reg; i++)
		regulator_disable(reg_clk->reg[i]);
}
EXPORT_SYMBOL(coresight_disable_reg_clk);

static int coresight_find_link_inport(struct coresight_device *csdev,
				      struct coresight_device *parent,
				      struct list_head *path)
@@ -159,10 +207,13 @@ static int coresight_enable_sink(struct coresight_device *csdev, u32 mode)

	if (!csdev->enable) {
		if (sink_ops(csdev)->enable) {
			coresight_enable_reg_clk(csdev);
			ret = sink_ops(csdev)->enable(csdev, mode);
			if (ret)
			if (ret) {
				coresight_disable_reg_clk(csdev);
				return ret;
			}
		}
		csdev->enable = true;
	}

@@ -176,6 +227,7 @@ static void coresight_disable_sink(struct coresight_device *csdev)
	if (atomic_dec_return(csdev->refcnt) == 0) {
		if (sink_ops(csdev)->disable) {
			sink_ops(csdev)->disable(csdev);
			coresight_disable_reg_clk(csdev);
			csdev->enable = false;
			csdev->activated = false;
		}
@@ -210,8 +262,10 @@ static int coresight_enable_link(struct coresight_device *csdev,

	if (atomic_inc_return(&csdev->refcnt[refport]) == 1) {
		if (link_ops(csdev)->enable) {
			coresight_enable_reg_clk(csdev);
			ret = link_ops(csdev)->enable(csdev, inport, outport);
			if (ret) {
				coresight_disable_reg_clk(csdev);
				atomic_dec(&csdev->refcnt[refport]);
				return ret;
			}
@@ -251,8 +305,10 @@ static void coresight_disable_link(struct coresight_device *csdev,
	}

	if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
		if (link_ops(csdev)->disable)
		if (link_ops(csdev)->disable) {
			link_ops(csdev)->disable(csdev, inport, outport);
			coresight_disable_reg_clk(csdev);
		}
	}

	for (i = 0; i < nr_conns; i++)
@@ -274,10 +330,13 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)

	if (!csdev->enable) {
		if (source_ops(csdev)->enable) {
			coresight_enable_reg_clk(csdev);
			ret = source_ops(csdev)->enable(csdev, NULL, mode);
			if (ret)
			if (ret) {
				coresight_disable_reg_clk(csdev);
				return ret;
			}
		}
		csdev->enable = true;
	}

@@ -297,8 +356,10 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
static bool coresight_disable_source(struct coresight_device *csdev)
{
	if (atomic_dec_return(csdev->refcnt) == 0) {
		if (source_ops(csdev)->disable)
		if (source_ops(csdev)->disable) {
			source_ops(csdev)->disable(csdev, NULL);
			coresight_disable_reg_clk(csdev);
		}
		csdev->enable = false;
	}
	return !csdev->enable;
@@ -1195,6 +1256,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
	csdev->subtype = desc->subtype;
	csdev->ops = desc->ops;
	csdev->orphan = false;
	csdev->reg_clk = desc->pdata->reg_clk;

	csdev->dev.type = &coresight_dev_type[desc->type];
	csdev->dev.groups = desc->groups;
+57 −0
Original line number Diff line number Diff line
@@ -122,6 +122,59 @@ int of_coresight_get_cpu(const struct device_node *node)
}
EXPORT_SYMBOL_GPL(of_coresight_get_cpu);

static struct coresight_reg_clk *
of_coresight_get_reg_clk(struct device *dev, const struct device_node *node)
{
	struct coresight_reg_clk *reg_clk;
	const char *clk_name, *reg_name;
	int nr_reg, nr_clk, i, ret;

	nr_reg = of_property_count_strings(node, "qcom,proxy-regs");
	nr_clk = of_property_count_strings(node, "qcom,proxy-clks");
	if (!nr_reg && !nr_clk)
		return NULL;

	reg_clk = devm_kzalloc(dev, sizeof(*reg_clk), GFP_KERNEL);
	if (!reg_clk)
		return ERR_PTR(-ENOMEM);

	reg_clk->nr_reg = nr_reg;
	reg_clk->nr_clk = nr_clk;
	if (nr_reg > 0) {
		reg_clk->reg = devm_kzalloc(dev, nr_reg *
			sizeof(reg_clk->reg), GFP_KERNEL);
		if (!reg_clk->reg)
			return ERR_PTR(-ENOMEM);

		for (i = 0; i < nr_reg; i++) {
			ret = of_property_read_string_index(node,
				"qcom,proxy-regs", i, &reg_name);
			if (ret)
				return ERR_PTR(ret);
			reg_clk->reg[i] = devm_regulator_get(dev, reg_name);
			if (IS_ERR(reg_clk->reg[i]))
				return ERR_PTR(-EINVAL);
		}
	}
	if (nr_clk > 0) {
		reg_clk->clk = devm_kzalloc(dev, nr_clk *
			sizeof(reg_clk->clk), GFP_KERNEL);
		if (!reg_clk->clk)
			return ERR_PTR(-ENOMEM);

		for (i = 0; i < nr_clk; i++) {
			ret = of_property_read_string_index(node,
				"qcom,proxy-clks", i, &clk_name);
			if (ret)
				return ERR_PTR(ret);
			reg_clk->clk[i] = devm_clk_get(dev, clk_name);
			if (IS_ERR(reg_clk->clk[i]))
				return ERR_PTR(-EINVAL);
		}
	}
	return reg_clk;
}

struct coresight_platform_data *
of_get_coresight_platform_data(struct device *dev,
			       const struct device_node *node)
@@ -212,6 +265,10 @@ of_get_coresight_platform_data(struct device *dev,

	pdata->cpu = of_coresight_get_cpu(node);

	pdata->reg_clk = of_coresight_get_reg_clk(dev, node);
	if (IS_ERR(pdata->reg_clk))
		return (void *)(pdata->reg_clk);

	return pdata;
}
EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
+27 −0
Original line number Diff line number Diff line
@@ -89,6 +89,20 @@ union coresight_dev_subtype {
	enum coresight_dev_subtype_helper helper_subtype;
};

/**
 * struct coresight_reg_clk - regulators and clocks need by coresight
 * @nr_reg:	number of regulators
 * @nr_clk:	number of clocks
 * @reg:	regulator list
 * @clk:	clock list
 */
struct coresight_reg_clk {
	int nr_reg;
	int nr_clk;
	struct regulator **reg;
	struct clk **clk;
};

/**
 * struct coresight_platform_data - data harvested from the DT specification
 * @cpu:	the CPU a source belongs to. Only applicable for ETM/PTMs.
@@ -100,6 +114,8 @@ union coresight_dev_subtype {
 * @child_ports:child component port number the current component is
		connected  to.
 * @nr_outport:	number of output ports for this component.
 * @clk:	The clock this component is associated to.
 * @reg_clk:	as defined by @coresight_reg_clk.
 */
struct coresight_platform_data {
	int cpu;
@@ -110,6 +126,8 @@ struct coresight_platform_data {
	const char **child_names;
	int *child_ports;
	int nr_outport;
	struct clk *clk;
	struct coresight_reg_clk *reg_clk;
};

/**
@@ -165,6 +183,8 @@ struct coresight_connection {
 * @activated:	'true' only if a _sink_ has been activated.  A sink can be
		activated but not yet enabled.  Enabling for a _sink_
		happens when a source has been selected for that it.
 * @abort:     captures sink trace on abort.
 * @reg_clk:	as defined by @coresight_reg_clk.
 */
struct coresight_device {
	struct coresight_connection *conns;
@@ -179,6 +199,7 @@ struct coresight_device {
	bool orphan;
	bool enable;	/* true only if configured as part of a path */
	bool activated;	/* true only if a sink is part of a path */
	struct coresight_reg_clk *reg_clk;
};

#define to_coresight_device(d) container_of(d, struct coresight_device, dev)
@@ -275,6 +296,9 @@ extern int coresight_enable(struct coresight_device *csdev);
extern void coresight_disable(struct coresight_device *csdev);
extern int coresight_timeout(void __iomem *addr, u32 offset,
			     int position, int value);
extern void coresight_abort(void);
extern void coresight_disable_reg_clk(struct coresight_device *csdev);
extern void coresight_enable_reg_clk(struct coresight_device *csdev);
#else
static inline struct coresight_device *
coresight_register(struct coresight_desc *desc) { return NULL; }
@@ -284,6 +308,9 @@ coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
static inline void coresight_disable(struct coresight_device *csdev) {}
static inline int coresight_timeout(void __iomem *addr, u32 offset,
				     int position, int value) { return 1; }
static inline void coresight_abort(void) {}
static inline void coresight_disable_reg_clk(struct coresight_device *csdev) {}
static inline void coresight_enable_reg_clk(struct coresight_device *csdev) {}
#endif

#ifdef CONFIG_OF