12bb70056SOleksij Rempel // SPDX-License-Identifier: GPL-2.0 22bb70056SOleksij Rempel /* 32bb70056SOleksij Rempel * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de> 42bb70056SOleksij Rempel */ 52bb70056SOleksij Rempel 62bb70056SOleksij Rempel #include <linux/clk.h> 72bb70056SOleksij Rempel #include <linux/interrupt.h> 82bb70056SOleksij Rempel #include <linux/io.h> 92bb70056SOleksij Rempel #include <linux/kernel.h> 102bb70056SOleksij Rempel #include <linux/mailbox_controller.h> 112bb70056SOleksij Rempel #include <linux/module.h> 122bb70056SOleksij Rempel #include <linux/of_device.h> 132bb70056SOleksij Rempel #include <linux/slab.h> 142bb70056SOleksij Rempel 152bb70056SOleksij Rempel #define IMX_MU_xSR_GIPn(x) BIT(28 + (3 - (x))) 162bb70056SOleksij Rempel #define IMX_MU_xSR_RFn(x) BIT(24 + (3 - (x))) 172bb70056SOleksij Rempel #define IMX_MU_xSR_TEn(x) BIT(20 + (3 - (x))) 182bb70056SOleksij Rempel #define IMX_MU_xSR_BRDIP BIT(9) 192bb70056SOleksij Rempel 202bb70056SOleksij Rempel /* General Purpose Interrupt Enable */ 212bb70056SOleksij Rempel #define IMX_MU_xCR_GIEn(x) BIT(28 + (3 - (x))) 222bb70056SOleksij Rempel /* Receive Interrupt Enable */ 232bb70056SOleksij Rempel #define IMX_MU_xCR_RIEn(x) BIT(24 + (3 - (x))) 242bb70056SOleksij Rempel /* Transmit Interrupt Enable */ 252bb70056SOleksij Rempel #define IMX_MU_xCR_TIEn(x) BIT(20 + (3 - (x))) 262bb70056SOleksij Rempel /* General Purpose Interrupt Request */ 272bb70056SOleksij Rempel #define IMX_MU_xCR_GIRn(x) BIT(16 + (3 - (x))) 282bb70056SOleksij Rempel 292bb70056SOleksij Rempel #define IMX_MU_CHANS 16 302bb70056SOleksij Rempel #define IMX_MU_CHAN_NAME_SIZE 20 312bb70056SOleksij Rempel 322bb70056SOleksij Rempel enum imx_mu_chan_type { 332bb70056SOleksij Rempel IMX_MU_TYPE_TX, /* Tx */ 342bb70056SOleksij Rempel IMX_MU_TYPE_RX, /* Rx */ 352bb70056SOleksij Rempel IMX_MU_TYPE_TXDB, /* Tx doorbell */ 362bb70056SOleksij Rempel IMX_MU_TYPE_RXDB, /* Rx doorbell */ 372bb70056SOleksij Rempel }; 382bb70056SOleksij Rempel 39c6c6bc6eSRichard Zhu struct imx_mu_dcfg { 40c6c6bc6eSRichard Zhu u32 xTR[4]; /* Transmit Registers */ 41c6c6bc6eSRichard Zhu u32 xRR[4]; /* Receive Registers */ 42c6c6bc6eSRichard Zhu u32 xSR; /* Status Register */ 43c6c6bc6eSRichard Zhu u32 xCR; /* Control Register */ 44c6c6bc6eSRichard Zhu }; 45c6c6bc6eSRichard Zhu 462bb70056SOleksij Rempel struct imx_mu_con_priv { 472bb70056SOleksij Rempel unsigned int idx; 482bb70056SOleksij Rempel char irq_desc[IMX_MU_CHAN_NAME_SIZE]; 492bb70056SOleksij Rempel enum imx_mu_chan_type type; 502bb70056SOleksij Rempel struct mbox_chan *chan; 512bb70056SOleksij Rempel struct tasklet_struct txdb_tasklet; 522bb70056SOleksij Rempel }; 532bb70056SOleksij Rempel 542bb70056SOleksij Rempel struct imx_mu_priv { 552bb70056SOleksij Rempel struct device *dev; 562bb70056SOleksij Rempel void __iomem *base; 572bb70056SOleksij Rempel spinlock_t xcr_lock; /* control register lock */ 582bb70056SOleksij Rempel 592bb70056SOleksij Rempel struct mbox_controller mbox; 602bb70056SOleksij Rempel struct mbox_chan mbox_chans[IMX_MU_CHANS]; 612bb70056SOleksij Rempel 622bb70056SOleksij Rempel struct imx_mu_con_priv con_priv[IMX_MU_CHANS]; 63c6c6bc6eSRichard Zhu const struct imx_mu_dcfg *dcfg; 642bb70056SOleksij Rempel struct clk *clk; 652bb70056SOleksij Rempel int irq; 662bb70056SOleksij Rempel 672bb70056SOleksij Rempel bool side_b; 682bb70056SOleksij Rempel }; 692bb70056SOleksij Rempel 70c6c6bc6eSRichard Zhu static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = { 71c6c6bc6eSRichard Zhu .xTR = {0x0, 0x4, 0x8, 0xc}, 72c6c6bc6eSRichard Zhu .xRR = {0x10, 0x14, 0x18, 0x1c}, 73c6c6bc6eSRichard Zhu .xSR = 0x20, 74c6c6bc6eSRichard Zhu .xCR = 0x24, 75c6c6bc6eSRichard Zhu }; 76c6c6bc6eSRichard Zhu 77c6c6bc6eSRichard Zhu static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = { 78c6c6bc6eSRichard Zhu .xTR = {0x20, 0x24, 0x28, 0x2c}, 79c6c6bc6eSRichard Zhu .xRR = {0x40, 0x44, 0x48, 0x4c}, 80c6c6bc6eSRichard Zhu .xSR = 0x60, 81c6c6bc6eSRichard Zhu .xCR = 0x64, 82c6c6bc6eSRichard Zhu }; 83c6c6bc6eSRichard Zhu 842bb70056SOleksij Rempel static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox) 852bb70056SOleksij Rempel { 862bb70056SOleksij Rempel return container_of(mbox, struct imx_mu_priv, mbox); 872bb70056SOleksij Rempel } 882bb70056SOleksij Rempel 892bb70056SOleksij Rempel static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) 902bb70056SOleksij Rempel { 912bb70056SOleksij Rempel iowrite32(val, priv->base + offs); 922bb70056SOleksij Rempel } 932bb70056SOleksij Rempel 942bb70056SOleksij Rempel static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) 952bb70056SOleksij Rempel { 962bb70056SOleksij Rempel return ioread32(priv->base + offs); 972bb70056SOleksij Rempel } 982bb70056SOleksij Rempel 992bb70056SOleksij Rempel static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, u32 set, u32 clr) 1002bb70056SOleksij Rempel { 1012bb70056SOleksij Rempel unsigned long flags; 1022bb70056SOleksij Rempel u32 val; 1032bb70056SOleksij Rempel 1042bb70056SOleksij Rempel spin_lock_irqsave(&priv->xcr_lock, flags); 105c6c6bc6eSRichard Zhu val = imx_mu_read(priv, priv->dcfg->xCR); 1062bb70056SOleksij Rempel val &= ~clr; 1072bb70056SOleksij Rempel val |= set; 108c6c6bc6eSRichard Zhu imx_mu_write(priv, val, priv->dcfg->xCR); 1092bb70056SOleksij Rempel spin_unlock_irqrestore(&priv->xcr_lock, flags); 1102bb70056SOleksij Rempel 1112bb70056SOleksij Rempel return val; 1122bb70056SOleksij Rempel } 1132bb70056SOleksij Rempel 1142bb70056SOleksij Rempel static void imx_mu_txdb_tasklet(unsigned long data) 1152bb70056SOleksij Rempel { 1162bb70056SOleksij Rempel struct imx_mu_con_priv *cp = (struct imx_mu_con_priv *)data; 1172bb70056SOleksij Rempel 1182bb70056SOleksij Rempel mbox_chan_txdone(cp->chan, 0); 1192bb70056SOleksij Rempel } 1202bb70056SOleksij Rempel 1212bb70056SOleksij Rempel static irqreturn_t imx_mu_isr(int irq, void *p) 1222bb70056SOleksij Rempel { 1232bb70056SOleksij Rempel struct mbox_chan *chan = p; 1242bb70056SOleksij Rempel struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); 1252bb70056SOleksij Rempel struct imx_mu_con_priv *cp = chan->con_priv; 1262bb70056SOleksij Rempel u32 val, ctrl, dat; 1272bb70056SOleksij Rempel 128c6c6bc6eSRichard Zhu ctrl = imx_mu_read(priv, priv->dcfg->xCR); 129c6c6bc6eSRichard Zhu val = imx_mu_read(priv, priv->dcfg->xSR); 1302bb70056SOleksij Rempel 1312bb70056SOleksij Rempel switch (cp->type) { 1322bb70056SOleksij Rempel case IMX_MU_TYPE_TX: 1332bb70056SOleksij Rempel val &= IMX_MU_xSR_TEn(cp->idx) & 1342bb70056SOleksij Rempel (ctrl & IMX_MU_xCR_TIEn(cp->idx)); 1352bb70056SOleksij Rempel break; 1362bb70056SOleksij Rempel case IMX_MU_TYPE_RX: 1372bb70056SOleksij Rempel val &= IMX_MU_xSR_RFn(cp->idx) & 1382bb70056SOleksij Rempel (ctrl & IMX_MU_xCR_RIEn(cp->idx)); 1392bb70056SOleksij Rempel break; 1402bb70056SOleksij Rempel case IMX_MU_TYPE_RXDB: 1412bb70056SOleksij Rempel val &= IMX_MU_xSR_GIPn(cp->idx) & 1422bb70056SOleksij Rempel (ctrl & IMX_MU_xCR_GIEn(cp->idx)); 1432bb70056SOleksij Rempel break; 1442bb70056SOleksij Rempel default: 1452bb70056SOleksij Rempel break; 1462bb70056SOleksij Rempel } 1472bb70056SOleksij Rempel 1482bb70056SOleksij Rempel if (!val) 1492bb70056SOleksij Rempel return IRQ_NONE; 1502bb70056SOleksij Rempel 1512bb70056SOleksij Rempel if (val == IMX_MU_xSR_TEn(cp->idx)) { 1522bb70056SOleksij Rempel imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx)); 1532bb70056SOleksij Rempel mbox_chan_txdone(chan, 0); 1542bb70056SOleksij Rempel } else if (val == IMX_MU_xSR_RFn(cp->idx)) { 155c6c6bc6eSRichard Zhu dat = imx_mu_read(priv, priv->dcfg->xRR[cp->idx]); 1562bb70056SOleksij Rempel mbox_chan_received_data(chan, (void *)&dat); 1572bb70056SOleksij Rempel } else if (val == IMX_MU_xSR_GIPn(cp->idx)) { 158c6c6bc6eSRichard Zhu imx_mu_write(priv, IMX_MU_xSR_GIPn(cp->idx), priv->dcfg->xSR); 1592bb70056SOleksij Rempel mbox_chan_received_data(chan, NULL); 1602bb70056SOleksij Rempel } else { 1612bb70056SOleksij Rempel dev_warn_ratelimited(priv->dev, "Not handled interrupt\n"); 1622bb70056SOleksij Rempel return IRQ_NONE; 1632bb70056SOleksij Rempel } 1642bb70056SOleksij Rempel 1652bb70056SOleksij Rempel return IRQ_HANDLED; 1662bb70056SOleksij Rempel } 1672bb70056SOleksij Rempel 1682bb70056SOleksij Rempel static int imx_mu_send_data(struct mbox_chan *chan, void *data) 1692bb70056SOleksij Rempel { 1702bb70056SOleksij Rempel struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); 1712bb70056SOleksij Rempel struct imx_mu_con_priv *cp = chan->con_priv; 1722bb70056SOleksij Rempel u32 *arg = data; 1732bb70056SOleksij Rempel 1742bb70056SOleksij Rempel switch (cp->type) { 1752bb70056SOleksij Rempel case IMX_MU_TYPE_TX: 176c6c6bc6eSRichard Zhu imx_mu_write(priv, *arg, priv->dcfg->xTR[cp->idx]); 1772bb70056SOleksij Rempel imx_mu_xcr_rmw(priv, IMX_MU_xCR_TIEn(cp->idx), 0); 1782bb70056SOleksij Rempel break; 1792bb70056SOleksij Rempel case IMX_MU_TYPE_TXDB: 1802bb70056SOleksij Rempel imx_mu_xcr_rmw(priv, IMX_MU_xCR_GIRn(cp->idx), 0); 1812bb70056SOleksij Rempel tasklet_schedule(&cp->txdb_tasklet); 1822bb70056SOleksij Rempel break; 1832bb70056SOleksij Rempel default: 1842bb70056SOleksij Rempel dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type); 1852bb70056SOleksij Rempel return -EINVAL; 1862bb70056SOleksij Rempel } 1872bb70056SOleksij Rempel 1882bb70056SOleksij Rempel return 0; 1892bb70056SOleksij Rempel } 1902bb70056SOleksij Rempel 1912bb70056SOleksij Rempel static int imx_mu_startup(struct mbox_chan *chan) 1922bb70056SOleksij Rempel { 1932bb70056SOleksij Rempel struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); 1942bb70056SOleksij Rempel struct imx_mu_con_priv *cp = chan->con_priv; 1952bb70056SOleksij Rempel int ret; 1962bb70056SOleksij Rempel 1972bb70056SOleksij Rempel if (cp->type == IMX_MU_TYPE_TXDB) { 1982bb70056SOleksij Rempel /* Tx doorbell don't have ACK support */ 1992bb70056SOleksij Rempel tasklet_init(&cp->txdb_tasklet, imx_mu_txdb_tasklet, 2002bb70056SOleksij Rempel (unsigned long)cp); 2012bb70056SOleksij Rempel return 0; 2022bb70056SOleksij Rempel } 2032bb70056SOleksij Rempel 20417b860bbSAnson Huang ret = request_irq(priv->irq, imx_mu_isr, IRQF_SHARED | 20517b860bbSAnson Huang IRQF_NO_SUSPEND, cp->irq_desc, chan); 2062bb70056SOleksij Rempel if (ret) { 2072bb70056SOleksij Rempel dev_err(priv->dev, 2082bb70056SOleksij Rempel "Unable to acquire IRQ %d\n", priv->irq); 2092bb70056SOleksij Rempel return ret; 2102bb70056SOleksij Rempel } 2112bb70056SOleksij Rempel 2122bb70056SOleksij Rempel switch (cp->type) { 2132bb70056SOleksij Rempel case IMX_MU_TYPE_RX: 2142bb70056SOleksij Rempel imx_mu_xcr_rmw(priv, IMX_MU_xCR_RIEn(cp->idx), 0); 2152bb70056SOleksij Rempel break; 2162bb70056SOleksij Rempel case IMX_MU_TYPE_RXDB: 2172bb70056SOleksij Rempel imx_mu_xcr_rmw(priv, IMX_MU_xCR_GIEn(cp->idx), 0); 2182bb70056SOleksij Rempel break; 2192bb70056SOleksij Rempel default: 2202bb70056SOleksij Rempel break; 2212bb70056SOleksij Rempel } 2222bb70056SOleksij Rempel 2232bb70056SOleksij Rempel return 0; 2242bb70056SOleksij Rempel } 2252bb70056SOleksij Rempel 2262bb70056SOleksij Rempel static void imx_mu_shutdown(struct mbox_chan *chan) 2272bb70056SOleksij Rempel { 2282bb70056SOleksij Rempel struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); 2292bb70056SOleksij Rempel struct imx_mu_con_priv *cp = chan->con_priv; 2302bb70056SOleksij Rempel 231bf159d15SDaniel Baluta if (cp->type == IMX_MU_TYPE_TXDB) { 2322bb70056SOleksij Rempel tasklet_kill(&cp->txdb_tasklet); 233bf159d15SDaniel Baluta return; 234bf159d15SDaniel Baluta } 2352bb70056SOleksij Rempel 2365f0af07eSDaniel Baluta switch (cp->type) { 2375f0af07eSDaniel Baluta case IMX_MU_TYPE_TX: 2385f0af07eSDaniel Baluta imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx)); 2395f0af07eSDaniel Baluta break; 2405f0af07eSDaniel Baluta case IMX_MU_TYPE_RX: 2415f0af07eSDaniel Baluta imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_RIEn(cp->idx)); 2425f0af07eSDaniel Baluta break; 2435f0af07eSDaniel Baluta case IMX_MU_TYPE_RXDB: 2445f0af07eSDaniel Baluta imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_GIEn(cp->idx)); 2455f0af07eSDaniel Baluta break; 2465f0af07eSDaniel Baluta default: 2475f0af07eSDaniel Baluta break; 2485f0af07eSDaniel Baluta } 2492bb70056SOleksij Rempel 2502bb70056SOleksij Rempel free_irq(priv->irq, chan); 2512bb70056SOleksij Rempel } 2522bb70056SOleksij Rempel 2532bb70056SOleksij Rempel static const struct mbox_chan_ops imx_mu_ops = { 2542bb70056SOleksij Rempel .send_data = imx_mu_send_data, 2552bb70056SOleksij Rempel .startup = imx_mu_startup, 2562bb70056SOleksij Rempel .shutdown = imx_mu_shutdown, 2572bb70056SOleksij Rempel }; 2582bb70056SOleksij Rempel 2592bb70056SOleksij Rempel static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox, 2602bb70056SOleksij Rempel const struct of_phandle_args *sp) 2612bb70056SOleksij Rempel { 2622bb70056SOleksij Rempel u32 type, idx, chan; 2632bb70056SOleksij Rempel 2642bb70056SOleksij Rempel if (sp->args_count != 2) { 2652bb70056SOleksij Rempel dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count); 2662bb70056SOleksij Rempel return ERR_PTR(-EINVAL); 2672bb70056SOleksij Rempel } 2682bb70056SOleksij Rempel 2692bb70056SOleksij Rempel type = sp->args[0]; /* channel type */ 2702bb70056SOleksij Rempel idx = sp->args[1]; /* index */ 2712bb70056SOleksij Rempel chan = type * 4 + idx; 2722bb70056SOleksij Rempel 2732bb70056SOleksij Rempel if (chan >= mbox->num_chans) { 2742bb70056SOleksij Rempel dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n", chan, type, idx); 2752bb70056SOleksij Rempel return ERR_PTR(-EINVAL); 2762bb70056SOleksij Rempel } 2772bb70056SOleksij Rempel 2782bb70056SOleksij Rempel return &mbox->chans[chan]; 2792bb70056SOleksij Rempel } 2802bb70056SOleksij Rempel 2812bb70056SOleksij Rempel static void imx_mu_init_generic(struct imx_mu_priv *priv) 2822bb70056SOleksij Rempel { 2832bb70056SOleksij Rempel if (priv->side_b) 2842bb70056SOleksij Rempel return; 2852bb70056SOleksij Rempel 2862bb70056SOleksij Rempel /* Set default MU configuration */ 287c6c6bc6eSRichard Zhu imx_mu_write(priv, 0, priv->dcfg->xCR); 2882bb70056SOleksij Rempel } 2892bb70056SOleksij Rempel 2902bb70056SOleksij Rempel static int imx_mu_probe(struct platform_device *pdev) 2912bb70056SOleksij Rempel { 2922bb70056SOleksij Rempel struct device *dev = &pdev->dev; 2932bb70056SOleksij Rempel struct device_node *np = dev->of_node; 2942bb70056SOleksij Rempel struct imx_mu_priv *priv; 295c6c6bc6eSRichard Zhu const struct imx_mu_dcfg *dcfg; 2962bb70056SOleksij Rempel unsigned int i; 2972bb70056SOleksij Rempel int ret; 2982bb70056SOleksij Rempel 2992bb70056SOleksij Rempel priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 3002bb70056SOleksij Rempel if (!priv) 3012bb70056SOleksij Rempel return -ENOMEM; 3022bb70056SOleksij Rempel 3032bb70056SOleksij Rempel priv->dev = dev; 3042bb70056SOleksij Rempel 3050c40e631SAnson Huang priv->base = devm_platform_ioremap_resource(pdev, 0); 3062bb70056SOleksij Rempel if (IS_ERR(priv->base)) 3072bb70056SOleksij Rempel return PTR_ERR(priv->base); 3082bb70056SOleksij Rempel 3092bb70056SOleksij Rempel priv->irq = platform_get_irq(pdev, 0); 3102bb70056SOleksij Rempel if (priv->irq < 0) 3112bb70056SOleksij Rempel return priv->irq; 3122bb70056SOleksij Rempel 313c6c6bc6eSRichard Zhu dcfg = of_device_get_match_data(dev); 314c6c6bc6eSRichard Zhu if (!dcfg) 315c6c6bc6eSRichard Zhu return -EINVAL; 316c6c6bc6eSRichard Zhu priv->dcfg = dcfg; 317c6c6bc6eSRichard Zhu 3182bb70056SOleksij Rempel priv->clk = devm_clk_get(dev, NULL); 3192bb70056SOleksij Rempel if (IS_ERR(priv->clk)) { 3202bb70056SOleksij Rempel if (PTR_ERR(priv->clk) != -ENOENT) 3212bb70056SOleksij Rempel return PTR_ERR(priv->clk); 3222bb70056SOleksij Rempel 3232bb70056SOleksij Rempel priv->clk = NULL; 3242bb70056SOleksij Rempel } 3252bb70056SOleksij Rempel 3262bb70056SOleksij Rempel ret = clk_prepare_enable(priv->clk); 3272bb70056SOleksij Rempel if (ret) { 3282bb70056SOleksij Rempel dev_err(dev, "Failed to enable clock\n"); 3292bb70056SOleksij Rempel return ret; 3302bb70056SOleksij Rempel } 3312bb70056SOleksij Rempel 3322bb70056SOleksij Rempel for (i = 0; i < IMX_MU_CHANS; i++) { 3332bb70056SOleksij Rempel struct imx_mu_con_priv *cp = &priv->con_priv[i]; 3342bb70056SOleksij Rempel 3352bb70056SOleksij Rempel cp->idx = i % 4; 3362bb70056SOleksij Rempel cp->type = i >> 2; 3372bb70056SOleksij Rempel cp->chan = &priv->mbox_chans[i]; 3382bb70056SOleksij Rempel priv->mbox_chans[i].con_priv = cp; 3392bb70056SOleksij Rempel snprintf(cp->irq_desc, sizeof(cp->irq_desc), 3402bb70056SOleksij Rempel "imx_mu_chan[%i-%i]", cp->type, cp->idx); 3412bb70056SOleksij Rempel } 3422bb70056SOleksij Rempel 3432bb70056SOleksij Rempel priv->side_b = of_property_read_bool(np, "fsl,mu-side-b"); 3442bb70056SOleksij Rempel 3452bb70056SOleksij Rempel spin_lock_init(&priv->xcr_lock); 3462bb70056SOleksij Rempel 3472bb70056SOleksij Rempel priv->mbox.dev = dev; 3482bb70056SOleksij Rempel priv->mbox.ops = &imx_mu_ops; 3492bb70056SOleksij Rempel priv->mbox.chans = priv->mbox_chans; 3502bb70056SOleksij Rempel priv->mbox.num_chans = IMX_MU_CHANS; 3512bb70056SOleksij Rempel priv->mbox.of_xlate = imx_mu_xlate; 3522bb70056SOleksij Rempel priv->mbox.txdone_irq = true; 3532bb70056SOleksij Rempel 3542bb70056SOleksij Rempel platform_set_drvdata(pdev, priv); 3552bb70056SOleksij Rempel 3562bb70056SOleksij Rempel imx_mu_init_generic(priv); 3572bb70056SOleksij Rempel 3584013286cSThierry Reding return devm_mbox_controller_register(dev, &priv->mbox); 3592bb70056SOleksij Rempel } 3602bb70056SOleksij Rempel 3612bb70056SOleksij Rempel static int imx_mu_remove(struct platform_device *pdev) 3622bb70056SOleksij Rempel { 3632bb70056SOleksij Rempel struct imx_mu_priv *priv = platform_get_drvdata(pdev); 3642bb70056SOleksij Rempel 3652bb70056SOleksij Rempel clk_disable_unprepare(priv->clk); 3662bb70056SOleksij Rempel 3672bb70056SOleksij Rempel return 0; 3682bb70056SOleksij Rempel } 3692bb70056SOleksij Rempel 3702bb70056SOleksij Rempel static const struct of_device_id imx_mu_dt_ids[] = { 371c6c6bc6eSRichard Zhu { .compatible = "fsl,imx7ulp-mu", .data = &imx_mu_cfg_imx7ulp }, 372c6c6bc6eSRichard Zhu { .compatible = "fsl,imx6sx-mu", .data = &imx_mu_cfg_imx6sx }, 3732bb70056SOleksij Rempel { }, 3742bb70056SOleksij Rempel }; 3752bb70056SOleksij Rempel MODULE_DEVICE_TABLE(of, imx_mu_dt_ids); 3762bb70056SOleksij Rempel 3772bb70056SOleksij Rempel static struct platform_driver imx_mu_driver = { 3782bb70056SOleksij Rempel .probe = imx_mu_probe, 3792bb70056SOleksij Rempel .remove = imx_mu_remove, 3802bb70056SOleksij Rempel .driver = { 3812bb70056SOleksij Rempel .name = "imx_mu", 3822bb70056SOleksij Rempel .of_match_table = imx_mu_dt_ids, 3832bb70056SOleksij Rempel }, 3842bb70056SOleksij Rempel }; 3852bb70056SOleksij Rempel module_platform_driver(imx_mu_driver); 3862bb70056SOleksij Rempel 3872bb70056SOleksij Rempel MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>"); 3882bb70056SOleksij Rempel MODULE_DESCRIPTION("Message Unit driver for i.MX"); 3892bb70056SOleksij Rempel MODULE_LICENSE("GPL v2"); 390