xref: /linux/drivers/soc/renesas/rcar-mfis.c (revision 637315cb400eed1dbe721954fea437a61a2d65b2)
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