Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1/*
  2 * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
  3 *
  4 * This program is free software; you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License version 2 and
  6 * only version 2 as published by the Free Software Foundation.
  7 *
  8 * This program is distributed in the hope that it will be useful,
  9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11 * GNU General Public License for more details.
 12 */
 13
 14#include <linux/amba/bus.h>
 15#include <linux/clk.h>
 16#include <linux/coresight.h>
 17#include <linux/device.h>
 18#include <linux/err.h>
 19#include <linux/init.h>
 20#include <linux/io.h>
 21#include <linux/kernel.h>
 22#include <linux/of.h>
 23#include <linux/pm_runtime.h>
 24#include <linux/slab.h>
 25
 26#include "coresight-priv.h"
 27
 28#define REPLICATOR_IDFILTER0		0x000
 29#define REPLICATOR_IDFILTER1		0x004
 30
 31/**
 32 * struct replicator_state - specifics associated to a replicator component
 33 * @base:	memory mapped base address for this component.
 34 * @dev:	the device entity associated with this component
 35 * @atclk:	optional clock for the core parts of the replicator.
 36 * @csdev:	component vitals needed by the framework
 37 */
 38struct replicator_state {
 39	void __iomem		*base;
 40	struct device		*dev;
 41	struct clk		*atclk;
 42	struct coresight_device	*csdev;
 43};
 44
 45static int replicator_enable(struct coresight_device *csdev, int inport,
 46			      int outport)
 47{
 48	struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent);
 49
 50	CS_UNLOCK(drvdata->base);
 51
 52	/*
 53	 * Ensure that the other port is disabled
 54	 * 0x00 - passing through the replicator unimpeded
 55	 * 0xff - disable (or impede) the flow of ATB data
 56	 */
 57	if (outport == 0) {
 58		writel_relaxed(0x00, drvdata->base + REPLICATOR_IDFILTER0);
 59		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
 60	} else {
 61		writel_relaxed(0x00, drvdata->base + REPLICATOR_IDFILTER1);
 62		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
 63	}
 64
 65	CS_LOCK(drvdata->base);
 66
 67	dev_info(drvdata->dev, "REPLICATOR enabled\n");
 68	return 0;
 69}
 70
 71static void replicator_disable(struct coresight_device *csdev, int inport,
 72				int outport)
 73{
 74	struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent);
 75
 76	CS_UNLOCK(drvdata->base);
 77
 78	/* disable the flow of ATB data through port */
 79	if (outport == 0)
 80		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
 81	else
 82		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
 83
 84	CS_LOCK(drvdata->base);
 85
 86	dev_info(drvdata->dev, "REPLICATOR disabled\n");
 87}
 88
 89static const struct coresight_ops_link replicator_link_ops = {
 90	.enable		= replicator_enable,
 91	.disable	= replicator_disable,
 92};
 93
 94static const struct coresight_ops replicator_cs_ops = {
 95	.link_ops	= &replicator_link_ops,
 96};
 97
 98static int replicator_probe(struct amba_device *adev, const struct amba_id *id)
 99{
100	int ret;
101	struct device *dev = &adev->dev;
102	struct resource *res = &adev->res;
103	struct coresight_platform_data *pdata = NULL;
104	struct replicator_state *drvdata;
105	struct coresight_desc *desc;
106	struct device_node *np = adev->dev.of_node;
107	void __iomem *base;
108
109	if (np) {
110		pdata = of_get_coresight_platform_data(dev, np);
111		if (IS_ERR(pdata))
112			return PTR_ERR(pdata);
113		adev->dev.platform_data = pdata;
114	}
115
116	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
117	if (!drvdata)
118		return -ENOMEM;
119
120	drvdata->dev = &adev->dev;
121	drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
122	if (!IS_ERR(drvdata->atclk)) {
123		ret = clk_prepare_enable(drvdata->atclk);
124		if (ret)
125			return ret;
126	}
127
128	/* Validity for the resource is already checked by the AMBA core */
129	base = devm_ioremap_resource(dev, res);
130	if (IS_ERR(base))
131		return PTR_ERR(base);
132
133	drvdata->base = base;
134	dev_set_drvdata(dev, drvdata);
135	pm_runtime_put(&adev->dev);
136
137	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
138	if (!desc)
139		return -ENOMEM;
140
141	desc->type = CORESIGHT_DEV_TYPE_LINK;
142	desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
143	desc->ops = &replicator_cs_ops;
144	desc->pdata = adev->dev.platform_data;
145	desc->dev = &adev->dev;
146	drvdata->csdev = coresight_register(desc);
147	if (IS_ERR(drvdata->csdev))
148		return PTR_ERR(drvdata->csdev);
149
150	dev_info(dev, "%s initialized\n", (char *)id->data);
151	return 0;
152}
153
154#ifdef CONFIG_PM
155static int replicator_runtime_suspend(struct device *dev)
156{
157	struct replicator_state *drvdata = dev_get_drvdata(dev);
158
159	if (drvdata && !IS_ERR(drvdata->atclk))
160		clk_disable_unprepare(drvdata->atclk);
161
162	return 0;
163}
164
165static int replicator_runtime_resume(struct device *dev)
166{
167	struct replicator_state *drvdata = dev_get_drvdata(dev);
168
169	if (drvdata && !IS_ERR(drvdata->atclk))
170		clk_prepare_enable(drvdata->atclk);
171
172	return 0;
173}
174#endif
175
176static const struct dev_pm_ops replicator_dev_pm_ops = {
177	SET_RUNTIME_PM_OPS(replicator_runtime_suspend,
178			   replicator_runtime_resume,
179			   NULL)
180};
181
182static struct amba_id replicator_ids[] = {
183	{
184		.id     = 0x0003b909,
185		.mask   = 0x0003ffff,
186		.data	= "REPLICATOR 1.0",
187	},
188	{ 0, 0 },
189};
190
191static struct amba_driver replicator_driver = {
192	.drv = {
193		.name	= "coresight-replicator-qcom",
194		.pm	= &replicator_dev_pm_ops,
195		.suppress_bind_attrs = true,
196	},
197	.probe		= replicator_probe,
198	.id_table	= replicator_ids,
199};
200builtin_amba_driver(replicator_driver);