blob: 80ec65acb57bba7ceff9c1cccff763c3362b0f7b [file] [log] [blame]
Pratik Patel74929432011-12-26 12:03:41 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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>
15#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/device.h>
18#include <linux/platform_device.h>
19#include <linux/io.h>
20#include <linux/err.h>
Pratik Patelbf3e77442012-03-18 18:30:43 -070021#include <linux/export.h>
Pratik Patel74929432011-12-26 12:03:41 -080022#include <mach/rpm.h>
23
24#include "rpm_resources.h"
Pratik Patelb27a9352012-03-17 22:37:21 -070025#include "qdss-priv.h"
Pratik Patel74929432011-12-26 12:03:41 -080026
27enum {
28 QDSS_CLK_OFF,
29 QDSS_CLK_ON_DBG,
30 QDSS_CLK_ON_HSDBG,
31};
32
Pratik Patel6630ebe2012-03-06 16:44:22 -080033struct qdss_ctx {
34 struct kobject *modulekobj;
35 uint8_t max_clk;
Pratik Patelbf3e77442012-03-18 18:30:43 -070036 uint8_t clk_count;
37 struct mutex clk_mutex;
Pratik Patel6630ebe2012-03-06 16:44:22 -080038};
39
40static struct qdss_ctx qdss;
41
42
43struct kobject *qdss_get_modulekobj(void)
44{
45 return qdss.modulekobj;
46}
Pratik Patel74929432011-12-26 12:03:41 -080047
Pratik Patelbf3e77442012-03-18 18:30:43 -070048/**
49 * qdss_clk_enable - enable qdss clocks
50 *
51 * Enables qdss clocks via RPM if they aren't already enabled, otherwise
52 * increments the reference count.
53 *
54 * CONTEXT:
55 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
56 *
57 * RETURNS:
58 * 0 on success, non-zero on failure
59 */
Pratik Patel74929432011-12-26 12:03:41 -080060int qdss_clk_enable(void)
61{
62 int ret;
Pratik Patel74929432011-12-26 12:03:41 -080063 struct msm_rpm_iv_pair iv;
Pratik Patel74929432011-12-26 12:03:41 -080064
Pratik Patelbf3e77442012-03-18 18:30:43 -070065 mutex_lock(&qdss.clk_mutex);
66 if (qdss.clk_count == 0) {
67 iv.id = MSM_RPM_ID_QDSS_CLK;
68 if (qdss.max_clk)
69 iv.value = QDSS_CLK_ON_HSDBG;
70 else
71 iv.value = QDSS_CLK_ON_DBG;
72 ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
73 if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
74 goto err_clk;
75 }
76 qdss.clk_count++;
77 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -080078 return 0;
Pratik Patel74929432011-12-26 12:03:41 -080079err_clk:
Pratik Patelbf3e77442012-03-18 18:30:43 -070080 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -080081 return ret;
82}
Pratik Patelbf3e77442012-03-18 18:30:43 -070083EXPORT_SYMBOL(qdss_clk_enable);
Pratik Patel74929432011-12-26 12:03:41 -080084
Pratik Patelbf3e77442012-03-18 18:30:43 -070085/**
86 * qdss_clk_disable - disable qdss clocks
87 *
88 * Disables qdss clocks via RPM if the reference count is one, otherwise
89 * decrements the reference count.
90 *
91 * CONTEXT:
92 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
93 */
Pratik Patel74929432011-12-26 12:03:41 -080094void qdss_clk_disable(void)
95{
96 int ret;
97 struct msm_rpm_iv_pair iv;
98
Pratik Patelbf3e77442012-03-18 18:30:43 -070099 mutex_lock(&qdss.clk_mutex);
100 if (WARN(qdss.clk_count == 0, "qdss clks are unbalanced\n"))
101 goto out;
102 if (qdss.clk_count == 1) {
103 iv.id = MSM_RPM_ID_QDSS_CLK;
104 iv.value = QDSS_CLK_OFF;
105 ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
106 WARN(ret, "qdss clks not disabled (%d)\n", ret);
107 }
108 qdss.clk_count--;
109out:
110 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -0800111}
Pratik Patelbf3e77442012-03-18 18:30:43 -0700112EXPORT_SYMBOL(qdss_clk_disable);
Pratik Patel59e29942011-12-27 10:31:33 -0800113
Pratik Patel6630ebe2012-03-06 16:44:22 -0800114#define QDSS_ATTR(name) \
115static struct kobj_attribute name##_attr = \
116 __ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
117
118static ssize_t max_clk_store(struct kobject *kobj,
119 struct kobj_attribute *attr,
120 const char *buf, size_t n)
121{
122 unsigned long val;
123
124 if (sscanf(buf, "%lx", &val) != 1)
125 return -EINVAL;
126
127 qdss.max_clk = val;
128 return n;
129}
130static ssize_t max_clk_show(struct kobject *kobj,
131 struct kobj_attribute *attr,
132 char *buf)
133{
134 unsigned long val = qdss.max_clk;
135 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
136}
137QDSS_ATTR(max_clk);
138
139static int __init qdss_sysfs_init(void)
140{
141 int ret;
142
143 qdss.modulekobj = kset_find_obj(module_kset, KBUILD_MODNAME);
144 if (!qdss.modulekobj) {
145 pr_err("failed to find QDSS sysfs module kobject\n");
146 ret = -ENOENT;
147 goto err;
148 }
149
150 ret = sysfs_create_file(qdss.modulekobj, &max_clk_attr.attr);
151 if (ret) {
152 pr_err("failed to create QDSS sysfs max_clk attribute\n");
153 goto err;
154 }
155
156 return 0;
157err:
158 return ret;
159}
160
161static void qdss_sysfs_exit(void)
162{
163 sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
164}
165
Pratik Patel59e29942011-12-27 10:31:33 -0800166static int __init qdss_init(void)
167{
168 int ret;
169
Pratik Patelbf3e77442012-03-18 18:30:43 -0700170 mutex_init(&qdss.clk_mutex);
171
Pratik Patel6630ebe2012-03-06 16:44:22 -0800172 ret = qdss_sysfs_init();
173 if (ret)
174 goto err_sysfs;
Pratik Patel59e29942011-12-27 10:31:33 -0800175 ret = etb_init();
176 if (ret)
177 goto err_etb;
178 ret = tpiu_init();
179 if (ret)
180 goto err_tpiu;
181 ret = funnel_init();
182 if (ret)
183 goto err_funnel;
Pratik Patel492b3012012-03-06 14:22:30 -0800184 ret = etm_init();
Pratik Patel59e29942011-12-27 10:31:33 -0800185 if (ret)
Pratik Patel492b3012012-03-06 14:22:30 -0800186 goto err_etm;
Pratik Patel59e29942011-12-27 10:31:33 -0800187
Pratik Patel61de7302012-03-07 12:06:10 -0800188 pr_info("QDSS initialized\n");
Pratik Patel59e29942011-12-27 10:31:33 -0800189 return 0;
Pratik Patel492b3012012-03-06 14:22:30 -0800190err_etm:
Pratik Patel59e29942011-12-27 10:31:33 -0800191 funnel_exit();
192err_funnel:
193 tpiu_exit();
194err_tpiu:
195 etb_exit();
196err_etb:
Pratik Patel6630ebe2012-03-06 16:44:22 -0800197 qdss_sysfs_exit();
198err_sysfs:
Pratik Patelbf3e77442012-03-18 18:30:43 -0700199 mutex_destroy(&qdss.clk_mutex);
Pratik Patel61de7302012-03-07 12:06:10 -0800200 pr_err("QDSS init failed\n");
Pratik Patel59e29942011-12-27 10:31:33 -0800201 return ret;
202}
203module_init(qdss_init);
204
205static void __exit qdss_exit(void)
206{
Pratik Patel6630ebe2012-03-06 16:44:22 -0800207 qdss_sysfs_exit();
Pratik Patel492b3012012-03-06 14:22:30 -0800208 etm_exit();
Pratik Patel59e29942011-12-27 10:31:33 -0800209 funnel_exit();
210 tpiu_exit();
211 etb_exit();
Pratik Patelbf3e77442012-03-18 18:30:43 -0700212 mutex_destroy(&qdss.clk_mutex);
Pratik Patel59e29942011-12-27 10:31:33 -0800213}
214module_exit(qdss_exit);
215
216MODULE_LICENSE("GPL v2");
217MODULE_DESCRIPTION("Qualcomm Debug SubSystem Driver");