aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mpu3050/slaveirq.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/misc/mpu3050/slaveirq.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/misc/mpu3050/slaveirq.c')
-rw-r--r--drivers/misc/mpu3050/slaveirq.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/drivers/misc/mpu3050/slaveirq.c b/drivers/misc/mpu3050/slaveirq.c
new file mode 100644
index 00000000000..a3c7bfec4b4
--- /dev/null
+++ b/drivers/misc/mpu3050/slaveirq.c
@@ -0,0 +1,273 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/stat.h>
25#include <linux/irq.h>
26#include <linux/signal.h>
27#include <linux/miscdevice.h>
28#include <linux/i2c.h>
29#include <linux/i2c-dev.h>
30#include <linux/poll.h>
31
32#include <linux/errno.h>
33#include <linux/fs.h>
34#include <linux/mm.h>
35#include <linux/sched.h>
36#include <linux/wait.h>
37#include <linux/uaccess.h>
38#include <linux/io.h>
39#include <linux/wait.h>
40#include <linux/slab.h>
41
42#include "mpu.h"
43#include "slaveirq.h"
44#include "mldl_cfg.h"
45#include "mpu-i2c.h"
46
47/* function which gets slave data and sends it to SLAVE */
48
49struct slaveirq_dev_data {
50 struct miscdevice dev;
51 struct i2c_client *slave_client;
52 struct mpuirq_data data;
53 wait_queue_head_t slaveirq_wait;
54 int irq;
55 int pid;
56 int data_ready;
57 int timeout;
58};
59
60/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28
61 * drivers: misc: pass miscdevice pointer via file private data
62 */
63static int slaveirq_open(struct inode *inode, struct file *file)
64{
65 /* Device node is availabe in the file->private_data, this is
66 * exactly what we want so we leave it there */
67 struct slaveirq_dev_data *data =
68 container_of(file->private_data, struct slaveirq_dev_data, dev);
69
70 dev_dbg(data->dev.this_device,
71 "%s current->pid %d\n", __func__, current->pid);
72 data->pid = current->pid;
73 return 0;
74}
75
76static int slaveirq_release(struct inode *inode, struct file *file)
77{
78 struct slaveirq_dev_data *data =
79 container_of(file->private_data, struct slaveirq_dev_data, dev);
80 dev_dbg(data->dev.this_device, "slaveirq_release\n");
81 return 0;
82}
83
84/* read function called when from /dev/slaveirq is read */
85static ssize_t slaveirq_read(struct file *file,
86 char *buf, size_t count, loff_t *ppos)
87{
88 int len, err;
89 struct slaveirq_dev_data *data =
90 container_of(file->private_data, struct slaveirq_dev_data, dev);
91
92 if (!data->data_ready &&
93 data->timeout &&
94 !(file->f_flags & O_NONBLOCK)) {
95 wait_event_interruptible_timeout(data->slaveirq_wait,
96 data->data_ready,
97 data->timeout);
98 }
99
100 if (data->data_ready && NULL != buf
101 && count >= sizeof(data->data)) {
102 err = copy_to_user(buf, &data->data, sizeof(data->data));
103 data->data.data_type = 0;
104 } else {
105 return 0;
106 }
107 if (err != 0) {
108 dev_err(data->dev.this_device,
109 "Copy to user returned %d\n", err);
110 return -EFAULT;
111 }
112 data->data_ready = 0;
113 len = sizeof(data->data);
114 return len;
115}
116
117static unsigned int slaveirq_poll(struct file *file,
118 struct poll_table_struct *poll)
119{
120 int mask = 0;
121 struct slaveirq_dev_data *data =
122 container_of(file->private_data, struct slaveirq_dev_data, dev);
123
124 poll_wait(file, &data->slaveirq_wait, poll);
125 if (data->data_ready)
126 mask |= POLLIN | POLLRDNORM;
127 return mask;
128}
129
130/* ioctl - I/O control */
131static long slaveirq_ioctl(struct file *file,
132 unsigned int cmd, unsigned long arg)
133{
134 int retval = 0;
135 int tmp;
136 struct slaveirq_dev_data *data =
137 container_of(file->private_data, struct slaveirq_dev_data, dev);
138
139 switch (cmd) {
140 case SLAVEIRQ_SET_TIMEOUT:
141 data->timeout = arg;
142 break;
143
144 case SLAVEIRQ_GET_INTERRUPT_CNT:
145 tmp = data->data.interruptcount - 1;
146 if (data->data.interruptcount > 1)
147 data->data.interruptcount = 1;
148
149 if (copy_to_user((int *) arg, &tmp, sizeof(int)))
150 return -EFAULT;
151 break;
152 case SLAVEIRQ_GET_IRQ_TIME:
153 if (copy_to_user((int *) arg, &data->data.irqtime,
154 sizeof(data->data.irqtime)))
155 return -EFAULT;
156 data->data.irqtime = 0;
157 break;
158 default:
159 retval = -EINVAL;
160 }
161 return retval;
162}
163
164static irqreturn_t slaveirq_handler(int irq, void *dev_id)
165{
166 struct slaveirq_dev_data *data = (struct slaveirq_dev_data *)dev_id;
167 static int mycount;
168 struct timeval irqtime;
169 mycount++;
170
171 data->data.interruptcount++;
172
173 /* wake up (unblock) for reading data from userspace */
174 data->data_ready = 1;
175
176 do_gettimeofday(&irqtime);
177 data->data.irqtime = (((long long) irqtime.tv_sec) << 32);
178 data->data.irqtime += irqtime.tv_usec;
179 data->data.data_type |= 1;
180
181 wake_up_interruptible(&data->slaveirq_wait);
182
183 return IRQ_HANDLED;
184
185}
186
187/* define which file operations are supported */
188static const struct file_operations slaveirq_fops = {
189 .owner = THIS_MODULE,
190 .read = slaveirq_read,
191 .poll = slaveirq_poll,
192
193#if HAVE_COMPAT_IOCTL
194 .compat_ioctl = slaveirq_ioctl,
195#endif
196#if HAVE_UNLOCKED_IOCTL
197 .unlocked_ioctl = slaveirq_ioctl,
198#endif
199 .open = slaveirq_open,
200 .release = slaveirq_release,
201};
202
203int slaveirq_init(struct i2c_adapter *slave_adapter,
204 struct ext_slave_platform_data *pdata,
205 char *name)
206{
207
208 int res;
209 struct slaveirq_dev_data *data;
210
211 if (!pdata->irq)
212 return -EINVAL;
213
214 pdata->irq_data = kzalloc(sizeof(*data),
215 GFP_KERNEL);
216 data = (struct slaveirq_dev_data *) pdata->irq_data;
217 if (!data)
218 return -ENOMEM;
219
220 data->dev.minor = MISC_DYNAMIC_MINOR;
221 data->dev.name = name;
222 data->dev.fops = &slaveirq_fops;
223 data->irq = pdata->irq;
224 data->pid = 0;
225 data->data_ready = 0;
226 data->timeout = 0;
227
228 init_waitqueue_head(&data->slaveirq_wait);
229
230 res = request_irq(data->irq, slaveirq_handler, IRQF_TRIGGER_RISING,
231 data->dev.name, data);
232
233 if (res) {
234 dev_err(&slave_adapter->dev,
235 "myirqtest: cannot register IRQ %d\n",
236 data->irq);
237 goto out_request_irq;
238 }
239
240 res = misc_register(&data->dev);
241 if (res < 0) {
242 dev_err(&slave_adapter->dev,
243 "misc_register returned %d\n",
244 res);
245 goto out_misc_register;
246 }
247
248 return res;
249
250out_misc_register:
251 free_irq(data->irq, data);
252out_request_irq:
253 kfree(pdata->irq_data);
254 pdata->irq_data = NULL;
255
256 return res;
257}
258
259void slaveirq_exit(struct ext_slave_platform_data *pdata)
260{
261 struct slaveirq_dev_data *data = pdata->irq_data;
262
263 if (!pdata->irq_data || data->irq <= 0)
264 return;
265
266 dev_info(data->dev.this_device, "Unregistering %s\n",
267 data->dev.name);
268
269 free_irq(data->irq, data);
270 misc_deregister(&data->dev);
271 kfree(pdata->irq_data);
272 pdata->irq_data = NULL;
273}