1005fa59aSWolfram Sang // SPDX-License-Identifier: GPL-2.0-only 2005fa59aSWolfram Sang /* 3005fa59aSWolfram Sang * Renesas R-Car MFIS (Multifunctional Interface) driver 4005fa59aSWolfram Sang * 5005fa59aSWolfram Sang * Copyright (C) Renesas Solutions Corp. 6005fa59aSWolfram Sang * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7005fa59aSWolfram Sang * Wolfram Sang <wsa+renesas@sang-engineering.com> 8005fa59aSWolfram Sang */ 9005fa59aSWolfram Sang #include <dt-bindings/soc/renesas,r8a78000-mfis.h> 10005fa59aSWolfram Sang #include <linux/device.h> 11005fa59aSWolfram Sang #include <linux/interrupt.h> 12005fa59aSWolfram Sang #include <linux/io.h> 13005fa59aSWolfram Sang #include <linux/kernel.h> 14005fa59aSWolfram Sang #include <linux/mailbox_controller.h> 15005fa59aSWolfram Sang #include <linux/module.h> 16005fa59aSWolfram Sang #include <linux/of.h> 17005fa59aSWolfram Sang #include <linux/of_irq.h> 18005fa59aSWolfram Sang #include <linux/of_platform.h> 19005fa59aSWolfram Sang #include <linux/platform_device.h> 20005fa59aSWolfram Sang #include <linux/spinlock.h> 21005fa59aSWolfram Sang 22005fa59aSWolfram Sang #define MFISWPCNTR 0x0900 23005fa59aSWolfram Sang #define MFISWACNTR 0x0904 24005fa59aSWolfram Sang 25005fa59aSWolfram Sang #define MFIS_X5H_IICR(i) ((i) * 0x1000 + 0x00) 26005fa59aSWolfram Sang #define MFIS_X5H_EICR(i) ((i) * 0x1000 + 0x04) 27005fa59aSWolfram Sang 28005fa59aSWolfram Sang #define MFIS_UNPROTECT_KEY 0xACCE0000 29005fa59aSWolfram Sang 30005fa59aSWolfram Sang struct mfis_priv; 31005fa59aSWolfram Sang 32005fa59aSWolfram Sang struct mfis_reg { 33005fa59aSWolfram Sang void __iomem *base; 34005fa59aSWolfram Sang resource_size_t start; 35005fa59aSWolfram Sang struct mfis_priv *priv; 36005fa59aSWolfram Sang }; 37005fa59aSWolfram Sang 38005fa59aSWolfram Sang struct mfis_info { 39005fa59aSWolfram Sang u32 unprotect_mask; 40005fa59aSWolfram Sang unsigned int mb_num_channels; 41005fa59aSWolfram Sang unsigned int mb_reg_comes_from_dt:1; 42005fa59aSWolfram Sang unsigned int mb_tx_uses_eicr:1; 43005fa59aSWolfram Sang unsigned int mb_channels_are_unidir:1; 44*b4d41ffaSWolfram Sang u32 (*mb_calc_reg)(u32 chan_num, bool tx_uses_eicr, bool is_only_rx); 45005fa59aSWolfram Sang }; 46005fa59aSWolfram Sang 47005fa59aSWolfram Sang struct mfis_chan_priv { 48005fa59aSWolfram Sang u32 reg; 49005fa59aSWolfram Sang int irq; 50005fa59aSWolfram Sang }; 51005fa59aSWolfram Sang 52005fa59aSWolfram Sang struct mfis_priv { 53005fa59aSWolfram Sang spinlock_t unprotect_lock; /* guards access to the unprotection reg */ 54005fa59aSWolfram Sang struct device *dev; 55005fa59aSWolfram Sang struct mfis_reg common_reg; 56005fa59aSWolfram Sang struct mfis_reg mbox_reg; 57005fa59aSWolfram Sang const struct mfis_info *info; 58005fa59aSWolfram Sang 59005fa59aSWolfram Sang /* mailbox private data */ 60005fa59aSWolfram Sang struct mbox_controller mbox; 61005fa59aSWolfram Sang struct mfis_chan_priv *chan_privs; 62005fa59aSWolfram Sang }; 63005fa59aSWolfram Sang 64005fa59aSWolfram Sang static u32 mfis_read(struct mfis_reg *mreg, unsigned int reg) 65005fa59aSWolfram Sang { 66005fa59aSWolfram Sang return ioread32(mreg->base + reg); 67005fa59aSWolfram Sang } 68005fa59aSWolfram Sang 69005fa59aSWolfram Sang static void mfis_write(struct mfis_reg *mreg, u32 reg, u32 val) 70005fa59aSWolfram Sang { 71005fa59aSWolfram Sang struct mfis_priv *priv = mreg->priv; 72005fa59aSWolfram Sang u32 unprotect_mask = priv->info->unprotect_mask; 73005fa59aSWolfram Sang unsigned long flags; 74005fa59aSWolfram Sang u32 unprotect_code; 75005fa59aSWolfram Sang 76005fa59aSWolfram Sang /* 77005fa59aSWolfram Sang * [Gen4] key: 0xACCE0000, mask: 0x0000FFFF 78005fa59aSWolfram Sang * [Gen5] key: 0xACC00000, mask: 0x000FFFFF 79005fa59aSWolfram Sang */ 80005fa59aSWolfram Sang unprotect_code = (MFIS_UNPROTECT_KEY & ~unprotect_mask) | 81005fa59aSWolfram Sang ((mreg->start + reg) & unprotect_mask); 82005fa59aSWolfram Sang 83005fa59aSWolfram Sang spin_lock_irqsave(&priv->unprotect_lock, flags); 84005fa59aSWolfram Sang iowrite32(unprotect_code, priv->common_reg.base + MFISWACNTR); 85005fa59aSWolfram Sang iowrite32(val, mreg->base + reg); 86005fa59aSWolfram Sang spin_unlock_irqrestore(&priv->unprotect_lock, flags); 87005fa59aSWolfram Sang } 88005fa59aSWolfram Sang 89005fa59aSWolfram Sang /******************************************************** 90005fa59aSWolfram Sang * Mailbox * 91005fa59aSWolfram Sang ********************************************************/ 92005fa59aSWolfram Sang 93005fa59aSWolfram Sang #define mfis_mb_mbox_to_priv(_m) container_of((_m), struct mfis_priv, mbox) 94005fa59aSWolfram Sang 95005fa59aSWolfram Sang static irqreturn_t mfis_mb_iicr_interrupt(int irq, void *data) 96005fa59aSWolfram Sang { 97005fa59aSWolfram Sang struct mbox_chan *chan = data; 98005fa59aSWolfram Sang struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox); 99005fa59aSWolfram Sang struct mfis_chan_priv *chan_priv = chan->con_priv; 100005fa59aSWolfram Sang 101005fa59aSWolfram Sang mbox_chan_received_data(chan, NULL); 102005fa59aSWolfram Sang /* Stop remote(!) doorbell */ 103005fa59aSWolfram Sang mfis_write(&priv->mbox_reg, chan_priv->reg, 0); 104005fa59aSWolfram Sang 105005fa59aSWolfram Sang return IRQ_HANDLED; 106005fa59aSWolfram Sang } 107005fa59aSWolfram Sang 108005fa59aSWolfram Sang static int mfis_mb_startup(struct mbox_chan *chan) 109005fa59aSWolfram Sang { 110005fa59aSWolfram Sang struct mfis_chan_priv *chan_priv = chan->con_priv; 111005fa59aSWolfram Sang 112005fa59aSWolfram Sang if (!chan_priv->irq) 113005fa59aSWolfram Sang return 0; 114005fa59aSWolfram Sang 115005fa59aSWolfram Sang return request_irq(chan_priv->irq, mfis_mb_iicr_interrupt, 0, 116005fa59aSWolfram Sang dev_name(chan->mbox->dev), chan); 117005fa59aSWolfram Sang } 118005fa59aSWolfram Sang 119005fa59aSWolfram Sang static void mfis_mb_shutdown(struct mbox_chan *chan) 120005fa59aSWolfram Sang { 121005fa59aSWolfram Sang struct mfis_chan_priv *chan_priv = chan->con_priv; 122005fa59aSWolfram Sang 123005fa59aSWolfram Sang if (chan_priv->irq) 124005fa59aSWolfram Sang free_irq(chan_priv->irq, chan); 125005fa59aSWolfram Sang } 126005fa59aSWolfram Sang 127005fa59aSWolfram Sang static int mfis_mb_iicr_send_data(struct mbox_chan *chan, void *data) 128005fa59aSWolfram Sang { 129005fa59aSWolfram Sang struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox); 130005fa59aSWolfram Sang struct mfis_chan_priv *chan_priv = chan->con_priv; 131005fa59aSWolfram Sang 132005fa59aSWolfram Sang /* Our doorbell still active? */ 133005fa59aSWolfram Sang if (mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0)) 134005fa59aSWolfram Sang return -EBUSY; 135005fa59aSWolfram Sang 136005fa59aSWolfram Sang /* Start our doorbell */ 137005fa59aSWolfram Sang mfis_write(&priv->mbox_reg, chan_priv->reg, BIT(0)); 138005fa59aSWolfram Sang 139005fa59aSWolfram Sang return 0; 140005fa59aSWolfram Sang } 141005fa59aSWolfram Sang 142005fa59aSWolfram Sang static bool mfis_mb_iicr_last_tx_done(struct mbox_chan *chan) 143005fa59aSWolfram Sang { 144005fa59aSWolfram Sang struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox); 145005fa59aSWolfram Sang struct mfis_chan_priv *chan_priv = chan->con_priv; 146005fa59aSWolfram Sang 147005fa59aSWolfram Sang /* Our doorbell still active? */ 148005fa59aSWolfram Sang return !(mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0)); 149005fa59aSWolfram Sang } 150005fa59aSWolfram Sang 151005fa59aSWolfram Sang /* For MFIS variants using the IICR/EICR register pair */ 152005fa59aSWolfram Sang static const struct mbox_chan_ops mfis_iicr_ops = { 153005fa59aSWolfram Sang .startup = mfis_mb_startup, 154005fa59aSWolfram Sang .shutdown = mfis_mb_shutdown, 155005fa59aSWolfram Sang .send_data = mfis_mb_iicr_send_data, 156005fa59aSWolfram Sang .last_tx_done = mfis_mb_iicr_last_tx_done, 157005fa59aSWolfram Sang }; 158005fa59aSWolfram Sang 159*b4d41ffaSWolfram Sang static u32 mfis_mb_r8a779g0_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx) 160*b4d41ffaSWolfram Sang { 161*b4d41ffaSWolfram Sang unsigned int i, k; 162*b4d41ffaSWolfram Sang u32 reg; 163*b4d41ffaSWolfram Sang 164*b4d41ffaSWolfram Sang i = chan_num & 3; 165*b4d41ffaSWolfram Sang k = chan_num >> 2; 166*b4d41ffaSWolfram Sang 167*b4d41ffaSWolfram Sang if (is_only_rx) { 168*b4d41ffaSWolfram Sang if (k < 2) 169*b4d41ffaSWolfram Sang reg = 0x9404 + 0x1020 * k + 0x08 * i; 170*b4d41ffaSWolfram Sang else 171*b4d41ffaSWolfram Sang reg = 0xb504 + 0x08 * i; 172*b4d41ffaSWolfram Sang } else { 173*b4d41ffaSWolfram Sang if (k < 2) 174*b4d41ffaSWolfram Sang reg = 0x1400 + 0x1008 * i + 0x20 * k; 175*b4d41ffaSWolfram Sang else 176*b4d41ffaSWolfram Sang reg = 0x1500 + 0x1008 * i; 177*b4d41ffaSWolfram Sang } 178*b4d41ffaSWolfram Sang 179*b4d41ffaSWolfram Sang return reg; 180*b4d41ffaSWolfram Sang } 181*b4d41ffaSWolfram Sang 182*b4d41ffaSWolfram Sang static u32 mfis_mb_r8a78000_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx) 183*b4d41ffaSWolfram Sang { 184*b4d41ffaSWolfram Sang return (tx_uses_eicr ^ is_only_rx) ? MFIS_X5H_EICR(chan_num) : 185*b4d41ffaSWolfram Sang MFIS_X5H_IICR(chan_num); 186*b4d41ffaSWolfram Sang } 187*b4d41ffaSWolfram Sang 188005fa59aSWolfram Sang static struct mbox_chan *mfis_mb_of_xlate(struct mbox_controller *mbox, 189005fa59aSWolfram Sang const struct of_phandle_args *sp) 190005fa59aSWolfram Sang { 191005fa59aSWolfram Sang struct mfis_priv *priv = mfis_mb_mbox_to_priv(mbox); 192005fa59aSWolfram Sang struct mfis_chan_priv *chan_priv; 193005fa59aSWolfram Sang bool tx_uses_eicr, is_only_rx; 194005fa59aSWolfram Sang u32 chan_num, chan_flags; 195005fa59aSWolfram Sang struct mbox_chan *chan; 196005fa59aSWolfram Sang 197005fa59aSWolfram Sang if (sp->args_count != 2) 198005fa59aSWolfram Sang return ERR_PTR(-EINVAL); 199005fa59aSWolfram Sang 200005fa59aSWolfram Sang chan_num = sp->args[0]; 201005fa59aSWolfram Sang chan_flags = sp->args[1]; 202005fa59aSWolfram Sang 203005fa59aSWolfram Sang if (chan_num >= priv->info->mb_num_channels) 204005fa59aSWolfram Sang return ERR_PTR(-EINVAL); 205005fa59aSWolfram Sang 206005fa59aSWolfram Sang /* Channel layout is described in mfis_mb_probe() */ 207005fa59aSWolfram Sang if (priv->info->mb_channels_are_unidir) { 208005fa59aSWolfram Sang is_only_rx = chan_flags & MFIS_CHANNEL_RX; 209005fa59aSWolfram Sang chan = mbox->chans + 2 * chan_num + is_only_rx; 210005fa59aSWolfram Sang } else { 211005fa59aSWolfram Sang is_only_rx = false; 212005fa59aSWolfram Sang chan = mbox->chans + chan_num; 213005fa59aSWolfram Sang } 214005fa59aSWolfram Sang 215005fa59aSWolfram Sang if (priv->info->mb_reg_comes_from_dt) { 216005fa59aSWolfram Sang tx_uses_eicr = chan_flags & MFIS_CHANNEL_EICR; 217005fa59aSWolfram Sang if (tx_uses_eicr) 218005fa59aSWolfram Sang chan += mbox->num_chans / 2; 219005fa59aSWolfram Sang } else { 220005fa59aSWolfram Sang tx_uses_eicr = priv->info->mb_tx_uses_eicr; 221005fa59aSWolfram Sang } 222005fa59aSWolfram Sang 223005fa59aSWolfram Sang chan_priv = chan->con_priv; 224*b4d41ffaSWolfram Sang chan_priv->reg = priv->info->mb_calc_reg(chan_num, tx_uses_eicr, is_only_rx); 225005fa59aSWolfram Sang 226005fa59aSWolfram Sang if (!priv->info->mb_channels_are_unidir || is_only_rx) { 227005fa59aSWolfram Sang char irqname[8]; 228005fa59aSWolfram Sang char suffix = tx_uses_eicr ? 'i' : 'e'; 229005fa59aSWolfram Sang 230005fa59aSWolfram Sang /* "ch0i" or "ch0e" */ 231005fa59aSWolfram Sang scnprintf(irqname, sizeof(irqname), "ch%u%c", chan_num, suffix); 232005fa59aSWolfram Sang 233005fa59aSWolfram Sang chan_priv->irq = of_irq_get_byname(mbox->dev->of_node, irqname); 234005fa59aSWolfram Sang if (chan_priv->irq < 0) 235005fa59aSWolfram Sang return ERR_PTR(chan_priv->irq); 236005fa59aSWolfram Sang if (chan_priv->irq == 0) 237005fa59aSWolfram Sang return ERR_PTR(-ENOENT); 238005fa59aSWolfram Sang } 239005fa59aSWolfram Sang 240005fa59aSWolfram Sang return chan; 241005fa59aSWolfram Sang } 242005fa59aSWolfram Sang 243005fa59aSWolfram Sang static int mfis_mb_probe(struct mfis_priv *priv) 244005fa59aSWolfram Sang { 245005fa59aSWolfram Sang unsigned int num_chan = priv->info->mb_num_channels; 246005fa59aSWolfram Sang struct device *dev = priv->dev; 247005fa59aSWolfram Sang struct mbox_controller *mbox; 248005fa59aSWolfram Sang struct mbox_chan *chan; 249005fa59aSWolfram Sang 250005fa59aSWolfram Sang if (priv->info->mb_channels_are_unidir) { 251005fa59aSWolfram Sang /* Channel layout: Ch0-TX, Ch0-RX, Ch1-TX... */ 252005fa59aSWolfram Sang num_chan *= 2; 253005fa59aSWolfram Sang } 254005fa59aSWolfram Sang 255005fa59aSWolfram Sang if (priv->info->mb_reg_comes_from_dt) { 256005fa59aSWolfram Sang /* Channel layout: <n> IICR channels, <n> EICR channels */ 257005fa59aSWolfram Sang num_chan *= 2; 258005fa59aSWolfram Sang } 259005fa59aSWolfram Sang 260005fa59aSWolfram Sang chan = devm_kcalloc(dev, num_chan, sizeof(*chan), GFP_KERNEL); 261005fa59aSWolfram Sang if (!chan) 262005fa59aSWolfram Sang return -ENOMEM; 263005fa59aSWolfram Sang 264005fa59aSWolfram Sang priv->chan_privs = devm_kcalloc(dev, num_chan, sizeof(*priv->chan_privs), 265005fa59aSWolfram Sang GFP_KERNEL); 266005fa59aSWolfram Sang if (!priv->chan_privs) 267005fa59aSWolfram Sang return -ENOMEM; 268005fa59aSWolfram Sang 269005fa59aSWolfram Sang mbox = &priv->mbox; 270005fa59aSWolfram Sang 271005fa59aSWolfram Sang for (unsigned int i = 0; i < num_chan; i++) 272005fa59aSWolfram Sang chan[i].con_priv = &priv->chan_privs[i]; 273005fa59aSWolfram Sang 274005fa59aSWolfram Sang mbox->chans = chan; 275005fa59aSWolfram Sang mbox->num_chans = num_chan; 276005fa59aSWolfram Sang mbox->txdone_poll = true; 277005fa59aSWolfram Sang mbox->ops = &mfis_iicr_ops; 278005fa59aSWolfram Sang mbox->dev = dev; 279005fa59aSWolfram Sang mbox->of_xlate = mfis_mb_of_xlate; 280005fa59aSWolfram Sang 281005fa59aSWolfram Sang return devm_mbox_controller_register(dev, mbox); 282005fa59aSWolfram Sang } 283005fa59aSWolfram Sang 284005fa59aSWolfram Sang /******************************************************** 285005fa59aSWolfram Sang * Common * 286005fa59aSWolfram Sang ********************************************************/ 287005fa59aSWolfram Sang static int mfis_reg_probe(struct platform_device *pdev, struct mfis_priv *priv, 288005fa59aSWolfram Sang struct mfis_reg *mreg, const char *name, bool required) 289005fa59aSWolfram Sang { 290005fa59aSWolfram Sang struct resource *res; 291005fa59aSWolfram Sang void __iomem *base; 292005fa59aSWolfram Sang 293005fa59aSWolfram Sang res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); 294005fa59aSWolfram Sang 295005fa59aSWolfram Sang /* If there is no mailbox resource, registers are in the common space */ 296005fa59aSWolfram Sang if (!res && !required) { 297005fa59aSWolfram Sang *mreg = priv->common_reg; 298005fa59aSWolfram Sang } else { 299005fa59aSWolfram Sang base = devm_ioremap_resource(&pdev->dev, res); 300005fa59aSWolfram Sang if (IS_ERR(base)) 301005fa59aSWolfram Sang return PTR_ERR(base); 302005fa59aSWolfram Sang 303005fa59aSWolfram Sang mreg->base = base; 304005fa59aSWolfram Sang mreg->start = res->start; 305005fa59aSWolfram Sang mreg->priv = priv; 306005fa59aSWolfram Sang } 307005fa59aSWolfram Sang 308005fa59aSWolfram Sang return 0; 309005fa59aSWolfram Sang } 310005fa59aSWolfram Sang 311005fa59aSWolfram Sang static int mfis_probe(struct platform_device *pdev) 312005fa59aSWolfram Sang { 313005fa59aSWolfram Sang struct device *dev = &pdev->dev; 314005fa59aSWolfram Sang struct mfis_priv *priv; 315005fa59aSWolfram Sang int ret; 316005fa59aSWolfram Sang 317005fa59aSWolfram Sang priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 318005fa59aSWolfram Sang if (!priv) 319005fa59aSWolfram Sang return -ENOMEM; 320005fa59aSWolfram Sang 321005fa59aSWolfram Sang priv->dev = dev; 322005fa59aSWolfram Sang priv->info = of_device_get_match_data(dev); 323005fa59aSWolfram Sang if (!priv->info) 324005fa59aSWolfram Sang return -ENOENT; 325005fa59aSWolfram Sang 326005fa59aSWolfram Sang spin_lock_init(&priv->unprotect_lock); 327005fa59aSWolfram Sang 328005fa59aSWolfram Sang ret = mfis_reg_probe(pdev, priv, &priv->common_reg, "common", true); 329005fa59aSWolfram Sang if (ret) 330005fa59aSWolfram Sang return ret; 331005fa59aSWolfram Sang 332005fa59aSWolfram Sang ret = mfis_reg_probe(pdev, priv, &priv->mbox_reg, "mboxes", false); 333005fa59aSWolfram Sang if (ret) 334005fa59aSWolfram Sang return ret; 335005fa59aSWolfram Sang 336005fa59aSWolfram Sang return mfis_mb_probe(priv); 337005fa59aSWolfram Sang } 338005fa59aSWolfram Sang 339*b4d41ffaSWolfram Sang static const struct mfis_info mfis_info_r8a779g0 = { 340*b4d41ffaSWolfram Sang .unprotect_mask = 0x0000ffff, 341*b4d41ffaSWolfram Sang .mb_num_channels = 12, 342*b4d41ffaSWolfram Sang .mb_channels_are_unidir = true, 343*b4d41ffaSWolfram Sang .mb_calc_reg = mfis_mb_r8a779g0_calc_reg, 344*b4d41ffaSWolfram Sang }; 345*b4d41ffaSWolfram Sang 346005fa59aSWolfram Sang static const struct mfis_info mfis_info_r8a78000 = { 347005fa59aSWolfram Sang .unprotect_mask = 0x000fffff, 348005fa59aSWolfram Sang .mb_num_channels = 64, 349005fa59aSWolfram Sang .mb_reg_comes_from_dt = true, 350005fa59aSWolfram Sang .mb_channels_are_unidir = true, 351*b4d41ffaSWolfram Sang .mb_calc_reg = mfis_mb_r8a78000_calc_reg, 352005fa59aSWolfram Sang }; 353005fa59aSWolfram Sang 354005fa59aSWolfram Sang static const struct mfis_info mfis_info_r8a78000_scp = { 355005fa59aSWolfram Sang .unprotect_mask = 0x000fffff, 356005fa59aSWolfram Sang .mb_num_channels = 32, 357005fa59aSWolfram Sang .mb_tx_uses_eicr = true, 358005fa59aSWolfram Sang .mb_channels_are_unidir = true, 359*b4d41ffaSWolfram Sang .mb_calc_reg = mfis_mb_r8a78000_calc_reg, 360005fa59aSWolfram Sang }; 361005fa59aSWolfram Sang 362005fa59aSWolfram Sang static const struct of_device_id mfis_mfd_of_match[] = { 363*b4d41ffaSWolfram Sang { .compatible = "renesas,r8a779g0-mfis", .data = &mfis_info_r8a779g0, }, 364*b4d41ffaSWolfram Sang { .compatible = "renesas,r8a779h0-mfis", .data = &mfis_info_r8a779g0, }, 365005fa59aSWolfram Sang { .compatible = "renesas,r8a78000-mfis", .data = &mfis_info_r8a78000, }, 366005fa59aSWolfram Sang { .compatible = "renesas,r8a78000-mfis-scp", .data = &mfis_info_r8a78000_scp, }, 367005fa59aSWolfram Sang {} 368005fa59aSWolfram Sang }; 369005fa59aSWolfram Sang MODULE_DEVICE_TABLE(of, mfis_mfd_of_match); 370005fa59aSWolfram Sang 371005fa59aSWolfram Sang static struct platform_driver mfis_driver = { 372005fa59aSWolfram Sang .driver = { 373005fa59aSWolfram Sang .name = "rcar-mfis", 374005fa59aSWolfram Sang .of_match_table = mfis_mfd_of_match, 375005fa59aSWolfram Sang .suppress_bind_attrs = true, 376005fa59aSWolfram Sang }, 377005fa59aSWolfram Sang .probe = mfis_probe, 378005fa59aSWolfram Sang }; 379005fa59aSWolfram Sang module_platform_driver(mfis_driver); 380005fa59aSWolfram Sang 381005fa59aSWolfram Sang MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 382005fa59aSWolfram Sang MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>"); 383005fa59aSWolfram Sang MODULE_LICENSE("GPL"); 384005fa59aSWolfram Sang MODULE_DESCRIPTION("Renesas R-Car MFIS driver"); 385