]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/mailbox.c
ARM: OMAP: mailbox restructure
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / mailbox.c
1 /*
2  * OMAP mailbox driver
3  *
4  * Copyright (C) 2006 Nokia Corporation. All rights reserved.
5  *
6  * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
7  *              Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * version 2 as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/sched.h>
28 #include <linux/interrupt.h>
29 #include <linux/device.h>
30 #include <linux/err.h>
31 #include <asm/io.h>
32 #include <asm/delay.h>
33 #include <asm/arch/mailbox.h>
34 #include "mailbox.h"
35
36 static struct omap_mbox *mboxes;
37 static DEFINE_RWLOCK(mboxes_lock);
38
39 static struct omap_mbox **find_mboxes(const char *name)
40 {
41         struct omap_mbox **p;
42
43         for (p = &mboxes; *p; p = &(*p)->next) {
44                 if (strcmp((*p)->name, name) == 0)
45                         break;
46         }
47
48         return p;
49 }
50
51 struct omap_mbox *omap_mbox_get(const char *name)
52 {
53         struct omap_mbox *mbox;
54
55         read_lock(&mboxes_lock);
56         mbox = *(find_mboxes(name));
57         read_unlock(&mboxes_lock);
58
59         return mbox;
60 }
61 EXPORT_SYMBOL(omap_mbox_get);
62
63 /* Mailbox Sequence Bit function */
64 void omap_mbox_init_seq(struct omap_mbox *mbox)
65 {
66         mbox_seq_init(mbox);
67 }
68 EXPORT_SYMBOL(omap_mbox_init_seq);
69
70 /*
71  * message sender
72  */
73 int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
74 {
75         int ret;
76         int i = 1000;
77         static DEFINE_MUTEX(msg_send_lock);
78
79         while (mbox_fifo_full(mbox)) {
80                 if (mbox->ops->type == OMAP_MBOX_TYPE2) {
81                         enable_mbox_irq(mbox, IRQ_TX);
82                         wait_event_interruptible(mbox->tx_waitq,
83                                                  !mbox_fifo_full(mbox));
84                 } else
85                         udelay(1);
86
87                 if (--i == 0)
88                         return -1;
89         }
90
91
92         mutex_lock(&msg_send_lock);
93
94         if (mbox->msg_sender_cb && arg) {
95                 ret = mbox->msg_sender_cb(arg);
96                 if (ret)
97                         goto out;
98         }
99
100         mbox_seq_toggle(mbox, &msg);
101         mbox_fifo_write(mbox, msg);
102  out:
103         mutex_unlock(&msg_send_lock);
104
105         return 0;
106 }
107 EXPORT_SYMBOL(omap_mbox_msg_send);
108
109 /*
110  * Message receiver(workqueue)
111  */
112 static void mbox_msg_receiver(void *p)
113 {
114         struct omap_mbox *mbox = (struct omap_mbox *)p;
115         struct omap_mbq *mbq = mbox->mbq;
116         mbox_msg_t msg;
117
118         while (!mbq_empty(mbq)) {
119                 msg = mbq_get(mbq);
120                 enable_mbox_irq(mbox, IRQ_RX);
121
122                 if (unlikely(mbox_seq_test(mbox, msg))) {
123                         printk(KERN_ERR
124                                "mbox: illegal seq bit! ignoring this command. "
125                                "(%08x)\n", msg);
126                         continue;
127                 }
128
129                 if (likely(mbox->msg_receive_cb))
130                         mbox->msg_receive_cb(msg);
131         }
132 }
133
134 /*
135  * Mailbox interrupt handler
136  */
137 static irqreturn_t mbox_interrupt(int irq, void *p, struct pt_regs *regs)
138 {
139         mbox_msg_t msg;
140         struct omap_mbox *mbox = (struct omap_mbox *)p;
141
142         if (is_mbox_irq(mbox, IRQ_TX)) {
143                 disable_mbox_irq(mbox, IRQ_TX);
144                 /*
145                  * NOTE: this doesn't seeem to work as explained in the manual.
146                  * IRQSTATUS:NOTFULL can't be cleared even we write 1 to that bit.
147                  * It is always set when it's not full, regardless of IRQENABLE setting.
148                  */
149                 ack_mbox_irq(mbox, IRQ_TX);
150                 wake_up_interruptible_all(&mbox->tx_waitq);
151         }
152
153         if (!is_mbox_irq(mbox, IRQ_RX))
154                 return IRQ_HANDLED;
155
156         while (!mbox_fifo_empty(mbox)) {
157                 msg = mbox_fifo_read(mbox);
158                 if (mbq_add(mbox->mbq, msg)) {  /* mbq full */
159                         disable_mbox_irq(mbox, IRQ_RX);
160                         goto flush_queue;
161                 }
162                 if (mbox->ops->type == OMAP_MBOX_TYPE1)
163                         break;
164         }
165
166         /* no more messages in the fifo. clear IRQ source. */
167         ack_mbox_irq(mbox, IRQ_RX);
168  flush_queue:
169         schedule_work(&mbox->msg_receive);
170
171         return IRQ_HANDLED;
172 }
173
174 /*
175  * sysfs files
176  */
177 static ssize_t mbox_attr_write(struct class_device *dev, const char *buf,
178                               size_t count)
179 {
180         int ret;
181         mbox_msg_t msg;
182         struct omap_mbox *mbox = class_get_devdata(dev);
183
184         msg = (mbox_msg_t) simple_strtoul(buf, NULL, 16);
185
186         ret = omap_mbox_msg_send(mbox, msg, NULL);
187         if (ret)
188                 return -1;
189
190         return count;
191 }
192
193 static ssize_t mbox_attr_read(struct class_device *dev, char *buf)
194 {
195         struct omap_mbox *mbox = class_get_devdata(dev);
196
197         return sprintf(buf, mbox->name);
198 }
199
200 static CLASS_DEVICE_ATTR(mbox, S_IALLUGO, mbox_attr_read, mbox_attr_write);
201
202 static ssize_t mbox_show(struct class *class, char *buf)
203 {
204         return sprintf(buf, "mbox");
205 }
206
207 static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
208
209 static struct class omap_mbox_class = {
210         .name = "mbox",
211 };
212
213 static int omap_mbox_init(struct omap_mbox *mbox)
214 {
215         int ret;
216
217         if (likely(mbox->ops->startup)) {
218                 ret = mbox->ops->startup(mbox);
219                 if (unlikely(ret))
220                         return ret;
221         }
222
223         mbox->class_dev.class = &omap_mbox_class;
224         strlcpy(mbox->class_dev.class_id, mbox->name, KOBJ_NAME_LEN);
225         class_set_devdata(&mbox->class_dev, mbox);
226
227         ret = class_device_register(&mbox->class_dev);
228         if (unlikely(ret))
229                 return ret;
230
231         class_device_create_file(&mbox->class_dev, &class_device_attr_mbox);
232
233         ret = request_irq(mbox->irq, mbox_interrupt, SA_INTERRUPT,
234                           mbox->name, mbox);
235         if (unlikely(ret)) {
236                 printk(KERN_ERR
237                        "failed to register mailbox interrupt:%d\n", ret);
238                 goto fail1;
239         }
240         enable_mbox_irq(mbox, IRQ_RX);
241
242         spin_lock_init(&mbox->lock);
243         INIT_WORK(&mbox->msg_receive, mbox_msg_receiver, mbox);
244         init_waitqueue_head(&mbox->tx_waitq);
245
246         ret = mbq_init(&mbox->mbq);
247         if (unlikely(ret))
248                 goto fail2;
249
250         return 0;
251  fail2:
252         free_irq(mbox->irq, mbox);
253         class_remove_file(&omap_mbox_class, &class_attr_mbox);
254         class_unregister(&omap_mbox_class);
255  fail1:
256         if (unlikely(mbox->ops->shutdown))
257                 mbox->ops->shutdown(mbox);
258
259         return ret;
260 }
261
262 static void omap_mbox_shutdown(struct omap_mbox *mbox)
263 {
264         free_irq(mbox->irq, mbox);
265         class_remove_file(&omap_mbox_class, &class_attr_mbox);
266         class_unregister(&omap_mbox_class);
267
268         if (unlikely(mbox->ops->shutdown))
269                 mbox->ops->shutdown(mbox);
270 }
271
272 int omap_mbox_register(struct omap_mbox *mbox)
273 {
274         int ret = 0;
275         struct omap_mbox **tmp;
276
277         if (!mbox)
278                 return -EINVAL;
279         if (mbox->next)
280                 return -EBUSY;
281
282         ret = omap_mbox_init(mbox);
283         if (ret)
284                 return ret;
285
286         write_lock(&mboxes_lock);
287         tmp = find_mboxes(mbox->name);
288         if (*tmp)
289                 ret = -EBUSY;
290         else
291                 *tmp = mbox;
292         write_unlock(&mboxes_lock);
293
294         return ret;
295 }
296 EXPORT_SYMBOL(omap_mbox_register);
297
298 int omap_mbox_unregister(struct omap_mbox *mbox)
299 {
300         struct omap_mbox **tmp;
301
302         write_lock(&mboxes_lock);
303         tmp = &mboxes;
304         while (*tmp) {
305                 if (mbox == *tmp) {
306                         *tmp = mbox->next;
307                         mbox->next = NULL;
308                         write_unlock(&mboxes_lock);
309
310                         omap_mbox_shutdown(mbox);
311
312                         return 0;
313                 }
314                 tmp = &(*tmp)->next;
315         }
316         write_unlock(&mboxes_lock);
317
318         return -EINVAL;
319 }
320 EXPORT_SYMBOL(omap_mbox_unregister);
321
322 static int __init omap_mbox_class_init(void)
323 {
324         int ret = class_register(&omap_mbox_class);
325         if (!ret)
326                 ret = class_create_file(&omap_mbox_class, &class_attr_mbox);
327
328         return ret;
329 }
330
331 static void __exit omap_mbox_class_exit(void)
332 {
333         class_remove_file(&omap_mbox_class, &class_attr_mbox);
334         class_unregister(&omap_mbox_class);
335 }
336
337 subsys_initcall(omap_mbox_class_init);
338 module_exit(omap_mbox_class_exit);