diff options
Diffstat (limited to 'arch/arm/plat-omap/mailbox.c')
-rw-r--r-- | arch/arm/plat-omap/mailbox.c | 152 |
1 files changed, 114 insertions, 38 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index b52ce053e6f2..0abfbaa59871 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c | |||
@@ -1,10 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * OMAP mailbox driver | 2 | * OMAP mailbox driver |
3 | * | 3 | * |
4 | * Copyright (C) 2006 Nokia Corporation. All rights reserved. | 4 | * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. |
5 | * | 5 | * |
6 | * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com> | 6 | * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com> |
7 | * Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.com> | ||
8 | * | 7 | * |
9 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 9 | * modify it under the terms of the GNU General Public License |
@@ -22,21 +21,98 @@ | |||
22 | * | 21 | * |
23 | */ | 22 | */ |
24 | 23 | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | 24 | #include <linux/module.h> |
27 | #include <linux/sched.h> | ||
28 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
29 | #include <linux/device.h> | 26 | #include <linux/device.h> |
30 | #include <linux/blkdev.h> | ||
31 | #include <linux/err.h> | ||
32 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
33 | #include <linux/io.h> | 28 | |
34 | #include <mach/mailbox.h> | 29 | #include <mach/mailbox.h> |
35 | #include "mailbox.h" | 30 | |
31 | static int enable_seq_bit; | ||
32 | module_param(enable_seq_bit, bool, 0); | ||
33 | MODULE_PARM_DESC(enable_seq_bit, "Enable sequence bit checking."); | ||
36 | 34 | ||
37 | static struct omap_mbox *mboxes; | 35 | static struct omap_mbox *mboxes; |
38 | static DEFINE_RWLOCK(mboxes_lock); | 36 | static DEFINE_RWLOCK(mboxes_lock); |
39 | 37 | ||
38 | /* | ||
39 | * Mailbox sequence bit API | ||
40 | */ | ||
41 | |||
42 | /* seq_rcv should be initialized with any value other than | ||
43 | * 0 and 1 << 31, to allow either value for the first | ||
44 | * message. */ | ||
45 | static inline void mbox_seq_init(struct omap_mbox *mbox) | ||
46 | { | ||
47 | if (!enable_seq_bit) | ||
48 | return; | ||
49 | |||
50 | /* any value other than 0 and 1 << 31 */ | ||
51 | mbox->seq_rcv = 0xffffffff; | ||
52 | } | ||
53 | |||
54 | static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg) | ||
55 | { | ||
56 | if (!enable_seq_bit) | ||
57 | return; | ||
58 | |||
59 | /* add seq_snd to msg */ | ||
60 | *msg = (*msg & 0x7fffffff) | mbox->seq_snd; | ||
61 | /* flip seq_snd */ | ||
62 | mbox->seq_snd ^= 1 << 31; | ||
63 | } | ||
64 | |||
65 | static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg) | ||
66 | { | ||
67 | mbox_msg_t seq; | ||
68 | |||
69 | if (!enable_seq_bit) | ||
70 | return 0; | ||
71 | |||
72 | seq = msg & (1 << 31); | ||
73 | if (seq == mbox->seq_rcv) | ||
74 | return -1; | ||
75 | mbox->seq_rcv = seq; | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | /* Mailbox FIFO handle functions */ | ||
80 | static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) | ||
81 | { | ||
82 | return mbox->ops->fifo_read(mbox); | ||
83 | } | ||
84 | static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) | ||
85 | { | ||
86 | mbox->ops->fifo_write(mbox, msg); | ||
87 | } | ||
88 | static inline int mbox_fifo_empty(struct omap_mbox *mbox) | ||
89 | { | ||
90 | return mbox->ops->fifo_empty(mbox); | ||
91 | } | ||
92 | static inline int mbox_fifo_full(struct omap_mbox *mbox) | ||
93 | { | ||
94 | return mbox->ops->fifo_full(mbox); | ||
95 | } | ||
96 | |||
97 | /* Mailbox IRQ handle functions */ | ||
98 | static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
99 | { | ||
100 | mbox->ops->enable_irq(mbox, irq); | ||
101 | } | ||
102 | static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
103 | { | ||
104 | mbox->ops->disable_irq(mbox, irq); | ||
105 | } | ||
106 | static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
107 | { | ||
108 | if (mbox->ops->ack_irq) | ||
109 | mbox->ops->ack_irq(mbox, irq); | ||
110 | } | ||
111 | static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
112 | { | ||
113 | return mbox->ops->is_irq(mbox, irq); | ||
114 | } | ||
115 | |||
40 | /* Mailbox Sequence Bit function */ | 116 | /* Mailbox Sequence Bit function */ |
41 | void omap_mbox_init_seq(struct omap_mbox *mbox) | 117 | void omap_mbox_init_seq(struct omap_mbox *mbox) |
42 | { | 118 | { |
@@ -136,7 +212,7 @@ static void mbox_rx_work(struct work_struct *work) | |||
136 | unsigned long flags; | 212 | unsigned long flags; |
137 | 213 | ||
138 | if (mbox->rxq->callback == NULL) { | 214 | if (mbox->rxq->callback == NULL) { |
139 | sysfs_notify(&mbox->dev.kobj, NULL, "mbox"); | 215 | sysfs_notify(&mbox->dev->kobj, NULL, "mbox"); |
140 | return; | 216 | return; |
141 | } | 217 | } |
142 | 218 | ||
@@ -204,7 +280,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) | |||
204 | /* no more messages in the fifo. clear IRQ source. */ | 280 | /* no more messages in the fifo. clear IRQ source. */ |
205 | ack_mbox_irq(mbox, IRQ_RX); | 281 | ack_mbox_irq(mbox, IRQ_RX); |
206 | enable_mbox_irq(mbox, IRQ_RX); | 282 | enable_mbox_irq(mbox, IRQ_RX); |
207 | nomem: | 283 | nomem: |
208 | schedule_work(&mbox->rxq->work); | 284 | schedule_work(&mbox->rxq->work); |
209 | } | 285 | } |
210 | 286 | ||
@@ -286,7 +362,7 @@ static ssize_t mbox_show(struct class *class, char *buf) | |||
286 | static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL); | 362 | static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL); |
287 | 363 | ||
288 | static struct class omap_mbox_class = { | 364 | static struct class omap_mbox_class = { |
289 | .name = "omap_mbox", | 365 | .name = "omap-mailbox", |
290 | }; | 366 | }; |
291 | 367 | ||
292 | static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, | 368 | static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, |
@@ -333,21 +409,6 @@ static int omap_mbox_init(struct omap_mbox *mbox) | |||
333 | return ret; | 409 | return ret; |
334 | } | 410 | } |
335 | 411 | ||
336 | mbox->dev.class = &omap_mbox_class; | ||
337 | dev_set_name(&mbox->dev, "%s", mbox->name); | ||
338 | dev_set_drvdata(&mbox->dev, mbox); | ||
339 | |||
340 | ret = device_register(&mbox->dev); | ||
341 | if (unlikely(ret)) | ||
342 | goto fail_device_reg; | ||
343 | |||
344 | ret = device_create_file(&mbox->dev, &dev_attr_mbox); | ||
345 | if (unlikely(ret)) { | ||
346 | printk(KERN_ERR | ||
347 | "device_create_file failed: %d\n", ret); | ||
348 | goto fail_create_mbox; | ||
349 | } | ||
350 | |||
351 | ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED, | 412 | ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED, |
352 | mbox->name, mbox); | 413 | mbox->name, mbox); |
353 | if (unlikely(ret)) { | 414 | if (unlikely(ret)) { |
@@ -377,10 +438,6 @@ static int omap_mbox_init(struct omap_mbox *mbox) | |||
377 | fail_alloc_txq: | 438 | fail_alloc_txq: |
378 | free_irq(mbox->irq, mbox); | 439 | free_irq(mbox->irq, mbox); |
379 | fail_request_irq: | 440 | fail_request_irq: |
380 | device_remove_file(&mbox->dev, &dev_attr_mbox); | ||
381 | fail_create_mbox: | ||
382 | device_unregister(&mbox->dev); | ||
383 | fail_device_reg: | ||
384 | if (unlikely(mbox->ops->shutdown)) | 441 | if (unlikely(mbox->ops->shutdown)) |
385 | mbox->ops->shutdown(mbox); | 442 | mbox->ops->shutdown(mbox); |
386 | 443 | ||
@@ -393,8 +450,6 @@ static void omap_mbox_fini(struct omap_mbox *mbox) | |||
393 | mbox_queue_free(mbox->rxq); | 450 | mbox_queue_free(mbox->rxq); |
394 | 451 | ||
395 | free_irq(mbox->irq, mbox); | 452 | free_irq(mbox->irq, mbox); |
396 | device_remove_file(&mbox->dev, &dev_attr_mbox); | ||
397 | class_unregister(&omap_mbox_class); | ||
398 | 453 | ||
399 | if (unlikely(mbox->ops->shutdown)) | 454 | if (unlikely(mbox->ops->shutdown)) |
400 | mbox->ops->shutdown(mbox); | 455 | mbox->ops->shutdown(mbox); |
@@ -440,7 +495,7 @@ void omap_mbox_put(struct omap_mbox *mbox) | |||
440 | } | 495 | } |
441 | EXPORT_SYMBOL(omap_mbox_put); | 496 | EXPORT_SYMBOL(omap_mbox_put); |
442 | 497 | ||
443 | int omap_mbox_register(struct omap_mbox *mbox) | 498 | int omap_mbox_register(struct device *parent, struct omap_mbox *mbox) |
444 | { | 499 | { |
445 | int ret = 0; | 500 | int ret = 0; |
446 | struct omap_mbox **tmp; | 501 | struct omap_mbox **tmp; |
@@ -450,14 +505,31 @@ int omap_mbox_register(struct omap_mbox *mbox) | |||
450 | if (mbox->next) | 505 | if (mbox->next) |
451 | return -EBUSY; | 506 | return -EBUSY; |
452 | 507 | ||
508 | mbox->dev = device_create(&omap_mbox_class, | ||
509 | parent, 0, mbox, "%s", mbox->name); | ||
510 | if (IS_ERR(mbox->dev)) | ||
511 | return PTR_ERR(mbox->dev); | ||
512 | |||
513 | ret = device_create_file(mbox->dev, &dev_attr_mbox); | ||
514 | if (ret) | ||
515 | goto err_sysfs; | ||
516 | |||
453 | write_lock(&mboxes_lock); | 517 | write_lock(&mboxes_lock); |
454 | tmp = find_mboxes(mbox->name); | 518 | tmp = find_mboxes(mbox->name); |
455 | if (*tmp) | 519 | if (*tmp) { |
456 | ret = -EBUSY; | 520 | ret = -EBUSY; |
457 | else | 521 | write_unlock(&mboxes_lock); |
458 | *tmp = mbox; | 522 | goto err_find; |
523 | } | ||
524 | *tmp = mbox; | ||
459 | write_unlock(&mboxes_lock); | 525 | write_unlock(&mboxes_lock); |
460 | 526 | ||
527 | return 0; | ||
528 | |||
529 | err_find: | ||
530 | device_remove_file(mbox->dev, &dev_attr_mbox); | ||
531 | err_sysfs: | ||
532 | device_unregister(mbox->dev); | ||
461 | return ret; | 533 | return ret; |
462 | } | 534 | } |
463 | EXPORT_SYMBOL(omap_mbox_register); | 535 | EXPORT_SYMBOL(omap_mbox_register); |
@@ -473,6 +545,8 @@ int omap_mbox_unregister(struct omap_mbox *mbox) | |||
473 | *tmp = mbox->next; | 545 | *tmp = mbox->next; |
474 | mbox->next = NULL; | 546 | mbox->next = NULL; |
475 | write_unlock(&mboxes_lock); | 547 | write_unlock(&mboxes_lock); |
548 | device_remove_file(mbox->dev, &dev_attr_mbox); | ||
549 | device_unregister(mbox->dev); | ||
476 | return 0; | 550 | return 0; |
477 | } | 551 | } |
478 | tmp = &(*tmp)->next; | 552 | tmp = &(*tmp)->next; |
@@ -501,4 +575,6 @@ static void __exit omap_mbox_class_exit(void) | |||
501 | subsys_initcall(omap_mbox_class_init); | 575 | subsys_initcall(omap_mbox_class_init); |
502 | module_exit(omap_mbox_class_exit); | 576 | module_exit(omap_mbox_class_exit); |
503 | 577 | ||
504 | MODULE_LICENSE("GPL"); | 578 | MODULE_LICENSE("GPL v2"); |
579 | MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); | ||
580 | MODULE_AUTHOR("Toshihiro Kobayashi and Hiroshi DOYU"); | ||