blob: 79a27f40504ce6c42abfde70b198792c03febaba [file] [log] [blame]
Pratik Patel17f3b822011-11-21 12:41:47 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Pratik Patel7831c082011-06-08 21:44:37 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
Pratik Patelcf418622011-09-22 11:15:11 -070015#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/device.h>
Pratik Patel7831c082011-06-08 21:44:37 -070018#include <linux/platform_device.h>
19#include <linux/io.h>
20#include <linux/err.h>
Pratik Patel16aefdb2012-05-30 10:41:23 -070021#include <linux/slab.h>
Pratik Patelf17b1472012-05-25 22:23:52 -070022#include <linux/clk.h>
Pratik Patel1746b8f2012-06-02 21:11:41 -070023#include <linux/coresight.h>
Pratik Patel7831c082011-06-08 21:44:37 -070024
Pratik Patel1746b8f2012-06-02 21:11:41 -070025#include "coresight-priv.h"
Pratik Patel7831c082011-06-08 21:44:37 -070026
Pratik Patel16aefdb2012-05-30 10:41:23 -070027#define funnel_writel(drvdata, id, val, off) \
28 __raw_writel((val), drvdata->base + (SZ_4K * id) + off)
29#define funnel_readl(drvdata, id, off) \
30 __raw_readl(drvdata->base + (SZ_4K * id) + off)
Pratik Patel7831c082011-06-08 21:44:37 -070031
Pratik Patel61de7302012-03-07 12:06:10 -080032#define FUNNEL_FUNCTL (0x000)
33#define FUNNEL_PRICTL (0x004)
34#define FUNNEL_ITATBDATA0 (0xEEC)
35#define FUNNEL_ITATBCTR2 (0xEF0)
36#define FUNNEL_ITATBCTR1 (0xEF4)
37#define FUNNEL_ITATBCTR0 (0xEF8)
Pratik Patel7831c082011-06-08 21:44:37 -070038
39
40#define FUNNEL_LOCK(id) \
41do { \
42 mb(); \
Pratik Patel6fb38342012-06-03 14:51:38 -070043 funnel_writel(drvdata, id, 0x0, CORESIGHT_LAR); \
Pratik Patel7831c082011-06-08 21:44:37 -070044} while (0)
45#define FUNNEL_UNLOCK(id) \
46do { \
Pratik Patel6fb38342012-06-03 14:51:38 -070047 funnel_writel(drvdata, id, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
Pratik Patel7831c082011-06-08 21:44:37 -070048 mb(); \
49} while (0)
50
Pratik Patel61de7302012-03-07 12:06:10 -080051#define FUNNEL_HOLDTIME_MASK (0xF00)
52#define FUNNEL_HOLDTIME_SHFT (0x8)
53#define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT)
Pratik Patel7831c082011-06-08 21:44:37 -070054
Pratik Patel16aefdb2012-05-30 10:41:23 -070055struct funnel_drvdata {
Pratik Patel7831c082011-06-08 21:44:37 -070056 void __iomem *base;
57 bool enabled;
Pratik Patel783408a2012-03-21 10:28:12 -070058 struct mutex mutex;
Pratik Patel7831c082011-06-08 21:44:37 -070059 struct device *dev;
Pratik Patel6630ebe2012-03-06 16:44:22 -080060 struct kobject *kobj;
Pratik Patelf17b1472012-05-25 22:23:52 -070061 struct clk *clk;
Pratik Patel6630ebe2012-03-06 16:44:22 -080062 uint32_t priority;
Pratik Patel7831c082011-06-08 21:44:37 -070063};
64
Pratik Patel16aefdb2012-05-30 10:41:23 -070065static struct funnel_drvdata *drvdata;
Pratik Patel7831c082011-06-08 21:44:37 -070066
67static void __funnel_enable(uint8_t id, uint32_t port_mask)
68{
69 uint32_t functl;
70
71 FUNNEL_UNLOCK(id);
72
Pratik Patel16aefdb2012-05-30 10:41:23 -070073 functl = funnel_readl(drvdata, id, FUNNEL_FUNCTL);
Pratik Patel61de7302012-03-07 12:06:10 -080074 functl &= ~FUNNEL_HOLDTIME_MASK;
75 functl |= FUNNEL_HOLDTIME;
Pratik Patel7831c082011-06-08 21:44:37 -070076 functl |= port_mask;
Pratik Patel16aefdb2012-05-30 10:41:23 -070077 funnel_writel(drvdata, id, functl, FUNNEL_FUNCTL);
78 funnel_writel(drvdata, id, drvdata->priority, FUNNEL_PRICTL);
Pratik Patel7831c082011-06-08 21:44:37 -070079
80 FUNNEL_LOCK(id);
81}
82
Pratik Patelf17b1472012-05-25 22:23:52 -070083int funnel_enable(uint8_t id, uint32_t port_mask)
Pratik Patel7831c082011-06-08 21:44:37 -070084{
Pratik Patelf17b1472012-05-25 22:23:52 -070085 int ret;
86
Pratik Patel16aefdb2012-05-30 10:41:23 -070087 ret = clk_prepare_enable(drvdata->clk);
Pratik Patelf17b1472012-05-25 22:23:52 -070088 if (ret)
89 return ret;
90
Pratik Patel16aefdb2012-05-30 10:41:23 -070091 mutex_lock(&drvdata->mutex);
Pratik Patel7831c082011-06-08 21:44:37 -070092 __funnel_enable(id, port_mask);
Pratik Patel16aefdb2012-05-30 10:41:23 -070093 drvdata->enabled = true;
94 dev_info(drvdata->dev, "FUNNEL port mask 0x%lx enabled\n",
Pratik Patel7831c082011-06-08 21:44:37 -070095 (unsigned long) port_mask);
Pratik Patel16aefdb2012-05-30 10:41:23 -070096 mutex_unlock(&drvdata->mutex);
Pratik Patelf17b1472012-05-25 22:23:52 -070097
98 return 0;
Pratik Patel7831c082011-06-08 21:44:37 -070099}
100
101static void __funnel_disable(uint8_t id, uint32_t port_mask)
102{
103 uint32_t functl;
104
105 FUNNEL_UNLOCK(id);
106
Pratik Patel16aefdb2012-05-30 10:41:23 -0700107 functl = funnel_readl(drvdata, id, FUNNEL_FUNCTL);
Pratik Patel7831c082011-06-08 21:44:37 -0700108 functl &= ~port_mask;
Pratik Patel16aefdb2012-05-30 10:41:23 -0700109 funnel_writel(drvdata, id, functl, FUNNEL_FUNCTL);
Pratik Patel7831c082011-06-08 21:44:37 -0700110
111 FUNNEL_LOCK(id);
112}
113
114void funnel_disable(uint8_t id, uint32_t port_mask)
115{
Pratik Patel16aefdb2012-05-30 10:41:23 -0700116 mutex_lock(&drvdata->mutex);
Pratik Patel7831c082011-06-08 21:44:37 -0700117 __funnel_disable(id, port_mask);
Pratik Patel16aefdb2012-05-30 10:41:23 -0700118 drvdata->enabled = false;
119 dev_info(drvdata->dev, "FUNNEL port mask 0x%lx disabled\n",
Pratik Patel7831c082011-06-08 21:44:37 -0700120 (unsigned long) port_mask);
Pratik Patel16aefdb2012-05-30 10:41:23 -0700121 mutex_unlock(&drvdata->mutex);
Pratik Patelf17b1472012-05-25 22:23:52 -0700122
Pratik Patel16aefdb2012-05-30 10:41:23 -0700123 clk_disable_unprepare(drvdata->clk);
Pratik Patel7831c082011-06-08 21:44:37 -0700124}
125
Pratik Patela9c0e062012-05-28 13:45:35 -0700126static ssize_t funnel_show_priority(struct device *dev,
127 struct device_attribute *attr, char *buf)
128{
Pratik Patel16aefdb2012-05-30 10:41:23 -0700129 unsigned long val = drvdata->priority;
Pratik Patela9c0e062012-05-28 13:45:35 -0700130 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
131}
Pratik Patel6630ebe2012-03-06 16:44:22 -0800132
Pratik Patela9c0e062012-05-28 13:45:35 -0700133static ssize_t funnel_store_priority(struct device *dev,
134 struct device_attribute *attr,
135 const char *buf, size_t size)
Pratik Patel6630ebe2012-03-06 16:44:22 -0800136{
137 unsigned long val;
138
139 if (sscanf(buf, "%lx", &val) != 1)
140 return -EINVAL;
141
Pratik Patel16aefdb2012-05-30 10:41:23 -0700142 drvdata->priority = val;
Pratik Patela9c0e062012-05-28 13:45:35 -0700143 return size;
Pratik Patel6630ebe2012-03-06 16:44:22 -0800144}
Pratik Patela9c0e062012-05-28 13:45:35 -0700145static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, funnel_show_priority,
146 funnel_store_priority);
Pratik Patel6630ebe2012-03-06 16:44:22 -0800147
Stephen Boyda9510502012-04-24 16:23:34 -0700148static int __devinit funnel_sysfs_init(void)
Pratik Patel6630ebe2012-03-06 16:44:22 -0800149{
150 int ret;
151
Pratik Patel16aefdb2012-05-30 10:41:23 -0700152 drvdata->kobj = kobject_create_and_add("funnel", qdss_get_modulekobj());
153 if (!drvdata->kobj) {
154 dev_err(drvdata->dev, "failed to create FUNNEL sysfs kobject\n");
Pratik Patel6630ebe2012-03-06 16:44:22 -0800155 ret = -ENOMEM;
156 goto err_create;
157 }
158
Pratik Patel16aefdb2012-05-30 10:41:23 -0700159 ret = sysfs_create_file(drvdata->kobj, &dev_attr_priority.attr);
Pratik Patel6630ebe2012-03-06 16:44:22 -0800160 if (ret) {
Pratik Patel16aefdb2012-05-30 10:41:23 -0700161 dev_err(drvdata->dev, "failed to create FUNNEL sysfs priority"
Pratik Patel6630ebe2012-03-06 16:44:22 -0800162 " attribute\n");
163 goto err_file;
164 }
165
166 return 0;
167err_file:
Pratik Patel16aefdb2012-05-30 10:41:23 -0700168 kobject_put(drvdata->kobj);
Pratik Patel6630ebe2012-03-06 16:44:22 -0800169err_create:
170 return ret;
171}
172
Stephen Boyda9510502012-04-24 16:23:34 -0700173static void __devexit funnel_sysfs_exit(void)
Pratik Patel6630ebe2012-03-06 16:44:22 -0800174{
Pratik Patel16aefdb2012-05-30 10:41:23 -0700175 sysfs_remove_file(drvdata->kobj, &dev_attr_priority.attr);
176 kobject_put(drvdata->kobj);
Pratik Patel6630ebe2012-03-06 16:44:22 -0800177}
178
Pratik Patel7831c082011-06-08 21:44:37 -0700179static int __devinit funnel_probe(struct platform_device *pdev)
180{
181 int ret;
182 struct resource *res;
183
Pratik Patel16aefdb2012-05-30 10:41:23 -0700184 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
185 if (!drvdata) {
186 ret = -ENOMEM;
187 goto err_kzalloc_drvdata;
188 }
189
Pratik Patel7831c082011-06-08 21:44:37 -0700190 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
191 if (!res) {
192 ret = -EINVAL;
193 goto err_res;
194 }
195
Pratik Patel16aefdb2012-05-30 10:41:23 -0700196 drvdata->base = ioremap_nocache(res->start, resource_size(res));
197 if (!drvdata->base) {
Pratik Patel7831c082011-06-08 21:44:37 -0700198 ret = -EINVAL;
199 goto err_ioremap;
200 }
201
Pratik Patel16aefdb2012-05-30 10:41:23 -0700202 drvdata->dev = &pdev->dev;
Pratik Patel7831c082011-06-08 21:44:37 -0700203
Pratik Patel16aefdb2012-05-30 10:41:23 -0700204 mutex_init(&drvdata->mutex);
Pratik Patel783408a2012-03-21 10:28:12 -0700205
Pratik Patel16aefdb2012-05-30 10:41:23 -0700206 drvdata->clk = clk_get(drvdata->dev, "core_clk");
207 if (IS_ERR(drvdata->clk)) {
208 ret = PTR_ERR(drvdata->clk);
Pratik Patelf17b1472012-05-25 22:23:52 -0700209 goto err_clk_get;
210 }
211
Pratik Patel6fb38342012-06-03 14:51:38 -0700212 ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
Pratik Patelf17b1472012-05-25 22:23:52 -0700213 if (ret)
214 goto err_clk_rate;
215
Pratik Patel6630ebe2012-03-06 16:44:22 -0800216 funnel_sysfs_init();
217
Pratik Patel16aefdb2012-05-30 10:41:23 -0700218 dev_info(drvdata->dev, "FUNNEL initialized\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700219 return 0;
220
Pratik Patelf17b1472012-05-25 22:23:52 -0700221err_clk_rate:
Pratik Patel16aefdb2012-05-30 10:41:23 -0700222 clk_put(drvdata->clk);
Pratik Patelf17b1472012-05-25 22:23:52 -0700223err_clk_get:
Pratik Patel16aefdb2012-05-30 10:41:23 -0700224 mutex_destroy(&drvdata->mutex);
225 iounmap(drvdata->base);
Pratik Patel7831c082011-06-08 21:44:37 -0700226err_ioremap:
227err_res:
Pratik Patel16aefdb2012-05-30 10:41:23 -0700228 kfree(drvdata);
229err_kzalloc_drvdata:
230 dev_err(drvdata->dev, "FUNNEL init failed\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700231 return ret;
232}
233
Pratik Patelf6fe9182012-03-20 14:04:18 -0700234static int __devexit funnel_remove(struct platform_device *pdev)
Pratik Patel7831c082011-06-08 21:44:37 -0700235{
Pratik Patel16aefdb2012-05-30 10:41:23 -0700236 if (drvdata->enabled)
Pratik Patel7831c082011-06-08 21:44:37 -0700237 funnel_disable(0x0, 0xFF);
Pratik Patel6630ebe2012-03-06 16:44:22 -0800238 funnel_sysfs_exit();
Pratik Patel16aefdb2012-05-30 10:41:23 -0700239 clk_put(drvdata->clk);
240 mutex_destroy(&drvdata->mutex);
241 iounmap(drvdata->base);
242 kfree(drvdata);
Pratik Patel7831c082011-06-08 21:44:37 -0700243
244 return 0;
245}
246
Pratik Patel9eae4822012-05-14 17:34:53 -0700247static struct of_device_id funnel_match[] = {
248 {.compatible = "qcom,msm-funnel"},
249 {}
250};
251
Pratik Patel7831c082011-06-08 21:44:37 -0700252static struct platform_driver funnel_driver = {
253 .probe = funnel_probe,
Pratik Patelf6fe9182012-03-20 14:04:18 -0700254 .remove = __devexit_p(funnel_remove),
Pratik Patel7831c082011-06-08 21:44:37 -0700255 .driver = {
256 .name = "msm_funnel",
Pratik Patel9eae4822012-05-14 17:34:53 -0700257 .owner = THIS_MODULE,
258 .of_match_table = funnel_match,
Pratik Patel7831c082011-06-08 21:44:37 -0700259 },
260};
261
Pratik Patelf6fe9182012-03-20 14:04:18 -0700262static int __init funnel_init(void)
Pratik Patel7831c082011-06-08 21:44:37 -0700263{
264 return platform_driver_register(&funnel_driver);
265}
Pratik Patelf6fe9182012-03-20 14:04:18 -0700266module_init(funnel_init);
Pratik Patel7831c082011-06-08 21:44:37 -0700267
Pratik Patelf6fe9182012-03-20 14:04:18 -0700268static void __exit funnel_exit(void)
Pratik Patel7831c082011-06-08 21:44:37 -0700269{
270 platform_driver_unregister(&funnel_driver);
271}
Pratik Patelf6fe9182012-03-20 14:04:18 -0700272module_exit(funnel_exit);
273
274MODULE_LICENSE("GPL v2");
275MODULE_DESCRIPTION("CoreSight Funnel driver");