392 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Renesas RZ/G2L Multi-Function Timer Pulse Unit 3(MTU3a) Core driver4 *5 * Copyright (C) 2023 Renesas Electronics Corporation6 */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(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(priv->mmio + offset);72 else73 return readb(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(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(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(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(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(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(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(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, 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(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, 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(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, 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(ch->dev->parent);163 struct rz_mtu3_priv *priv = mtu->priv_data;164 165 if (rz_mtu3_is_16bit_shared_reg(offset))166 writew(value, priv->mmio + offset);167 else168 writeb((u8)value, 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(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(pos, &tmdr, !!val);182 rz_mtu3_shared_reg_write(ch, offset, tmdr);183 spin_unlock_irqrestore(&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(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(bitpos, &tstr, start);263 rz_mtu3_shared_reg_write(ch, offset, tstr);264 265 spin_unlock_irqrestore(&priv->lock, flags);266}267 268bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch)269{270 struct rz_mtu3 *mtu = dev_get_drvdata(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(&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, 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, 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(data);307 struct rz_mtu3_priv *priv = mtu->priv_data;308 309 mfd_remove_devices(data);310 reset_control_assert(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(&pdev->dev, sizeof(*ddata), GFP_KERNEL);330 if (!ddata)331 return -ENOMEM;332 333 ddata->priv_data = devm_kzalloc(&pdev->dev, 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, 0);340 if (IS_ERR(priv->mmio))341 return PTR_ERR(priv->mmio);342 343 priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);344 if (IS_ERR(priv->rstc))345 return PTR_ERR(priv->rstc);346 347 ddata->clk = devm_clk_get(&pdev->dev, NULL);348 if (IS_ERR(ddata->clk))349 return PTR_ERR(ddata->clk);350 351 reset_control_deassert(priv->rstc);352 spin_lock_init(&priv->lock);353 platform_set_drvdata(pdev, 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(&pdev->dev, 0, rz_mtu3_devs,362 ARRAY_SIZE(rz_mtu3_devs), NULL, 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(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