blob: 3564bbeeb2e81fcb9030e60b13b6242a1740d817 [file] [log] [blame]
Pankaj Kumar32ce1ea2012-04-04 20:29:29 +05301/*
Duy Truong790f06d2013-02-13 16:38:12 -08002 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Pankaj Kumar32ce1ea2012-04-04 20:29:29 +05303 *
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
15#define pr_fmt(fmt) "%s: " fmt, __func__
16
17#include <linux/io.h>
18#include <linux/kernel.h>
19#include <linux/slab.h>
20#include <linux/err.h>
21#include <linux/debugfs.h>
22#include <linux/module.h>
23
24struct msm_cpr_debug_device {
25 struct mutex debug_mutex;
26 struct dentry *dir;
27 int addr_offset;
28 void __iomem *base;
29};
30
31static inline
32void write_reg(struct msm_cpr_debug_device *cpr, u32 value)
33{
34 writel_relaxed(value, cpr->base + cpr->addr_offset);
35}
36
37static inline u32 read_reg(struct msm_cpr_debug_device *cpr)
38{
39 return readl_relaxed(cpr->base + cpr->addr_offset);
40}
41
42static bool msm_cpr_debug_addr_is_valid(int addr)
43{
44 if (addr < 0 || addr > 0x15C) {
45 pr_err("CPR register address is invalid: %d\n", addr);
46 return false;
47 }
48 return true;
49}
50
51static int msm_cpr_debug_data_set(void *data, u64 val)
52{
53 struct msm_cpr_debug_device *debugdev = data;
54 uint32_t reg = val;
55
56 mutex_lock(&debugdev->debug_mutex);
57
58 if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset))
59 write_reg(debugdev, reg);
60
61 mutex_unlock(&debugdev->debug_mutex);
62 return 0;
63}
64
65static int msm_cpr_debug_data_get(void *data, u64 *val)
66{
67 struct msm_cpr_debug_device *debugdev = data;
68 uint32_t reg;
69
70 mutex_lock(&debugdev->debug_mutex);
71
72 if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset)) {
73 reg = read_reg(debugdev);
74 *val = reg;
75 }
76 mutex_unlock(&debugdev->debug_mutex);
77 return 0;
78}
79
80DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, msm_cpr_debug_data_get,
81 msm_cpr_debug_data_set, "0x%02llX\n");
82
83static int msm_cpr_debug_addr_set(void *data, u64 val)
84{
85 struct msm_cpr_debug_device *debugdev = data;
86
87 if (msm_cpr_debug_addr_is_valid(val)) {
88 mutex_lock(&debugdev->debug_mutex);
89 debugdev->addr_offset = val;
90 mutex_unlock(&debugdev->debug_mutex);
91 }
92
93 return 0;
94}
95
96static int msm_cpr_debug_addr_get(void *data, u64 *val)
97{
98 struct msm_cpr_debug_device *debugdev = data;
99
100 mutex_lock(&debugdev->debug_mutex);
101
102 if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset))
103 *val = debugdev->addr_offset;
104
105 mutex_unlock(&debugdev->debug_mutex);
106 return 0;
107}
108
109DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, msm_cpr_debug_addr_get,
110 msm_cpr_debug_addr_set, "0x%03llX\n");
111
112int msm_cpr_debug_init(void *data)
113{
114 char *name = "cpr-debug";
115 struct msm_cpr_debug_device *debugdev;
116 struct dentry *dir;
117 struct dentry *temp;
118 int rc;
119
120 debugdev = kzalloc(sizeof(struct msm_cpr_debug_device), GFP_KERNEL);
121 if (debugdev == NULL) {
122 pr_err("kzalloc failed\n");
123 return -ENOMEM;
124 }
125
126 dir = debugfs_create_dir(name, NULL);
127 if (dir == NULL || IS_ERR(dir)) {
128 pr_err("debugfs_create_dir failed: rc=%ld\n", PTR_ERR(dir));
129 rc = PTR_ERR(dir);
130 goto dir_error;
131 }
132
133 temp = debugfs_create_file("address", S_IRUGO | S_IWUSR, dir, debugdev,
134 &debug_addr_fops);
135 if (temp == NULL || IS_ERR(temp)) {
136 pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
137 rc = PTR_ERR(temp);
138 goto file_error;
139 }
140
141 temp = debugfs_create_file("data", S_IRUGO | S_IWUSR, dir, debugdev,
142 &debug_data_fops);
143 if (temp == NULL || IS_ERR(temp)) {
144 pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
145 rc = PTR_ERR(temp);
146 goto file_error;
147 }
148 debugdev->base = data;
149 debugdev->addr_offset = -1;
150 debugdev->dir = dir;
151 mutex_init(&debugdev->debug_mutex);
152
153 return 0;
154
155file_error:
156 debugfs_remove_recursive(dir);
157dir_error:
158 kfree(debugdev);
159
160 return rc;
161}