1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Renesas RZ/G2L Multi-Function Timer Pulse Unit 3(MTU3a) Core driver
4 *
5 * Copyright (C) 2023 Renesas Electronics Corporation
6 */
7
8#include <linux/bitfield.h>
9#include <linux/clk.h>
10#include <linux/interrupt.h>
11#include <linux/irq.h>
12#include <linux/mfd/core.h>
13#include <linux/mfd/rz-mtu3.h>
14#include <linux/module.h>
15#include <linux/mod_devicetable.h>
16#include <linux/platform_device.h>
17#include <linux/reset.h>
18#include <linux/spinlock.h>
19
20#include "rz-mtu3.h"
21
22struct rz_mtu3_priv {
23 void __iomem *mmio;
24 struct reset_control *rstc;
25 spinlock_t lock;
26};
27
28/******* MTU3 registers (original offset is +0x1200) *******/
29static const unsigned long rz_mtu3_8bit_ch_reg_offs[][13] = {
30 [RZ_MTU3_CHAN_0] = MTU_8BIT_CH_0(0x104, 0x090, 0x100, 0x128, 0x101, 0x102, 0x103, 0x126),
31 [RZ_MTU3_CHAN_1] = MTU_8BIT_CH_1_2(0x184, 0x091, 0x185, 0x180, 0x194, 0x181, 0x182),
32 [RZ_MTU3_CHAN_2] = MTU_8BIT_CH_1_2(0x204, 0x092, 0x205, 0x200, 0x20c, 0x201, 0x202),
33 [RZ_MTU3_CHAN_3] = MTU_8BIT_CH_3_4_6_7(0x008, 0x093, 0x02c, 0x000, 0x04c, 0x002, 0x004, 0x005, 0x038),
34 [RZ_MTU3_CHAN_4] = MTU_8BIT_CH_3_4_6_7(0x009, 0x094, 0x02d, 0x001, 0x04d, 0x003, 0x006, 0x007, 0x039),
35 [RZ_MTU3_CHAN_5] = MTU_8BIT_CH_5(0xab2, 0x1eb, 0xab4, 0xab6, 0xa84, 0xa85, 0xa86, 0xa94, 0xa95, 0xa96, 0xaa4, 0xaa5, 0xaa6),
36 [RZ_MTU3_CHAN_6] = MTU_8BIT_CH_3_4_6_7(0x808, 0x893, 0x82c, 0x800, 0x84c, 0x802, 0x804, 0x805, 0x838),
37 [RZ_MTU3_CHAN_7] = MTU_8BIT_CH_3_4_6_7(0x809, 0x894, 0x82d, 0x801, 0x84d, 0x803, 0x806, 0x807, 0x839),
38 [RZ_MTU3_CHAN_8] = MTU_8BIT_CH_8(0x404, 0x098, 0x400, 0x406, 0x401, 0x402, 0x403)
39};
40
41static const unsigned long rz_mtu3_16bit_ch_reg_offs[][12] = {
42 [RZ_MTU3_CHAN_0] = MTU_16BIT_CH_0(0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x120, 0x122),
43 [RZ_MTU3_CHAN_1] = MTU_16BIT_CH_1_2(0x186, 0x188, 0x18a),
44 [RZ_MTU3_CHAN_2] = MTU_16BIT_CH_1_2(0x206, 0x208, 0x20a),
45 [RZ_MTU3_CHAN_3] = MTU_16BIT_CH_3_6(0x010, 0x018, 0x01a, 0x024, 0x026, 0x072),
46 [RZ_MTU3_CHAN_4] = MTU_16BIT_CH_4_7(0x012, 0x01c, 0x01e, 0x028, 0x2a, 0x074, 0x076, 0x040, 0x044, 0x046, 0x048, 0x04a),
47 [RZ_MTU3_CHAN_5] = MTU_16BIT_CH_5(0xa80, 0xa82, 0xa90, 0xa92, 0xaa0, 0xaa2),
48 [RZ_MTU3_CHAN_6] = MTU_16BIT_CH_3_6(0x810, 0x818, 0x81a, 0x824, 0x826, 0x872),
49 [RZ_MTU3_CHAN_7] = MTU_16BIT_CH_4_7(0x812, 0x81c, 0x81e, 0x828, 0x82a, 0x874, 0x876, 0x840, 0x844, 0x846, 0x848, 0x84a)
50};
51
52static const unsigned long rz_mtu3_32bit_ch_reg_offs[][5] = {
53 [RZ_MTU3_CHAN_1] = MTU_32BIT_CH_1(0x1a0, 0x1a4, 0x1a8),
54 [RZ_MTU3_CHAN_8] = MTU_32BIT_CH_8(0x408, 0x40c, 0x410, 0x414, 0x418)
55};
56
57static bool rz_mtu3_is_16bit_shared_reg(u16 offset)
58{
59 return (offset == RZ_MTU3_TDDRA || offset == RZ_MTU3_TDDRB ||
60 offset == RZ_MTU3_TCDRA || offset == RZ_MTU3_TCDRB ||
61 offset == RZ_MTU3_TCBRA || offset == RZ_MTU3_TCBRB ||
62 offset == RZ_MTU3_TCNTSA || offset == RZ_MTU3_TCNTSB);
63}
64
65u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 offset)
66{
67 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
68 struct rz_mtu3_priv *priv = mtu->priv_data;
69
70 if (rz_mtu3_is_16bit_shared_reg(offset))
71 return readw(addr: priv->mmio + offset);
72 else
73 return readb(addr: priv->mmio + offset);
74}
75EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_read);
76
77u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
78{
79 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
80 struct rz_mtu3_priv *priv = mtu->priv_data;
81 u16 ch_offs;
82
83 ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset];
84
85 return readb(addr: priv->mmio + ch_offs);
86}
87EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_read);
88
89u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
90{
91 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
92 struct rz_mtu3_priv *priv = mtu->priv_data;
93 u16 ch_offs;
94
95 /* MTU8 doesn't have 16-bit registers */
96 if (ch->channel_number == RZ_MTU3_CHAN_8)
97 return 0;
98
99 ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset];
100
101 return readw(addr: priv->mmio + ch_offs);
102}
103EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_read);
104
105u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
106{
107 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
108 struct rz_mtu3_priv *priv = mtu->priv_data;
109 u16 ch_offs;
110
111 if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8)
112 return 0;
113
114 ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset];
115
116 return readl(addr: priv->mmio + ch_offs);
117}
118EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_read);
119
120void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u8 val)
121{
122 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
123 struct rz_mtu3_priv *priv = mtu->priv_data;
124 u16 ch_offs;
125
126 ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset];
127 writeb(val, addr: priv->mmio + ch_offs);
128}
129EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_write);
130
131void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u16 val)
132{
133 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
134 struct rz_mtu3_priv *priv = mtu->priv_data;
135 u16 ch_offs;
136
137 /* MTU8 doesn't have 16-bit registers */
138 if (ch->channel_number == RZ_MTU3_CHAN_8)
139 return;
140
141 ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset];
142 writew(val, addr: priv->mmio + ch_offs);
143}
144EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_write);
145
146void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u32 val)
147{
148 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
149 struct rz_mtu3_priv *priv = mtu->priv_data;
150 u16 ch_offs;
151
152 if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8)
153 return;
154
155 ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset];
156 writel(val, addr: priv->mmio + ch_offs);
157}
158EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_write);
159
160void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 offset, u16 value)
161{
162 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
163 struct rz_mtu3_priv *priv = mtu->priv_data;
164
165 if (rz_mtu3_is_16bit_shared_reg(offset))
166 writew(val: value, addr: priv->mmio + offset);
167 else
168 writeb(val: (u8)value, addr: priv->mmio + offset);
169}
170EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_write);
171
172void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 offset,
173 u16 pos, u8 val)
174{
175 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
176 struct rz_mtu3_priv *priv = mtu->priv_data;
177 unsigned long tmdr, flags;
178
179 spin_lock_irqsave(&priv->lock, flags);
180 tmdr = rz_mtu3_shared_reg_read(ch, offset);
181 __assign_bit(nr: pos, addr: &tmdr, value: !!val);
182 rz_mtu3_shared_reg_write(ch, offset, tmdr);
183 spin_unlock_irqrestore(lock: &priv->lock, flags);
184}
185EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_update_bit);
186
187static u16 rz_mtu3_get_tstr_offset(struct rz_mtu3_channel *ch)
188{
189 u16 offset;
190
191 switch (ch->channel_number) {
192 case RZ_MTU3_CHAN_0:
193 case RZ_MTU3_CHAN_1:
194 case RZ_MTU3_CHAN_2:
195 case RZ_MTU3_CHAN_3:
196 case RZ_MTU3_CHAN_4:
197 case RZ_MTU3_CHAN_8:
198 offset = RZ_MTU3_TSTRA;
199 break;
200 case RZ_MTU3_CHAN_5:
201 offset = RZ_MTU3_TSTR;
202 break;
203 case RZ_MTU3_CHAN_6:
204 case RZ_MTU3_CHAN_7:
205 offset = RZ_MTU3_TSTRB;
206 break;
207 default:
208 offset = 0;
209 break;
210 }
211
212 return offset;
213}
214
215static u8 rz_mtu3_get_tstr_bit_pos(struct rz_mtu3_channel *ch)
216{
217 u8 bitpos;
218
219 switch (ch->channel_number) {
220 case RZ_MTU3_CHAN_0:
221 case RZ_MTU3_CHAN_1:
222 case RZ_MTU3_CHAN_2:
223 case RZ_MTU3_CHAN_6:
224 case RZ_MTU3_CHAN_7:
225 bitpos = ch->channel_number;
226 break;
227 case RZ_MTU3_CHAN_3:
228 bitpos = 6;
229 break;
230 case RZ_MTU3_CHAN_4:
231 bitpos = 7;
232 break;
233 case RZ_MTU3_CHAN_5:
234 bitpos = 2;
235 break;
236 case RZ_MTU3_CHAN_8:
237 bitpos = 3;
238 break;
239 default:
240 bitpos = 0;
241 break;
242 }
243
244 return bitpos;
245}
246
247static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start)
248{
249 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
250 struct rz_mtu3_priv *priv = mtu->priv_data;
251 unsigned long flags, tstr;
252 u16 offset;
253 u8 bitpos;
254
255 offset = rz_mtu3_get_tstr_offset(ch);
256 bitpos = rz_mtu3_get_tstr_bit_pos(ch);
257
258 /* start stop register shared by multiple timer channels */
259 spin_lock_irqsave(&priv->lock, flags);
260
261 tstr = rz_mtu3_shared_reg_read(ch, offset);
262 __assign_bit(nr: bitpos, addr: &tstr, value: start);
263 rz_mtu3_shared_reg_write(ch, offset, tstr);
264
265 spin_unlock_irqrestore(lock: &priv->lock, flags);
266}
267
268bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch)
269{
270 struct rz_mtu3 *mtu = dev_get_drvdata(dev: ch->dev->parent);
271 struct rz_mtu3_priv *priv = mtu->priv_data;
272 unsigned long flags, tstr;
273 u16 offset;
274 u8 bitpos;
275
276 offset = rz_mtu3_get_tstr_offset(ch);
277 bitpos = rz_mtu3_get_tstr_bit_pos(ch);
278
279 /* start stop register shared by multiple timer channels */
280 spin_lock_irqsave(&priv->lock, flags);
281 tstr = rz_mtu3_shared_reg_read(ch, offset);
282 spin_unlock_irqrestore(lock: &priv->lock, flags);
283
284 return tstr & BIT(bitpos);
285}
286EXPORT_SYMBOL_GPL(rz_mtu3_is_enabled);
287
288int rz_mtu3_enable(struct rz_mtu3_channel *ch)
289{
290 /* enable channel */
291 rz_mtu3_start_stop_ch(ch, start: true);
292
293 return 0;
294}
295EXPORT_SYMBOL_GPL(rz_mtu3_enable);
296
297void rz_mtu3_disable(struct rz_mtu3_channel *ch)
298{
299 /* disable channel */
300 rz_mtu3_start_stop_ch(ch, start: false);
301}
302EXPORT_SYMBOL_GPL(rz_mtu3_disable);
303
304static void rz_mtu3_reset_assert(void *data)
305{
306 struct rz_mtu3 *mtu = dev_get_drvdata(dev: data);
307 struct rz_mtu3_priv *priv = mtu->priv_data;
308
309 mfd_remove_devices(parent: data);
310 reset_control_assert(rstc: priv->rstc);
311}
312
313static const struct mfd_cell rz_mtu3_devs[] = {
314 {
315 .name = "rz-mtu3-counter",
316 },
317 {
318 .name = "pwm-rz-mtu3",
319 },
320};
321
322static int rz_mtu3_probe(struct platform_device *pdev)
323{
324 struct rz_mtu3_priv *priv;
325 struct rz_mtu3 *ddata;
326 unsigned int i;
327 int ret;
328
329 ddata = devm_kzalloc(dev: &pdev->dev, size: sizeof(*ddata), GFP_KERNEL);
330 if (!ddata)
331 return -ENOMEM;
332
333 ddata->priv_data = devm_kzalloc(dev: &pdev->dev, size: sizeof(*priv), GFP_KERNEL);
334 if (!ddata->priv_data)
335 return -ENOMEM;
336
337 priv = ddata->priv_data;
338
339 priv->mmio = devm_platform_ioremap_resource(pdev, index: 0);
340 if (IS_ERR(ptr: priv->mmio))
341 return PTR_ERR(ptr: priv->mmio);
342
343 priv->rstc = devm_reset_control_get_exclusive(dev: &pdev->dev, NULL);
344 if (IS_ERR(ptr: priv->rstc))
345 return PTR_ERR(ptr: priv->rstc);
346
347 ddata->clk = devm_clk_get(dev: &pdev->dev, NULL);
348 if (IS_ERR(ptr: ddata->clk))
349 return PTR_ERR(ptr: ddata->clk);
350
351 reset_control_deassert(rstc: priv->rstc);
352 spin_lock_init(&priv->lock);
353 platform_set_drvdata(pdev, data: ddata);
354
355 for (i = 0; i < RZ_MTU_NUM_CHANNELS; i++) {
356 ddata->channels[i].channel_number = i;
357 ddata->channels[i].is_busy = false;
358 mutex_init(&ddata->channels[i].lock);
359 }
360
361 ret = mfd_add_devices(parent: &pdev->dev, id: 0, cells: rz_mtu3_devs,
362 ARRAY_SIZE(rz_mtu3_devs), NULL, irq_base: 0, NULL);
363 if (ret < 0)
364 goto err_assert;
365
366 return devm_add_action_or_reset(&pdev->dev, rz_mtu3_reset_assert,
367 &pdev->dev);
368
369err_assert:
370 reset_control_assert(rstc: priv->rstc);
371 return ret;
372}
373
374static const struct of_device_id rz_mtu3_of_match[] = {
375 { .compatible = "renesas,rz-mtu3", },
376 { /* sentinel */ }
377};
378MODULE_DEVICE_TABLE(of, rz_mtu3_of_match);
379
380static struct platform_driver rz_mtu3_driver = {
381 .probe = rz_mtu3_probe,
382 .driver = {
383 .name = "rz-mtu3",
384 .of_match_table = rz_mtu3_of_match,
385 },
386};
387module_platform_driver(rz_mtu3_driver);
388
389MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
390MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a Core Driver");
391MODULE_LICENSE("GPL");
392

source code of linux/drivers/mfd/rz-mtu3.c