4 * Copyright (C) 2006 Nokia Corporation. All rights reserved.
6 * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
7 * Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
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.
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.
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
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/blkdev.h>
31 #include <linux/err.h>
32 #include <linux/delay.h>
34 #include <mach/mailbox.h>
37 static struct omap_mbox
*mboxes
;
38 static DEFINE_RWLOCK(mboxes_lock
);
40 /* Mailbox Sequence Bit function */
41 void omap_mbox_init_seq(struct omap_mbox
*mbox
)
45 EXPORT_SYMBOL(omap_mbox_init_seq
);
50 static int __mbox_msg_send(struct omap_mbox
*mbox
, mbox_msg_t msg
, void *arg
)
52 int ret
= 0, i
= 1000;
54 while (mbox_fifo_full(mbox
)) {
55 if (mbox
->ops
->type
== OMAP_MBOX_TYPE2
)
62 if (arg
&& mbox
->txq
->callback
) {
63 ret
= mbox
->txq
->callback(arg
);
68 mbox_seq_toggle(mbox
, &msg
);
69 mbox_fifo_write(mbox
, msg
);
74 int omap_mbox_msg_send(struct omap_mbox
*mbox
, mbox_msg_t msg
, void* arg
)
77 struct request_queue
*q
= mbox
->txq
->queue
;
80 rq
= blk_get_request(q
, WRITE
, GFP_ATOMIC
);
86 rq
->data
= (void *)msg
;
87 blk_insert_request(q
, rq
, 0, arg
);
89 schedule_work(&mbox
->txq
->work
);
93 EXPORT_SYMBOL(omap_mbox_msg_send
);
95 static void mbox_tx_work(struct work_struct
*work
)
99 struct omap_mbox_queue
*mq
= container_of(work
,
100 struct omap_mbox_queue
, work
);
101 struct omap_mbox
*mbox
= mq
->queue
->queuedata
;
102 struct request_queue
*q
= mbox
->txq
->queue
;
105 spin_lock(q
->queue_lock
);
106 rq
= elv_next_request(q
);
107 spin_unlock(q
->queue_lock
);
112 ret
= __mbox_msg_send(mbox
, (mbox_msg_t
) rq
->data
, rq
->special
);
114 enable_mbox_irq(mbox
, IRQ_TX
);
118 spin_lock(q
->queue_lock
);
119 if (__blk_end_request(rq
, 0, 0))
121 spin_unlock(q
->queue_lock
);
126 * Message receiver(workqueue)
128 static void mbox_rx_work(struct work_struct
*work
)
130 struct omap_mbox_queue
*mq
=
131 container_of(work
, struct omap_mbox_queue
, work
);
132 struct omap_mbox
*mbox
= mq
->queue
->queuedata
;
133 struct request_queue
*q
= mbox
->rxq
->queue
;
138 if (mbox
->rxq
->callback
== NULL
) {
139 sysfs_notify(&mbox
->dev
.kobj
, NULL
, "mbox");
144 spin_lock_irqsave(q
->queue_lock
, flags
);
145 rq
= elv_next_request(q
);
146 spin_unlock_irqrestore(q
->queue_lock
, flags
);
150 msg
= (mbox_msg_t
) rq
->data
;
152 if (blk_end_request(rq
, 0, 0))
155 mbox
->rxq
->callback((void *)msg
);
160 * Mailbox interrupt handler
162 static void mbox_txq_fn(struct request_queue
* q
)
166 static void mbox_rxq_fn(struct request_queue
* q
)
170 static void __mbox_tx_interrupt(struct omap_mbox
*mbox
)
172 disable_mbox_irq(mbox
, IRQ_TX
);
173 ack_mbox_irq(mbox
, IRQ_TX
);
174 schedule_work(&mbox
->txq
->work
);
177 static void __mbox_rx_interrupt(struct omap_mbox
*mbox
)
181 struct request_queue
*q
= mbox
->rxq
->queue
;
183 disable_mbox_irq(mbox
, IRQ_RX
);
185 while (!mbox_fifo_empty(mbox
)) {
186 rq
= blk_get_request(q
, WRITE
, GFP_ATOMIC
);
190 msg
= mbox_fifo_read(mbox
);
191 rq
->data
= (void *)msg
;
193 if (unlikely(mbox_seq_test(mbox
, msg
))) {
194 pr_info("mbox: Illegal seq bit!(%08x)\n", msg
);
195 if (mbox
->err_notify
)
199 blk_insert_request(q
, rq
, 0, NULL
);
200 if (mbox
->ops
->type
== OMAP_MBOX_TYPE1
)
204 /* no more messages in the fifo. clear IRQ source. */
205 ack_mbox_irq(mbox
, IRQ_RX
);
206 enable_mbox_irq(mbox
, IRQ_RX
);
208 schedule_work(&mbox
->rxq
->work
);
211 static irqreturn_t
mbox_interrupt(int irq
, void *p
)
213 struct omap_mbox
*mbox
= p
;
215 if (is_mbox_irq(mbox
, IRQ_TX
))
216 __mbox_tx_interrupt(mbox
);
218 if (is_mbox_irq(mbox
, IRQ_RX
))
219 __mbox_rx_interrupt(mbox
);
228 omap_mbox_write(struct device
*dev
, struct device_attribute
*attr
,
229 const char * buf
, size_t count
)
232 mbox_msg_t
*p
= (mbox_msg_t
*)buf
;
233 struct omap_mbox
*mbox
= dev_get_drvdata(dev
);
235 for (; count
>= sizeof(mbox_msg_t
); count
-= sizeof(mbox_msg_t
)) {
236 ret
= omap_mbox_msg_send(mbox
, be32_to_cpu(*p
), NULL
);
242 return (size_t)((char *)p
- buf
);
246 omap_mbox_read(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
250 mbox_msg_t
*p
= (mbox_msg_t
*) buf
;
251 struct omap_mbox
*mbox
= dev_get_drvdata(dev
);
252 struct request_queue
*q
= mbox
->rxq
->queue
;
255 spin_lock_irqsave(q
->queue_lock
, flags
);
256 rq
= elv_next_request(q
);
257 spin_unlock_irqrestore(q
->queue_lock
, flags
);
262 *p
= (mbox_msg_t
) rq
->data
;
264 if (blk_end_request(rq
, 0, 0))
267 if (unlikely(mbox_seq_test(mbox
, *p
))) {
268 pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p
);
274 pr_debug("%02x %02x %02x %02x\n", buf
[0], buf
[1], buf
[2], buf
[3]);
276 return (size_t) ((char *)p
- buf
);
279 static DEVICE_ATTR(mbox
, S_IRUGO
| S_IWUSR
, omap_mbox_read
, omap_mbox_write
);
281 static ssize_t
mbox_show(struct class *class, char *buf
)
283 return sprintf(buf
, "mbox");
286 static CLASS_ATTR(mbox
, S_IRUGO
, mbox_show
, NULL
);
288 static struct class omap_mbox_class
= {
292 static struct omap_mbox_queue
*mbox_queue_alloc(struct omap_mbox
*mbox
,
293 request_fn_proc
* proc
,
294 void (*work
) (struct work_struct
*))
296 struct request_queue
*q
;
297 struct omap_mbox_queue
*mq
;
299 mq
= kzalloc(sizeof(struct omap_mbox_queue
), GFP_KERNEL
);
303 spin_lock_init(&mq
->lock
);
305 q
= blk_init_queue(proc
, &mq
->lock
);
311 INIT_WORK(&mq
->work
, work
);
319 static void mbox_queue_free(struct omap_mbox_queue
*q
)
321 blk_cleanup_queue(q
->queue
);
325 static int omap_mbox_init(struct omap_mbox
*mbox
)
328 struct omap_mbox_queue
*mq
;
330 if (likely(mbox
->ops
->startup
)) {
331 ret
= mbox
->ops
->startup(mbox
);
336 mbox
->dev
.class = &omap_mbox_class
;
337 dev_set_name(&mbox
->dev
, "%s", mbox
->name
);
338 dev_set_drvdata(&mbox
->dev
, mbox
);
340 ret
= device_register(&mbox
->dev
);
342 goto fail_device_reg
;
344 ret
= device_create_file(&mbox
->dev
, &dev_attr_mbox
);
347 "device_create_file failed: %d\n", ret
);
348 goto fail_create_mbox
;
351 ret
= request_irq(mbox
->irq
, mbox_interrupt
, IRQF_DISABLED
,
355 "failed to register mailbox interrupt:%d\n", ret
);
356 goto fail_request_irq
;
359 mq
= mbox_queue_alloc(mbox
, mbox_txq_fn
, mbox_tx_work
);
366 mq
= mbox_queue_alloc(mbox
, mbox_rxq_fn
, mbox_rx_work
);
376 mbox_queue_free(mbox
->txq
);
378 free_irq(mbox
->irq
, mbox
);
380 device_remove_file(&mbox
->dev
, &dev_attr_mbox
);
382 device_unregister(&mbox
->dev
);
384 if (unlikely(mbox
->ops
->shutdown
))
385 mbox
->ops
->shutdown(mbox
);
390 static void omap_mbox_fini(struct omap_mbox
*mbox
)
392 mbox_queue_free(mbox
->txq
);
393 mbox_queue_free(mbox
->rxq
);
395 free_irq(mbox
->irq
, mbox
);
396 device_remove_file(&mbox
->dev
, &dev_attr_mbox
);
397 class_unregister(&omap_mbox_class
);
399 if (unlikely(mbox
->ops
->shutdown
))
400 mbox
->ops
->shutdown(mbox
);
403 static struct omap_mbox
**find_mboxes(const char *name
)
405 struct omap_mbox
**p
;
407 for (p
= &mboxes
; *p
; p
= &(*p
)->next
) {
408 if (strcmp((*p
)->name
, name
) == 0)
415 struct omap_mbox
*omap_mbox_get(const char *name
)
417 struct omap_mbox
*mbox
;
420 read_lock(&mboxes_lock
);
421 mbox
= *(find_mboxes(name
));
423 read_unlock(&mboxes_lock
);
424 return ERR_PTR(-ENOENT
);
427 read_unlock(&mboxes_lock
);
429 ret
= omap_mbox_init(mbox
);
431 return ERR_PTR(-ENODEV
);
435 EXPORT_SYMBOL(omap_mbox_get
);
437 void omap_mbox_put(struct omap_mbox
*mbox
)
439 omap_mbox_fini(mbox
);
441 EXPORT_SYMBOL(omap_mbox_put
);
443 int omap_mbox_register(struct omap_mbox
*mbox
)
446 struct omap_mbox
**tmp
;
453 write_lock(&mboxes_lock
);
454 tmp
= find_mboxes(mbox
->name
);
459 write_unlock(&mboxes_lock
);
463 EXPORT_SYMBOL(omap_mbox_register
);
465 int omap_mbox_unregister(struct omap_mbox
*mbox
)
467 struct omap_mbox
**tmp
;
469 write_lock(&mboxes_lock
);
475 write_unlock(&mboxes_lock
);
480 write_unlock(&mboxes_lock
);
484 EXPORT_SYMBOL(omap_mbox_unregister
);
486 static int __init
omap_mbox_class_init(void)
488 int ret
= class_register(&omap_mbox_class
);
490 ret
= class_create_file(&omap_mbox_class
, &class_attr_mbox
);
495 static void __exit
omap_mbox_class_exit(void)
497 class_remove_file(&omap_mbox_class
, &class_attr_mbox
);
498 class_unregister(&omap_mbox_class
);
501 subsys_initcall(omap_mbox_class_init
);
502 module_exit(omap_mbox_class_exit
);
504 MODULE_LICENSE("GPL");