blob: ec0e1596b4f3eb003e7b80a171397a3fe51b4cc1 [file] [log] [blame]
Hiroshi DOYU340a6142006-12-07 15:43:59 -08001/*
2 * OMAP mailbox driver
3 *
Hiroshi DOYUf48cca82009-03-23 18:07:24 -07004 * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.
Hiroshi DOYU340a6142006-12-07 15:43:59 -08005 *
Hiroshi DOYUf48cca82009-03-23 18:07:24 -07006 * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Hiroshi DOYU340a6142006-12-07 15:43:59 -08007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +000024#include <linux/kernel.h>
Hiroshi DOYU340a6142006-12-07 15:43:59 -080025#include <linux/module.h>
Hiroshi DOYU340a6142006-12-07 15:43:59 -080026#include <linux/interrupt.h>
27#include <linux/device.h>
Hiroshi DOYU340a6142006-12-07 15:43:59 -080028#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090029#include <linux/slab.h>
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +000030#include <linux/kfifo.h>
31#include <linux/err.h>
Hiroshi DOYU8dff0fa2009-03-23 18:07:32 -070032
Tony Lindgrence491cf2009-10-20 09:40:47 -070033#include <plat/mailbox.h>
Hiroshi DOYU340a6142006-12-07 15:43:59 -080034
Rob Clark8250a5c2010-01-04 19:22:03 +053035static struct workqueue_struct *mboxd;
Hiroshi DOYU340a6142006-12-07 15:43:59 -080036static struct omap_mbox *mboxes;
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +000037static DEFINE_SPINLOCK(mboxes_lock);
Fernando Guzman Lugo1ea5d6d2010-02-08 13:35:40 -060038static bool rq_full;
Hiroshi DOYU340a6142006-12-07 15:43:59 -080039
C A Subramaniam5f00ec62009-11-22 10:11:22 -080040static int mbox_configured;
Hiroshi DOYU72b917e2010-02-18 00:48:55 -060041static DEFINE_MUTEX(mbox_configured_lock);
C A Subramaniam5f00ec62009-11-22 10:11:22 -080042
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +000043static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
44module_param(mbox_kfifo_size, uint, S_IRUGO);
45MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
46
Hiroshi DOYU9ae0ee02009-03-23 18:07:26 -070047/* Mailbox FIFO handle functions */
48static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
49{
50 return mbox->ops->fifo_read(mbox);
51}
52static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
53{
54 mbox->ops->fifo_write(mbox, msg);
55}
56static inline int mbox_fifo_empty(struct omap_mbox *mbox)
57{
58 return mbox->ops->fifo_empty(mbox);
59}
60static inline int mbox_fifo_full(struct omap_mbox *mbox)
61{
62 return mbox->ops->fifo_full(mbox);
63}
64
65/* Mailbox IRQ handle functions */
Hiroshi DOYU9ae0ee02009-03-23 18:07:26 -070066static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
67{
68 if (mbox->ops->ack_irq)
69 mbox->ops->ack_irq(mbox, irq);
70}
71static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
72{
73 return mbox->ops->is_irq(mbox, irq);
74}
75
Hiroshi DOYU340a6142006-12-07 15:43:59 -080076/*
77 * message sender
78 */
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +000079static int __mbox_poll_for_space(struct omap_mbox *mbox)
Hiroshi DOYU340a6142006-12-07 15:43:59 -080080{
81 int ret = 0, i = 1000;
82
83 while (mbox_fifo_full(mbox)) {
84 if (mbox->ops->type == OMAP_MBOX_TYPE2)
85 return -1;
86 if (--i == 0)
87 return -1;
88 udelay(1);
89 }
Hiroshi DOYU340a6142006-12-07 15:43:59 -080090 return ret;
91}
92
C A Subramaniamb2b63622009-11-22 10:11:20 -080093int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
Hiroshi DOYU340a6142006-12-07 15:43:59 -080094{
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +000095 struct omap_mbox_queue *mq = mbox->txq;
96 int ret = 0, len;
C A Subramaniam5ed8d322009-11-22 10:11:24 -080097
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +000098 spin_lock(&mq->lock);
Tejun Heoec247512009-04-23 11:05:20 +090099
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000100 if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
101 ret = -ENOMEM;
102 goto out;
103 }
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800104
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000105 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
106 WARN_ON(len != sizeof(msg));
107
C A Subramaniam5ed8d322009-11-22 10:11:24 -0800108 tasklet_schedule(&mbox->txq->tasklet);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800109
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000110out:
111 spin_unlock(&mq->lock);
112 return ret;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800113}
114EXPORT_SYMBOL(omap_mbox_msg_send);
115
C A Subramaniam5ed8d322009-11-22 10:11:24 -0800116static void mbox_tx_tasklet(unsigned long tx_data)
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800117{
C A Subramaniam5ed8d322009-11-22 10:11:24 -0800118 struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000119 struct omap_mbox_queue *mq = mbox->txq;
120 mbox_msg_t msg;
121 int ret;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800122
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000123 while (kfifo_len(&mq->fifo)) {
124 if (__mbox_poll_for_space(mbox)) {
Hiroshi DOYUeb188582009-11-22 10:11:22 -0800125 omap_mbox_enable_irq(mbox, IRQ_TX);
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000126 break;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800127 }
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000128
129 ret = kfifo_out(&mq->fifo, (unsigned char *)&msg,
130 sizeof(msg));
131 WARN_ON(ret != sizeof(msg));
132
133 mbox_fifo_write(mbox, msg);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800134 }
135}
136
137/*
138 * Message receiver(workqueue)
139 */
140static void mbox_rx_work(struct work_struct *work)
141{
142 struct omap_mbox_queue *mq =
143 container_of(work, struct omap_mbox_queue, work);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800144 mbox_msg_t msg;
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000145 int len;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800146
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000147 while (kfifo_len(&mq->fifo) >= sizeof(msg)) {
148 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
149 WARN_ON(len != sizeof(msg));
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800150
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000151 if (mq->callback)
152 mq->callback((void *)msg);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800153 }
154}
155
156/*
157 * Mailbox interrupt handler
158 */
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800159static void __mbox_tx_interrupt(struct omap_mbox *mbox)
160{
Hiroshi DOYUeb188582009-11-22 10:11:22 -0800161 omap_mbox_disable_irq(mbox, IRQ_TX);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800162 ack_mbox_irq(mbox, IRQ_TX);
C A Subramaniam5ed8d322009-11-22 10:11:24 -0800163 tasklet_schedule(&mbox->txq->tasklet);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800164}
165
166static void __mbox_rx_interrupt(struct omap_mbox *mbox)
167{
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000168 struct omap_mbox_queue *mq = mbox->rxq;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800169 mbox_msg_t msg;
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000170 int len;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800171
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800172 while (!mbox_fifo_empty(mbox)) {
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000173 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
Fernando Guzman Lugo1ea5d6d2010-02-08 13:35:40 -0600174 omap_mbox_disable_irq(mbox, IRQ_RX);
175 rq_full = true;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800176 goto nomem;
Fernando Guzman Lugo1ea5d6d2010-02-08 13:35:40 -0600177 }
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800178
179 msg = mbox_fifo_read(mbox);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800180
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000181 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
182 WARN_ON(len != sizeof(msg));
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800183
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800184 if (mbox->ops->type == OMAP_MBOX_TYPE1)
185 break;
186 }
187
188 /* no more messages in the fifo. clear IRQ source. */
189 ack_mbox_irq(mbox, IRQ_RX);
Hiroshi DOYUf48cca82009-03-23 18:07:24 -0700190nomem:
Rob Clark8250a5c2010-01-04 19:22:03 +0530191 queue_work(mboxd, &mbox->rxq->work);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800192}
193
194static irqreturn_t mbox_interrupt(int irq, void *p)
195{
Jeff Garzik2a7057e2007-10-26 05:40:22 -0400196 struct omap_mbox *mbox = p;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800197
198 if (is_mbox_irq(mbox, IRQ_TX))
199 __mbox_tx_interrupt(mbox);
200
201 if (is_mbox_irq(mbox, IRQ_RX))
202 __mbox_rx_interrupt(mbox);
203
204 return IRQ_HANDLED;
205}
206
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800207static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
C A Subramaniam5ed8d322009-11-22 10:11:24 -0800208 void (*work) (struct work_struct *),
209 void (*tasklet)(unsigned long))
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800210{
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800211 struct omap_mbox_queue *mq;
212
213 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
214 if (!mq)
215 return NULL;
216
217 spin_lock_init(&mq->lock);
218
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000219 if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800220 goto error;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800221
C A Subramaniam5ed8d322009-11-22 10:11:24 -0800222 if (work)
223 INIT_WORK(&mq->work, work);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800224
C A Subramaniam5ed8d322009-11-22 10:11:24 -0800225 if (tasklet)
226 tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800227 return mq;
228error:
229 kfree(mq);
230 return NULL;
231}
232
233static void mbox_queue_free(struct omap_mbox_queue *q)
234{
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000235 kfifo_free(&q->fifo);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800236 kfree(q);
237}
238
Hiroshi DOYUc7c158e2009-11-22 10:11:19 -0800239static int omap_mbox_startup(struct omap_mbox *mbox)
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800240{
C A Subramaniam5f00ec62009-11-22 10:11:22 -0800241 int ret = 0;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800242 struct omap_mbox_queue *mq;
243
Ohad Ben-Cohen01072d82010-05-05 15:33:08 +0000244 if (mbox->ops->startup) {
Hiroshi DOYU72b917e2010-02-18 00:48:55 -0600245 mutex_lock(&mbox_configured_lock);
C A Subramaniam5f00ec62009-11-22 10:11:22 -0800246 if (!mbox_configured)
247 ret = mbox->ops->startup(mbox);
248
Ohad Ben-Cohen01072d82010-05-05 15:33:08 +0000249 if (ret) {
Hiroshi DOYU72b917e2010-02-18 00:48:55 -0600250 mutex_unlock(&mbox_configured_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800251 return ret;
C A Subramaniam5f00ec62009-11-22 10:11:22 -0800252 }
253 mbox_configured++;
Hiroshi DOYU72b917e2010-02-18 00:48:55 -0600254 mutex_unlock(&mbox_configured_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800255 }
256
C A Subramaniam5e683822009-11-22 10:11:23 -0800257 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800258 mbox->name, mbox);
Ohad Ben-Cohen01072d82010-05-05 15:33:08 +0000259 if (ret) {
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800260 printk(KERN_ERR
261 "failed to register mailbox interrupt:%d\n", ret);
262 goto fail_request_irq;
263 }
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800264
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000265 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800266 if (!mq) {
267 ret = -ENOMEM;
268 goto fail_alloc_txq;
269 }
270 mbox->txq = mq;
271
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000272 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800273 if (!mq) {
274 ret = -ENOMEM;
275 goto fail_alloc_rxq;
276 }
277 mbox->rxq = mq;
278
279 return 0;
280
281 fail_alloc_rxq:
282 mbox_queue_free(mbox->txq);
283 fail_alloc_txq:
284 free_irq(mbox->irq, mbox);
285 fail_request_irq:
Ohad Ben-Cohen01072d82010-05-05 15:33:08 +0000286 if (mbox->ops->shutdown)
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800287 mbox->ops->shutdown(mbox);
288
289 return ret;
290}
291
292static void omap_mbox_fini(struct omap_mbox *mbox)
293{
Fernando Guzman Lugoad6d9622010-02-12 19:02:32 -0600294 free_irq(mbox->irq, mbox);
Fernando Guzman Lugo0e828e82010-02-12 19:07:14 -0600295 tasklet_kill(&mbox->txq->tasklet);
296 flush_work(&mbox->rxq->work);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800297 mbox_queue_free(mbox->txq);
298 mbox_queue_free(mbox->rxq);
299
Ohad Ben-Cohen01072d82010-05-05 15:33:08 +0000300 if (mbox->ops->shutdown) {
Hiroshi DOYU72b917e2010-02-18 00:48:55 -0600301 mutex_lock(&mbox_configured_lock);
C A Subramaniam5f00ec62009-11-22 10:11:22 -0800302 if (mbox_configured > 0)
303 mbox_configured--;
304 if (!mbox_configured)
305 mbox->ops->shutdown(mbox);
Hiroshi DOYU72b917e2010-02-18 00:48:55 -0600306 mutex_unlock(&mbox_configured_lock);
C A Subramaniam5f00ec62009-11-22 10:11:22 -0800307 }
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800308}
309
310static struct omap_mbox **find_mboxes(const char *name)
311{
312 struct omap_mbox **p;
313
314 for (p = &mboxes; *p; p = &(*p)->next) {
315 if (strcmp((*p)->name, name) == 0)
316 break;
317 }
318
319 return p;
320}
321
322struct omap_mbox *omap_mbox_get(const char *name)
323{
324 struct omap_mbox *mbox;
325 int ret;
326
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000327 spin_lock(&mboxes_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800328 mbox = *(find_mboxes(name));
329 if (mbox == NULL) {
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000330 spin_unlock(&mboxes_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800331 return ERR_PTR(-ENOENT);
332 }
333
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000334 spin_unlock(&mboxes_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800335
Hiroshi DOYUc7c158e2009-11-22 10:11:19 -0800336 ret = omap_mbox_startup(mbox);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800337 if (ret)
338 return ERR_PTR(-ENODEV);
339
340 return mbox;
341}
342EXPORT_SYMBOL(omap_mbox_get);
343
344void omap_mbox_put(struct omap_mbox *mbox)
345{
346 omap_mbox_fini(mbox);
347}
348EXPORT_SYMBOL(omap_mbox_put);
349
Hiroshi DOYUf48cca82009-03-23 18:07:24 -0700350int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800351{
352 int ret = 0;
353 struct omap_mbox **tmp;
354
355 if (!mbox)
356 return -EINVAL;
357 if (mbox->next)
358 return -EBUSY;
359
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000360 spin_lock(&mboxes_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800361 tmp = find_mboxes(mbox->name);
Hiroshi DOYUf48cca82009-03-23 18:07:24 -0700362 if (*tmp) {
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800363 ret = -EBUSY;
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000364 spin_unlock(&mboxes_lock);
Hiroshi DOYUf48cca82009-03-23 18:07:24 -0700365 goto err_find;
366 }
367 *tmp = mbox;
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000368 spin_unlock(&mboxes_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800369
Hiroshi DOYUf48cca82009-03-23 18:07:24 -0700370 return 0;
371
372err_find:
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800373 return ret;
374}
375EXPORT_SYMBOL(omap_mbox_register);
376
377int omap_mbox_unregister(struct omap_mbox *mbox)
378{
379 struct omap_mbox **tmp;
380
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000381 spin_lock(&mboxes_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800382 tmp = &mboxes;
383 while (*tmp) {
384 if (mbox == *tmp) {
385 *tmp = mbox->next;
386 mbox->next = NULL;
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000387 spin_unlock(&mboxes_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800388 return 0;
389 }
390 tmp = &(*tmp)->next;
391 }
Ohad Ben-Cohen10d1a002010-05-05 15:33:06 +0000392 spin_unlock(&mboxes_lock);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800393
394 return -EINVAL;
395}
396EXPORT_SYMBOL(omap_mbox_unregister);
397
Hiroshi DOYUc7c158e2009-11-22 10:11:19 -0800398static int __init omap_mbox_init(void)
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800399{
Rob Clark8250a5c2010-01-04 19:22:03 +0530400 mboxd = create_workqueue("mboxd");
401 if (!mboxd)
402 return -ENOMEM;
403
Ohad Ben-Cohenb5bebe42010-05-05 15:33:09 +0000404 /* kfifo size sanity check: alignment and minimal size */
405 mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
406 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(mbox_msg_t));
407
Hiroshi DOYUc7c158e2009-11-22 10:11:19 -0800408 return 0;
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800409}
Hiroshi DOYUc7c158e2009-11-22 10:11:19 -0800410module_init(omap_mbox_init);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800411
Hiroshi DOYUc7c158e2009-11-22 10:11:19 -0800412static void __exit omap_mbox_exit(void)
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800413{
Rob Clark8250a5c2010-01-04 19:22:03 +0530414 destroy_workqueue(mboxd);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800415}
Hiroshi DOYUc7c158e2009-11-22 10:11:19 -0800416module_exit(omap_mbox_exit);
Hiroshi DOYU340a6142006-12-07 15:43:59 -0800417
Hiroshi DOYUf48cca82009-03-23 18:07:24 -0700418MODULE_LICENSE("GPL v2");
419MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
Ohad Ben-Cohenf3753252010-05-05 15:33:07 +0000420MODULE_AUTHOR("Toshihiro Kobayashi");
421MODULE_AUTHOR("Hiroshi DOYU");