1f62092f6SLey Foon Tan /* 2f62092f6SLey Foon Tan * Copyright Altera Corporation (C) 2013-2014. All rights reserved 3f62092f6SLey Foon Tan * 4f62092f6SLey Foon Tan * This program is free software; you can redistribute it and/or modify it 5f62092f6SLey Foon Tan * under the terms and conditions of the GNU General Public License, 6f62092f6SLey Foon Tan * version 2, as published by the Free Software Foundation. 7f62092f6SLey Foon Tan * 8f62092f6SLey Foon Tan * This program is distributed in the hope it will be useful, but WITHOUT 9f62092f6SLey Foon Tan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10f62092f6SLey Foon Tan * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11f62092f6SLey Foon Tan * more details. 12f62092f6SLey Foon Tan * 13f62092f6SLey Foon Tan * You should have received a copy of the GNU General Public License along with 14f62092f6SLey Foon Tan * this program. If not, see <http://www.gnu.org/licenses/>. 15f62092f6SLey Foon Tan */ 16f62092f6SLey Foon Tan 17f62092f6SLey Foon Tan #include <linux/device.h> 18f62092f6SLey Foon Tan #include <linux/interrupt.h> 19f62092f6SLey Foon Tan #include <linux/io.h> 20f62092f6SLey Foon Tan #include <linux/kernel.h> 21f62092f6SLey Foon Tan #include <linux/mailbox_controller.h> 22f62092f6SLey Foon Tan #include <linux/module.h> 23f62092f6SLey Foon Tan #include <linux/of.h> 24f62092f6SLey Foon Tan #include <linux/platform_device.h> 25f62092f6SLey Foon Tan 26f62092f6SLey Foon Tan #define DRIVER_NAME "altera-mailbox" 27f62092f6SLey Foon Tan 28f62092f6SLey Foon Tan #define MAILBOX_CMD_REG 0x00 29f62092f6SLey Foon Tan #define MAILBOX_PTR_REG 0x04 30f62092f6SLey Foon Tan #define MAILBOX_STS_REG 0x08 31f62092f6SLey Foon Tan #define MAILBOX_INTMASK_REG 0x0C 32f62092f6SLey Foon Tan 33f62092f6SLey Foon Tan #define INT_PENDING_MSK 0x1 34f62092f6SLey Foon Tan #define INT_SPACE_MSK 0x2 35f62092f6SLey Foon Tan 36f62092f6SLey Foon Tan #define STS_PENDING_MSK 0x1 37f62092f6SLey Foon Tan #define STS_FULL_MSK 0x2 38f62092f6SLey Foon Tan #define STS_FULL_OFT 0x1 39f62092f6SLey Foon Tan 40f62092f6SLey Foon Tan #define MBOX_PENDING(status) (((status) & STS_PENDING_MSK)) 41f62092f6SLey Foon Tan #define MBOX_FULL(status) (((status) & STS_FULL_MSK) >> STS_FULL_OFT) 42f62092f6SLey Foon Tan 43f62092f6SLey Foon Tan enum altera_mbox_msg { 44f62092f6SLey Foon Tan MBOX_CMD = 0, 45f62092f6SLey Foon Tan MBOX_PTR, 46f62092f6SLey Foon Tan }; 47f62092f6SLey Foon Tan 48f62092f6SLey Foon Tan #define MBOX_POLLING_MS 5 /* polling interval 5ms */ 49f62092f6SLey Foon Tan 50f62092f6SLey Foon Tan struct altera_mbox { 51f62092f6SLey Foon Tan bool is_sender; /* 1-sender, 0-receiver */ 52f62092f6SLey Foon Tan bool intr_mode; 53f62092f6SLey Foon Tan int irq; 54f62092f6SLey Foon Tan void __iomem *mbox_base; 55f62092f6SLey Foon Tan struct device *dev; 56f62092f6SLey Foon Tan struct mbox_controller controller; 57f62092f6SLey Foon Tan 58f62092f6SLey Foon Tan /* If the controller supports only RX polling mode */ 59f62092f6SLey Foon Tan struct timer_list rxpoll_timer; 60c6f15047SKees Cook struct mbox_chan *chan; 61f62092f6SLey Foon Tan }; 62f62092f6SLey Foon Tan 63f62092f6SLey Foon Tan static struct altera_mbox *mbox_chan_to_altera_mbox(struct mbox_chan *chan) 64f62092f6SLey Foon Tan { 65f62092f6SLey Foon Tan if (!chan || !chan->con_priv) 66f62092f6SLey Foon Tan return NULL; 67f62092f6SLey Foon Tan 68f62092f6SLey Foon Tan return (struct altera_mbox *)chan->con_priv; 69f62092f6SLey Foon Tan } 70f62092f6SLey Foon Tan 71f62092f6SLey Foon Tan static inline int altera_mbox_full(struct altera_mbox *mbox) 72f62092f6SLey Foon Tan { 73f62092f6SLey Foon Tan u32 status; 74f62092f6SLey Foon Tan 75f62092f6SLey Foon Tan status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG); 76f62092f6SLey Foon Tan return MBOX_FULL(status); 77f62092f6SLey Foon Tan } 78f62092f6SLey Foon Tan 79f62092f6SLey Foon Tan static inline int altera_mbox_pending(struct altera_mbox *mbox) 80f62092f6SLey Foon Tan { 81f62092f6SLey Foon Tan u32 status; 82f62092f6SLey Foon Tan 83f62092f6SLey Foon Tan status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG); 84f62092f6SLey Foon Tan return MBOX_PENDING(status); 85f62092f6SLey Foon Tan } 86f62092f6SLey Foon Tan 87f62092f6SLey Foon Tan static void altera_mbox_rx_intmask(struct altera_mbox *mbox, bool enable) 88f62092f6SLey Foon Tan { 89f62092f6SLey Foon Tan u32 mask; 90f62092f6SLey Foon Tan 91f62092f6SLey Foon Tan mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG); 92f62092f6SLey Foon Tan if (enable) 93f62092f6SLey Foon Tan mask |= INT_PENDING_MSK; 94f62092f6SLey Foon Tan else 95f62092f6SLey Foon Tan mask &= ~INT_PENDING_MSK; 96f62092f6SLey Foon Tan writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG); 97f62092f6SLey Foon Tan } 98f62092f6SLey Foon Tan 99f62092f6SLey Foon Tan static void altera_mbox_tx_intmask(struct altera_mbox *mbox, bool enable) 100f62092f6SLey Foon Tan { 101f62092f6SLey Foon Tan u32 mask; 102f62092f6SLey Foon Tan 103f62092f6SLey Foon Tan mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG); 104f62092f6SLey Foon Tan if (enable) 105f62092f6SLey Foon Tan mask |= INT_SPACE_MSK; 106f62092f6SLey Foon Tan else 107f62092f6SLey Foon Tan mask &= ~INT_SPACE_MSK; 108f62092f6SLey Foon Tan writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG); 109f62092f6SLey Foon Tan } 110f62092f6SLey Foon Tan 111f62092f6SLey Foon Tan static bool altera_mbox_is_sender(struct altera_mbox *mbox) 112f62092f6SLey Foon Tan { 113f62092f6SLey Foon Tan u32 reg; 114f62092f6SLey Foon Tan /* Write a magic number to PTR register and read back this register. 115f62092f6SLey Foon Tan * This register is read-write if it is a sender. 116f62092f6SLey Foon Tan */ 117f62092f6SLey Foon Tan #define MBOX_MAGIC 0xA5A5AA55 118f62092f6SLey Foon Tan writel_relaxed(MBOX_MAGIC, mbox->mbox_base + MAILBOX_PTR_REG); 119f62092f6SLey Foon Tan reg = readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG); 120f62092f6SLey Foon Tan if (reg == MBOX_MAGIC) { 121f62092f6SLey Foon Tan /* Clear to 0 */ 122f62092f6SLey Foon Tan writel_relaxed(0, mbox->mbox_base + MAILBOX_PTR_REG); 123f62092f6SLey Foon Tan return true; 124f62092f6SLey Foon Tan } 125f62092f6SLey Foon Tan return false; 126f62092f6SLey Foon Tan } 127f62092f6SLey Foon Tan 128f62092f6SLey Foon Tan static void altera_mbox_rx_data(struct mbox_chan *chan) 129f62092f6SLey Foon Tan { 130f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 131f62092f6SLey Foon Tan u32 data[2]; 132f62092f6SLey Foon Tan 133f62092f6SLey Foon Tan if (altera_mbox_pending(mbox)) { 134f62092f6SLey Foon Tan data[MBOX_PTR] = 135f62092f6SLey Foon Tan readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG); 136f62092f6SLey Foon Tan data[MBOX_CMD] = 137f62092f6SLey Foon Tan readl_relaxed(mbox->mbox_base + MAILBOX_CMD_REG); 138f62092f6SLey Foon Tan mbox_chan_received_data(chan, (void *)data); 139f62092f6SLey Foon Tan } 140f62092f6SLey Foon Tan } 141f62092f6SLey Foon Tan 142c6f15047SKees Cook static void altera_mbox_poll_rx(struct timer_list *t) 143f62092f6SLey Foon Tan { 144c6f15047SKees Cook struct altera_mbox *mbox = from_timer(mbox, t, rxpoll_timer); 145f62092f6SLey Foon Tan 146c6f15047SKees Cook altera_mbox_rx_data(mbox->chan); 147f62092f6SLey Foon Tan 148f62092f6SLey Foon Tan mod_timer(&mbox->rxpoll_timer, 149f62092f6SLey Foon Tan jiffies + msecs_to_jiffies(MBOX_POLLING_MS)); 150f62092f6SLey Foon Tan } 151f62092f6SLey Foon Tan 152f62092f6SLey Foon Tan static irqreturn_t altera_mbox_tx_interrupt(int irq, void *p) 153f62092f6SLey Foon Tan { 154f62092f6SLey Foon Tan struct mbox_chan *chan = (struct mbox_chan *)p; 155f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 156f62092f6SLey Foon Tan 157f62092f6SLey Foon Tan altera_mbox_tx_intmask(mbox, false); 158f62092f6SLey Foon Tan mbox_chan_txdone(chan, 0); 159f62092f6SLey Foon Tan 160f62092f6SLey Foon Tan return IRQ_HANDLED; 161f62092f6SLey Foon Tan } 162f62092f6SLey Foon Tan 163f62092f6SLey Foon Tan static irqreturn_t altera_mbox_rx_interrupt(int irq, void *p) 164f62092f6SLey Foon Tan { 165f62092f6SLey Foon Tan struct mbox_chan *chan = (struct mbox_chan *)p; 166f62092f6SLey Foon Tan 167f62092f6SLey Foon Tan altera_mbox_rx_data(chan); 168f62092f6SLey Foon Tan return IRQ_HANDLED; 169f62092f6SLey Foon Tan } 170f62092f6SLey Foon Tan 171f62092f6SLey Foon Tan static int altera_mbox_startup_sender(struct mbox_chan *chan) 172f62092f6SLey Foon Tan { 173f62092f6SLey Foon Tan int ret; 174f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 175f62092f6SLey Foon Tan 176f62092f6SLey Foon Tan if (mbox->intr_mode) { 177f62092f6SLey Foon Tan ret = request_irq(mbox->irq, altera_mbox_tx_interrupt, 0, 178f62092f6SLey Foon Tan DRIVER_NAME, chan); 179f62092f6SLey Foon Tan if (unlikely(ret)) { 180f62092f6SLey Foon Tan dev_err(mbox->dev, 181f62092f6SLey Foon Tan "failed to register mailbox interrupt:%d\n", 182f62092f6SLey Foon Tan ret); 183f62092f6SLey Foon Tan return ret; 184f62092f6SLey Foon Tan } 185f62092f6SLey Foon Tan } 186f62092f6SLey Foon Tan 187f62092f6SLey Foon Tan return 0; 188f62092f6SLey Foon Tan } 189f62092f6SLey Foon Tan 190f62092f6SLey Foon Tan static int altera_mbox_startup_receiver(struct mbox_chan *chan) 191f62092f6SLey Foon Tan { 192f62092f6SLey Foon Tan int ret; 193f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 194f62092f6SLey Foon Tan 195f62092f6SLey Foon Tan if (mbox->intr_mode) { 196f62092f6SLey Foon Tan ret = request_irq(mbox->irq, altera_mbox_rx_interrupt, 0, 197f62092f6SLey Foon Tan DRIVER_NAME, chan); 198f62092f6SLey Foon Tan if (unlikely(ret)) { 199f62092f6SLey Foon Tan mbox->intr_mode = false; 200f62092f6SLey Foon Tan goto polling; /* use polling if failed */ 201f62092f6SLey Foon Tan } 202f62092f6SLey Foon Tan 203f62092f6SLey Foon Tan altera_mbox_rx_intmask(mbox, true); 204f62092f6SLey Foon Tan return 0; 205f62092f6SLey Foon Tan } 206f62092f6SLey Foon Tan 207f62092f6SLey Foon Tan polling: 208f62092f6SLey Foon Tan /* Setup polling timer */ 209c6f15047SKees Cook mbox->chan = chan; 210c6f15047SKees Cook timer_setup(&mbox->rxpoll_timer, altera_mbox_poll_rx, 0); 211f62092f6SLey Foon Tan mod_timer(&mbox->rxpoll_timer, 212f62092f6SLey Foon Tan jiffies + msecs_to_jiffies(MBOX_POLLING_MS)); 213f62092f6SLey Foon Tan 214f62092f6SLey Foon Tan return 0; 215f62092f6SLey Foon Tan } 216f62092f6SLey Foon Tan 217f62092f6SLey Foon Tan static int altera_mbox_send_data(struct mbox_chan *chan, void *data) 218f62092f6SLey Foon Tan { 219f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 220f62092f6SLey Foon Tan u32 *udata = (u32 *)data; 221f62092f6SLey Foon Tan 222f62092f6SLey Foon Tan if (!mbox || !data) 223f62092f6SLey Foon Tan return -EINVAL; 224f62092f6SLey Foon Tan if (!mbox->is_sender) { 225f62092f6SLey Foon Tan dev_warn(mbox->dev, 226f62092f6SLey Foon Tan "failed to send. This is receiver mailbox.\n"); 227f62092f6SLey Foon Tan return -EINVAL; 228f62092f6SLey Foon Tan } 229f62092f6SLey Foon Tan 230f62092f6SLey Foon Tan if (altera_mbox_full(mbox)) 231f62092f6SLey Foon Tan return -EBUSY; 232f62092f6SLey Foon Tan 233f62092f6SLey Foon Tan /* Enable interrupt before send */ 234f62092f6SLey Foon Tan if (mbox->intr_mode) 235f62092f6SLey Foon Tan altera_mbox_tx_intmask(mbox, true); 236f62092f6SLey Foon Tan 237f62092f6SLey Foon Tan /* Pointer register must write before command register */ 238f62092f6SLey Foon Tan writel_relaxed(udata[MBOX_PTR], mbox->mbox_base + MAILBOX_PTR_REG); 239f62092f6SLey Foon Tan writel_relaxed(udata[MBOX_CMD], mbox->mbox_base + MAILBOX_CMD_REG); 240f62092f6SLey Foon Tan 241f62092f6SLey Foon Tan return 0; 242f62092f6SLey Foon Tan } 243f62092f6SLey Foon Tan 244f62092f6SLey Foon Tan static bool altera_mbox_last_tx_done(struct mbox_chan *chan) 245f62092f6SLey Foon Tan { 246f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 247f62092f6SLey Foon Tan 248f62092f6SLey Foon Tan /* Return false if mailbox is full */ 249f62092f6SLey Foon Tan return altera_mbox_full(mbox) ? false : true; 250f62092f6SLey Foon Tan } 251f62092f6SLey Foon Tan 252f62092f6SLey Foon Tan static bool altera_mbox_peek_data(struct mbox_chan *chan) 253f62092f6SLey Foon Tan { 254f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 255f62092f6SLey Foon Tan 256f62092f6SLey Foon Tan return altera_mbox_pending(mbox) ? true : false; 257f62092f6SLey Foon Tan } 258f62092f6SLey Foon Tan 259f62092f6SLey Foon Tan static int altera_mbox_startup(struct mbox_chan *chan) 260f62092f6SLey Foon Tan { 261f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 262f62092f6SLey Foon Tan int ret = 0; 263f62092f6SLey Foon Tan 264f62092f6SLey Foon Tan if (!mbox) 265f62092f6SLey Foon Tan return -EINVAL; 266f62092f6SLey Foon Tan 267f62092f6SLey Foon Tan if (mbox->is_sender) 268f62092f6SLey Foon Tan ret = altera_mbox_startup_sender(chan); 269f62092f6SLey Foon Tan else 270f62092f6SLey Foon Tan ret = altera_mbox_startup_receiver(chan); 271f62092f6SLey Foon Tan 272f62092f6SLey Foon Tan return ret; 273f62092f6SLey Foon Tan } 274f62092f6SLey Foon Tan 275f62092f6SLey Foon Tan static void altera_mbox_shutdown(struct mbox_chan *chan) 276f62092f6SLey Foon Tan { 277f62092f6SLey Foon Tan struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); 278f62092f6SLey Foon Tan 279f62092f6SLey Foon Tan if (mbox->intr_mode) { 280f62092f6SLey Foon Tan /* Unmask all interrupt masks */ 281f62092f6SLey Foon Tan writel_relaxed(~0, mbox->mbox_base + MAILBOX_INTMASK_REG); 282f62092f6SLey Foon Tan free_irq(mbox->irq, chan); 283f62092f6SLey Foon Tan } else if (!mbox->is_sender) { 284f62092f6SLey Foon Tan del_timer_sync(&mbox->rxpoll_timer); 285f62092f6SLey Foon Tan } 286f62092f6SLey Foon Tan } 287f62092f6SLey Foon Tan 28805ae7975SAndrew Bresticker static const struct mbox_chan_ops altera_mbox_ops = { 289f62092f6SLey Foon Tan .send_data = altera_mbox_send_data, 290f62092f6SLey Foon Tan .startup = altera_mbox_startup, 291f62092f6SLey Foon Tan .shutdown = altera_mbox_shutdown, 292f62092f6SLey Foon Tan .last_tx_done = altera_mbox_last_tx_done, 293f62092f6SLey Foon Tan .peek_data = altera_mbox_peek_data, 294f62092f6SLey Foon Tan }; 295f62092f6SLey Foon Tan 296f62092f6SLey Foon Tan static int altera_mbox_probe(struct platform_device *pdev) 297f62092f6SLey Foon Tan { 298f62092f6SLey Foon Tan struct altera_mbox *mbox; 299f62092f6SLey Foon Tan struct resource *regs; 300f62092f6SLey Foon Tan struct mbox_chan *chans; 301f62092f6SLey Foon Tan int ret; 302f62092f6SLey Foon Tan 303f62092f6SLey Foon Tan mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), 304f62092f6SLey Foon Tan GFP_KERNEL); 305f62092f6SLey Foon Tan if (!mbox) 306f62092f6SLey Foon Tan return -ENOMEM; 307f62092f6SLey Foon Tan 308f62092f6SLey Foon Tan /* Allocated one channel */ 309f62092f6SLey Foon Tan chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL); 310f62092f6SLey Foon Tan if (!chans) 311f62092f6SLey Foon Tan return -ENOMEM; 312f62092f6SLey Foon Tan 313f62092f6SLey Foon Tan regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 314f62092f6SLey Foon Tan 315f62092f6SLey Foon Tan mbox->mbox_base = devm_ioremap_resource(&pdev->dev, regs); 316f62092f6SLey Foon Tan if (IS_ERR(mbox->mbox_base)) 317f62092f6SLey Foon Tan return PTR_ERR(mbox->mbox_base); 318f62092f6SLey Foon Tan 319f62092f6SLey Foon Tan /* Check is it a sender or receiver? */ 320f62092f6SLey Foon Tan mbox->is_sender = altera_mbox_is_sender(mbox); 321f62092f6SLey Foon Tan 322f62092f6SLey Foon Tan mbox->irq = platform_get_irq(pdev, 0); 323f62092f6SLey Foon Tan if (mbox->irq >= 0) 324f62092f6SLey Foon Tan mbox->intr_mode = true; 325f62092f6SLey Foon Tan 326f62092f6SLey Foon Tan mbox->dev = &pdev->dev; 327f62092f6SLey Foon Tan 328f62092f6SLey Foon Tan /* Hardware supports only one channel. */ 329f62092f6SLey Foon Tan chans[0].con_priv = mbox; 330f62092f6SLey Foon Tan mbox->controller.dev = mbox->dev; 331f62092f6SLey Foon Tan mbox->controller.num_chans = 1; 332f62092f6SLey Foon Tan mbox->controller.chans = chans; 333f62092f6SLey Foon Tan mbox->controller.ops = &altera_mbox_ops; 334f62092f6SLey Foon Tan 335f62092f6SLey Foon Tan if (mbox->is_sender) { 336f62092f6SLey Foon Tan if (mbox->intr_mode) { 337f62092f6SLey Foon Tan mbox->controller.txdone_irq = true; 338f62092f6SLey Foon Tan } else { 339f62092f6SLey Foon Tan mbox->controller.txdone_poll = true; 340f62092f6SLey Foon Tan mbox->controller.txpoll_period = MBOX_POLLING_MS; 341f62092f6SLey Foon Tan } 342f62092f6SLey Foon Tan } 343f62092f6SLey Foon Tan 344*87f63f57SThierry Reding ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller); 345f62092f6SLey Foon Tan if (ret) { 346f62092f6SLey Foon Tan dev_err(&pdev->dev, "Register mailbox failed\n"); 347f62092f6SLey Foon Tan goto err; 348f62092f6SLey Foon Tan } 349f62092f6SLey Foon Tan 350f62092f6SLey Foon Tan platform_set_drvdata(pdev, mbox); 351f62092f6SLey Foon Tan err: 352f62092f6SLey Foon Tan return ret; 353f62092f6SLey Foon Tan } 354f62092f6SLey Foon Tan 355f62092f6SLey Foon Tan static const struct of_device_id altera_mbox_match[] = { 356f62092f6SLey Foon Tan { .compatible = "altr,mailbox-1.0" }, 357f62092f6SLey Foon Tan { /* Sentinel */ } 358f62092f6SLey Foon Tan }; 359f62092f6SLey Foon Tan 360f62092f6SLey Foon Tan MODULE_DEVICE_TABLE(of, altera_mbox_match); 361f62092f6SLey Foon Tan 362f62092f6SLey Foon Tan static struct platform_driver altera_mbox_driver = { 363f62092f6SLey Foon Tan .probe = altera_mbox_probe, 364f62092f6SLey Foon Tan .driver = { 365f62092f6SLey Foon Tan .name = DRIVER_NAME, 366f62092f6SLey Foon Tan .of_match_table = altera_mbox_match, 367f62092f6SLey Foon Tan }, 368f62092f6SLey Foon Tan }; 369f62092f6SLey Foon Tan 370f62092f6SLey Foon Tan module_platform_driver(altera_mbox_driver); 371f62092f6SLey Foon Tan 372f62092f6SLey Foon Tan MODULE_LICENSE("GPL v2"); 373f62092f6SLey Foon Tan MODULE_DESCRIPTION("Altera mailbox specific functions"); 374f62092f6SLey Foon Tan MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>"); 375f62092f6SLey Foon Tan MODULE_ALIAS("platform:altera-mailbox"); 376