xref: /openbmc/linux/drivers/mfd/rz-mtu3.c (revision d92df6fb)
1654c293eSBiju Das // SPDX-License-Identifier: GPL-2.0
2654c293eSBiju Das /*
3654c293eSBiju Das  * Renesas RZ/G2L Multi-Function Timer Pulse Unit 3(MTU3a) Core driver
4654c293eSBiju Das  *
5654c293eSBiju Das  * Copyright (C) 2023 Renesas Electronics Corporation
6654c293eSBiju Das  */
7654c293eSBiju Das 
8654c293eSBiju Das #include <linux/bitfield.h>
9654c293eSBiju Das #include <linux/clk.h>
10654c293eSBiju Das #include <linux/interrupt.h>
11654c293eSBiju Das #include <linux/irq.h>
12654c293eSBiju Das #include <linux/mfd/core.h>
13654c293eSBiju Das #include <linux/mfd/rz-mtu3.h>
14edae0946SBiju Das #include <linux/module.h>
15dc0c386eSRob Herring #include <linux/mod_devicetable.h>
16dc0c386eSRob Herring #include <linux/platform_device.h>
17654c293eSBiju Das #include <linux/reset.h>
18654c293eSBiju Das #include <linux/spinlock.h>
19654c293eSBiju Das 
20654c293eSBiju Das #include "rz-mtu3.h"
21654c293eSBiju Das 
22654c293eSBiju Das struct rz_mtu3_priv {
23654c293eSBiju Das 	void __iomem *mmio;
24654c293eSBiju Das 	struct reset_control *rstc;
25*d92df6fbSBiju Das 	spinlock_t lock;
26654c293eSBiju Das };
27654c293eSBiju Das 
28654c293eSBiju Das /******* MTU3 registers (original offset is +0x1200) *******/
29654c293eSBiju Das static const unsigned long rz_mtu3_8bit_ch_reg_offs[][13] = {
30654c293eSBiju Das 	[RZ_MTU3_CHAN_0] = MTU_8BIT_CH_0(0x104, 0x090, 0x100, 0x128, 0x101, 0x102, 0x103, 0x126),
31654c293eSBiju Das 	[RZ_MTU3_CHAN_1] = MTU_8BIT_CH_1_2(0x184, 0x091, 0x185, 0x180, 0x194, 0x181, 0x182),
32654c293eSBiju Das 	[RZ_MTU3_CHAN_2] = MTU_8BIT_CH_1_2(0x204, 0x092, 0x205, 0x200, 0x20c, 0x201, 0x202),
33654c293eSBiju Das 	[RZ_MTU3_CHAN_3] = MTU_8BIT_CH_3_4_6_7(0x008, 0x093, 0x02c, 0x000, 0x04c, 0x002, 0x004, 0x005, 0x038),
34654c293eSBiju Das 	[RZ_MTU3_CHAN_4] = MTU_8BIT_CH_3_4_6_7(0x009, 0x094, 0x02d, 0x001, 0x04d, 0x003, 0x006, 0x007, 0x039),
35654c293eSBiju Das 	[RZ_MTU3_CHAN_5] = MTU_8BIT_CH_5(0xab2, 0x1eb, 0xab4, 0xab6, 0xa84, 0xa85, 0xa86, 0xa94, 0xa95, 0xa96, 0xaa4, 0xaa5, 0xaa6),
36654c293eSBiju Das 	[RZ_MTU3_CHAN_6] = MTU_8BIT_CH_3_4_6_7(0x808, 0x893, 0x82c, 0x800, 0x84c, 0x802, 0x804, 0x805, 0x838),
37654c293eSBiju Das 	[RZ_MTU3_CHAN_7] = MTU_8BIT_CH_3_4_6_7(0x809, 0x894, 0x82d, 0x801, 0x84d, 0x803, 0x806, 0x807, 0x839),
38654c293eSBiju Das 	[RZ_MTU3_CHAN_8] = MTU_8BIT_CH_8(0x404, 0x098, 0x400, 0x406, 0x401, 0x402, 0x403)
39654c293eSBiju Das };
40654c293eSBiju Das 
41654c293eSBiju Das static const unsigned long rz_mtu3_16bit_ch_reg_offs[][12] = {
42654c293eSBiju Das 	[RZ_MTU3_CHAN_0] = MTU_16BIT_CH_0(0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x120, 0x122),
43654c293eSBiju Das 	[RZ_MTU3_CHAN_1] = MTU_16BIT_CH_1_2(0x186, 0x188, 0x18a),
44654c293eSBiju Das 	[RZ_MTU3_CHAN_2] = MTU_16BIT_CH_1_2(0x206, 0x208, 0x20a),
45654c293eSBiju Das 	[RZ_MTU3_CHAN_3] = MTU_16BIT_CH_3_6(0x010, 0x018, 0x01a, 0x024, 0x026, 0x072),
46654c293eSBiju Das 	[RZ_MTU3_CHAN_4] = MTU_16BIT_CH_4_7(0x012, 0x01c, 0x01e, 0x028, 0x2a, 0x074, 0x076, 0x040, 0x044, 0x046, 0x048, 0x04a),
47654c293eSBiju Das 	[RZ_MTU3_CHAN_5] = MTU_16BIT_CH_5(0xa80, 0xa82, 0xa90, 0xa92, 0xaa0, 0xaa2),
48654c293eSBiju Das 	[RZ_MTU3_CHAN_6] = MTU_16BIT_CH_3_6(0x810, 0x818, 0x81a, 0x824, 0x826, 0x872),
49654c293eSBiju Das 	[RZ_MTU3_CHAN_7] = MTU_16BIT_CH_4_7(0x812, 0x81c, 0x81e, 0x828, 0x82a, 0x874, 0x876, 0x840, 0x844, 0x846, 0x848, 0x84a)
50654c293eSBiju Das };
51654c293eSBiju Das 
52654c293eSBiju Das static const unsigned long rz_mtu3_32bit_ch_reg_offs[][5] = {
53654c293eSBiju Das 	[RZ_MTU3_CHAN_1] = MTU_32BIT_CH_1(0x1a0, 0x1a4, 0x1a8),
54654c293eSBiju Das 	[RZ_MTU3_CHAN_8] = MTU_32BIT_CH_8(0x408, 0x40c, 0x410, 0x414, 0x418)
55654c293eSBiju Das };
56654c293eSBiju Das 
rz_mtu3_is_16bit_shared_reg(u16 offset)57654c293eSBiju Das static bool rz_mtu3_is_16bit_shared_reg(u16 offset)
58654c293eSBiju Das {
59654c293eSBiju Das 	return (offset == RZ_MTU3_TDDRA || offset == RZ_MTU3_TDDRB ||
60654c293eSBiju Das 		offset == RZ_MTU3_TCDRA || offset == RZ_MTU3_TCDRB ||
61654c293eSBiju Das 		offset == RZ_MTU3_TCBRA || offset == RZ_MTU3_TCBRB ||
62654c293eSBiju Das 		offset == RZ_MTU3_TCNTSA || offset == RZ_MTU3_TCNTSB);
63654c293eSBiju Das }
64654c293eSBiju Das 
rz_mtu3_shared_reg_read(struct rz_mtu3_channel * ch,u16 offset)65654c293eSBiju Das u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 offset)
66654c293eSBiju Das {
67654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
68654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
69654c293eSBiju Das 
70654c293eSBiju Das 	if (rz_mtu3_is_16bit_shared_reg(offset))
71654c293eSBiju Das 		return readw(priv->mmio + offset);
72654c293eSBiju Das 	else
73654c293eSBiju Das 		return readb(priv->mmio + offset);
74654c293eSBiju Das }
75654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_read);
76654c293eSBiju Das 
rz_mtu3_8bit_ch_read(struct rz_mtu3_channel * ch,u16 offset)77654c293eSBiju Das u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
78654c293eSBiju Das {
79654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
80654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
81654c293eSBiju Das 	u16 ch_offs;
82654c293eSBiju Das 
83654c293eSBiju Das 	ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset];
84654c293eSBiju Das 
85654c293eSBiju Das 	return readb(priv->mmio + ch_offs);
86654c293eSBiju Das }
87654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_read);
88654c293eSBiju Das 
rz_mtu3_16bit_ch_read(struct rz_mtu3_channel * ch,u16 offset)89654c293eSBiju Das u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
90654c293eSBiju Das {
91654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
92654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
93654c293eSBiju Das 	u16 ch_offs;
94654c293eSBiju Das 
95654c293eSBiju Das 	/* MTU8 doesn't have 16-bit registers */
96654c293eSBiju Das 	if (ch->channel_number == RZ_MTU3_CHAN_8)
97654c293eSBiju Das 		return 0;
98654c293eSBiju Das 
99654c293eSBiju Das 	ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset];
100654c293eSBiju Das 
101654c293eSBiju Das 	return readw(priv->mmio + ch_offs);
102654c293eSBiju Das }
103654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_read);
104654c293eSBiju Das 
rz_mtu3_32bit_ch_read(struct rz_mtu3_channel * ch,u16 offset)105654c293eSBiju Das u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
106654c293eSBiju Das {
107654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
108654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
109654c293eSBiju Das 	u16 ch_offs;
110654c293eSBiju Das 
111654c293eSBiju Das 	if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8)
112654c293eSBiju Das 		return 0;
113654c293eSBiju Das 
114654c293eSBiju Das 	ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset];
115654c293eSBiju Das 
116654c293eSBiju Das 	return readl(priv->mmio + ch_offs);
117654c293eSBiju Das }
118654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_read);
119654c293eSBiju Das 
rz_mtu3_8bit_ch_write(struct rz_mtu3_channel * ch,u16 offset,u8 val)120654c293eSBiju Das void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u8 val)
121654c293eSBiju Das {
122654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
123654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
124654c293eSBiju Das 	u16 ch_offs;
125654c293eSBiju Das 
126654c293eSBiju Das 	ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset];
127654c293eSBiju Das 	writeb(val, priv->mmio + ch_offs);
128654c293eSBiju Das }
129654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_write);
130654c293eSBiju Das 
rz_mtu3_16bit_ch_write(struct rz_mtu3_channel * ch,u16 offset,u16 val)131654c293eSBiju Das void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u16 val)
132654c293eSBiju Das {
133654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
134654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
135654c293eSBiju Das 	u16 ch_offs;
136654c293eSBiju Das 
137654c293eSBiju Das 	/* MTU8 doesn't have 16-bit registers */
138654c293eSBiju Das 	if (ch->channel_number == RZ_MTU3_CHAN_8)
139654c293eSBiju Das 		return;
140654c293eSBiju Das 
141654c293eSBiju Das 	ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset];
142654c293eSBiju Das 	writew(val, priv->mmio + ch_offs);
143654c293eSBiju Das }
144654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_write);
145654c293eSBiju Das 
rz_mtu3_32bit_ch_write(struct rz_mtu3_channel * ch,u16 offset,u32 val)146654c293eSBiju Das void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u32 val)
147654c293eSBiju Das {
148654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
149654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
150654c293eSBiju Das 	u16 ch_offs;
151654c293eSBiju Das 
152654c293eSBiju Das 	if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8)
153654c293eSBiju Das 		return;
154654c293eSBiju Das 
155654c293eSBiju Das 	ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset];
156654c293eSBiju Das 	writel(val, priv->mmio + ch_offs);
157654c293eSBiju Das }
158654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_write);
159654c293eSBiju Das 
rz_mtu3_shared_reg_write(struct rz_mtu3_channel * ch,u16 offset,u16 value)160654c293eSBiju Das void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 offset, u16 value)
161654c293eSBiju Das {
162654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
163654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
164654c293eSBiju Das 
165654c293eSBiju Das 	if (rz_mtu3_is_16bit_shared_reg(offset))
166654c293eSBiju Das 		writew(value, priv->mmio + offset);
167654c293eSBiju Das 	else
168654c293eSBiju Das 		writeb((u8)value, priv->mmio + offset);
169654c293eSBiju Das }
170654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_write);
171654c293eSBiju Das 
rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel * ch,u16 offset,u16 pos,u8 val)172654c293eSBiju Das void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 offset,
173654c293eSBiju Das 				   u16 pos, u8 val)
174654c293eSBiju Das {
175654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
176654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
177654c293eSBiju Das 	unsigned long tmdr, flags;
178654c293eSBiju Das 
179*d92df6fbSBiju Das 	spin_lock_irqsave(&priv->lock, flags);
180654c293eSBiju Das 	tmdr = rz_mtu3_shared_reg_read(ch, offset);
181654c293eSBiju Das 	__assign_bit(pos, &tmdr, !!val);
182654c293eSBiju Das 	rz_mtu3_shared_reg_write(ch, offset, tmdr);
183*d92df6fbSBiju Das 	spin_unlock_irqrestore(&priv->lock, flags);
184654c293eSBiju Das }
185654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_update_bit);
186654c293eSBiju Das 
rz_mtu3_get_tstr_offset(struct rz_mtu3_channel * ch)187654c293eSBiju Das static u16 rz_mtu3_get_tstr_offset(struct rz_mtu3_channel *ch)
188654c293eSBiju Das {
189654c293eSBiju Das 	u16 offset;
190654c293eSBiju Das 
191654c293eSBiju Das 	switch (ch->channel_number) {
192654c293eSBiju Das 	case RZ_MTU3_CHAN_0:
193654c293eSBiju Das 	case RZ_MTU3_CHAN_1:
194654c293eSBiju Das 	case RZ_MTU3_CHAN_2:
195654c293eSBiju Das 	case RZ_MTU3_CHAN_3:
196654c293eSBiju Das 	case RZ_MTU3_CHAN_4:
197654c293eSBiju Das 	case RZ_MTU3_CHAN_8:
198654c293eSBiju Das 		offset = RZ_MTU3_TSTRA;
199654c293eSBiju Das 		break;
200654c293eSBiju Das 	case RZ_MTU3_CHAN_5:
201654c293eSBiju Das 		offset = RZ_MTU3_TSTR;
202654c293eSBiju Das 		break;
203654c293eSBiju Das 	case RZ_MTU3_CHAN_6:
204654c293eSBiju Das 	case RZ_MTU3_CHAN_7:
205654c293eSBiju Das 		offset = RZ_MTU3_TSTRB;
206654c293eSBiju Das 		break;
207654c293eSBiju Das 	default:
208654c293eSBiju Das 		offset = 0;
209654c293eSBiju Das 		break;
210654c293eSBiju Das 	}
211654c293eSBiju Das 
212654c293eSBiju Das 	return offset;
213654c293eSBiju Das }
214654c293eSBiju Das 
rz_mtu3_get_tstr_bit_pos(struct rz_mtu3_channel * ch)215654c293eSBiju Das static u8 rz_mtu3_get_tstr_bit_pos(struct rz_mtu3_channel *ch)
216654c293eSBiju Das {
217654c293eSBiju Das 	u8 bitpos;
218654c293eSBiju Das 
219654c293eSBiju Das 	switch (ch->channel_number) {
220654c293eSBiju Das 	case RZ_MTU3_CHAN_0:
221654c293eSBiju Das 	case RZ_MTU3_CHAN_1:
222654c293eSBiju Das 	case RZ_MTU3_CHAN_2:
223654c293eSBiju Das 	case RZ_MTU3_CHAN_6:
224654c293eSBiju Das 	case RZ_MTU3_CHAN_7:
225654c293eSBiju Das 		bitpos = ch->channel_number;
226654c293eSBiju Das 		break;
227654c293eSBiju Das 	case RZ_MTU3_CHAN_3:
228654c293eSBiju Das 		bitpos = 6;
229654c293eSBiju Das 		break;
230654c293eSBiju Das 	case RZ_MTU3_CHAN_4:
231654c293eSBiju Das 		bitpos = 7;
232654c293eSBiju Das 		break;
233654c293eSBiju Das 	case RZ_MTU3_CHAN_5:
234654c293eSBiju Das 		bitpos = 2;
235654c293eSBiju Das 		break;
236654c293eSBiju Das 	case RZ_MTU3_CHAN_8:
237654c293eSBiju Das 		bitpos = 3;
238654c293eSBiju Das 		break;
239654c293eSBiju Das 	default:
240654c293eSBiju Das 		bitpos = 0;
241654c293eSBiju Das 		break;
242654c293eSBiju Das 	}
243654c293eSBiju Das 
244654c293eSBiju Das 	return bitpos;
245654c293eSBiju Das }
246654c293eSBiju Das 
rz_mtu3_start_stop_ch(struct rz_mtu3_channel * ch,bool start)247654c293eSBiju Das static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start)
248654c293eSBiju Das {
249654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
250654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
251654c293eSBiju Das 	unsigned long flags, tstr;
252654c293eSBiju Das 	u16 offset;
253654c293eSBiju Das 	u8 bitpos;
254654c293eSBiju Das 
255a160d128SBiju Das 	offset = rz_mtu3_get_tstr_offset(ch);
256a160d128SBiju Das 	bitpos = rz_mtu3_get_tstr_bit_pos(ch);
257a160d128SBiju Das 
258654c293eSBiju Das 	/* start stop register shared by multiple timer channels */
259*d92df6fbSBiju Das 	spin_lock_irqsave(&priv->lock, flags);
260654c293eSBiju Das 
261654c293eSBiju Das 	tstr = rz_mtu3_shared_reg_read(ch, offset);
262654c293eSBiju Das 	__assign_bit(bitpos, &tstr, start);
263654c293eSBiju Das 	rz_mtu3_shared_reg_write(ch, offset, tstr);
264654c293eSBiju Das 
265*d92df6fbSBiju Das 	spin_unlock_irqrestore(&priv->lock, flags);
266654c293eSBiju Das }
267654c293eSBiju Das 
rz_mtu3_is_enabled(struct rz_mtu3_channel * ch)268654c293eSBiju Das bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch)
269654c293eSBiju Das {
270654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
271654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
272654c293eSBiju Das 	unsigned long flags, tstr;
273654c293eSBiju Das 	u16 offset;
274654c293eSBiju Das 	u8 bitpos;
275654c293eSBiju Das 
276654c293eSBiju Das 	offset = rz_mtu3_get_tstr_offset(ch);
277654c293eSBiju Das 	bitpos = rz_mtu3_get_tstr_bit_pos(ch);
278654c293eSBiju Das 
279a160d128SBiju Das 	/* start stop register shared by multiple timer channels */
280*d92df6fbSBiju Das 	spin_lock_irqsave(&priv->lock, flags);
281a160d128SBiju Das 	tstr = rz_mtu3_shared_reg_read(ch, offset);
282*d92df6fbSBiju Das 	spin_unlock_irqrestore(&priv->lock, flags);
283654c293eSBiju Das 
284a160d128SBiju Das 	return tstr & BIT(bitpos);
285654c293eSBiju Das }
286654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_is_enabled);
287654c293eSBiju Das 
rz_mtu3_enable(struct rz_mtu3_channel * ch)288654c293eSBiju Das int rz_mtu3_enable(struct rz_mtu3_channel *ch)
289654c293eSBiju Das {
290654c293eSBiju Das 	/* enable channel */
291654c293eSBiju Das 	rz_mtu3_start_stop_ch(ch, true);
292654c293eSBiju Das 
293654c293eSBiju Das 	return 0;
294654c293eSBiju Das }
295654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_enable);
296654c293eSBiju Das 
rz_mtu3_disable(struct rz_mtu3_channel * ch)297654c293eSBiju Das void rz_mtu3_disable(struct rz_mtu3_channel *ch)
298654c293eSBiju Das {
299654c293eSBiju Das 	/* disable channel */
300654c293eSBiju Das 	rz_mtu3_start_stop_ch(ch, false);
301654c293eSBiju Das }
302654c293eSBiju Das EXPORT_SYMBOL_GPL(rz_mtu3_disable);
303654c293eSBiju Das 
rz_mtu3_reset_assert(void * data)304654c293eSBiju Das static void rz_mtu3_reset_assert(void *data)
305654c293eSBiju Das {
306654c293eSBiju Das 	struct rz_mtu3 *mtu = dev_get_drvdata(data);
307654c293eSBiju Das 	struct rz_mtu3_priv *priv = mtu->priv_data;
308654c293eSBiju Das 
309654c293eSBiju Das 	mfd_remove_devices(data);
310654c293eSBiju Das 	reset_control_assert(priv->rstc);
311654c293eSBiju Das }
312654c293eSBiju Das 
313654c293eSBiju Das static const struct mfd_cell rz_mtu3_devs[] = {
314654c293eSBiju Das 	{
315654c293eSBiju Das 		.name = "rz-mtu3-counter",
316654c293eSBiju Das 	},
317654c293eSBiju Das 	{
318654c293eSBiju Das 		.name = "pwm-rz-mtu3",
319654c293eSBiju Das 	},
320654c293eSBiju Das };
321654c293eSBiju Das 
rz_mtu3_probe(struct platform_device * pdev)322654c293eSBiju Das static int rz_mtu3_probe(struct platform_device *pdev)
323654c293eSBiju Das {
324654c293eSBiju Das 	struct rz_mtu3_priv *priv;
325654c293eSBiju Das 	struct rz_mtu3 *ddata;
326654c293eSBiju Das 	unsigned int i;
327654c293eSBiju Das 	int ret;
328654c293eSBiju Das 
329654c293eSBiju Das 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
330654c293eSBiju Das 	if (!ddata)
331654c293eSBiju Das 		return -ENOMEM;
332654c293eSBiju Das 
333654c293eSBiju Das 	ddata->priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
334654c293eSBiju Das 	if (!ddata->priv_data)
335654c293eSBiju Das 		return -ENOMEM;
336654c293eSBiju Das 
337654c293eSBiju Das 	priv = ddata->priv_data;
338654c293eSBiju Das 
339654c293eSBiju Das 	priv->mmio = devm_platform_ioremap_resource(pdev, 0);
340654c293eSBiju Das 	if (IS_ERR(priv->mmio))
341654c293eSBiju Das 		return PTR_ERR(priv->mmio);
342654c293eSBiju Das 
343654c293eSBiju Das 	priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
344654c293eSBiju Das 	if (IS_ERR(priv->rstc))
345654c293eSBiju Das 		return PTR_ERR(priv->rstc);
346654c293eSBiju Das 
347654c293eSBiju Das 	ddata->clk = devm_clk_get(&pdev->dev, NULL);
348654c293eSBiju Das 	if (IS_ERR(ddata->clk))
349654c293eSBiju Das 		return PTR_ERR(ddata->clk);
350654c293eSBiju Das 
351654c293eSBiju Das 	reset_control_deassert(priv->rstc);
352*d92df6fbSBiju Das 	spin_lock_init(&priv->lock);
353654c293eSBiju Das 	platform_set_drvdata(pdev, ddata);
354654c293eSBiju Das 
355654c293eSBiju Das 	for (i = 0; i < RZ_MTU_NUM_CHANNELS; i++) {
356654c293eSBiju Das 		ddata->channels[i].channel_number = i;
357654c293eSBiju Das 		ddata->channels[i].is_busy = false;
358654c293eSBiju Das 		mutex_init(&ddata->channels[i].lock);
359654c293eSBiju Das 	}
360654c293eSBiju Das 
361654c293eSBiju Das 	ret = mfd_add_devices(&pdev->dev, 0, rz_mtu3_devs,
362654c293eSBiju Das 			      ARRAY_SIZE(rz_mtu3_devs), NULL, 0, NULL);
363654c293eSBiju Das 	if (ret < 0)
364654c293eSBiju Das 		goto err_assert;
365654c293eSBiju Das 
366654c293eSBiju Das 	return devm_add_action_or_reset(&pdev->dev, rz_mtu3_reset_assert,
367654c293eSBiju Das 					&pdev->dev);
368654c293eSBiju Das 
369654c293eSBiju Das err_assert:
370654c293eSBiju Das 	reset_control_assert(priv->rstc);
371654c293eSBiju Das 	return ret;
372654c293eSBiju Das }
373654c293eSBiju Das 
374654c293eSBiju Das static const struct of_device_id rz_mtu3_of_match[] = {
375654c293eSBiju Das 	{ .compatible = "renesas,rz-mtu3", },
376654c293eSBiju Das 	{ /* sentinel */ }
377654c293eSBiju Das };
378654c293eSBiju Das MODULE_DEVICE_TABLE(of, rz_mtu3_of_match);
379654c293eSBiju Das 
380654c293eSBiju Das static struct platform_driver rz_mtu3_driver = {
381654c293eSBiju Das 	.probe = rz_mtu3_probe,
382654c293eSBiju Das 	.driver	= {
383654c293eSBiju Das 		.name = "rz-mtu3",
384654c293eSBiju Das 		.of_match_table = rz_mtu3_of_match,
385654c293eSBiju Das 	},
386654c293eSBiju Das };
387654c293eSBiju Das module_platform_driver(rz_mtu3_driver);
388654c293eSBiju Das 
389654c293eSBiju Das MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
390654c293eSBiju Das MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a Core Driver");
391654c293eSBiju Das MODULE_LICENSE("GPL");
392