blob: 92741379785f0e0be92599e5a33a8db3f46228e9 [file] [log] [blame]
Rohit Vaswani8f709c02013-02-13 15:49:56 -08001/* Copyright (c) 2013, The Linux Foundation. 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/module.h>
14#include <linux/kernel.h>
15#include <linux/spinlock.h>
16#include <linux/semaphore.h>
17#include <linux/kthread.h>
18#include <linux/sched.h>
19#include <linux/timer.h>
20#include <linux/ctype.h>
21#include <linux/uaccess.h>
22#include <linux/errno.h>
23
24#include "wallclk.h"
25
26#define WALLCLK_SYSFS_MODULE_NAME "wallclk_sysfs"
27
28static struct kobject *wallclk_kobj;
29
30static ssize_t sfn_show(struct kobject *kobj,
31 struct kobj_attribute *attr,
32 char *buf)
33{
34 int rc;
35
36 rc = wallclk_get_sfn();
37 if (rc < 0)
38 return rc;
39 return snprintf(buf, 10, "%d\n", rc);
40}
41
42static ssize_t sfn_store(struct kobject *kobj,
43 struct kobj_attribute *attr,
44 const char *buf,
45 size_t count)
46{
47 u16 sfn;
48 int rc;
49
50 if (kstrtou16(buf, 0, &sfn)) {
51 printk(KERN_ERR "%s: sfn input is not a valid u16 value\n",
52 WALLCLK_SYSFS_MODULE_NAME);
53 rc = -EINVAL;
54 goto out;
55 }
56
57 rc = wallclk_set_sfn(sfn);
58
59 if (rc) {
60 printk(KERN_ERR "%s: fail to set sfn\n",
61 WALLCLK_SYSFS_MODULE_NAME);
62 goto out;
63 }
64 rc = count;
65
66out:
67 return rc;
68}
69
70static struct kobj_attribute sfn_attribute =
71 __ATTR(sfn, 0666, sfn_show, sfn_store);
72
73static ssize_t sfn_ref_show(struct kobject *kobj,
74 struct kobj_attribute *attr,
75 char *buf)
76{
77 int rc;
78
79 rc = wallclk_get_sfn_ref();
80 if (rc < 0)
81 return rc;
82 return snprintf(buf, 10, "%d\n", rc);
83}
84
85static ssize_t sfn_ref_store(struct kobject *kobj,
86 struct kobj_attribute *attr,
87 const char *buf,
88 size_t count)
89{
90 u16 sfn_ref;
91 int rc;
92
93 if (kstrtou16(buf, 0, &sfn_ref)) {
94 printk(KERN_ERR "%s: sfn_ref input is not a valid u16 value\n",
95 WALLCLK_SYSFS_MODULE_NAME);
96 rc = -EINVAL;
97 goto out;
98 }
99
100 rc = wallclk_set_sfn_ref(sfn_ref);
101
102 if (rc) {
103 printk(KERN_ERR "%s: fail to set sfn_ref\n",
104 WALLCLK_SYSFS_MODULE_NAME);
105 goto out;
106 }
107 rc = count;
108
109out:
110 return rc;
111}
112
113static struct kobj_attribute sfn_ref_attribute =
114 __ATTR(sfn_ref, 0666, sfn_ref_show, sfn_ref_store);
115
116static ssize_t reg_show(struct kobject *kobj,
117 struct kobj_attribute *attr,
118 char *buf,
119 u32 offset)
120{
121 int rc;
122 u32 val;
123
124 rc = wallclk_reg_read(offset, &val);
125 if (rc)
126 return rc;
127
128 return snprintf(buf, 20, "%08x\n", val);
129}
130
131static ssize_t reg_store(struct kobject *kobj,
132 struct kobj_attribute *attr,
133 const char *buf,
134 const size_t count,
135 u32 offset)
136{
137 u32 v;
138 int rc;
139
140 if (kstrtou32(buf, 0, &v)) {
141 printk(KERN_ERR "%s: input is not a valid u32 value\n",
142 WALLCLK_SYSFS_MODULE_NAME);
143 rc = -EINVAL;
144 goto out;
145 }
146
147 rc = wallclk_reg_write(offset, v);
148
149 if (rc) {
150 printk(KERN_ERR "%s: fail to set register(offset=0x%x)\n",
151 WALLCLK_SYSFS_MODULE_NAME, offset);
152 goto out;
153 }
154 rc = count;
155
156out:
157 return rc;
158}
159
160static ssize_t ctrl_reg_show(struct kobject *kobj,
161 struct kobj_attribute *attr,
162 char *buf)
163{
164 return reg_show(kobj, attr, buf, CTRL_REG_OFFSET);
165}
166
167static ssize_t ctrl_reg_store(struct kobject *kobj,
168 struct kobj_attribute *attr,
169 const char *buf,
170 const size_t count)
171{
172 return reg_store(kobj, attr, buf, count, CTRL_REG_OFFSET);
173}
174
175static struct kobj_attribute ctrl_reg_attribute =
176 __ATTR(ctrl_reg, 0666, ctrl_reg_show, ctrl_reg_store);
177
178static ssize_t basetime0_reg_show(struct kobject *kobj,
179 struct kobj_attribute *attr,
180 char *buf)
181{
182 return reg_show(kobj, attr, buf, CLK_BASE_TIME0_OFFSET);
183}
184
185static ssize_t basetime0_reg_store(struct kobject *kobj,
186 struct kobj_attribute *attr,
187 const char *buf,
188 size_t count)
189{
190 return reg_store(kobj, attr, buf, count, CLK_BASE_TIME0_OFFSET);
191}
192
193static struct kobj_attribute basetime0_reg_attribute =
194 __ATTR(base_time0_reg, 0666, basetime0_reg_show, basetime0_reg_store);
195
196static ssize_t basetime1_reg_show(struct kobject *kobj,
197 struct kobj_attribute *attr,
198 char *buf)
199{
200 return reg_show(kobj, attr, buf, CLK_BASE_TIME1_OFFSET);
201}
202
203static ssize_t basetime1_reg_store(struct kobject *kobj,
204 struct kobj_attribute *attr,
205 const char *buf,
206 size_t count)
207{
208 return reg_store(kobj, attr, buf, count, CLK_BASE_TIME1_OFFSET);
209}
210
211static struct kobj_attribute basetime1_reg_attribute =
212 __ATTR(base_time1_reg, 0666, basetime1_reg_show, basetime1_reg_store);
213
214static ssize_t pulse_cnt_reg_show(struct kobject *kobj,
215 struct kobj_attribute *attr,
216 char *buf)
217{
218 return reg_show(kobj, attr, buf, PULSE_CNT_REG_OFFSET);
219}
220
221static ssize_t pulse_cnt_reg_store(struct kobject *kobj,
222 struct kobj_attribute *attr,
223 const char *buf,
224 size_t count)
225{
226 return reg_store(kobj, attr, buf, count, PULSE_CNT_REG_OFFSET);
227}
228
229static struct kobj_attribute pulse_cnt_reg_attribute =
230 __ATTR(pulse_cnt_reg, 0666, pulse_cnt_reg_show, pulse_cnt_reg_store);
231
232static ssize_t clk_cnt_reg_show(struct kobject *kobj,
233 struct kobj_attribute *attr,
234 char *buf)
235{
236 return reg_show(kobj, attr, buf, CLK_CNT_REG_OFFSET);
237}
238
239static ssize_t clk_cnt_reg_store(struct kobject *kobj,
240 struct kobj_attribute *attr,
241 const char *buf,
242 size_t count)
243{
244 return reg_store(kobj, attr, buf, count, CLK_CNT_REG_OFFSET);
245}
246
247static struct kobj_attribute clk_cnt_reg_attribute =
248 __ATTR(clock_cnt_reg, 0666, clk_cnt_reg_show, clk_cnt_reg_store);
249
250static ssize_t clk_cnt_snapshot_reg_show(struct kobject *kobj,
251 struct kobj_attribute *attr,
252 char *buf)
253{
254 return reg_show(kobj, attr, buf, CLK_CNT_SNAPSHOT_REG_OFFSET);
255}
256
257static struct kobj_attribute clk_cnt_snapshot_reg_attribute =
258 __ATTR(clock_cnt_snapshot_reg, 0444, clk_cnt_snapshot_reg_show, NULL);
259
260static struct attribute *wallclk_attrs[] = {
261 &sfn_attribute.attr,
262 &sfn_ref_attribute.attr,
263 &ctrl_reg_attribute.attr,
264 &pulse_cnt_reg_attribute.attr,
265 &clk_cnt_snapshot_reg_attribute.attr,
266 &clk_cnt_reg_attribute.attr,
267 &basetime0_reg_attribute.attr,
268 &basetime1_reg_attribute.attr,
269 NULL
270};
271
272static struct attribute_group wallclk_attr_group = {
273 .attrs = wallclk_attrs,
274};
275
276static int __init wallclk_sysfs_init(void)
277{
278 int rc;
279
280 wallclk_kobj = kobject_create_and_add("wallclk", kernel_kobj);
281 if (!wallclk_kobj) {
282 printk(KERN_ERR "%s: failed to create kobject\n",
283 WALLCLK_SYSFS_MODULE_NAME);
284 rc = -ENOMEM;
285 goto out;
286 }
287
288 rc = sysfs_create_group(wallclk_kobj, &wallclk_attr_group);
289 if (rc) {
290 kobject_put(wallclk_kobj);
291 printk(KERN_ERR "%s: failed to create sysfs group\n",
292 WALLCLK_SYSFS_MODULE_NAME);
293 }
294
295out:
296 return rc;
297}
298
299static void __exit wallclk_sysfs_exit(void)
300{
301 kobject_put(wallclk_kobj);
302}
303
304module_init(wallclk_sysfs_init);
305module_exit(wallclk_sysfs_exit);
306
307MODULE_DESCRIPTION("Wall clock SysFS");
308MODULE_LICENSE("GPL v2");