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 <asm/arch/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 blkdev_dequeue_request(rq
);
120 end_that_request_last(rq
, 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 spin_lock_irqsave(q
->queue_lock
, flags
);
153 blkdev_dequeue_request(rq
);
154 end_that_request_last(rq
, 0);
155 spin_unlock_irqrestore(q
->queue_lock
, flags
);
157 mbox
->rxq
->callback((void *)msg
);
162 * Mailbox interrupt handler
164 static void mbox_txq_fn(struct request_queue
* q
)
168 static void mbox_rxq_fn(struct request_queue
* q
)
172 static void __mbox_tx_interrupt(struct omap_mbox
*mbox
)
174 disable_mbox_irq(mbox
, IRQ_TX
);
175 ack_mbox_irq(mbox
, IRQ_TX
);
176 schedule_work(&mbox
->txq
->work
);
179 static void __mbox_rx_interrupt(struct omap_mbox
*mbox
)
183 struct request_queue
*q
= mbox
->rxq
->queue
;
185 disable_mbox_irq(mbox
, IRQ_RX
);
187 while (!mbox_fifo_empty(mbox
)) {
188 rq
= blk_get_request(q
, WRITE
, GFP_ATOMIC
);
192 msg
= mbox_fifo_read(mbox
);
193 rq
->data
= (void *)msg
;
195 if (unlikely(mbox_seq_test(mbox
, msg
))) {
196 pr_info("mbox: Illegal seq bit!(%08x)\n", msg
);
197 if (mbox
->err_notify
)
201 blk_insert_request(q
, rq
, 0, NULL
);
202 if (mbox
->ops
->type
== OMAP_MBOX_TYPE1
)
206 /* no more messages in the fifo. clear IRQ source. */
207 ack_mbox_irq(mbox
, IRQ_RX
);
208 enable_mbox_irq(mbox
, IRQ_RX
);
210 schedule_work(&mbox
->rxq
->work
);
213 static irqreturn_t
mbox_interrupt(int irq
, void *p
)
215 struct omap_mbox
*mbox
= (struct omap_mbox
*)p
;
217 if (is_mbox_irq(mbox
, IRQ_TX
))
218 __mbox_tx_interrupt(mbox
);
220 if (is_mbox_irq(mbox
, IRQ_RX
))
221 __mbox_rx_interrupt(mbox
);
230 omap_mbox_write(struct device
*dev
, struct device_attribute
*attr
,
231 const char * buf
, size_t count
)
234 mbox_msg_t
*p
= (mbox_msg_t
*)buf
;
235 struct omap_mbox
*mbox
= dev_get_drvdata(dev
);
237 for (; count
>= sizeof(mbox_msg_t
); count
-= sizeof(mbox_msg_t
)) {
238 ret
= omap_mbox_msg_send(mbox
, be32_to_cpu(*p
), NULL
);
244 return (size_t)((char *)p
- buf
);
248 omap_mbox_read(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
252 mbox_msg_t
*p
= (mbox_msg_t
*) buf
;
253 struct omap_mbox
*mbox
= dev_get_drvdata(dev
);
254 struct request_queue
*q
= mbox
->rxq
->queue
;
257 spin_lock_irqsave(q
->queue_lock
, flags
);
258 rq
= elv_next_request(q
);
259 spin_unlock_irqrestore(q
->queue_lock
, flags
);
264 *p
= (mbox_msg_t
) rq
->data
;
266 spin_lock_irqsave(q
->queue_lock
, flags
);
267 blkdev_dequeue_request(rq
);
268 end_that_request_last(rq
, 0);
269 spin_unlock_irqrestore(q
->queue_lock
, flags
);
271 if (unlikely(mbox_seq_test(mbox
, *p
))) {
272 pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p
);
278 pr_debug("%02x %02x %02x %02x\n", buf
[0], buf
[1], buf
[2], buf
[3]);
280 return (size_t) ((char *)p
- buf
);
283 static DEVICE_ATTR(mbox
, S_IRUGO
| S_IWUSR
, omap_mbox_read
, omap_mbox_write
);
285 static ssize_t
mbox_show(struct class *class, char *buf
)
287 return sprintf(buf
, "mbox");
290 static CLASS_ATTR(mbox
, S_IRUGO
, mbox_show
, NULL
);
292 static struct class omap_mbox_class
= {
296 static struct omap_mbox_queue
*mbox_queue_alloc(struct omap_mbox
*mbox
,
297 request_fn_proc
* proc
,
298 void (*work
) (struct work_struct
*))
300 struct request_queue
*q
;
301 struct omap_mbox_queue
*mq
;
303 mq
= kzalloc(sizeof(struct omap_mbox_queue
), GFP_KERNEL
);
307 spin_lock_init(&mq
->lock
);
309 q
= blk_init_queue(proc
, &mq
->lock
);
315 INIT_WORK(&mq
->work
, work
);
323 static void mbox_queue_free(struct omap_mbox_queue
*q
)
325 blk_cleanup_queue(q
->queue
);
329 static int omap_mbox_init(struct omap_mbox
*mbox
)
332 struct omap_mbox_queue
*mq
;
334 if (likely(mbox
->ops
->startup
)) {
335 ret
= mbox
->ops
->startup(mbox
);
340 mbox
->dev
.class = &omap_mbox_class
;
341 strlcpy(mbox
->dev
.bus_id
, mbox
->name
, KOBJ_NAME_LEN
);
342 dev_set_drvdata(&mbox
->dev
, mbox
);
344 ret
= device_register(&mbox
->dev
);
346 goto fail_device_reg
;
348 ret
= device_create_file(&mbox
->dev
, &dev_attr_mbox
);
351 "device_create_file failed: %d\n", ret
);
352 goto fail_create_mbox
;
355 ret
= request_irq(mbox
->irq
, mbox_interrupt
, IRQF_DISABLED
,
359 "failed to register mailbox interrupt:%d\n", ret
);
360 goto fail_request_irq
;
362 enable_mbox_irq(mbox
, IRQ_RX
);
364 mq
= mbox_queue_alloc(mbox
, mbox_txq_fn
, mbox_tx_work
);
371 mq
= mbox_queue_alloc(mbox
, mbox_rxq_fn
, mbox_rx_work
);
381 mbox_queue_free(mbox
->txq
);
383 free_irq(mbox
->irq
, mbox
);
385 device_remove_file(&mbox
->dev
, &dev_attr_mbox
);
387 device_unregister(&mbox
->dev
);
389 if (unlikely(mbox
->ops
->shutdown
))
390 mbox
->ops
->shutdown(mbox
);
395 static void omap_mbox_fini(struct omap_mbox
*mbox
)
397 mbox_queue_free(mbox
->txq
);
398 mbox_queue_free(mbox
->rxq
);
400 free_irq(mbox
->irq
, mbox
);
401 device_remove_file(&mbox
->dev
, &dev_attr_mbox
);
402 class_unregister(&omap_mbox_class
);
404 if (unlikely(mbox
->ops
->shutdown
))
405 mbox
->ops
->shutdown(mbox
);
408 static struct omap_mbox
**find_mboxes(const char *name
)
410 struct omap_mbox
**p
;
412 for (p
= &mboxes
; *p
; p
= &(*p
)->next
) {
413 if (strcmp((*p
)->name
, name
) == 0)
420 struct omap_mbox
*omap_mbox_get(const char *name
)
422 struct omap_mbox
*mbox
;
425 read_lock(&mboxes_lock
);
426 mbox
= *(find_mboxes(name
));
428 read_unlock(&mboxes_lock
);
429 return ERR_PTR(-ENOENT
);
432 read_unlock(&mboxes_lock
);
434 ret
= omap_mbox_init(mbox
);
436 return ERR_PTR(-ENODEV
);
440 EXPORT_SYMBOL(omap_mbox_get
);
442 void omap_mbox_put(struct omap_mbox
*mbox
)
444 omap_mbox_fini(mbox
);
446 EXPORT_SYMBOL(omap_mbox_put
);
448 int omap_mbox_register(struct omap_mbox
*mbox
)
451 struct omap_mbox
**tmp
;
458 write_lock(&mboxes_lock
);
459 tmp
= find_mboxes(mbox
->name
);
464 write_unlock(&mboxes_lock
);
468 EXPORT_SYMBOL(omap_mbox_register
);
470 int omap_mbox_unregister(struct omap_mbox
*mbox
)
472 struct omap_mbox
**tmp
;
474 write_lock(&mboxes_lock
);
480 write_unlock(&mboxes_lock
);
485 write_unlock(&mboxes_lock
);
489 EXPORT_SYMBOL(omap_mbox_unregister
);
491 static int __init
omap_mbox_class_init(void)
493 int ret
= class_register(&omap_mbox_class
);
495 ret
= class_create_file(&omap_mbox_class
, &class_attr_mbox
);
500 static void __exit
omap_mbox_class_exit(void)
502 class_remove_file(&omap_mbox_class
, &class_attr_mbox
);
503 class_unregister(&omap_mbox_class
);
506 subsys_initcall(omap_mbox_class_init
);
507 module_exit(omap_mbox_class_exit
);
509 MODULE_LICENSE("GPL");