|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | /* | 
|  | * Renesas RZ/G2L MTU3a Counter driver | 
|  | * | 
|  | * Copyright (C) 2022 Renesas Electronics Corporation | 
|  | */ | 
|  |  | 
|  | #include <linux/clk.h> | 
|  | #include <linux/counter.h> | 
|  | #include <linux/mfd/rz-mtu3.h> | 
|  | #include <linux/module.h> | 
|  | #include <linux/platform_device.h> | 
|  | #include <linux/pm_runtime.h> | 
|  | #include <linux/types.h> | 
|  |  | 
|  | /* | 
|  | * Register descriptions | 
|  | *   TSR: Timer Status Register | 
|  | *   TMDR1: Timer Mode Register 1 | 
|  | *   TMDR3: Timer Mode Register 3 | 
|  | *   TIOR: Timer I/O Control Register | 
|  | *   TCR: Timer Control Register | 
|  | *   TCNT: Timer Counter | 
|  | *   TGRA: Timer general register A | 
|  | *   TCNTLW: Timer Longword Counter | 
|  | *   TGRALW: Timer longword general register A | 
|  | */ | 
|  |  | 
|  | #define RZ_MTU3_TSR_TCFD	BIT(7) /* Count Direction Flag */ | 
|  |  | 
|  | #define RZ_MTU3_TMDR1_PH_CNT_MODE_1	(4) /* Phase counting mode 1 */ | 
|  | #define RZ_MTU3_TMDR1_PH_CNT_MODE_2	(5) /* Phase counting mode 2 */ | 
|  | #define RZ_MTU3_TMDR1_PH_CNT_MODE_3	(6) /* Phase counting mode 3 */ | 
|  | #define RZ_MTU3_TMDR1_PH_CNT_MODE_4	(7) /* Phase counting mode 4 */ | 
|  | #define RZ_MTU3_TMDR1_PH_CNT_MODE_5	(9) /* Phase counting mode 5 */ | 
|  | #define RZ_MTU3_TMDR1_PH_CNT_MODE_MASK	(0xf) | 
|  |  | 
|  | /* | 
|  | * LWA: MTU1/MTU2 Combination Longword Access Control | 
|  | * 0: 16-bit, 1: 32-bit | 
|  | */ | 
|  | #define RZ_MTU3_TMDR3_LWA	(0) | 
|  |  | 
|  | /* | 
|  | * PHCKSEL: External Input Phase Clock Select | 
|  | * 0: MTCLKA and MTCLKB, 1: MTCLKC and MTCLKD | 
|  | */ | 
|  | #define RZ_MTU3_TMDR3_PHCKSEL	(1) | 
|  |  | 
|  | #define RZ_MTU3_16_BIT_MTU1_CH	(0) | 
|  | #define RZ_MTU3_16_BIT_MTU2_CH	(1) | 
|  | #define RZ_MTU3_32_BIT_CH	(2) | 
|  |  | 
|  | #define RZ_MTU3_TIOR_NO_OUTPUT	(0) /* Output prohibited */ | 
|  | #define RZ_MTU3_TIOR_IC_BOTH	(10) /* Input capture at both edges */ | 
|  |  | 
|  | #define SIGNAL_A_ID	(0) | 
|  | #define SIGNAL_B_ID	(1) | 
|  | #define SIGNAL_C_ID	(2) | 
|  | #define SIGNAL_D_ID	(3) | 
|  |  | 
|  | #define RZ_MTU3_MAX_HW_CNTR_CHANNELS	(2) | 
|  | #define RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS	(3) | 
|  |  | 
|  | /** | 
|  | * struct rz_mtu3_cnt - MTU3 counter private data | 
|  | * | 
|  | * @clk: MTU3 module clock | 
|  | * @lock: Lock to prevent concurrent access for ceiling and count | 
|  | * @ch: HW channels for the counters | 
|  | * @count_is_enabled: Enabled state of Counter value channel | 
|  | * @mtu_16bit_max: Cache for 16-bit counters | 
|  | * @mtu_32bit_max: Cache for 32-bit counters | 
|  | */ | 
|  | struct rz_mtu3_cnt { | 
|  | struct clk *clk; | 
|  | struct mutex lock; | 
|  | struct rz_mtu3_channel *ch; | 
|  | bool count_is_enabled[RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS]; | 
|  | union { | 
|  | u16 mtu_16bit_max[RZ_MTU3_MAX_HW_CNTR_CHANNELS]; | 
|  | u32 mtu_32bit_max; | 
|  | }; | 
|  | }; | 
|  |  | 
|  | static const enum counter_function rz_mtu3_count_functions[] = { | 
|  | COUNTER_FUNCTION_QUADRATURE_X4, | 
|  | COUNTER_FUNCTION_PULSE_DIRECTION, | 
|  | COUNTER_FUNCTION_QUADRATURE_X2_B, | 
|  | }; | 
|  |  | 
|  | static inline size_t rz_mtu3_get_hw_ch(const size_t id) | 
|  | { | 
|  | return (id == RZ_MTU3_32_BIT_CH) ? 0 : id; | 
|  | } | 
|  |  | 
|  | static inline struct rz_mtu3_channel *rz_mtu3_get_ch(struct counter_device *counter, int id) | 
|  | { | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | const size_t ch_id = rz_mtu3_get_hw_ch(id); | 
|  |  | 
|  | return &priv->ch[ch_id]; | 
|  | } | 
|  |  | 
|  | static bool rz_mtu3_is_counter_invalid(struct counter_device *counter, int id) | 
|  | { | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | unsigned long tmdr; | 
|  |  | 
|  | pm_runtime_get_sync(priv->ch->dev); | 
|  | tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); | 
|  | pm_runtime_put(priv->ch->dev); | 
|  |  | 
|  | if (id == RZ_MTU3_32_BIT_CH && test_bit(RZ_MTU3_TMDR3_LWA, &tmdr)) | 
|  | return false; | 
|  |  | 
|  | if (id != RZ_MTU3_32_BIT_CH && !test_bit(RZ_MTU3_TMDR3_LWA, &tmdr)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_lock_if_counter_is_valid(struct counter_device *counter, | 
|  | struct rz_mtu3_channel *const ch, | 
|  | struct rz_mtu3_cnt *const priv, | 
|  | int id) | 
|  | { | 
|  | mutex_lock(&priv->lock); | 
|  |  | 
|  | if (ch->is_busy && !priv->count_is_enabled[id]) { | 
|  | mutex_unlock(&priv->lock); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | if (rz_mtu3_is_counter_invalid(counter, id)) { | 
|  | mutex_unlock(&priv->lock); | 
|  | return -EBUSY; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_lock_if_count_is_enabled(struct rz_mtu3_channel *const ch, | 
|  | struct rz_mtu3_cnt *const priv, | 
|  | int id) | 
|  | { | 
|  | mutex_lock(&priv->lock); | 
|  |  | 
|  | if (ch->is_busy && !priv->count_is_enabled[id]) { | 
|  | mutex_unlock(&priv->lock); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_read(struct counter_device *counter, | 
|  | struct counter_count *count, u64 *val) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | pm_runtime_get_sync(ch->dev); | 
|  | if (count->id == RZ_MTU3_32_BIT_CH) | 
|  | *val = rz_mtu3_32bit_ch_read(ch, RZ_MTU3_TCNTLW); | 
|  | else | 
|  | *val = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TCNT); | 
|  | pm_runtime_put(ch->dev); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_write(struct counter_device *counter, | 
|  | struct counter_count *count, const u64 val) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | pm_runtime_get_sync(ch->dev); | 
|  | if (count->id == RZ_MTU3_32_BIT_CH) | 
|  | rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TCNTLW, val); | 
|  | else | 
|  | rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TCNT, val); | 
|  | pm_runtime_put(ch->dev); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_function_read_helper(struct rz_mtu3_channel *const ch, | 
|  | struct rz_mtu3_cnt *const priv, | 
|  | enum counter_function *function) | 
|  | { | 
|  | u8 timer_mode; | 
|  |  | 
|  | pm_runtime_get_sync(ch->dev); | 
|  | timer_mode = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TMDR1); | 
|  | pm_runtime_put(ch->dev); | 
|  |  | 
|  | switch (timer_mode & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) { | 
|  | case RZ_MTU3_TMDR1_PH_CNT_MODE_1: | 
|  | *function = COUNTER_FUNCTION_QUADRATURE_X4; | 
|  | return 0; | 
|  | case RZ_MTU3_TMDR1_PH_CNT_MODE_2: | 
|  | *function = COUNTER_FUNCTION_PULSE_DIRECTION; | 
|  | return 0; | 
|  | case RZ_MTU3_TMDR1_PH_CNT_MODE_4: | 
|  | *function = COUNTER_FUNCTION_QUADRATURE_X2_B; | 
|  | return 0; | 
|  | default: | 
|  | /* | 
|  | * TODO: | 
|  | *  - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_3 | 
|  | *  - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_5 | 
|  | */ | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_function_read(struct counter_device *counter, | 
|  | struct counter_count *count, | 
|  | enum counter_function *function) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | ret = rz_mtu3_count_function_read_helper(ch, priv, function); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_function_write(struct counter_device *counter, | 
|  | struct counter_count *count, | 
|  | enum counter_function function) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | u8 timer_mode; | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | switch (function) { | 
|  | case COUNTER_FUNCTION_QUADRATURE_X4: | 
|  | timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_1; | 
|  | break; | 
|  | case COUNTER_FUNCTION_PULSE_DIRECTION: | 
|  | timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_2; | 
|  | break; | 
|  | case COUNTER_FUNCTION_QUADRATURE_X2_B: | 
|  | timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_4; | 
|  | break; | 
|  | default: | 
|  | /* | 
|  | * TODO: | 
|  | *  - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_3 | 
|  | *  - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_5 | 
|  | */ | 
|  | mutex_unlock(&priv->lock); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | pm_runtime_get_sync(ch->dev); | 
|  | rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, timer_mode); | 
|  | pm_runtime_put(ch->dev); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_direction_read(struct counter_device *counter, | 
|  | struct counter_count *count, | 
|  | enum counter_count_direction *direction) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | int ret; | 
|  | u8 tsr; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | pm_runtime_get_sync(ch->dev); | 
|  | tsr = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TSR); | 
|  | pm_runtime_put(ch->dev); | 
|  |  | 
|  | *direction = (tsr & RZ_MTU3_TSR_TCFD) ? | 
|  | COUNTER_COUNT_DIRECTION_FORWARD : COUNTER_COUNT_DIRECTION_BACKWARD; | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_ceiling_read(struct counter_device *counter, | 
|  | struct counter_count *count, | 
|  | u64 *ceiling) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | const size_t ch_id = rz_mtu3_get_hw_ch(count->id); | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | switch (count->id) { | 
|  | case RZ_MTU3_16_BIT_MTU1_CH: | 
|  | case RZ_MTU3_16_BIT_MTU2_CH: | 
|  | *ceiling = priv->mtu_16bit_max[ch_id]; | 
|  | break; | 
|  | case RZ_MTU3_32_BIT_CH: | 
|  | *ceiling = priv->mtu_32bit_max; | 
|  | break; | 
|  | default: | 
|  | /* should never reach this path */ | 
|  | mutex_unlock(&priv->lock); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | mutex_unlock(&priv->lock); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_ceiling_write(struct counter_device *counter, | 
|  | struct counter_count *count, | 
|  | u64 ceiling) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | const size_t ch_id = rz_mtu3_get_hw_ch(count->id); | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | switch (count->id) { | 
|  | case RZ_MTU3_16_BIT_MTU1_CH: | 
|  | case RZ_MTU3_16_BIT_MTU2_CH: | 
|  | if (ceiling > U16_MAX) { | 
|  | mutex_unlock(&priv->lock); | 
|  | return -ERANGE; | 
|  | } | 
|  | priv->mtu_16bit_max[ch_id] = ceiling; | 
|  | break; | 
|  | case RZ_MTU3_32_BIT_CH: | 
|  | if (ceiling > U32_MAX) { | 
|  | mutex_unlock(&priv->lock); | 
|  | return -ERANGE; | 
|  | } | 
|  | priv->mtu_32bit_max = ceiling; | 
|  | break; | 
|  | default: | 
|  | /* should never reach this path */ | 
|  | mutex_unlock(&priv->lock); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | pm_runtime_get_sync(ch->dev); | 
|  | if (count->id == RZ_MTU3_32_BIT_CH) | 
|  | rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TGRALW, ceiling); | 
|  | else | 
|  | rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRA, ceiling); | 
|  |  | 
|  | rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); | 
|  | pm_runtime_put(ch->dev); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void rz_mtu3_32bit_cnt_setting(struct counter_device *counter) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); | 
|  | struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); | 
|  |  | 
|  | /* Phase counting mode 1 is used as default in initialization. */ | 
|  | rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_PH_CNT_MODE_1); | 
|  |  | 
|  | rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); | 
|  | rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TIOR, RZ_MTU3_TIOR_IC_BOTH); | 
|  |  | 
|  | rz_mtu3_enable(ch1); | 
|  | rz_mtu3_enable(ch2); | 
|  | } | 
|  |  | 
|  | static void rz_mtu3_16bit_cnt_setting(struct counter_device *counter, int id) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); | 
|  |  | 
|  | /* Phase counting mode 1 is used as default in initialization. */ | 
|  | rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_PH_CNT_MODE_1); | 
|  |  | 
|  | rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); | 
|  | rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TIOR, RZ_MTU3_TIOR_NO_OUTPUT); | 
|  | rz_mtu3_enable(ch); | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_initialize_counter(struct counter_device *counter, int id) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); | 
|  | struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); | 
|  | struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); | 
|  |  | 
|  | switch (id) { | 
|  | case RZ_MTU3_16_BIT_MTU1_CH: | 
|  | case RZ_MTU3_16_BIT_MTU2_CH: | 
|  | if (!rz_mtu3_request_channel(ch)) | 
|  | return -EBUSY; | 
|  |  | 
|  | rz_mtu3_16bit_cnt_setting(counter, id); | 
|  | return 0; | 
|  | case RZ_MTU3_32_BIT_CH: | 
|  | /* | 
|  | * 32-bit phase counting need MTU1 and MTU2 to create 32-bit | 
|  | * cascade counter. | 
|  | */ | 
|  | if (!rz_mtu3_request_channel(ch1)) | 
|  | return -EBUSY; | 
|  |  | 
|  | if (!rz_mtu3_request_channel(ch2)) { | 
|  | rz_mtu3_release_channel(ch1); | 
|  | return -EBUSY; | 
|  | } | 
|  |  | 
|  | rz_mtu3_32bit_cnt_setting(counter); | 
|  | return 0; | 
|  | default: | 
|  | /* should never reach this path */ | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void rz_mtu3_terminate_counter(struct counter_device *counter, int id) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); | 
|  | struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); | 
|  | struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); | 
|  |  | 
|  | if (id == RZ_MTU3_32_BIT_CH) { | 
|  | rz_mtu3_release_channel(ch2); | 
|  | rz_mtu3_release_channel(ch1); | 
|  | rz_mtu3_disable(ch2); | 
|  | rz_mtu3_disable(ch1); | 
|  | } else { | 
|  | rz_mtu3_release_channel(ch); | 
|  | rz_mtu3_disable(ch); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_enable_read(struct counter_device *counter, | 
|  | struct counter_count *count, u8 *enable) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); | 
|  | struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | if (count->id == RZ_MTU3_32_BIT_CH) | 
|  | *enable = rz_mtu3_is_enabled(ch1) && rz_mtu3_is_enabled(ch2); | 
|  | else | 
|  | *enable = rz_mtu3_is_enabled(ch); | 
|  |  | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_count_enable_write(struct counter_device *counter, | 
|  | struct counter_count *count, u8 enable) | 
|  | { | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | int ret = 0; | 
|  |  | 
|  | if (enable) { | 
|  | mutex_lock(&priv->lock); | 
|  | pm_runtime_get_sync(ch->dev); | 
|  | ret = rz_mtu3_initialize_counter(counter, count->id); | 
|  | if (ret == 0) | 
|  | priv->count_is_enabled[count->id] = true; | 
|  | mutex_unlock(&priv->lock); | 
|  | } else { | 
|  | mutex_lock(&priv->lock); | 
|  | rz_mtu3_terminate_counter(counter, count->id); | 
|  | priv->count_is_enabled[count->id] = false; | 
|  | pm_runtime_put(ch->dev); | 
|  | mutex_unlock(&priv->lock); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_lock_if_ch0_is_enabled(struct rz_mtu3_cnt *const priv) | 
|  | { | 
|  | mutex_lock(&priv->lock); | 
|  | if (priv->ch->is_busy && !(priv->count_is_enabled[RZ_MTU3_16_BIT_MTU1_CH] || | 
|  | priv->count_is_enabled[RZ_MTU3_32_BIT_CH])) { | 
|  | mutex_unlock(&priv->lock); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_cascade_counts_enable_get(struct counter_device *counter, | 
|  | u8 *cascade_enable) | 
|  | { | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | unsigned long tmdr; | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_ch0_is_enabled(priv); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | pm_runtime_get_sync(priv->ch->dev); | 
|  | tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); | 
|  | pm_runtime_put(priv->ch->dev); | 
|  | *cascade_enable = test_bit(RZ_MTU3_TMDR3_LWA, &tmdr); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_cascade_counts_enable_set(struct counter_device *counter, | 
|  | u8 cascade_enable) | 
|  | { | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_ch0_is_enabled(priv); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | pm_runtime_get_sync(priv->ch->dev); | 
|  | rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3, | 
|  | RZ_MTU3_TMDR3_LWA, cascade_enable); | 
|  | pm_runtime_put(priv->ch->dev); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_ext_input_phase_clock_select_get(struct counter_device *counter, | 
|  | u32 *ext_input_phase_clock_select) | 
|  | { | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | unsigned long tmdr; | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_ch0_is_enabled(priv); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | pm_runtime_get_sync(priv->ch->dev); | 
|  | tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); | 
|  | pm_runtime_put(priv->ch->dev); | 
|  | *ext_input_phase_clock_select = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_ext_input_phase_clock_select_set(struct counter_device *counter, | 
|  | u32 ext_input_phase_clock_select) | 
|  | { | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_ch0_is_enabled(priv); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | pm_runtime_get_sync(priv->ch->dev); | 
|  | rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3, | 
|  | RZ_MTU3_TMDR3_PHCKSEL, | 
|  | ext_input_phase_clock_select); | 
|  | pm_runtime_put(priv->ch->dev); | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct counter_comp rz_mtu3_count_ext[] = { | 
|  | COUNTER_COMP_DIRECTION(rz_mtu3_count_direction_read), | 
|  | COUNTER_COMP_ENABLE(rz_mtu3_count_enable_read, | 
|  | rz_mtu3_count_enable_write), | 
|  | COUNTER_COMP_CEILING(rz_mtu3_count_ceiling_read, | 
|  | rz_mtu3_count_ceiling_write), | 
|  | }; | 
|  |  | 
|  | static const enum counter_synapse_action rz_mtu3_synapse_actions[] = { | 
|  | COUNTER_SYNAPSE_ACTION_BOTH_EDGES, | 
|  | COUNTER_SYNAPSE_ACTION_RISING_EDGE, | 
|  | COUNTER_SYNAPSE_ACTION_NONE, | 
|  | }; | 
|  |  | 
|  | static int rz_mtu3_action_read(struct counter_device *counter, | 
|  | struct counter_count *count, | 
|  | struct counter_synapse *synapse, | 
|  | enum counter_synapse_action *action) | 
|  | { | 
|  | const bool is_signal_ab = (synapse->signal->id == SIGNAL_A_ID) || | 
|  | (synapse->signal->id == SIGNAL_B_ID); | 
|  | struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); | 
|  | struct rz_mtu3_cnt *const priv = counter_priv(counter); | 
|  | enum counter_function function; | 
|  | bool mtclkc_mtclkd; | 
|  | unsigned long tmdr; | 
|  | int ret; | 
|  |  | 
|  | ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | ret = rz_mtu3_count_function_read_helper(ch, priv, &function); | 
|  | if (ret) { | 
|  | mutex_unlock(&priv->lock); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Default action mode */ | 
|  | *action = COUNTER_SYNAPSE_ACTION_NONE; | 
|  |  | 
|  | if (count->id != RZ_MTU3_16_BIT_MTU1_CH) { | 
|  | tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); | 
|  | mtclkc_mtclkd = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr); | 
|  | if ((mtclkc_mtclkd && is_signal_ab) || | 
|  | (!mtclkc_mtclkd && !is_signal_ab)) { | 
|  | mutex_unlock(&priv->lock); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | switch (function) { | 
|  | case COUNTER_FUNCTION_PULSE_DIRECTION: | 
|  | /* | 
|  | * Rising edges on signal A (signal C) updates the respective | 
|  | * count. The input level of signal B (signal D) determines | 
|  | * direction. | 
|  | */ | 
|  | if (synapse->signal->id == SIGNAL_A_ID || | 
|  | synapse->signal->id == SIGNAL_C_ID) | 
|  | *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; | 
|  | break; | 
|  | case COUNTER_FUNCTION_QUADRATURE_X2_B: | 
|  | /* | 
|  | * Any state transition on quadrature pair signal B (signal D) | 
|  | * updates the respective count. | 
|  | */ | 
|  | if (synapse->signal->id == SIGNAL_B_ID || | 
|  | synapse->signal->id == SIGNAL_D_ID) | 
|  | *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; | 
|  | break; | 
|  | case COUNTER_FUNCTION_QUADRATURE_X4: | 
|  | /* counts up/down on both edges of A (C)  and B (D) signal */ | 
|  | *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; | 
|  | break; | 
|  | default: | 
|  | /* should never reach this path */ | 
|  | mutex_unlock(&priv->lock); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | mutex_unlock(&priv->lock); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const struct counter_ops rz_mtu3_cnt_ops = { | 
|  | .count_read = rz_mtu3_count_read, | 
|  | .count_write = rz_mtu3_count_write, | 
|  | .function_read = rz_mtu3_count_function_read, | 
|  | .function_write = rz_mtu3_count_function_write, | 
|  | .action_read = rz_mtu3_action_read, | 
|  | }; | 
|  |  | 
|  | #define RZ_MTU3_PHASE_SIGNAL(_id, _name) {		\ | 
|  | .id = (_id),				\ | 
|  | .name = (_name),			\ | 
|  | } | 
|  |  | 
|  | static struct counter_signal rz_mtu3_signals[] = { | 
|  | RZ_MTU3_PHASE_SIGNAL(SIGNAL_A_ID, "MTU1 MTCLKA"), | 
|  | RZ_MTU3_PHASE_SIGNAL(SIGNAL_B_ID, "MTU1 MTCLKB"), | 
|  | RZ_MTU3_PHASE_SIGNAL(SIGNAL_C_ID, "MTU2 MTCLKC"), | 
|  | RZ_MTU3_PHASE_SIGNAL(SIGNAL_D_ID, "MTU2 MTCLKD"), | 
|  | }; | 
|  |  | 
|  | static struct counter_synapse rz_mtu3_mtu1_count_synapses[] = { | 
|  | { | 
|  | .actions_list = rz_mtu3_synapse_actions, | 
|  | .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), | 
|  | .signal = rz_mtu3_signals, | 
|  | }, | 
|  | { | 
|  | .actions_list = rz_mtu3_synapse_actions, | 
|  | .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), | 
|  | .signal = rz_mtu3_signals + 1, | 
|  | } | 
|  | }; | 
|  |  | 
|  | static struct counter_synapse rz_mtu3_mtu2_count_synapses[] = { | 
|  | { | 
|  | .actions_list = rz_mtu3_synapse_actions, | 
|  | .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), | 
|  | .signal = rz_mtu3_signals, | 
|  | }, | 
|  | { | 
|  | .actions_list = rz_mtu3_synapse_actions, | 
|  | .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), | 
|  | .signal = rz_mtu3_signals + 1, | 
|  | }, | 
|  | { | 
|  | .actions_list = rz_mtu3_synapse_actions, | 
|  | .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), | 
|  | .signal = rz_mtu3_signals + 2, | 
|  | }, | 
|  | { | 
|  | .actions_list = rz_mtu3_synapse_actions, | 
|  | .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), | 
|  | .signal = rz_mtu3_signals + 3, | 
|  | } | 
|  | }; | 
|  |  | 
|  | static struct counter_count rz_mtu3_counts[] = { | 
|  | { | 
|  | .id = RZ_MTU3_16_BIT_MTU1_CH, | 
|  | .name = "Channel 1 Count", | 
|  | .functions_list = rz_mtu3_count_functions, | 
|  | .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), | 
|  | .synapses = rz_mtu3_mtu1_count_synapses, | 
|  | .num_synapses = ARRAY_SIZE(rz_mtu3_mtu1_count_synapses), | 
|  | .ext = rz_mtu3_count_ext, | 
|  | .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), | 
|  | }, | 
|  | { | 
|  | .id = RZ_MTU3_16_BIT_MTU2_CH, | 
|  | .name = "Channel 2 Count", | 
|  | .functions_list = rz_mtu3_count_functions, | 
|  | .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), | 
|  | .synapses = rz_mtu3_mtu2_count_synapses, | 
|  | .num_synapses = ARRAY_SIZE(rz_mtu3_mtu2_count_synapses), | 
|  | .ext = rz_mtu3_count_ext, | 
|  | .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), | 
|  | }, | 
|  | { | 
|  | .id = RZ_MTU3_32_BIT_CH, | 
|  | .name = "Channel 1 and 2 (cascaded) Count", | 
|  | .functions_list = rz_mtu3_count_functions, | 
|  | .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), | 
|  | .synapses = rz_mtu3_mtu2_count_synapses, | 
|  | .num_synapses = ARRAY_SIZE(rz_mtu3_mtu2_count_synapses), | 
|  | .ext = rz_mtu3_count_ext, | 
|  | .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), | 
|  | } | 
|  | }; | 
|  |  | 
|  | static const char *const rz_mtu3_ext_input_phase_clock_select[] = { | 
|  | "MTCLKA-MTCLKB", | 
|  | "MTCLKC-MTCLKD", | 
|  | }; | 
|  |  | 
|  | static DEFINE_COUNTER_ENUM(rz_mtu3_ext_input_phase_clock_select_enum, | 
|  | rz_mtu3_ext_input_phase_clock_select); | 
|  |  | 
|  | static struct counter_comp rz_mtu3_device_ext[] = { | 
|  | COUNTER_COMP_DEVICE_BOOL("cascade_counts_enable", | 
|  | rz_mtu3_cascade_counts_enable_get, | 
|  | rz_mtu3_cascade_counts_enable_set), | 
|  | COUNTER_COMP_DEVICE_ENUM("external_input_phase_clock_select", | 
|  | rz_mtu3_ext_input_phase_clock_select_get, | 
|  | rz_mtu3_ext_input_phase_clock_select_set, | 
|  | rz_mtu3_ext_input_phase_clock_select_enum), | 
|  | }; | 
|  |  | 
|  | static int rz_mtu3_cnt_pm_runtime_suspend(struct device *dev) | 
|  | { | 
|  | struct clk *const clk = dev_get_drvdata(dev); | 
|  |  | 
|  | clk_disable_unprepare(clk); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_cnt_pm_runtime_resume(struct device *dev) | 
|  | { | 
|  | struct clk *const clk = dev_get_drvdata(dev); | 
|  |  | 
|  | clk_prepare_enable(clk); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static DEFINE_RUNTIME_DEV_PM_OPS(rz_mtu3_cnt_pm_ops, | 
|  | rz_mtu3_cnt_pm_runtime_suspend, | 
|  | rz_mtu3_cnt_pm_runtime_resume, NULL); | 
|  |  | 
|  | static void rz_mtu3_cnt_pm_disable(void *data) | 
|  | { | 
|  | struct device *dev = data; | 
|  |  | 
|  | pm_runtime_disable(dev); | 
|  | pm_runtime_set_suspended(dev); | 
|  | } | 
|  |  | 
|  | static int rz_mtu3_cnt_probe(struct platform_device *pdev) | 
|  | { | 
|  | struct rz_mtu3 *ddata = dev_get_drvdata(pdev->dev.parent); | 
|  | struct device *dev = &pdev->dev; | 
|  | struct counter_device *counter; | 
|  | struct rz_mtu3_channel *ch; | 
|  | struct rz_mtu3_cnt *priv; | 
|  | unsigned int i; | 
|  | int ret; | 
|  |  | 
|  | counter = devm_counter_alloc(dev, sizeof(*priv)); | 
|  | if (!counter) | 
|  | return -ENOMEM; | 
|  |  | 
|  | priv = counter_priv(counter); | 
|  | priv->clk = ddata->clk; | 
|  | priv->mtu_32bit_max = U32_MAX; | 
|  | priv->ch = &ddata->channels[RZ_MTU3_CHAN_1]; | 
|  | ch = &priv->ch[0]; | 
|  | for (i = 0; i < RZ_MTU3_MAX_HW_CNTR_CHANNELS; i++) { | 
|  | ch->dev = dev; | 
|  | priv->mtu_16bit_max[i] = U16_MAX; | 
|  | ch++; | 
|  | } | 
|  |  | 
|  | mutex_init(&priv->lock); | 
|  | platform_set_drvdata(pdev, priv->clk); | 
|  | clk_prepare_enable(priv->clk); | 
|  | pm_runtime_set_active(&pdev->dev); | 
|  | pm_runtime_enable(&pdev->dev); | 
|  | ret = devm_add_action_or_reset(&pdev->dev, rz_mtu3_cnt_pm_disable, dev); | 
|  | if (ret < 0) | 
|  | goto disable_clock; | 
|  |  | 
|  | counter->name = dev_name(dev); | 
|  | counter->parent = dev; | 
|  | counter->ops = &rz_mtu3_cnt_ops; | 
|  | counter->counts = rz_mtu3_counts; | 
|  | counter->num_counts = ARRAY_SIZE(rz_mtu3_counts); | 
|  | counter->signals = rz_mtu3_signals; | 
|  | counter->num_signals = ARRAY_SIZE(rz_mtu3_signals); | 
|  | counter->ext = rz_mtu3_device_ext; | 
|  | counter->num_ext = ARRAY_SIZE(rz_mtu3_device_ext); | 
|  |  | 
|  | /* Register Counter device */ | 
|  | ret = devm_counter_add(dev, counter); | 
|  | if (ret < 0) { | 
|  | dev_err_probe(dev, ret, "Failed to add counter\n"); | 
|  | goto disable_clock; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | disable_clock: | 
|  | clk_disable_unprepare(priv->clk); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static struct platform_driver rz_mtu3_cnt_driver = { | 
|  | .probe = rz_mtu3_cnt_probe, | 
|  | .driver = { | 
|  | .name = "rz-mtu3-counter", | 
|  | .pm = pm_ptr(&rz_mtu3_cnt_pm_ops), | 
|  | }, | 
|  | }; | 
|  | module_platform_driver(rz_mtu3_cnt_driver); | 
|  |  | 
|  | MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); | 
|  | MODULE_ALIAS("platform:rz-mtu3-counter"); | 
|  | MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a counter driver"); | 
|  | MODULE_LICENSE("GPL"); | 
|  | MODULE_IMPORT_NS(COUNTER); |