]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/plat-omap/mailbox.c
ARM: OMAP: mailbox restructure
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / mailbox.c
index bb3ccd05931415378e19bf4b0fee56d1a73763fd..e8ed9fba738c7ceb87b96e5bc1c18abc443a08fe 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2006 Nokia Corporation. All rights reserved.
  *
  * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *             Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/device.h>
 #include <linux/err.h>
-#ifdef CONFIG_ARCH_OMAP2
-#include <linux/clk.h>
-#endif
 #include <asm/io.h>
-#ifdef CONFIG_ARCH_OMAP1
 #include <asm/delay.h>
-#endif
 #include <asm/arch/mailbox.h>
-#include "mailbox_hw.h"
-
-#if defined(CONFIG_ARCH_OMAP1)
-
-#define read_mbox(m, msgp) \
-               do { \
-                       *(msgp) = omap_readw((m)->data_r); \
-                       *(msgp) |= ((mbox_msg_t)omap_readw((m)->cmd_r)) << 16; \
-               } while (0)
-#define write_mbox(m, msg) \
-               do { \
-                       omap_writew((msg) & 0xffff, (m)->data_w); \
-                       omap_writew((msg) >> 16, (m)->cmd_w); \
-               } while (0)
-#define enable_newmsg_irq(m)   enable_irq((m)->irq)
-#define disable_newmsg_irq(m)  disable_irq((m)->irq)
-#define mbox_is_notfull(m)     (omap_readw((m)->flag_w) == 0)
-
-#elif defined(CONFIG_ARCH_OMAP2)
-
-#define omap_bit_setl(b,r) \
-               do { omap_writel(omap_readl(r) | (b), (r)); } while(0)
-#define omap_bit_clrl(b,r) \
-               do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0)
-
-#define read_mbox(m, msgp) \
-               do { *(msgp) = omap_readl((m)->message_r); } while (0)
-#define write_mbox(m, msg)     omap_writel(msg, (m)->message_w)
-#define enable_newmsg_irq(m)   omap_bit_setl((m)->newmsg_bit, (m)->irqenable)
-#define disable_newmsg_irq(m)  omap_bit_clrl((m)->newmsg_bit, (m)->irqenable)
-#define enable_notfull_irq(m)  omap_bit_setl((m)->notfull_bit, (m)->irqenable)
-#define disable_notfull_irq(m) omap_bit_clrl((m)->notfull_bit, (m)->irqenable)
-#define clear_newmsg_irq(m)    omap_writel((m)->newmsg_bit, (m)->irqstatus)
-#define clear_notfull_irq(m)   omap_writel((m)->notfull_bit, (m)->irqstatus)
-#define notfull_irq_enabled(m) (omap_readl((m)->irqenable) & (m)->notfull_bit)
-#define has_newmsg_irq(m)      (omap_readl((m)->irqstatus) & (m)->newmsg_bit)
-#define has_notfull_irq(m)     (omap_readl((m)->irqstatus) & (m)->notfull_bit)
-#define mbox_nomsg(m)          (omap_readl((m)->msgstatus_r) == 0)
-#define mbox_is_notfull(m)     (omap_readl((m)->fifostatus_w) == 0)
-
-#endif /* CONFIG_ARCH_OMAP2 */
-
-static void do_mbox(void *p);
-
-#define MBQ_DEPTH      16
-struct mbq {
-       mbox_msg_t msg[MBQ_DEPTH];
-       int rp, wp, full;
-};
+#include "mailbox.h"
 
