2023-03-30 12:16:30 +01:00
// 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 :
2023-04-20 18:02:11 +03:00
if ( ceiling > U16_MAX ) {
mutex_unlock ( & priv - > lock ) ;
2023-03-30 12:16:30 +01:00
return - ERANGE ;
2023-04-20 18:02:11 +03:00
}
2023-03-30 12:16:30 +01:00
priv - > mtu_16bit_max [ ch_id ] = ceiling ;
break ;
case RZ_MTU3_32_BIT_CH :
2023-04-20 18:02:11 +03:00
if ( ceiling > U32_MAX ) {
mutex_unlock ( & priv - > lock ) ;
2023-03-30 12:16:30 +01:00
return - ERANGE ;
2023-04-20 18:02:11 +03:00
}
2023-03-30 12:16:30 +01:00
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 ) {
pm_runtime_get_sync ( ch - > dev ) ;
mutex_lock ( & priv - > lock ) ;
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 ;
mutex_unlock ( & priv - > lock ) ;
pm_runtime_put ( ch - > dev ) ;
}
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 ) ;