// SPDX-License-Identifier: GPL-2.0 /* * Renesas RZ/G2L MTU3a Counter driver * * Copyright (C) 2022 Renesas Electronics Corporation */ #include #include #include #include #include #include #include /* * 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 "); MODULE_ALIAS("platform:rz-mtu3-counter"); MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a counter driver"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(COUNTER);