mfd: Add Renesas RZ/G2L MTU3a core driver
The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in the Renesas RZ/G2L family SoCs. It consists of eight 16-bit timer channels and one 32-bit timer channel. It supports the following functions - Counter - Timer - PWM The 8/16/32 bit registers are mixed in each channel. Add MTU3a core driver for RZ/G2L SoC. The core driver shares the clk and channel register access for the other child devices like Counter, PWM and Clock event. Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com> Signed-off-by: Lee Jones <lee@kernel.org> Link: https://lore.kernel.org/r/20230330111632.169434-3-biju.das.jz@bp.renesas.com
This commit is contained in:
parent
0a9d6b5429
commit
654c293e16
|
@ -1315,6 +1315,16 @@ config MFD_SC27XX_PMIC
|
|||
This driver provides common support for accessing the SC27xx PMICs,
|
||||
and it also adds the irq_chip parts for handling the PMIC chip events.
|
||||
|
||||
config RZ_MTU3
|
||||
bool "Renesas RZ/G2L MTU3a core driver"
|
||||
depends on (ARCH_RZG2L && OF) || COMPILE_TEST
|
||||
help
|
||||
Select this option to enable Renesas RZ/G2L MTU3a core driver for
|
||||
the Multi-Function Timer Pulse Unit 3 (MTU3a) hardware available
|
||||
on SoCs from Renesas. The core driver shares the clk and channel
|
||||
register access for the other child devices like Counter, PWM,
|
||||
Clock Source, and Clock event.
|
||||
|
||||
config ABX500_CORE
|
||||
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
|
||||
depends on ARCH_U8500 || COMPILE_TEST
|
||||
|
|
|
@ -174,6 +174,7 @@ pcf50633-objs := pcf50633-core.o pcf50633-irq.o
|
|||
obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
|
||||
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
|
||||
obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
|
||||
obj-$(CONFIG_RZ_MTU3) += rz-mtu3.o
|
||||
obj-$(CONFIG_ABX500_CORE) += abx500-core.o
|
||||
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
|
||||
# ab8500-core need to come after db8500-prcmu (which provides the channel)
|
||||
|
|
|
@ -0,0 +1,391 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Renesas RZ/G2L Multi-Function Timer Pulse Unit 3(MTU3a) Core driver
|
||||
*
|
||||
* Copyright (C) 2023 Renesas Electronics Corporation
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rz-mtu3.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "rz-mtu3.h"
|
||||
|
||||
struct rz_mtu3_priv {
|
||||
void __iomem *mmio;
|
||||
struct reset_control *rstc;
|
||||
raw_spinlock_t lock;
|
||||
};
|
||||
|
||||
/******* MTU3 registers (original offset is +0x1200) *******/
|
||||
static const unsigned long rz_mtu3_8bit_ch_reg_offs[][13] = {
|
||||
[RZ_MTU3_CHAN_0] = MTU_8BIT_CH_0(0x104, 0x090, 0x100, 0x128, 0x101, 0x102, 0x103, 0x126),
|
||||
[RZ_MTU3_CHAN_1] = MTU_8BIT_CH_1_2(0x184, 0x091, 0x185, 0x180, 0x194, 0x181, 0x182),
|
||||
[RZ_MTU3_CHAN_2] = MTU_8BIT_CH_1_2(0x204, 0x092, 0x205, 0x200, 0x20c, 0x201, 0x202),
|
||||
[RZ_MTU3_CHAN_3] = MTU_8BIT_CH_3_4_6_7(0x008, 0x093, 0x02c, 0x000, 0x04c, 0x002, 0x004, 0x005, 0x038),
|
||||
[RZ_MTU3_CHAN_4] = MTU_8BIT_CH_3_4_6_7(0x009, 0x094, 0x02d, 0x001, 0x04d, 0x003, 0x006, 0x007, 0x039),
|
||||
[RZ_MTU3_CHAN_5] = MTU_8BIT_CH_5(0xab2, 0x1eb, 0xab4, 0xab6, 0xa84, 0xa85, 0xa86, 0xa94, 0xa95, 0xa96, 0xaa4, 0xaa5, 0xaa6),
|
||||
[RZ_MTU3_CHAN_6] = MTU_8BIT_CH_3_4_6_7(0x808, 0x893, 0x82c, 0x800, 0x84c, 0x802, 0x804, 0x805, 0x838),
|
||||
[RZ_MTU3_CHAN_7] = MTU_8BIT_CH_3_4_6_7(0x809, 0x894, 0x82d, 0x801, 0x84d, 0x803, 0x806, 0x807, 0x839),
|
||||
[RZ_MTU3_CHAN_8] = MTU_8BIT_CH_8(0x404, 0x098, 0x400, 0x406, 0x401, 0x402, 0x403)
|
||||
};
|
||||
|
||||
static const unsigned long rz_mtu3_16bit_ch_reg_offs[][12] = {
|
||||
[RZ_MTU3_CHAN_0] = MTU_16BIT_CH_0(0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x120, 0x122),
|
||||
[RZ_MTU3_CHAN_1] = MTU_16BIT_CH_1_2(0x186, 0x188, 0x18a),
|
||||
[RZ_MTU3_CHAN_2] = MTU_16BIT_CH_1_2(0x206, 0x208, 0x20a),
|
||||
[RZ_MTU3_CHAN_3] = MTU_16BIT_CH_3_6(0x010, 0x018, 0x01a, 0x024, 0x026, 0x072),
|
||||
[RZ_MTU3_CHAN_4] = MTU_16BIT_CH_4_7(0x012, 0x01c, 0x01e, 0x028, 0x2a, 0x074, 0x076, 0x040, 0x044, 0x046, 0x048, 0x04a),
|
||||
[RZ_MTU3_CHAN_5] = MTU_16BIT_CH_5(0xa80, 0xa82, 0xa90, 0xa92, 0xaa0, 0xaa2),
|
||||
[RZ_MTU3_CHAN_6] = MTU_16BIT_CH_3_6(0x810, 0x818, 0x81a, 0x824, 0x826, 0x872),
|
||||
[RZ_MTU3_CHAN_7] = MTU_16BIT_CH_4_7(0x812, 0x81c, 0x81e, 0x828, 0x82a, 0x874, 0x876, 0x840, 0x844, 0x846, 0x848, 0x84a)
|
||||
};
|
||||
|
||||
static const unsigned long rz_mtu3_32bit_ch_reg_offs[][5] = {
|
||||
[RZ_MTU3_CHAN_1] = MTU_32BIT_CH_1(0x1a0, 0x1a4, 0x1a8),
|
||||
[RZ_MTU3_CHAN_8] = MTU_32BIT_CH_8(0x408, 0x40c, 0x410, 0x414, 0x418)
|
||||
};
|
||||
|
||||
static bool rz_mtu3_is_16bit_shared_reg(u16 offset)
|
||||
{
|
||||
return (offset == RZ_MTU3_TDDRA || offset == RZ_MTU3_TDDRB ||
|
||||
offset == RZ_MTU3_TCDRA || offset == RZ_MTU3_TCDRB ||
|
||||
offset == RZ_MTU3_TCBRA || offset == RZ_MTU3_TCBRB ||
|
||||
offset == RZ_MTU3_TCNTSA || offset == RZ_MTU3_TCNTSB);
|
||||
}
|
||||
|
||||
u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 offset)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
|
||||
if (rz_mtu3_is_16bit_shared_reg(offset))
|
||||
return readw(priv->mmio + offset);
|
||||
else
|
||||
return readb(priv->mmio + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_read);
|
||||
|
||||
u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
u16 ch_offs;
|
||||
|
||||
ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset];
|
||||
|
||||
return readb(priv->mmio + ch_offs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_read);
|
||||
|
||||
u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
u16 ch_offs;
|
||||
|
||||
/* MTU8 doesn't have 16-bit registers */
|
||||
if (ch->channel_number == RZ_MTU3_CHAN_8)
|
||||
return 0;
|
||||
|
||||
ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset];
|
||||
|
||||
return readw(priv->mmio + ch_offs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_read);
|
||||
|
||||
u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 offset)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
u16 ch_offs;
|
||||
|
||||
if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8)
|
||||
return 0;
|
||||
|
||||
ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset];
|
||||
|
||||
return readl(priv->mmio + ch_offs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_read);
|
||||
|
||||
void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u8 val)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
u16 ch_offs;
|
||||
|
||||
ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset];
|
||||
writeb(val, priv->mmio + ch_offs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_write);
|
||||
|
||||
void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u16 val)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
u16 ch_offs;
|
||||
|
||||
/* MTU8 doesn't have 16-bit registers */
|
||||
if (ch->channel_number == RZ_MTU3_CHAN_8)
|
||||
return;
|
||||
|
||||
ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset];
|
||||
writew(val, priv->mmio + ch_offs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_write);
|
||||
|
||||
void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u32 val)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
u16 ch_offs;
|
||||
|
||||
if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8)
|
||||
return;
|
||||
|
||||
ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset];
|
||||
writel(val, priv->mmio + ch_offs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_write);
|
||||
|
||||
void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 offset, u16 value)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
|
||||
if (rz_mtu3_is_16bit_shared_reg(offset))
|
||||
writew(value, priv->mmio + offset);
|
||||
else
|
||||
writeb((u8)value, priv->mmio + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_write);
|
||||
|
||||
void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 offset,
|
||||
u16 pos, u8 val)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
unsigned long tmdr, flags;
|
||||
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
tmdr = rz_mtu3_shared_reg_read(ch, offset);
|
||||
__assign_bit(pos, &tmdr, !!val);
|
||||
rz_mtu3_shared_reg_write(ch, offset, tmdr);
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_update_bit);
|
||||
|
||||
static u16 rz_mtu3_get_tstr_offset(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
u16 offset;
|
||||
|
||||
switch (ch->channel_number) {
|
||||
case RZ_MTU3_CHAN_0:
|
||||
case RZ_MTU3_CHAN_1:
|
||||
case RZ_MTU3_CHAN_2:
|
||||
case RZ_MTU3_CHAN_3:
|
||||
case RZ_MTU3_CHAN_4:
|
||||
case RZ_MTU3_CHAN_8:
|
||||
offset = RZ_MTU3_TSTRA;
|
||||
break;
|
||||
case RZ_MTU3_CHAN_5:
|
||||
offset = RZ_MTU3_TSTR;
|
||||
break;
|
||||
case RZ_MTU3_CHAN_6:
|
||||
case RZ_MTU3_CHAN_7:
|
||||
offset = RZ_MTU3_TSTRB;
|
||||
break;
|
||||
default:
|
||||
offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static u8 rz_mtu3_get_tstr_bit_pos(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
u8 bitpos;
|
||||
|
||||
switch (ch->channel_number) {
|
||||
case RZ_MTU3_CHAN_0:
|
||||
case RZ_MTU3_CHAN_1:
|
||||
case RZ_MTU3_CHAN_2:
|
||||
case RZ_MTU3_CHAN_6:
|
||||
case RZ_MTU3_CHAN_7:
|
||||
bitpos = ch->channel_number;
|
||||
break;
|
||||
case RZ_MTU3_CHAN_3:
|
||||
bitpos = 6;
|
||||
break;
|
||||
case RZ_MTU3_CHAN_4:
|
||||
bitpos = 7;
|
||||
break;
|
||||
case RZ_MTU3_CHAN_5:
|
||||
bitpos = 2;
|
||||
break;
|
||||
case RZ_MTU3_CHAN_8:
|
||||
bitpos = 3;
|
||||
break;
|
||||
default:
|
||||
bitpos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return bitpos;
|
||||
}
|
||||
|
||||
static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
unsigned long flags, tstr;
|
||||
u16 offset;
|
||||
u8 bitpos;
|
||||
|
||||
/* start stop register shared by multiple timer channels */
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
offset = rz_mtu3_get_tstr_offset(ch);
|
||||
bitpos = rz_mtu3_get_tstr_bit_pos(ch);
|
||||
tstr = rz_mtu3_shared_reg_read(ch, offset);
|
||||
__assign_bit(bitpos, &tstr, start);
|
||||
rz_mtu3_shared_reg_write(ch, offset, tstr);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
unsigned long flags, tstr;
|
||||
bool ret = false;
|
||||
u16 offset;
|
||||
u8 bitpos;
|
||||
|
||||
/* start stop register shared by multiple timer channels */
|
||||
raw_spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
offset = rz_mtu3_get_tstr_offset(ch);
|
||||
bitpos = rz_mtu3_get_tstr_bit_pos(ch);
|
||||
tstr = rz_mtu3_shared_reg_read(ch, offset);
|
||||
ret = tstr & BIT(bitpos);
|
||||
|
||||
raw_spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_is_enabled);
|
||||
|
||||
int rz_mtu3_enable(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
/* enable channel */
|
||||
rz_mtu3_start_stop_ch(ch, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_enable);
|
||||
|
||||
void rz_mtu3_disable(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
/* disable channel */
|
||||
rz_mtu3_start_stop_ch(ch, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rz_mtu3_disable);
|
||||
|
||||
static void rz_mtu3_reset_assert(void *data)
|
||||
{
|
||||
struct rz_mtu3 *mtu = dev_get_drvdata(data);
|
||||
struct rz_mtu3_priv *priv = mtu->priv_data;
|
||||
|
||||
mfd_remove_devices(data);
|
||||
reset_control_assert(priv->rstc);
|
||||
}
|
||||
|
||||
static const struct mfd_cell rz_mtu3_devs[] = {
|
||||
{
|
||||
.name = "rz-mtu3-counter",
|
||||
},
|
||||
{
|
||||
.name = "pwm-rz-mtu3",
|
||||
},
|
||||
};
|
||||
|
||||
static int rz_mtu3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rz_mtu3_priv *priv;
|
||||
struct rz_mtu3 *ddata;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
ddata->priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!ddata->priv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = ddata->priv_data;
|
||||
|
||||
priv->mmio = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->mmio))
|
||||
return PTR_ERR(priv->mmio);
|
||||
|
||||
priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(priv->rstc))
|
||||
return PTR_ERR(priv->rstc);
|
||||
|
||||
ddata->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(ddata->clk))
|
||||
return PTR_ERR(ddata->clk);
|
||||
|
||||
reset_control_deassert(priv->rstc);
|
||||
raw_spin_lock_init(&priv->lock);
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
for (i = 0; i < RZ_MTU_NUM_CHANNELS; i++) {
|
||||
ddata->channels[i].channel_number = i;
|
||||
ddata->channels[i].is_busy = false;
|
||||
mutex_init(&ddata->channels[i].lock);
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, 0, rz_mtu3_devs,
|
||||
ARRAY_SIZE(rz_mtu3_devs), NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
goto err_assert;
|
||||
|
||||
return devm_add_action_or_reset(&pdev->dev, rz_mtu3_reset_assert,
|
||||
&pdev->dev);
|
||||
|
||||
err_assert:
|
||||
reset_control_assert(priv->rstc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id rz_mtu3_of_match[] = {
|
||||
{ .compatible = "renesas,rz-mtu3", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rz_mtu3_of_match);
|
||||
|
||||
static struct platform_driver rz_mtu3_driver = {
|
||||
.probe = rz_mtu3_probe,
|
||||
.driver = {
|
||||
.name = "rz-mtu3",
|
||||
.of_match_table = rz_mtu3_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(rz_mtu3_driver);
|
||||
|
||||
MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
|
||||
MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a Core Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,147 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* MFD internals for Renesas RZ/G2L MTU3 Core driver
|
||||
*
|
||||
* Copyright (C) 2023 Renesas Electronics Corporation
|
||||
*/
|
||||
|
||||
#ifndef RZ_MTU3_MFD_H
|
||||
#define RZ_MTU3_MFD_H
|
||||
|
||||
#define MTU_8BIT_CH_0(_tier, _nfcr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl, _tbtm) \
|
||||
{ \
|
||||
[RZ_MTU3_TIER] = _tier, \
|
||||
[RZ_MTU3_NFCR] = _nfcr, \
|
||||
[RZ_MTU3_TCR] = _tcr, \
|
||||
[RZ_MTU3_TCR2] = _tcr2, \
|
||||
[RZ_MTU3_TMDR1] = _tmdr1, \
|
||||
[RZ_MTU3_TIORH] = _tiorh, \
|
||||
[RZ_MTU3_TIORL] = _tiorl, \
|
||||
[RZ_MTU3_TBTM] = _tbtm \
|
||||
}
|
||||
|
||||
#define MTU_8BIT_CH_1_2(_tier, _nfcr, _tsr, _tcr, _tcr2, _tmdr1, _tior) \
|
||||
{ \
|
||||
[RZ_MTU3_TIER] = _tier, \
|
||||
[RZ_MTU3_NFCR] = _nfcr, \
|
||||
[RZ_MTU3_TSR] = _tsr, \
|
||||
[RZ_MTU3_TCR] = _tcr, \
|
||||
[RZ_MTU3_TCR2] = _tcr2, \
|
||||
[RZ_MTU3_TMDR1] = _tmdr1, \
|
||||
[RZ_MTU3_TIOR] = _tior \
|
||||
} \
|
||||
|
||||
#define MTU_8BIT_CH_3_4_6_7(_tier, _nfcr, _tsr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl, _tbtm) \
|
||||
{ \
|
||||
[RZ_MTU3_TIER] = _tier, \
|
||||
[RZ_MTU3_NFCR] = _nfcr, \
|
||||
[RZ_MTU3_TSR] = _tsr, \
|
||||
[RZ_MTU3_TCR] = _tcr, \
|
||||
[RZ_MTU3_TCR2] = _tcr2, \
|
||||
[RZ_MTU3_TMDR1] = _tmdr1, \
|
||||
[RZ_MTU3_TIORH] = _tiorh, \
|
||||
[RZ_MTU3_TIORL] = _tiorl, \
|
||||
[RZ_MTU3_TBTM] = _tbtm \
|
||||
} \
|
||||
|
||||
#define MTU_8BIT_CH_5(_tier, _nfcr, _tstr, _tcntcmpclr, _tcru, _tcr2u, _tioru, \
|
||||
_tcrv, _tcr2v, _tiorv, _tcrw, _tcr2w, _tiorw) \
|
||||
{ \
|
||||
[RZ_MTU3_TIER] = _tier, \
|
||||
[RZ_MTU3_NFCR] = _nfcr, \
|
||||
[RZ_MTU3_TSTR] = _tstr, \
|
||||
[RZ_MTU3_TCNTCMPCLR] = _tcntcmpclr, \
|
||||
[RZ_MTU3_TCRU] = _tcru, \
|
||||
[RZ_MTU3_TCR2U] = _tcr2u, \
|
||||
[RZ_MTU3_TIORU] = _tioru, \
|
||||
[RZ_MTU3_TCRV] = _tcrv, \
|
||||
[RZ_MTU3_TCR2V] = _tcr2v, \
|
||||
[RZ_MTU3_TIORV] = _tiorv, \
|
||||
[RZ_MTU3_TCRW] = _tcrw, \
|
||||
[RZ_MTU3_TCR2W] = _tcr2w, \
|
||||
[RZ_MTU3_TIORW] = _tiorw \
|
||||
} \
|
||||
|
||||
#define MTU_8BIT_CH_8(_tier, _nfcr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl) \
|
||||
{ \
|
||||
[RZ_MTU3_TIER] = _tier, \
|
||||
[RZ_MTU3_NFCR] = _nfcr, \
|
||||
[RZ_MTU3_TCR] = _tcr, \
|
||||
[RZ_MTU3_TCR2] = _tcr2, \
|
||||
[RZ_MTU3_TMDR1] = _tmdr1, \
|
||||
[RZ_MTU3_TIORH] = _tiorh, \
|
||||
[RZ_MTU3_TIORL] = _tiorl \
|
||||
} \
|
||||
|
||||
#define MTU_16BIT_CH_0(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre, _tgrf) \
|
||||
{ \
|
||||
[RZ_MTU3_TCNT] = _tcnt, \
|
||||
[RZ_MTU3_TGRA] = _tgra, \
|
||||
[RZ_MTU3_TGRB] = _tgrb, \
|
||||
[RZ_MTU3_TGRC] = _tgrc, \
|
||||
[RZ_MTU3_TGRD] = _tgrd, \
|
||||
[RZ_MTU3_TGRE] = _tgre, \
|
||||
[RZ_MTU3_TGRF] = _tgrf \
|
||||
}
|
||||
|
||||
#define MTU_16BIT_CH_1_2(_tcnt, _tgra, _tgrb) \
|
||||
{ \
|
||||
[RZ_MTU3_TCNT] = _tcnt, \
|
||||
[RZ_MTU3_TGRA] = _tgra, \
|
||||
[RZ_MTU3_TGRB] = _tgrb \
|
||||
}
|
||||
|
||||
#define MTU_16BIT_CH_3_6(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre) \
|
||||
{ \
|
||||
[RZ_MTU3_TCNT] = _tcnt, \
|
||||
[RZ_MTU3_TGRA] = _tgra, \
|
||||
[RZ_MTU3_TGRB] = _tgrb, \
|
||||
[RZ_MTU3_TGRC] = _tgrc, \
|
||||
[RZ_MTU3_TGRD] = _tgrd, \
|
||||
[RZ_MTU3_TGRE] = _tgre \
|
||||
}
|
||||
|
||||
#define MTU_16BIT_CH_4_7(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre, _tgrf, \
|
||||
_tadcr, _tadcora, _tadcorb, _tadcobra, _tadcobrb) \
|
||||
{ \
|
||||
[RZ_MTU3_TCNT] = _tcnt, \
|
||||
[RZ_MTU3_TGRA] = _tgra, \
|
||||
[RZ_MTU3_TGRB] = _tgrb, \
|
||||
[RZ_MTU3_TGRC] = _tgrc, \
|
||||
[RZ_MTU3_TGRD] = _tgrd, \
|
||||
[RZ_MTU3_TGRE] = _tgre, \
|
||||
[RZ_MTU3_TGRF] = _tgrf, \
|
||||
[RZ_MTU3_TADCR] = _tadcr, \
|
||||
[RZ_MTU3_TADCORA] = _tadcora, \
|
||||
[RZ_MTU3_TADCORB] = _tadcorb, \
|
||||
[RZ_MTU3_TADCOBRA] = _tadcobra, \
|
||||
[RZ_MTU3_TADCOBRB] = _tadcobrb \
|
||||
}
|
||||
|
||||
#define MTU_16BIT_CH_5(_tcntu, _tgru, _tcntv, _tgrv, _tcntw, _tgrw) \
|
||||
{ \
|
||||
[RZ_MTU3_TCNTU] = _tcntu, \
|
||||
[RZ_MTU3_TGRU] = _tgru, \
|
||||
[RZ_MTU3_TCNTV] = _tcntv, \
|
||||
[RZ_MTU3_TGRV] = _tgrv, \
|
||||
[RZ_MTU3_TCNTW] = _tcntw, \
|
||||
[RZ_MTU3_TGRW] = _tgrw \
|
||||
}
|
||||
|
||||
#define MTU_32BIT_CH_1(_tcntlw, _tgralw, _tgrblw) \
|
||||
{ \
|
||||
[RZ_MTU3_TCNTLW] = _tcntlw, \
|
||||
[RZ_MTU3_TGRALW] = _tgralw, \
|
||||
[RZ_MTU3_TGRBLW] = _tgrblw \
|
||||
}
|
||||
|
||||
#define MTU_32BIT_CH_8(_tcnt, _tgra, _tgrb, _tgrc, _tgrd) \
|
||||
{ \
|
||||
[RZ_MTU3_TCNT] = _tcnt, \
|
||||
[RZ_MTU3_TGRA] = _tgra, \
|
||||
[RZ_MTU3_TGRB] = _tgrb, \
|
||||
[RZ_MTU3_TGRC] = _tgrc, \
|
||||
[RZ_MTU3_TGRD] = _tgrd \
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,257 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2022 Renesas Electronics Corporation
|
||||
*/
|
||||
#ifndef __MFD_RZ_MTU3_H__
|
||||
#define __MFD_RZ_MTU3_H__
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
/* 8-bit shared register offsets macros */
|
||||
#define RZ_MTU3_TSTRA 0x080 /* Timer start register A */
|
||||
#define RZ_MTU3_TSTRB 0x880 /* Timer start register B */
|
||||
|
||||
/* 16-bit shared register offset macros */
|
||||
#define RZ_MTU3_TDDRA 0x016 /* Timer dead time data register A */
|
||||
#define RZ_MTU3_TDDRB 0x816 /* Timer dead time data register B */
|
||||
#define RZ_MTU3_TCDRA 0x014 /* Timer cycle data register A */
|
||||
#define RZ_MTU3_TCDRB 0x814 /* Timer cycle data register B */
|
||||
#define RZ_MTU3_TCBRA 0x022 /* Timer cycle buffer register A */
|
||||
#define RZ_MTU3_TCBRB 0x822 /* Timer cycle buffer register B */
|
||||
#define RZ_MTU3_TCNTSA 0x020 /* Timer subcounter A */
|
||||
#define RZ_MTU3_TCNTSB 0x820 /* Timer subcounter B */
|
||||
|
||||
/*
|
||||
* MTU5 contains 3 timer counter registers and is totaly different
|
||||
* from other channels, so we must separate its offset
|
||||
*/
|
||||
|
||||
/* 8-bit register offset macros of MTU3 channels except MTU5 */
|
||||
#define RZ_MTU3_TIER 0 /* Timer interrupt register */
|
||||
#define RZ_MTU3_NFCR 1 /* Noise filter control register */
|
||||
#define RZ_MTU3_TSR 2 /* Timer status register */
|
||||
#define RZ_MTU3_TCR 3 /* Timer control register */
|
||||
#define RZ_MTU3_TCR2 4 /* Timer control register 2 */
|
||||
|
||||
/* Timer mode register 1 */
|
||||
#define RZ_MTU3_TMDR1 5
|
||||
#define RZ_MTU3_TMDR1_MD GENMASK(3, 0)
|
||||
#define RZ_MTU3_TMDR1_MD_NORMAL FIELD_PREP(RZ_MTU3_TMDR1_MD, 0)
|
||||
#define RZ_MTU3_TMDR1_MD_PWMMODE1 FIELD_PREP(RZ_MTU3_TMDR1_MD, 2)
|
||||
|
||||
#define RZ_MTU3_TIOR 6 /* Timer I/O control register */
|
||||
#define RZ_MTU3_TIORH 6 /* Timer I/O control register H */
|
||||
#define RZ_MTU3_TIORL 7 /* Timer I/O control register L */
|
||||
/* Only MTU3/4/6/7 have TBTM registers */
|
||||
#define RZ_MTU3_TBTM 8 /* Timer buffer operation transfer mode register */
|
||||
|
||||
/* 8-bit MTU5 register offset macros */
|
||||
#define RZ_MTU3_TSTR 2 /* MTU5 Timer start register */
|
||||
#define RZ_MTU3_TCNTCMPCLR 3 /* MTU5 Timer compare match clear register */
|
||||
#define RZ_MTU3_TCRU 4 /* Timer control register U */
|
||||
#define RZ_MTU3_TCR2U 5 /* Timer control register 2U */
|
||||
#define RZ_MTU3_TIORU 6 /* Timer I/O control register U */
|
||||
#define RZ_MTU3_TCRV 7 /* Timer control register V */
|
||||
#define RZ_MTU3_TCR2V 8 /* Timer control register 2V */
|
||||
#define RZ_MTU3_TIORV 9 /* Timer I/O control register V */
|
||||
#define RZ_MTU3_TCRW 10 /* Timer control register W */
|
||||
#define RZ_MTU3_TCR2W 11 /* Timer control register 2W */
|
||||
#define RZ_MTU3_TIORW 12 /* Timer I/O control register W */
|
||||
|
||||
/* 16-bit register offset macros of MTU3 channels except MTU5 */
|
||||
#define RZ_MTU3_TCNT 0 /* Timer counter */
|
||||
#define RZ_MTU3_TGRA 1 /* Timer general register A */
|
||||
#define RZ_MTU3_TGRB 2 /* Timer general register B */
|
||||
#define RZ_MTU3_TGRC 3 /* Timer general register C */
|
||||
#define RZ_MTU3_TGRD 4 /* Timer general register D */
|
||||
#define RZ_MTU3_TGRE 5 /* Timer general register E */
|
||||
#define RZ_MTU3_TGRF 6 /* Timer general register F */
|
||||
/* Timer A/D converter start request registers */
|
||||
#define RZ_MTU3_TADCR 7 /* control register */
|
||||
#define RZ_MTU3_TADCORA 8 /* cycle set register A */
|
||||
#define RZ_MTU3_TADCORB 9 /* cycle set register B */
|
||||
#define RZ_MTU3_TADCOBRA 10 /* cycle set buffer register A */
|
||||
#define RZ_MTU3_TADCOBRB 11 /* cycle set buffer register B */
|
||||
|
||||
/* 16-bit MTU5 register offset macros */
|
||||
#define RZ_MTU3_TCNTU 0 /* MTU5 Timer counter U */
|
||||
#define RZ_MTU3_TGRU 1 /* MTU5 Timer general register U */
|
||||
#define RZ_MTU3_TCNTV 2 /* MTU5 Timer counter V */
|
||||
#define RZ_MTU3_TGRV 3 /* MTU5 Timer general register V */
|
||||
#define RZ_MTU3_TCNTW 4 /* MTU5 Timer counter W */
|
||||
#define RZ_MTU3_TGRW 5 /* MTU5 Timer general register W */
|
||||
|
||||
/* 32-bit register offset */
|
||||
#define RZ_MTU3_TCNTLW 0 /* Timer longword counter */
|
||||
#define RZ_MTU3_TGRALW 1 /* Timer longword general register A */
|
||||
#define RZ_MTU3_TGRBLW 2 /* Timer longowrd general register B */
|
||||
|
||||
#define RZ_MTU3_TMDR3 0x191 /* MTU1 Timer Mode Register 3 */
|
||||
|
||||
/* Macros for setting registers */
|
||||
#define RZ_MTU3_TCR_CCLR GENMASK(7, 5)
|
||||
#define RZ_MTU3_TCR_CKEG GENMASK(4, 3)
|
||||
#define RZ_MTU3_TCR_TPCS GENMASK(2, 0)
|
||||
#define RZ_MTU3_TCR_CCLR_TGRA BIT(5)
|
||||
#define RZ_MTU3_TCR_CCLR_TGRC FIELD_PREP(RZ_MTU3_TCR_CCLR, 5)
|
||||
#define RZ_MTU3_TCR_CKEG_RISING FIELD_PREP(RZ_MTU3_TCR_CKEG, 0)
|
||||
|
||||
#define RZ_MTU3_TIOR_IOB GENMASK(7, 4)
|
||||
#define RZ_MTU3_TIOR_IOA GENMASK(3, 0)
|
||||
#define RZ_MTU3_TIOR_OC_RETAIN 0
|
||||
#define RZ_MTU3_TIOR_OC_INIT_OUT_LO_HI_OUT 2
|
||||
#define RZ_MTU3_TIOR_OC_INIT_OUT_HI_TOGGLE_OUT 7
|
||||
|
||||
#define RZ_MTU3_TIOR_OC_IOA_H_COMP_MATCH \
|
||||
FIELD_PREP(RZ_MTU3_TIOR_IOA, RZ_MTU3_TIOR_OC_INIT_OUT_LO_HI_OUT)
|
||||
#define RZ_MTU3_TIOR_OC_IOB_TOGGLE \
|
||||
FIELD_PREP(RZ_MTU3_TIOR_IOB, RZ_MTU3_TIOR_OC_INIT_OUT_HI_TOGGLE_OUT)
|
||||
|
||||
enum rz_mtu3_channels {
|
||||
RZ_MTU3_CHAN_0,
|
||||
RZ_MTU3_CHAN_1,
|
||||
RZ_MTU3_CHAN_2,
|
||||
RZ_MTU3_CHAN_3,
|
||||
RZ_MTU3_CHAN_4,
|
||||
RZ_MTU3_CHAN_5,
|
||||
RZ_MTU3_CHAN_6,
|
||||
RZ_MTU3_CHAN_7,
|
||||
RZ_MTU3_CHAN_8,
|
||||
RZ_MTU_NUM_CHANNELS
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rz_mtu3_channel - MTU3 channel private data
|
||||
*
|
||||
* @dev: device handle
|
||||
* @channel_number: channel number
|
||||
* @lock: Lock to protect channel state
|
||||
* @is_busy: channel state
|
||||
*/
|
||||
struct rz_mtu3_channel {
|
||||
struct device *dev;
|
||||
unsigned int channel_number;
|
||||
struct mutex lock;
|
||||
bool is_busy;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rz_mtu3 - MTU3 core private data
|
||||
*
|
||||
* @clk: MTU3 module clock
|
||||
* @rz_mtu3_channel: HW channels
|
||||
* @priv_data: MTU3 core driver private data
|
||||
*/
|
||||
struct rz_mtu3 {
|
||||
struct clk *clk;
|
||||
struct rz_mtu3_channel channels[RZ_MTU_NUM_CHANNELS];
|
||||
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_RZ_MTU3)
|
||||
static inline bool rz_mtu3_request_channel(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
mutex_lock(&ch->lock);
|
||||
if (ch->is_busy) {
|
||||
mutex_unlock(&ch->lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
ch->is_busy = true;
|
||||
mutex_unlock(&ch->lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void rz_mtu3_release_channel(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
mutex_lock(&ch->lock);
|
||||
ch->is_busy = false;
|
||||
mutex_unlock(&ch->lock);
|
||||
}
|
||||
|
||||
bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch);
|
||||
void rz_mtu3_disable(struct rz_mtu3_channel *ch);
|
||||
int rz_mtu3_enable(struct rz_mtu3_channel *ch);
|
||||
|
||||
u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 off);
|
||||
u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 off);
|
||||
u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 off);
|
||||
u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 off);
|
||||
|
||||
void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u8 val);
|
||||
void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u16 val);
|
||||
void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u32 val);
|
||||
void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 off, u16 val);
|
||||
void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 off,
|
||||
u16 pos, u8 val);
|
||||
#else
|
||||
static inline bool rz_mtu3_request_channel(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void rz_mtu3_release_channel(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void rz_mtu3_disable(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int rz_mtu3_enable(struct rz_mtu3_channel *ch)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 off)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u8 val)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u16 val)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u32 val)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 off, u16 val)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch,
|
||||
u16 off, u16 pos, u8 val)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MFD_RZ_MTU3_H__ */
|
Loading…
Reference in New Issue