4 * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.
6 * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
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.
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.
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
24 #include <linux/interrupt.h>
25 #include <linux/spinlock.h>
26 #include <linux/mutex.h>
27 #include <linux/delay.h>
28 #include <linux/slab.h>
29 #include <linux/kfifo.h>
30 #include <linux/err.h>
31 #include <linux/notifier.h>
32 #include <linux/pm_qos_params.h>
34 #include <plat/mailbox.h>
36 static struct omap_mbox
**mboxes
;
38 static int mbox_configured
;
39 static DEFINE_MUTEX(mbox_configured_lock
);
40 struct pm_qos_request_list mbox_qos_request
;
42 #define SET_MPU_CORE_CONSTRAINT 10
43 #define CLEAR_MPU_CORE_CONSTRAINT -1
45 static unsigned int mbox_kfifo_size
= CONFIG_OMAP_MBOX_KFIFO_SIZE
;
46 module_param(mbox_kfifo_size
, uint
, S_IRUGO
);
47 MODULE_PARM_DESC(mbox_kfifo_size
, "Size of omap's mailbox kfifo (bytes)");
49 /* Mailbox FIFO handle functions */
50 static inline mbox_msg_t
mbox_fifo_read(struct omap_mbox
*mbox
)
52 return mbox
->ops
->fifo_read(mbox
);
54 static inline void mbox_fifo_write(struct omap_mbox
*mbox
, mbox_msg_t msg
)
56 mbox
->ops
->fifo_write(mbox
, msg
);
58 static inline int mbox_fifo_empty(struct omap_mbox
*mbox
)
60 return mbox
->ops
->fifo_empty(mbox
);
62 static inline int mbox_fifo_full(struct omap_mbox
*mbox
)
64 return mbox
->ops
->fifo_full(mbox
);
67 /* Mailbox IRQ handle functions */
68 static inline void ack_mbox_irq(struct omap_mbox
*mbox
, omap_mbox_irq_t irq
)
70 if (mbox
->ops
->ack_irq
)
71 mbox
->ops
->ack_irq(mbox
, irq
);
73 static inline int is_mbox_irq(struct omap_mbox
*mbox
, omap_mbox_irq_t irq
)
75 return mbox
->ops
->is_irq(mbox
, irq
);
81 static int __mbox_poll_for_space(struct omap_mbox
*mbox
)
83 int ret
= 0, i
= 1000;
85 while (mbox_fifo_full(mbox
)) {
86 if (mbox
->ops
->type
== OMAP_MBOX_TYPE2
)
95 int omap_mbox_msg_send(struct omap_mbox
*mbox
, mbox_msg_t msg
)
97 struct omap_mbox_queue
*mq
= mbox
->txq
;
100 spin_lock_bh(&mq
->lock
);
102 if (kfifo_avail(&mq
->fifo
) < sizeof(msg
)) {
107 if (kfifo_is_empty(&mq
->fifo
) && !__mbox_poll_for_space(mbox
)) {
108 mbox_fifo_write(mbox
, msg
);
112 len
= kfifo_in(&mq
->fifo
, (unsigned char *)&msg
, sizeof(msg
));
113 WARN_ON(len
!= sizeof(msg
));
115 tasklet_schedule(&mbox
->txq
->tasklet
);
118 spin_unlock_bh(&mq
->lock
);
121 EXPORT_SYMBOL(omap_mbox_msg_send
);
123 static void mbox_tx_tasklet(unsigned long tx_data
)
125 struct omap_mbox
*mbox
= (struct omap_mbox
*)tx_data
;
126 struct omap_mbox_queue
*mq
= mbox
->txq
;
130 while (kfifo_len(&mq
->fifo
)) {
131 if (__mbox_poll_for_space(mbox
)) {
132 omap_mbox_enable_irq(mbox
, IRQ_TX
);
136 ret
= kfifo_out(&mq
->fifo
, (unsigned char *)&msg
,
138 WARN_ON(ret
!= sizeof(msg
));
140 mbox_fifo_write(mbox
, msg
);
145 * Message receiver(workqueue)
147 static void mbox_rx_work(struct work_struct
*work
)
149 struct omap_mbox_queue
*mq
=
150 container_of(work
, struct omap_mbox_queue
, work
);
154 while (kfifo_len(&mq
->fifo
) >= sizeof(msg
)) {
155 len
= kfifo_out(&mq
->fifo
, (unsigned char *)&msg
, sizeof(msg
));
156 WARN_ON(len
!= sizeof(msg
));
158 blocking_notifier_call_chain(&mq
->mbox
->notifier
, len
,
160 spin_lock_irq(&mq
->lock
);
163 omap_mbox_enable_irq(mq
->mbox
, IRQ_RX
);
165 spin_unlock_irq(&mq
->lock
);
170 * Mailbox interrupt handler
172 static void __mbox_tx_interrupt(struct omap_mbox
*mbox
)
174 omap_mbox_disable_irq(mbox
, IRQ_TX
);
175 ack_mbox_irq(mbox
, IRQ_TX
);
176 tasklet_schedule(&mbox
->txq
->tasklet
);
179 static void __mbox_rx_interrupt(struct omap_mbox
*mbox
)
181 struct omap_mbox_queue
*mq
= mbox
->rxq
;
185 while (!mbox_fifo_empty(mbox
)) {
186 if (unlikely(kfifo_avail(&mq
->fifo
) < sizeof(msg
))) {
187 omap_mbox_disable_irq(mbox
, IRQ_RX
);
192 msg
= mbox_fifo_read(mbox
);
194 len
= kfifo_in(&mq
->fifo
, (unsigned char *)&msg
, sizeof(msg
));
195 WARN_ON(len
!= sizeof(msg
));
197 if (mbox
->ops
->type
== OMAP_MBOX_TYPE1
)
201 /* no more messages in the fifo. clear IRQ source. */
202 ack_mbox_irq(mbox
, IRQ_RX
);
204 schedule_work(&mbox
->rxq
->work
);
207 static irqreturn_t
mbox_interrupt(int irq
, void *p
)
209 struct omap_mbox
*mbox
= p
;
211 if (is_mbox_irq(mbox
, IRQ_TX
))
212 __mbox_tx_interrupt(mbox
);
214 if (is_mbox_irq(mbox
, IRQ_RX
))
215 __mbox_rx_interrupt(mbox
);
220 static struct omap_mbox_queue
*mbox_queue_alloc(struct omap_mbox
*mbox
,
221 void (*work
) (struct work_struct
*),
222 void (*tasklet
)(unsigned long))
224 struct omap_mbox_queue
*mq
;
226 mq
= kzalloc(sizeof(struct omap_mbox_queue
), GFP_KERNEL
);
230 spin_lock_init(&mq
->lock
);
232 if (kfifo_alloc(&mq
->fifo
, mbox_kfifo_size
, GFP_KERNEL
))
236 INIT_WORK(&mq
->work
, work
);
239 tasklet_init(&mq
->tasklet
, tasklet
, (unsigned long)mbox
);
246 static void mbox_queue_free(struct omap_mbox_queue
*q
)
248 kfifo_free(&q
->fifo
);
252 static int omap_mbox_startup(struct omap_mbox
*mbox
)
255 struct omap_mbox_queue
*mq
;
257 mutex_lock(&mbox_configured_lock
);
258 if (!mbox_configured
++) {
259 pm_qos_update_request(&mbox_qos_request
,
260 SET_MPU_CORE_CONSTRAINT
);
261 if (likely(mbox
->ops
->startup
)) {
262 ret
= mbox
->ops
->startup(mbox
);
269 if (!mbox
->use_count
++) {
270 mq
= mbox_queue_alloc(mbox
, NULL
, mbox_tx_tasklet
);
277 mq
= mbox_queue_alloc(mbox
, mbox_rx_work
, NULL
);
284 ret
= request_irq(mbox
->irq
, mbox_interrupt
, IRQF_SHARED
,
287 pr_err("failed to register mailbox interrupt:%d\n",
289 goto fail_request_irq
;
292 mutex_unlock(&mbox_configured_lock
);
296 mbox_queue_free(mbox
->rxq
);
298 mbox_queue_free(mbox
->txq
);
300 if (mbox
->ops
->shutdown
)
301 mbox
->ops
->shutdown(mbox
);
304 if (!--mbox_configured
)
305 pm_qos_update_request(&mbox_qos_request
,
306 CLEAR_MPU_CORE_CONSTRAINT
);
307 mutex_unlock(&mbox_configured_lock
);
311 static void omap_mbox_fini(struct omap_mbox
*mbox
)
313 mutex_lock(&mbox_configured_lock
);
315 if (!--mbox
->use_count
) {
316 free_irq(mbox
->irq
, mbox
);
317 tasklet_kill(&mbox
->txq
->tasklet
);
318 flush_work_sync(&mbox
->rxq
->work
);
319 mbox_queue_free(mbox
->txq
);
320 mbox_queue_free(mbox
->rxq
);
323 if (likely(mbox
->ops
->shutdown
)) {
324 if (!--mbox_configured
) {
325 mbox
->ops
->shutdown(mbox
);
326 pm_qos_update_request(&mbox_qos_request
,
327 CLEAR_MPU_CORE_CONSTRAINT
);
331 mutex_unlock(&mbox_configured_lock
);
334 struct omap_mbox
*omap_mbox_get(const char *name
, struct notifier_block
*nb
)
336 struct omap_mbox
*_mbox
, *mbox
= NULL
;
340 return ERR_PTR(-EINVAL
);
342 for (i
= 0; (_mbox
= mboxes
[i
]); i
++) {
343 if (!strcmp(_mbox
->name
, name
)) {
350 return ERR_PTR(-ENOENT
);
352 ret
= omap_mbox_startup(mbox
);
354 return ERR_PTR(-ENODEV
);
357 blocking_notifier_chain_register(&mbox
->notifier
, nb
);
361 EXPORT_SYMBOL(omap_mbox_get
);
363 void omap_mbox_put(struct omap_mbox
*mbox
, struct notifier_block
*nb
)
366 blocking_notifier_chain_unregister(&mbox
->notifier
, nb
);
367 omap_mbox_fini(mbox
);
369 EXPORT_SYMBOL(omap_mbox_put
);
371 static struct class omap_mbox_class
= { .name
= "mbox", };
373 int omap_mbox_register(struct device
*parent
, struct omap_mbox
**list
)
382 for (i
= 0; mboxes
[i
]; i
++) {
383 struct omap_mbox
*mbox
= mboxes
[i
];
384 mbox
->dev
= device_create(&omap_mbox_class
,
385 parent
, 0, mbox
, "%s", mbox
->name
);
386 if (IS_ERR(mbox
->dev
)) {
387 ret
= PTR_ERR(mbox
->dev
);
391 BLOCKING_INIT_NOTIFIER_HEAD(&mbox
->notifier
);
397 device_unregister(mboxes
[i
]->dev
);
400 EXPORT_SYMBOL(omap_mbox_register
);
402 int omap_mbox_unregister(void)
409 for (i
= 0; mboxes
[i
]; i
++)
410 device_unregister(mboxes
[i
]->dev
);
415 EXPORT_SYMBOL(omap_mbox_unregister
);
417 static int __init
omap_mbox_init(void)
421 err
= class_register(&omap_mbox_class
);
425 /* kfifo size sanity check: alignment and minimal size */
426 mbox_kfifo_size
= ALIGN(mbox_kfifo_size
, sizeof(mbox_msg_t
));
427 mbox_kfifo_size
= max_t(unsigned int, mbox_kfifo_size
,
430 pm_qos_add_request(&mbox_qos_request
, PM_QOS_CPU_DMA_LATENCY
,
431 PM_QOS_DEFAULT_VALUE
);
434 subsys_initcall(omap_mbox_init
);
436 static void __exit
omap_mbox_exit(void)
438 class_unregister(&omap_mbox_class
);
439 pm_qos_remove_request(&mbox_qos_request
);
441 module_exit(omap_mbox_exit
);
443 MODULE_LICENSE("GPL v2");
444 MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
445 MODULE_AUTHOR("Toshihiro Kobayashi");
446 MODULE_AUTHOR("Hiroshi DOYU");