-#define mbq_inc(p)     do { if (++(p) == MBQ_DEPTH) (p) = 0; } while(0)
-
-#if defined(CONFIG_ARCH_OMAP1)
-#  define MBOX_USE_SEQ_BIT     /* XXX */
-#elif defined(CONFIG_ARCH_OMAP2)
-#  undef MBOX_USE_SEQ_BIT
-#endif
-
-struct mbox {
-       char *name;
-       unsigned int irq;
-       char irq_devid_newmsg;
-#ifdef CONFIG_ARCH_OMAP2
-       char irq_devid_notfull;
-#endif
-#ifdef MBOX_USE_SEQ_BIT
-       mbox_msg_t seq_snd;
-       mbox_msg_t seq_rcv;
-               /* seq_rcv should be initialized with any value other than
-                * 0 and 1 << 31, to allow either value for the first
-                * message.  */
-#endif
-       mbox_receiver_t *receiver_map[MBOX_CMD_MAX];
-       struct work_struct work;
-       struct mbq mbq;
-#ifdef CONFIG_ARCH_OMAP2
-       wait_queue_head_t full_wait_q;
-#endif
-
-#if defined(CONFIG_ARCH_OMAP1)
-       void *cmd_w;
-       void *data_w;
-       void *flag_w;
-       void *cmd_r;
-       void *data_r;
-#elif defined(CONFIG_ARCH_OMAP2)
-       void *irqenable;
-       void *irqstatus;
-       void *message_w;
-       void *message_r;
-       void *fifostatus_w;
-       void *msgstatus_r;
-       u32 notfull_bit;
-       u32 newmsg_bit;
-#endif
-};
+static struct omap_mbox *mboxes;
+static DEFINE_RWLOCK(mboxes_lock);
 
-#if defined(CONFIG_ARCH_OMAP1)
+static struct omap_mbox **find_mboxes(const char *name)
+{
+       struct omap_mbox **p;
 
-#if defined(CONFIG_ARCH_OMAP15XX)
-#define INT_DSP_MAILBOX1       INT_1510_DSP_MAILBOX1
-#elif defined(CONFIG_ARCH_OMAP16XX)
-#define INT_DSP_MAILBOX1       INT_1610_DSP_MAILBOX1
-#endif
+       for (p = &mboxes; *p; p = &(*p)->next) {
+               if (strcmp((*p)->name, name) == 0)
+                       break;
+       }
 
-static struct mbox mbox_dsp = {
-       .name = "DSP",
-       .irq = INT_DSP_MAILBOX1,
-       .work = __WORK_INITIALIZER(mbox_dsp.work, do_mbox, &mbox_dsp),
+       return p;
+}
 
-       .cmd_w  = (void *)MAILBOX_ARM2DSP1b,
-       .data_w = (void *)MAILBOX_ARM2DSP1,
-       .flag_w = (void *)MAILBOX_ARM2DSP1_Flag,
-       .cmd_r  = (void *)MAILBOX_DSP2ARM1b,
-       .data_r = (void *)MAILBOX_DSP2ARM1,
-};
+struct omap_mbox *omap_mbox_get(const char *name)
+{
+       struct omap_mbox *mbox;
 
-#elif defined(CONFIG_ARCH_OMAP2)
+       read_lock(&mboxes_lock);
+       mbox = *(find_mboxes(name));
+       read_unlock(&mboxes_lock);
+
+       return mbox;
+}
+EXPORT_SYMBOL(omap_mbox_get);
+
+/* Mailbox Sequence Bit function */
+void omap_mbox_init_seq(struct omap_mbox *mbox)
+{
+       mbox_seq_init(mbox);
+}
+EXPORT_SYMBOL(omap_mbox_init_seq);
 
 /*
- * MAILBOX 0: ARM -> DSP,
- * MAILBOX 1: ARM <- DSP.
- * MAILBOX 2: ARM -> IVA,
- * MAILBOX 3: ARM <- IVA.
+ * message sender
  */
