mailbox/omap: consolidate OMAP mailbox driver
[deliverable/linux.git] / drivers / mailbox / omap-mailbox.c
CommitLineData
340a614a
HD
1/*
2 * OMAP mailbox driver
3 *
f48cca87 4 * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.
5040f534 5 * Copyright (C) 2013-2014 Texas Instruments Inc.
340a614a 6 *
f48cca87 7 * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
5040f534 8 * Suman Anna <s-anna@ti.com>
340a614a
HD
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
340a614a 26#include <linux/interrupt.h>
b3e69146
FC
27#include <linux/spinlock.h>
28#include <linux/mutex.h>
5a0e3ad6 29#include <linux/slab.h>
b5bebe41
OBC
30#include <linux/kfifo.h>
31#include <linux/err.h>
58256307 32#include <linux/notifier.h>
73017a54 33#include <linux/module.h>
5040f534
SA
34#include <linux/platform_device.h>
35#include <linux/pm_runtime.h>
36#include <linux/platform_data/mailbox-omap.h>
37#include <linux/omap-mailbox.h>
38
39#define MAILBOX_REVISION 0x000
40#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
41#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
42#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
43
44#define OMAP2_MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
45#define OMAP2_MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
46
47#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
48#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
49#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
50
51#define MAILBOX_IRQSTATUS(type, u) (type ? OMAP4_MAILBOX_IRQSTATUS(u) : \
52 OMAP2_MAILBOX_IRQSTATUS(u))
53#define MAILBOX_IRQENABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE(u) : \
54 OMAP2_MAILBOX_IRQENABLE(u))
55#define MAILBOX_IRQDISABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE_CLR(u) \
56 : OMAP2_MAILBOX_IRQENABLE(u))
57
58#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
59#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
60
61#define MBOX_REG_SIZE 0x120
62
63#define OMAP4_MBOX_REG_SIZE 0x130
64
65#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
66#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32))
67
68struct omap_mbox_fifo {
69 unsigned long msg;
70 unsigned long fifo_stat;
71 unsigned long msg_stat;
72};
73
74struct omap_mbox_priv {
75 struct omap_mbox_fifo tx_fifo;
76 struct omap_mbox_fifo rx_fifo;
77 unsigned long irqenable;
78 unsigned long irqstatus;
79 u32 newmsg_bit;
80 u32 notfull_bit;
81 u32 ctx[OMAP4_MBOX_NR_REGS];
82 unsigned long irqdisable;
83 u32 intr_type;
84};
85
86struct omap_mbox_queue {
87 spinlock_t lock;
88 struct kfifo fifo;
89 struct work_struct work;
90 struct tasklet_struct tasklet;
91 struct omap_mbox *mbox;
92 bool full;
93};
94
95struct omap_mbox {
96 const char *name;
97 int irq;
98 struct omap_mbox_queue *txq, *rxq;
99 struct device *dev;
100 void *priv;
101 int use_count;
102 struct blocking_notifier_head notifier;
103};
104
105static void __iomem *mbox_base;
9c80c8cd 106static struct omap_mbox **mboxes;
340a614a 107
72b917ef 108static DEFINE_MUTEX(mbox_configured_lock);
5f00ec64 109
b5bebe41
OBC
110static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
111module_param(mbox_kfifo_size, uint, S_IRUGO);
112MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
113
5040f534
SA
114static inline unsigned int mbox_read_reg(size_t ofs)
115{
116 return __raw_readl(mbox_base + ofs);
117}
118
119static inline void mbox_write_reg(u32 val, size_t ofs)
120{
121 __raw_writel(val, mbox_base + ofs);
122}
123
9ae0ee00 124/* Mailbox FIFO handle functions */
5040f534 125static mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
9ae0ee00 126{
5040f534
SA
127 struct omap_mbox_fifo *fifo =
128 &((struct omap_mbox_priv *)mbox->priv)->rx_fifo;
129 return (mbox_msg_t) mbox_read_reg(fifo->msg);
9ae0ee00 130}
5040f534
SA
131
132static void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
9ae0ee00 133{
5040f534
SA
134 struct omap_mbox_fifo *fifo =
135 &((struct omap_mbox_priv *)mbox->priv)->tx_fifo;
136 mbox_write_reg(msg, fifo->msg);
9ae0ee00 137}
5040f534
SA
138
139static int mbox_fifo_empty(struct omap_mbox *mbox)
9ae0ee00 140{
5040f534
SA
141 struct omap_mbox_fifo *fifo =
142 &((struct omap_mbox_priv *)mbox->priv)->rx_fifo;
143 return (mbox_read_reg(fifo->msg_stat) == 0);
9ae0ee00 144}
5040f534
SA
145
146static int mbox_fifo_full(struct omap_mbox *mbox)
9ae0ee00 147{
5040f534
SA
148 struct omap_mbox_fifo *fifo =
149 &((struct omap_mbox_priv *)mbox->priv)->tx_fifo;
150 return mbox_read_reg(fifo->fifo_stat);
9ae0ee00
HD
151}
152
153/* Mailbox IRQ handle functions */
5040f534 154static void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
9ae0ee00 155{
5040f534
SA
156 struct omap_mbox_priv *p = mbox->priv;
157 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
158
159 mbox_write_reg(bit, p->irqstatus);
160
161 /* Flush posted write for irq status to avoid spurious interrupts */
162 mbox_read_reg(p->irqstatus);
9ae0ee00 163}
5040f534
SA
164
165static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
9ae0ee00 166{
5040f534
SA
167 struct omap_mbox_priv *p = mbox->priv;
168 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
169 u32 enable = mbox_read_reg(p->irqenable);
170 u32 status = mbox_read_reg(p->irqstatus);
171
172 return (int)(enable & status & bit);
9ae0ee00
HD
173}
174
340a614a
HD
175/*
176 * message sender
177 */
b2b6362e 178int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
340a614a 179{
b5bebe41
OBC
180 struct omap_mbox_queue *mq = mbox->txq;
181 int ret = 0, len;
5ed8d32e 182
a42743c2 183 spin_lock_bh(&mq->lock);
ec24751a 184
b5bebe41
OBC
185 if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
186 ret = -ENOMEM;
187 goto out;
188 }
189
fe714a46 190 if (kfifo_is_empty(&mq->fifo) && !mbox_fifo_full(mbox)) {
a42743c2
KH
191 mbox_fifo_write(mbox, msg);
192 goto out;
193 }
194
b5bebe41
OBC
195 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
196 WARN_ON(len != sizeof(msg));
340a614a 197
5ed8d32e 198 tasklet_schedule(&mbox->txq->tasklet);
340a614a 199
b5bebe41 200out:
a42743c2 201 spin_unlock_bh(&mq->lock);
b5bebe41 202 return ret;
340a614a
HD
203}
204EXPORT_SYMBOL(omap_mbox_msg_send);
205
c869c75c
SA
206void omap_mbox_save_ctx(struct omap_mbox *mbox)
207{
5040f534
SA
208 int i;
209 struct omap_mbox_priv *p = mbox->priv;
210 int nr_regs;
211
212 if (p->intr_type)
213 nr_regs = OMAP4_MBOX_NR_REGS;
214 else
215 nr_regs = MBOX_NR_REGS;
216 for (i = 0; i < nr_regs; i++) {
217 p->ctx[i] = mbox_read_reg(i * sizeof(u32));
218
219 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
220 i, p->ctx[i]);
c869c75c 221 }
c869c75c
SA
222}
223EXPORT_SYMBOL(omap_mbox_save_ctx);
224
225void omap_mbox_restore_ctx(struct omap_mbox *mbox)
226{
5040f534
SA
227 int i;
228 struct omap_mbox_priv *p = mbox->priv;
229 int nr_regs;
230
231 if (p->intr_type)
232 nr_regs = OMAP4_MBOX_NR_REGS;
233 else
234 nr_regs = MBOX_NR_REGS;
235 for (i = 0; i < nr_regs; i++) {
236 mbox_write_reg(p->ctx[i], i * sizeof(u32));
237
238 dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
239 i, p->ctx[i]);
c869c75c 240 }
c869c75c
SA
241}
242EXPORT_SYMBOL(omap_mbox_restore_ctx);
243
244void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
245{
5040f534
SA
246 struct omap_mbox_priv *p = mbox->priv;
247 u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
248
249 l = mbox_read_reg(p->irqenable);
250 l |= bit;
251 mbox_write_reg(l, p->irqenable);
c869c75c
SA
252}
253EXPORT_SYMBOL(omap_mbox_enable_irq);
254
255void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
256{
5040f534
SA
257 struct omap_mbox_priv *p = mbox->priv;
258 u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
259
260 /*
261 * Read and update the interrupt configuration register for pre-OMAP4.
262 * OMAP4 and later SoCs have a dedicated interrupt disabling register.
263 */
264 if (!p->intr_type)
265 bit = mbox_read_reg(p->irqdisable) & ~bit;
266
267 mbox_write_reg(bit, p->irqdisable);
c869c75c
SA
268}
269EXPORT_SYMBOL(omap_mbox_disable_irq);
270
5ed8d32e 271static void mbox_tx_tasklet(unsigned long tx_data)
340a614a 272{
5ed8d32e 273 struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
b5bebe41
OBC
274 struct omap_mbox_queue *mq = mbox->txq;
275 mbox_msg_t msg;
276 int ret;
340a614a 277
b5bebe41 278 while (kfifo_len(&mq->fifo)) {
fe714a46 279 if (mbox_fifo_full(mbox)) {
eb18858e 280 omap_mbox_enable_irq(mbox, IRQ_TX);
b5bebe41 281 break;
340a614a 282 }
b5bebe41
OBC
283
284 ret = kfifo_out(&mq->fifo, (unsigned char *)&msg,
285 sizeof(msg));
286 WARN_ON(ret != sizeof(msg));
287
288 mbox_fifo_write(mbox, msg);
340a614a
HD
289 }
290}
291
292/*
293 * Message receiver(workqueue)
294 */
295static void mbox_rx_work(struct work_struct *work)
296{
297 struct omap_mbox_queue *mq =
298 container_of(work, struct omap_mbox_queue, work);
340a614a 299 mbox_msg_t msg;
b5bebe41
OBC
300 int len;
301
302 while (kfifo_len(&mq->fifo) >= sizeof(msg)) {
303 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
304 WARN_ON(len != sizeof(msg));
340a614a 305
58256307
KH
306 blocking_notifier_call_chain(&mq->mbox->notifier, len,
307 (void *)msg);
d2295042
FGL
308 spin_lock_irq(&mq->lock);
309 if (mq->full) {
310 mq->full = false;
311 omap_mbox_enable_irq(mq->mbox, IRQ_RX);
312 }
313 spin_unlock_irq(&mq->lock);
340a614a
HD
314 }
315}
316
317/*
318 * Mailbox interrupt handler
319 */
340a614a
HD
320static void __mbox_tx_interrupt(struct omap_mbox *mbox)
321{
eb18858e 322 omap_mbox_disable_irq(mbox, IRQ_TX);
340a614a 323 ack_mbox_irq(mbox, IRQ_TX);
5ed8d32e 324 tasklet_schedule(&mbox->txq->tasklet);
340a614a
HD
325}
326
327static void __mbox_rx_interrupt(struct omap_mbox *mbox)
328{
b5bebe41 329 struct omap_mbox_queue *mq = mbox->rxq;
340a614a 330 mbox_msg_t msg;
b5bebe41 331 int len;
340a614a 332
340a614a 333 while (!mbox_fifo_empty(mbox)) {
b5bebe41 334 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
1ea5d6d1 335 omap_mbox_disable_irq(mbox, IRQ_RX);
d2295042 336 mq->full = true;
340a614a 337 goto nomem;
1ea5d6d1 338 }
340a614a
HD
339
340 msg = mbox_fifo_read(mbox);
340a614a 341
b5bebe41
OBC
342 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
343 WARN_ON(len != sizeof(msg));
340a614a
HD
344 }
345
346 /* no more messages in the fifo. clear IRQ source. */
347 ack_mbox_irq(mbox, IRQ_RX);
f48cca87 348nomem:
c4873005 349 schedule_work(&mbox->rxq->work);
340a614a
HD
350}
351
352static irqreturn_t mbox_interrupt(int irq, void *p)
353{
2a7057e3 354 struct omap_mbox *mbox = p;
340a614a
HD
355
356 if (is_mbox_irq(mbox, IRQ_TX))
357 __mbox_tx_interrupt(mbox);
358
359 if (is_mbox_irq(mbox, IRQ_RX))
360 __mbox_rx_interrupt(mbox);
361
362 return IRQ_HANDLED;
363}
364
340a614a 365static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
5ed8d32e
S
366 void (*work) (struct work_struct *),
367 void (*tasklet)(unsigned long))
340a614a 368{
340a614a
HD
369 struct omap_mbox_queue *mq;
370
371 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
372 if (!mq)
373 return NULL;
374
375 spin_lock_init(&mq->lock);
376
b5bebe41 377 if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
340a614a 378 goto error;
340a614a 379
5ed8d32e
S
380 if (work)
381 INIT_WORK(&mq->work, work);
340a614a 382
5ed8d32e
S
383 if (tasklet)
384 tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
340a614a
HD
385 return mq;
386error:
387 kfree(mq);
388 return NULL;
389}
390
391static void mbox_queue_free(struct omap_mbox_queue *q)
392{
b5bebe41 393 kfifo_free(&q->fifo);
340a614a
HD
394 kfree(q);
395}
396
c7c158e5 397static int omap_mbox_startup(struct omap_mbox *mbox)
340a614a 398{
5f00ec64 399 int ret = 0;
340a614a
HD
400 struct omap_mbox_queue *mq;
401
58256307 402 mutex_lock(&mbox_configured_lock);
5040f534
SA
403 ret = pm_runtime_get_sync(mbox->dev->parent);
404 if (unlikely(ret < 0))
405 goto fail_startup;
340a614a 406
58256307 407 if (!mbox->use_count++) {
58256307
KH
408 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
409 if (!mq) {
410 ret = -ENOMEM;
411 goto fail_alloc_txq;
412 }
413 mbox->txq = mq;
340a614a 414
58256307
KH
415 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
416 if (!mq) {
417 ret = -ENOMEM;
418 goto fail_alloc_rxq;
419 }
420 mbox->rxq = mq;
421 mq->mbox = mbox;
ecf305cf
SA
422 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
423 mbox->name, mbox);
424 if (unlikely(ret)) {
425 pr_err("failed to register mailbox interrupt:%d\n",
426 ret);
427 goto fail_request_irq;
428 }
1d8a0e96
JG
429
430 omap_mbox_enable_irq(mbox, IRQ_RX);
340a614a 431 }
58256307 432 mutex_unlock(&mbox_configured_lock);
340a614a
HD
433 return 0;
434
ecf305cf
SA
435fail_request_irq:
436 mbox_queue_free(mbox->rxq);
ab66ac30 437fail_alloc_rxq:
340a614a 438 mbox_queue_free(mbox->txq);
ab66ac30 439fail_alloc_txq:
5040f534 440 pm_runtime_put_sync(mbox->dev->parent);
58256307
KH
441 mbox->use_count--;
442fail_startup:
58256307 443 mutex_unlock(&mbox_configured_lock);
340a614a
HD
444 return ret;
445}
446
447static void omap_mbox_fini(struct omap_mbox *mbox)
448{
58256307
KH
449 mutex_lock(&mbox_configured_lock);
450
451 if (!--mbox->use_count) {
1d8a0e96 452 omap_mbox_disable_irq(mbox, IRQ_RX);
58256307
KH
453 free_irq(mbox->irq, mbox);
454 tasklet_kill(&mbox->txq->tasklet);
43829731 455 flush_work(&mbox->rxq->work);
58256307
KH
456 mbox_queue_free(mbox->txq);
457 mbox_queue_free(mbox->rxq);
458 }
340a614a 459
5040f534 460 pm_runtime_put_sync(mbox->dev->parent);
58256307
KH
461
462 mutex_unlock(&mbox_configured_lock);
340a614a
HD
463}
464
58256307 465struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
340a614a 466{
c0377320
KH
467 struct omap_mbox *_mbox, *mbox = NULL;
468 int i, ret;
340a614a 469
9c80c8cd
FC
470 if (!mboxes)
471 return ERR_PTR(-EINVAL);
340a614a 472
c0377320
KH
473 for (i = 0; (_mbox = mboxes[i]); i++) {
474 if (!strcmp(_mbox->name, name)) {
475 mbox = _mbox;
9c80c8cd 476 break;
c0377320
KH
477 }
478 }
9c80c8cd
FC
479
480 if (!mbox)
481 return ERR_PTR(-ENOENT);
340a614a 482
58256307
KH
483 if (nb)
484 blocking_notifier_chain_register(&mbox->notifier, nb);
485
1d8a0e96
JG
486 ret = omap_mbox_startup(mbox);
487 if (ret) {
488 blocking_notifier_chain_unregister(&mbox->notifier, nb);
489 return ERR_PTR(-ENODEV);
490 }
491
340a614a
HD
492 return mbox;
493}
494EXPORT_SYMBOL(omap_mbox_get);
495
58256307 496void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
340a614a 497{
58256307 498 blocking_notifier_chain_unregister(&mbox->notifier, nb);
340a614a
HD
499 omap_mbox_fini(mbox);
500}
501EXPORT_SYMBOL(omap_mbox_put);
502
6b233985
HD
503static struct class omap_mbox_class = { .name = "mbox", };
504
5040f534 505static int omap_mbox_register(struct device *parent, struct omap_mbox **list)
340a614a 506{
9c80c8cd
FC
507 int ret;
508 int i;
340a614a 509
9c80c8cd
FC
510 mboxes = list;
511 if (!mboxes)
340a614a 512 return -EINVAL;
340a614a 513
9c80c8cd
FC
514 for (i = 0; mboxes[i]; i++) {
515 struct omap_mbox *mbox = mboxes[i];
516 mbox->dev = device_create(&omap_mbox_class,
517 parent, 0, mbox, "%s", mbox->name);
518 if (IS_ERR(mbox->dev)) {
519 ret = PTR_ERR(mbox->dev);
520 goto err_out;
521 }
58256307
KH
522
523 BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
9c80c8cd 524 }
f48cca87
HD
525 return 0;
526
9c80c8cd
FC
527err_out:
528 while (i--)
529 device_unregister(mboxes[i]->dev);
340a614a
HD
530 return ret;
531}
340a614a 532
5040f534 533static int omap_mbox_unregister(void)
340a614a 534{
9c80c8cd 535 int i;
340a614a 536
9c80c8cd
FC
537 if (!mboxes)
538 return -EINVAL;
539
540 for (i = 0; mboxes[i]; i++)
541 device_unregister(mboxes[i]->dev);
542 mboxes = NULL;
543 return 0;
340a614a 544}
5040f534
SA
545
546static int omap_mbox_probe(struct platform_device *pdev)
547{
548 struct resource *mem;
549 int ret;
550 struct omap_mbox **list, *mbox, *mboxblk;
551 struct omap_mbox_priv *priv, *privblk;
552 struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
553 struct omap_mbox_dev_info *info;
554 u32 intr_type;
555 u32 l;
556 int i;
557
558 if (!pdata || !pdata->info_cnt || !pdata->info) {
559 pr_err("%s: platform not supported\n", __func__);
560 return -ENODEV;
561 }
562
563 /* allocate one extra for marking end of list */
564 list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list),
565 GFP_KERNEL);
566 if (!list)
567 return -ENOMEM;
568
569 mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox),
570 GFP_KERNEL);
571 if (!mboxblk)
572 return -ENOMEM;
573
574 privblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*priv),
575 GFP_KERNEL);
576 if (!privblk)
577 return -ENOMEM;
578
579 info = pdata->info;
580 intr_type = pdata->intr_type;
581 mbox = mboxblk;
582 priv = privblk;
583 for (i = 0; i < pdata->info_cnt; i++, info++, priv++) {
584 priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id);
585 priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id);
586 priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id);
587 priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id);
588 priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id);
589 priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id);
590 priv->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
591 priv->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
592 priv->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
593 priv->intr_type = intr_type;
594
595 mbox->priv = priv;
596 mbox->name = info->name;
597 mbox->irq = platform_get_irq(pdev, info->irq_id);
598 if (mbox->irq < 0)
599 return mbox->irq;
600 list[i] = mbox++;
601 }
602
603 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
604 mbox_base = devm_ioremap_resource(&pdev->dev, mem);
605 if (IS_ERR(mbox_base))
606 return PTR_ERR(mbox_base);
607
608 ret = omap_mbox_register(&pdev->dev, list);
609 if (ret)
610 return ret;
611
612 platform_set_drvdata(pdev, list);
613 pm_runtime_enable(&pdev->dev);
614
615 ret = pm_runtime_get_sync(&pdev->dev);
616 if (ret < 0) {
617 pm_runtime_put_noidle(&pdev->dev);
618 goto unregister;
619 }
620
621 /*
622 * just print the raw revision register, the format is not
623 * uniform across all SoCs
624 */
625 l = mbox_read_reg(MAILBOX_REVISION);
626 dev_info(&pdev->dev, "omap mailbox rev 0x%x\n", l);
627
628 ret = pm_runtime_put_sync(&pdev->dev);
629 if (ret < 0)
630 goto unregister;
631
632 return 0;
633
634unregister:
635 pm_runtime_disable(&pdev->dev);
636 omap_mbox_unregister();
637 return ret;
638}
639
640static int omap_mbox_remove(struct platform_device *pdev)
641{
642 pm_runtime_disable(&pdev->dev);
643 omap_mbox_unregister();
644
645 return 0;
646}
647
648static struct platform_driver omap_mbox_driver = {
649 .probe = omap_mbox_probe,
650 .remove = omap_mbox_remove,
651 .driver = {
652 .name = "omap-mailbox",
653 .owner = THIS_MODULE,
654 },
655};
340a614a 656
c7c158e5 657static int __init omap_mbox_init(void)
340a614a 658{
6b233985
HD
659 int err;
660
661 err = class_register(&omap_mbox_class);
662 if (err)
663 return err;
664
b5bebe41
OBC
665 /* kfifo size sanity check: alignment and minimal size */
666 mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
ab66ac30
KH
667 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size,
668 sizeof(mbox_msg_t));
b5bebe41 669
5040f534 670 return platform_driver_register(&omap_mbox_driver);
340a614a 671}
6b233985 672subsys_initcall(omap_mbox_init);
340a614a 673
c7c158e5 674static void __exit omap_mbox_exit(void)
340a614a 675{
5040f534 676 platform_driver_unregister(&omap_mbox_driver);
6b233985 677 class_unregister(&omap_mbox_class);
340a614a 678}
c7c158e5 679module_exit(omap_mbox_exit);
340a614a 680
f48cca87
HD
681MODULE_LICENSE("GPL v2");
682MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
f375325a
OBC
683MODULE_AUTHOR("Toshihiro Kobayashi");
684MODULE_AUTHOR("Hiroshi DOYU");
This page took 0.590613 seconds and 5 git commands to generate.