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

Commit 88f8f14a 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 b55100db
Loading
Loading
Loading
Loading
+67 −5
Original line number Diff line number Diff line
/* Copyright (c) 2012, 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012, 2017-2019, 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
@@ -25,6 +25,7 @@
#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>

#include "coresight-priv.h"

@@ -116,6 +117,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)
{
@@ -158,10 +206,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;
	}

@@ -175,6 +226,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;
		}
@@ -208,8 +260,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;
			}
@@ -248,8 +302,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++)
@@ -271,10 +327,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;
	}

@@ -294,8 +353,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;
@@ -1150,6 +1211,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
@@ -118,6 +118,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)
@@ -199,6 +252,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);
+23 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012, 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012, 2017-2019, 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
@@ -84,6 +84,20 @@ struct coresight_dev_subtype {
	enum coresight_dev_subtype_source source_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.
@@ -95,6 +109,7 @@ struct coresight_dev_subtype {
		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;
@@ -105,6 +120,7 @@ struct coresight_platform_data {
	int *child_ports;
	int nr_outport;
	struct clk *clk;
	struct coresight_reg_clk *reg_clk;
};

/**
@@ -159,6 +175,7 @@ struct coresight_connection {
		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;
@@ -173,6 +190,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)
@@ -255,6 +273,8 @@ 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; }
@@ -265,6 +285,8 @@ 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