-static struct mbox mbox_dsp = {
-       .name = "DSP",
-       .irq = INT_24XX_MAIL_U0_MPU,
-       .work = __WORK_INITIALIZER(mbox_dsp.work, do_mbox, &mbox_dsp),
-       .full_wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(mbox_dsp.full_wait_q),
-
-       .irqenable    = (void *)MAILBOX_IRQENABLE_0,
-       .irqstatus    = (void *)MAILBOX_IRQSTATUS_0,
-       .message_w    = (void *)MAILBOX_MESSAGE_0,
-       .message_r    = (void *)MAILBOX_MESSAGE_1,
-       .fifostatus_w = (void *)MAILBOX_FIFOSTATUS_0,
-       .msgstatus_r  = (void *)MAILBOX_MSGSTATUS_1,
-       .notfull_bit  = MAILBOX_IRQ_NOTFULL(0),
-       .newmsg_bit   = MAILBOX_IRQ_NEWMSG(1),
-};
-static struct mbox mbox_iva = {
-       .name = "IVA",
-       .irq = INT_24XX_MAIL_U3_MPU,
-       .work = __WORK_INITIALIZER(mbox_iva.work, do_mbox, &mbox_iva),
-       .full_wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(mbox_iva.full_wait_q),
-
-       .irqenable    = (void *)MAILBOX_IRQENABLE_3,
-       .irqstatus    = (void *)MAILBOX_IRQSTATUS_3,
-       .message_w    = (void *)MAILBOX_MESSAGE_2,
-       .message_r    = (void *)MAILBOX_MESSAGE_3,
-       .fifostatus_w = (void *)MAILBOX_FIFOSTATUS_2,
-       .msgstatus_r  = (void *)MAILBOX_MSGSTATUS_3,
-       .notfull_bit  = MAILBOX_IRQ_NOTFULL(2),
-       .newmsg_bit   = MAILBOX_IRQ_NEWMSG(3),
-};
-
-#endif /* CONFIG_ARCH_OMAP2 */
+int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
+{
+       int ret;
+       int i = 1000;
+       static DEFINE_MUTEX(msg_send_lock);
+
+       while (mbox_fifo_full(mbox)) {
+               if (mbox->ops->type == OMAP_MBOX_TYPE2) {
+                       enable_mbox_irq(mbox, IRQ_TX);
+                       wait_event_interruptible(mbox->tx_waitq,
+                                                !mbox_fifo_full(mbox));
+               } else
+                       udelay(1);
+
+               if (--i == 0)
+                       return -1;
+       }
 
-static struct mbox *mboxes[] = {
-       &mbox_dsp,
-#ifdef CONFIG_ARCH_OMAP2
-       &mbox_iva,
-#endif
-};
 
-struct mbox *mbox_get(const char *id)
-{
-       int i;
+       mutex_lock(&msg_send_lock);
 
-       for (i = 0; i < ARRAY_SIZE(mboxes); i++) {
-               if (!strcmp(id, mboxes[i]->name))
-                       return mboxes[i];
+       if (mbox->msg_sender_cb && arg) {
+               ret = mbox->msg_sender_cb(arg);
+               if (ret)
+                       goto out;
        }
 
-       return ERR_PTR(-ENOENT);
+       mbox_seq_toggle(mbox, &msg);
+       mbox_fifo_write(mbox, msg);
+ out:
+       mutex_unlock(&msg_send_lock);
+
+       return 0;
 }
+EXPORT_SYMBOL(omap_mbox_msg_send);
 
-#if defined(CONFIG_ARCH_OMAP1)
-static __inline__ int mbsync_irq_save(struct mbox *mbox, unsigned long *flags,
-                                     int try_cnt)
+/*
+ * Message receiver(workqueue)
+ */
+static void mbox_msg_receiver(void *p)
 {
-       int cnt;
-
-       local_irq_save(*flags);
-       if (mbox_is_notfull(mbox))
-               return 0;
-       /*
-        * mailbox is busy. wait for some usecs...
-        */
-       local_irq_restore(*flags);
-       for (cnt = 0; cnt < try_cnt; cnt++) {
-               udelay(1);
-               local_irq_save(*flags);
-               if (mbox_is_notfull(mbox))      /* success! */
-                       return 0;
-               local_irq_restore(*flags);
-       }
+       struct omap_mbox *mbox = (struct omap_mbox *)p;
+       struct omap_mbq *mbq = mbox->mbq;
+       mbox_msg_t msg;
 
-       /* fail! */
-       return -1;
-}
-#elif defined(CONFIG_ARCH_OMAP2)
-static __inline__ int mbsync_irq_save(struct mbox *mbox, unsigned long *flags)
-{
-       long current_state;
-       DECLARE_WAITQUEUE(wait, current);
+       while (!mbq_empty(mbq)) {
+               msg = mbq_get(mbq);
+               enable_mbox_irq(mbox, IRQ_RX);
 
-       do {
-               local_irq_save(*flags);
-               if (mbox_is_notfull(mbox))
-                       return 0;
+               if (unlikely(mbox_seq_test(mbox, msg))) {
+                       printk(KERN_ERR
+                              "mbox: illegal seq bit! ignoring this command. "
+                              "(%08x)\n", msg);
+                       continue;
+               }
 
-               /*
-                * mailbox is busy.
-                */
-               local_irq_restore(*flags);
-               enable_notfull_irq(mbox);
-
-               /* wait until the FIFO becomes not-full */
-               add_wait_queue(&mbox->full_wait_q, &wait);
-               current_state = current->state;
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (!mbox_is_notfull(mbox))     /* last check */
-                       schedule();
-               set_current_state(current_state);
-               remove_wait_queue(&mbox->full_wait_q, &wait);
-
-               if (signal_pending(current))
-                       return -1;
-       } while (1);
+               if (likely(mbox->msg_receive_cb))
+                       mbox->msg_receive_cb(msg);
+       }
 }
-#endif
 
 /*
- * message dispatcher API
+ * Mailbox interrupt handler
  */
-int mbox_send(struct mbox *mbox, mbox_msg_t msg)
+static irqreturn_t mbox_interrupt(int irq, void *p, struct pt_regs *regs)
 {
-       unsigned long flags;
+       mbox_msg_t msg;
+       struct omap_mbox *mbox = (struct omap_mbox *)p;
 
-#if defined(CONFIG_ARCH_OMAP1)
-       /*
-        * DSP mailbox interrupt latency must be less than 1ms.
-        */
-       if (mbsync_irq_save(mbox, &flags, 1000) < 0) {
-               printk(KERN_ERR
-                      "mailbox(%s) is busy. message 0x%08x is aborting.\n",
-                      mbox->name, msg);
-               return -1;
+       if (is_mbox_irq(mbox, IRQ_TX)) {
+               disable_mbox_irq(mbox, IRQ_TX);
+               /*
+                * NOTE: this doesn't seeem to work as explained in the manual.
+                * IRQSTATUS:NOTFULL can't be cleared even we write 1 to that bit.
+                * It is always set when it's not full, regardless of IRQENABLE setting.
+                */
+               ack_mbox_irq(mbox, IRQ_TX);
+               wake_up_interruptible_all(&mbox->tx_waitq);
        }
-#elif defined(CONFIG_ARCH_OMAP2)
-       if (mbsync_irq_save(mbox, &flags) < 0)
-               return -1;
-#endif
 
-#ifdef MBOX_USE_SEQ_BIT
-       /* add seq_snd to msg */
-       msg = (msg & 0x7fffffff) | mbox->seq_snd;
-       /* flip seq_snd */
-       mbox->seq_snd ^= 1 << 31;
-#endif
+       if (!is_mbox_irq(mbox, IRQ_RX))
+               return IRQ_HANDLED;
 
-       write_mbox(mbox, msg);
+       while (!mbox_fifo_empty(mbox)) {
+               msg = mbox_fifo_read(mbox);
+               if (mbq_add(mbox->mbq, msg)) {  /* mbq full */
+                       disable_mbox_irq(mbox, IRQ_RX);
+                       goto flush_queue;
+               }
+               if (mbox->ops->type == OMAP_MBOX_TYPE1)
+                       break;
+       }
 
-       local_irq_restore(flags);
-       return 0;
+       /* no more messages in the fifo. clear IRQ source. */
+       ack_mbox_irq(mbox, IRQ_RX);
+ flush_queue:
+       schedule_work(&mbox->msg_receive);
+
+       return IRQ_HANDLED;
 }
 
 /*
- * register / unregister API
+ * sysfs files
  */
-int register_mbox_receiver(struct mbox *mbox, unsigned char cmd,
-                         mbox_receiver_t *rcv)
+static ssize_t mbox_attr_write(struct class_device *dev, const char *buf,
+                             size_t count)
 {
-       if (cmd >= MBOX_CMD_MAX) {
-               printk(KERN_ERR "register_mbox_receiver(): "
-                      "bad cmd (0x%x)\n", cmd);
-               return -EINVAL;
-       }
-       if (mbox->receiver_map[cmd] != NULL) {
-               printk(KERN_ERR "register_mbox_receiver(): cmd 0x%x is "
-                      "already reserved.\n", cmd);
-               return -EINVAL;
-       }
+       int ret;
+       mbox_msg_t msg;
+       struct omap_mbox *mbox = class_get_devdata(dev);
 
-       mbox->receiver_map[cmd] = rcv;
-       return 0;
-}
+       msg = (mbox_msg_t) simple_strtoul(buf, NULL, 16);
 
-int unregister_mbox_receiver(struct mbox *mbox, unsigned char cmd,
-                           mbox_receiver_t *rcv)
-{
-       if (cmd >= MBOX_CMD_MAX) {
-               printk(KERN_ERR "unregister_mbox_receiver(): "
-                      "bad cmd (0x%x)\n", cmd);
-               return -EINVAL;
-       }
-       if (mbox->receiver_map[cmd] != rcv) {
-               printk(KERN_ERR "unregister_mbox_receiver(): cmd 0x%x and "
-                      "receiver function mismatch!\n", cmd);
-               return -EINVAL;
-       }
+       ret = omap_mbox_msg_send(mbox, msg, NULL);
+       if (ret)
+               return -1;
 
-       mbox->receiver_map[cmd] = NULL;
-       return 0;
+       return count;
 }
 
-/*
- * IRQ disable / enable API
- */
-void disable_mbox_irq(struct mbox *mbox)
+static ssize_t mbox_attr_read(struct class_device *dev, char *buf)
 {
-       disable_irq(mbox->irq);
+       struct omap_mbox *mbox = class_get_devdata(dev);
+
+       return sprintf(buf, mbox->name);
 }
 
-void enable_mbox_irq(struct mbox *mbox)
+static CLASS_DEVICE_ATTR(mbox, S_IALLUGO, mbox_attr_read, mbox_attr_write);
+
+static ssize_t mbox_show(struct class *class, char *buf)
 {
-       enable_irq(mbox->irq);
+       return sprintf(buf, "mbox");
 }
 
-/*
- * init_seq API
- */
-void mbox_init_seq(struct mbox *mbox)
-{
-#ifdef MBOX_USE_SEQ_BIT
-       /* backward compatibility */
-       mbox->seq_snd = 0x80000000;
+static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
 
-       /* any value other than 0 and 1 << 31 */
-       mbox->seq_rcv = 0xffffffff;
-#endif /* MBOX_USE_SEQ_BIT */
-}
+static struct class omap_mbox_class = {
+       .name = "mbox",
+};
 
-/*
- * receiver workqueue
- */
-static void do_mbox(void *p)
+static int omap_mbox_init(struct omap_mbox *mbox)
 {
-       int empty = 0;
-       struct mbox *mbox = (struct mbox *)p;
-       struct mbq *mbq = &mbox->mbq;
-       mbox_receiver_t *receiver;
-       mbox_msg_t msg;
-#ifdef MBOX_USE_SEQ_BIT
-       mbox_msg_t seq;
-#endif
+       int ret;
 
-       disable_newmsg_irq(mbox);
-       if ((mbq->rp == mbq->wp) && !mbq->full)
-               empty = 1;
-       enable_newmsg_irq(mbox);
+       if (likely(mbox->ops->startup)) {
+               ret = mbox->ops->startup(mbox);
+               if (unlikely(ret))
+                       return ret;
+       }
 
-       while (!empty) {
-               msg = mbq->msg[mbq->rp];
-#ifdef MBOX_USE_SEQ_BIT
-               seq = msg & (1 << 31);
+       mbox->class_dev.class = &omap_mbox_class;
+       strlcpy(mbox->class_dev.class_id, mbox->name, KOBJ_NAME_LEN);
+       class_set_devdata(&mbox->class_dev, mbox);
 
-               if (seq == mbox->seq_rcv) {
-                       printk(KERN_ERR
-                              "mbox: illegal seq bit! ignoring this command. "
-                              "(%08x)\n", msg);
-                       goto inc;
-               }
-               mbox->seq_rcv = seq;
-#endif
+       ret = class_device_register(&mbox->class_dev);
+       if (unlikely(ret))
+               return ret;
 
-               /* call receiver function */
-               if ((receiver = mbox->receiver_map[(msg >> 24) & 0x7f]) == NULL)
-                       printk(KERN_ERR
-                              "mbox: unknown message (%08x) received from "
-                              "%s.\n", msg, mbox->name);
-               else
-                       receiver(msg);
-
-#ifdef MBOX_USE_SEQ_BIT
-inc:
-#endif
-               disable_newmsg_irq(mbox);
-               mbq_inc(mbq->rp);
-               if (mbq->rp == mbq->wp)
-                       empty = 1;
-               /* if mbq has been full, now we have a room. */
-               if (mbq->full) {
-                       mbq->full = 0;
-                       enable_newmsg_irq(mbox);
-               }
-               enable_newmsg_irq(mbox);
-       }
-}
+       class_device_create_file(&mbox->class_dev, &class_device_attr_mbox);
 
-/*
- * interrupt handler
- */
-static irqreturn_t mbox_int_newmsg(int irq, void *p, struct pt_regs *regs)
-{
-       struct mbox *mbox = container_of(p, struct mbox, irq_devid_newmsg);
-       struct mbq *mbq = &mbox->mbq;
-       mbox_msg_t *msg;
-
-#ifdef CONFIG_ARCH_OMAP2
-       /*
-        * mailbox IRQ can be muxed.
-        * if it is not a newmsg interrupt, do nothing.
-        */
-       if (!has_newmsg_irq(mbox))
-               return IRQ_NONE;
-#endif
-
-       do {
-#ifdef CONFIG_ARCH_OMAP2
-               if (mbox_nomsg(mbox)) {
-                       /* no more messages in the fifo. clear IRQ source. */
-                       clear_newmsg_irq(mbox);
-                       break;
-               }
-#endif
+       ret = request_irq(mbox->irq, mbox_interrupt, SA_INTERRUPT,
+                         mbox->name, mbox);
+       if (unlikely(ret)) {
+               printk(KERN_ERR
+                      "failed to register mailbox interrupt:%d\n", ret);
+               goto fail1;
+       }
+       enable_mbox_irq(mbox, IRQ_RX);
 
-               msg = &mbq->msg[mbq->wp];
-               read_mbox(mbox, msg);
+       spin_lock_init(&mbox->lock);
+       INIT_WORK(&mbox->msg_receive, mbox_msg_receiver, mbox);
+       init_waitqueue_head(&mbox->tx_waitq);
 
-               mbq_inc(mbq->wp);
-               if (mbq->wp == mbq->rp) {       /* mbq is full */
-                       mbq->full = 1;
-                       disable_newmsg_irq(mbox);
-                       break;
-               }
-#if defined(CONFIG_ARCH_OMAP1)
-       } while (0);    /* do it once */
-#elif defined(CONFIG_ARCH_OMAP2)
-       } while (1);
-#endif
+       ret = mbq_init(&mbox->mbq);
+       if (unlikely(ret))
+               goto fail2;
 
-       schedule_work(&mbox->work);
-       return IRQ_HANDLED;
+       return 0;
+ fail2:
+       free_irq(mbox->irq, mbox);
+       class_remove_file(&omap_mbox_class, &class_attr_mbox);
+       class_unregister(&omap_mbox_class);
+ fail1:
+       if (unlikely(mbox->ops->shutdown))
+               mbox->ops->shutdown(mbox);
+
+       return ret;
 }
 
-#ifdef CONFIG_ARCH_OMAP2
-static irqreturn_t mbox_int_notfull(int irq, void *p, struct pt_regs *regs)
+static void omap_mbox_shutdown(struct omap_mbox *mbox)
 {
-       struct mbox *mbox = container_of(p, struct mbox, irq_devid_notfull);
-
-       /*
-        * mailbox IRQ can be muxed.
-        * if it is not a notfull interrupt, we do nothing.
-        */
-#if 0
-       if (!has_notfull_irq(mbox))
-#else
-       if (!(has_notfull_irq(mbox) && notfull_irq_enabled(mbox)))
-#endif
-               return IRQ_NONE;
-
-       disable_notfull_irq(mbox);
-
-#if 0  /*
-        * note: this doesn't seeem to work as explained in the manual.
-        * IRQSTATUS:NOTFULL can't be cleared even we write 1 to that bit.
-        * It is always set when it's not full, regardless of IRQENABLE setting.
-        */
-       clear_notfull_irq(mbox);
-#endif
-
-       wake_up_interruptible_all(&mbox->full_wait_q);
-       return IRQ_HANDLED;
+       free_irq(mbox->irq, mbox);
+       class_remove_file(&omap_mbox_class, &class_attr_mbox);
+       class_unregister(&omap_mbox_class);
+
+       if (unlikely(mbox->ops->shutdown))
+               mbox->ops->shutdown(mbox);
 }
-#endif /* CONFIG_ARCH_OMAP2 */
 
-static int __init mbox_request_irq(struct mbox *mbox, const char *devname)
+int omap_mbox_register(struct omap_mbox *mbox)
 {
-       int ret;
+       int ret = 0;
+       struct omap_mbox **tmp;
 
-#ifdef CONFIG_ARCH_OMAP2
-       enable_newmsg_irq(mbox);
-#endif
+       if (!mbox)
+               return -EINVAL;
+       if (mbox->next)
+               return -EBUSY;
 
-       ret = request_irq(mbox->irq, mbox_int_newmsg, SA_INTERRUPT | SA_SHIRQ,
-                         devname, &mbox->irq_devid_newmsg);
-       if (ret) {
-               printk(KERN_ERR
-                      "failed to register DSP mailbox newmsg interrupt: "
-                      "%d\n", ret);
+       ret = omap_mbox_init(mbox);
+       if (ret)
                return ret;
-       }
 
-#ifdef CONFIG_ARCH_OMAP2
-       ret = request_irq(mbox->irq, mbox_int_notfull, SA_INTERRUPT | SA_SHIRQ,
-                         devname, &mbox->irq_devid_notfull);
-       if (ret) {
-               printk(KERN_ERR
-                      "failed to register DSP mailbox notfull interrupt: "
-                      "%d\n", ret);
-               return ret;
+       write_lock(&mboxes_lock);
+       tmp = find_mboxes(mbox->name);
+       if (*tmp)
+               ret = -EBUSY;
+       else
+               *tmp = mbox;
+       write_unlock(&mboxes_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(omap_mbox_register);
+
+int omap_mbox_unregister(struct omap_mbox *mbox)
+{
+       struct omap_mbox **tmp;
+
+       write_lock(&mboxes_lock);
+       tmp = &mboxes;
+       while (*tmp) {
+               if (mbox == *tmp) {
+                       *tmp = mbox->next;
+                       mbox->next = NULL;
+                       write_unlock(&mboxes_lock);
+
+                       omap_mbox_shutdown(mbox);
+
+                       return 0;
+               }
+               tmp = &(*tmp)->next;
        }
-#endif
+       write_unlock(&mboxes_lock);
 
-       return 0;
+       return -EINVAL;
 }
+EXPORT_SYMBOL(omap_mbox_unregister);
 
-static int __init omap_mailbox_init(void)
+static int __init omap_mbox_class_init(void)
 {
-       int ret;
-#ifdef CONFIG_ARCH_OMAP2
-       struct clk *mbox_ick_handle;
-#endif
-
-       printk(KERN_INFO "Initializing OMAP Mailboxes\n");
-#ifdef CONFIG_ARCH_OMAP2
-       /*
-        * FIXME: mbox_ick will never unsed
-        */
-       mbox_ick_handle = clk_get(NULL, "mailboxes_ick");
-       if (IS_ERR(mbox_ick_handle)) {
-               printk("Could not get mailboxes_ick\n");
-               return -ENODEV;
-       } else
-               clk_enable(mbox_ick_handle);
-#endif
-
-       if ((ret = mbox_request_irq(&mbox_dsp, "mbox_dsp")) != 0)
-               return ret;
-#ifdef CONFIG_ARCH_OMAP2
-       if ((ret = mbox_request_irq(&mbox_iva, "mbox_iva")) != 0)
-               return ret;
-#endif
+       int ret = class_register(&omap_mbox_class);
+       if (!ret)
+               ret = class_create_file(&omap_mbox_class, &class_attr_mbox);
 
-       return 0;
+       return ret;
 }
 
-arch_initcall(omap_mailbox_init);
+static void __exit omap_mbox_class_exit(void)
+{
+       class_remove_file(&omap_mbox_class, &class_attr_mbox);
+       class_unregister(&omap_mbox_class);
+}
 
-EXPORT_SYMBOL(mbox_get);
-EXPORT_SYMBOL(mbox_send);
-EXPORT_SYMBOL(register_mbox_receiver);
-EXPORT_SYMBOL(unregister_mbox_receiver);
-EXPORT_SYMBOL(disable_mbox_irq);
-EXPORT_SYMBOL(enable_mbox_irq);
-EXPORT_SYMBOL(mbox_init_seq);
+subsys_initcall(omap_mbox_class_init);
+module_exit(omap_mbox_class_exit);