2017-12-05 15:55:59 +01:00
// SPDX-License-Identifier: GPL-2.0
2017-01-20 10:15:07 +01:00
/*
* Copyright ( C ) STMicroelectronics 2016
*
* Author : Benjamin Gaignard < benjamin . gaignard @ st . com >
*
*/
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
# include <linux/iio/timer/stm32-timer-trigger.h>
# include <linux/iio/trigger.h>
# include <linux/mfd/stm32-timers.h>
2022-02-02 22:41:12 +02:00
# include <linux/mod_devicetable.h>
2017-01-20 10:15:07 +01:00
# include <linux/module.h>
# include <linux/platform_device.h>
2022-02-02 22:41:12 +02:00
# include <linux/property.h>
2017-01-20 10:15:07 +01:00
2017-05-02 14:33:45 +02:00
# define MAX_TRIGGERS 7
2017-04-04 09:47:51 +02:00
# define MAX_VALIDS 5
2017-01-20 10:15:07 +01:00
/* List the triggers created by each timer */
static const void * triggers_table [ ] [ MAX_TRIGGERS ] = {
2017-05-02 14:33:45 +02:00
{ TIM1_TRGO , TIM1_TRGO2 , TIM1_CH1 , TIM1_CH2 , TIM1_CH3 , TIM1_CH4 , } ,
2017-01-20 10:15:07 +01:00
{ TIM2_TRGO , TIM2_CH1 , TIM2_CH2 , TIM2_CH3 , TIM2_CH4 , } ,
{ TIM3_TRGO , TIM3_CH1 , TIM3_CH2 , TIM3_CH3 , TIM3_CH4 , } ,
{ TIM4_TRGO , TIM4_CH1 , TIM4_CH2 , TIM4_CH3 , TIM4_CH4 , } ,
{ TIM5_TRGO , TIM5_CH1 , TIM5_CH2 , TIM5_CH3 , TIM5_CH4 , } ,
{ TIM6_TRGO , } ,
{ TIM7_TRGO , } ,
2017-05-02 14:33:45 +02:00
{ TIM8_TRGO , TIM8_TRGO2 , TIM8_CH1 , TIM8_CH2 , TIM8_CH3 , TIM8_CH4 , } ,
2017-01-20 10:15:07 +01:00
{ TIM9_TRGO , TIM9_CH1 , TIM9_CH2 , } ,
2017-08-03 11:14:14 +02:00
{ TIM10_OC1 , } ,
{ TIM11_OC1 , } ,
2017-01-20 10:15:07 +01:00
{ TIM12_TRGO , TIM12_CH1 , TIM12_CH2 , } ,
2017-08-03 11:14:14 +02:00
{ TIM13_OC1 , } ,
{ TIM14_OC1 , } ,
2017-08-03 11:14:13 +02:00
{ TIM15_TRGO , } ,
2017-08-03 11:14:14 +02:00
{ TIM16_OC1 , } ,
{ TIM17_OC1 , } ,
2017-01-20 10:15:07 +01:00
} ;
2017-04-04 09:47:51 +02:00
/* List the triggers accepted by each timer */
static const void * valids_table [ ] [ MAX_VALIDS ] = {
{ TIM5_TRGO , TIM2_TRGO , TIM3_TRGO , TIM4_TRGO , } ,
{ TIM1_TRGO , TIM8_TRGO , TIM3_TRGO , TIM4_TRGO , } ,
{ TIM1_TRGO , TIM2_TRGO , TIM5_TRGO , TIM4_TRGO , } ,
{ TIM1_TRGO , TIM2_TRGO , TIM3_TRGO , TIM8_TRGO , } ,
{ TIM2_TRGO , TIM3_TRGO , TIM4_TRGO , TIM8_TRGO , } ,
{ } , /* timer 6 */
{ } , /* timer 7 */
{ TIM1_TRGO , TIM2_TRGO , TIM4_TRGO , TIM5_TRGO , } ,
2017-08-03 11:14:14 +02:00
{ TIM2_TRGO , TIM3_TRGO , TIM10_OC1 , TIM11_OC1 , } ,
2017-04-04 09:47:51 +02:00
{ } , /* timer 10 */
{ } , /* timer 11 */
2017-08-03 11:14:14 +02:00
{ TIM4_TRGO , TIM5_TRGO , TIM13_OC1 , TIM14_OC1 , } ,
2017-04-04 09:47:51 +02:00
} ;
2017-08-03 11:14:13 +02:00
static const void * stm32h7_valids_table [ ] [ MAX_VALIDS ] = {
{ TIM15_TRGO , TIM2_TRGO , TIM3_TRGO , TIM4_TRGO , } ,
{ TIM1_TRGO , TIM8_TRGO , TIM3_TRGO , TIM4_TRGO , } ,
{ TIM1_TRGO , TIM2_TRGO , TIM15_TRGO , TIM4_TRGO , } ,
{ TIM1_TRGO , TIM2_TRGO , TIM3_TRGO , TIM8_TRGO , } ,
{ TIM1_TRGO , TIM8_TRGO , TIM3_TRGO , TIM4_TRGO , } ,
{ } , /* timer 6 */
{ } , /* timer 7 */
{ TIM1_TRGO , TIM2_TRGO , TIM4_TRGO , TIM5_TRGO , } ,
{ } , /* timer 9 */
{ } , /* timer 10 */
{ } , /* timer 11 */
2017-08-03 11:14:14 +02:00
{ TIM4_TRGO , TIM5_TRGO , TIM13_OC1 , TIM14_OC1 , } ,
2017-08-03 11:14:13 +02:00
{ } , /* timer 13 */
{ } , /* timer 14 */
2017-08-03 11:14:14 +02:00
{ TIM1_TRGO , TIM3_TRGO , TIM16_OC1 , TIM17_OC1 , } ,
{ } , /* timer 16 */
{ } , /* timer 17 */
2017-08-03 11:14:13 +02:00
} ;
2020-03-03 15:59:45 +01:00
struct stm32_timer_trigger_regs {
u32 cr1 ;
u32 cr2 ;
u32 psc ;
u32 arr ;
u32 cnt ;
u32 smcr ;
} ;
2017-01-20 10:15:07 +01:00
struct stm32_timer_trigger {
struct device * dev ;
struct regmap * regmap ;
struct clk * clk ;
2020-03-03 15:59:44 +01:00
bool enabled ;
2017-01-20 10:15:07 +01:00
u32 max_arr ;
const void * triggers ;
2017-04-04 09:47:51 +02:00
const void * valids ;
2017-05-02 14:33:45 +02:00
bool has_trgo2 ;
2020-02-14 17:23:57 +01:00
struct mutex lock ; /* concurrent sysfs configuration */
struct list_head tr_list ;
2020-03-03 15:59:45 +01:00
struct stm32_timer_trigger_regs bak ;
2017-01-20 10:15:07 +01:00
} ;
2017-08-03 11:14:13 +02:00
struct stm32_timer_trigger_cfg {
const void * ( * valids_table ) [ MAX_VALIDS ] ;
const unsigned int num_valids_table ;
} ;
2017-05-02 14:33:45 +02:00
static bool stm32_timer_is_trgo2_name ( const char * name )
{
return ! ! strstr ( name , " trgo2 " ) ;
}
2017-08-03 11:14:14 +02:00
static bool stm32_timer_is_trgo_name ( const char * name )
{
return ( ! ! strstr ( name , " trgo " ) & & ! strstr ( name , " trgo2 " ) ) ;
}
2017-01-20 10:15:07 +01:00
static int stm32_timer_start ( struct stm32_timer_trigger * priv ,
2017-05-02 14:33:45 +02:00
struct iio_trigger * trig ,
2017-01-20 10:15:07 +01:00
unsigned int frequency )
{
unsigned long long prd , div ;
int prescaler = 0 ;
2020-02-14 17:23:57 +01:00
u32 ccer ;
2017-01-20 10:15:07 +01:00
/* Period and prescaler values depends of clock rate */
div = ( unsigned long long ) clk_get_rate ( priv - > clk ) ;
do_div ( div , frequency ) ;
prd = div ;
/*
* Increase prescaler value until we get a result that fit
* with auto reload register maximum value .
*/
while ( div > priv - > max_arr ) {
prescaler + + ;
div = prd ;
do_div ( div , ( prescaler + 1 ) ) ;
}
prd = div ;
if ( prescaler > MAX_TIM_PSC ) {
dev_err ( priv - > dev , " prescaler exceeds the maximum value \n " ) ;
return - EINVAL ;
}
/* Check if nobody else use the timer */
regmap_read ( priv - > regmap , TIM_CCER , & ccer ) ;
if ( ccer & TIM_CCER_CCXE )
return - EBUSY ;
2020-02-14 17:23:57 +01:00
mutex_lock ( & priv - > lock ) ;
2020-03-03 15:59:44 +01:00
if ( ! priv - > enabled ) {
priv - > enabled = true ;
2017-01-20 10:15:07 +01:00
clk_enable ( priv - > clk ) ;
2020-02-14 17:23:57 +01:00
}
2017-01-20 10:15:07 +01:00
regmap_write ( priv - > regmap , TIM_PSC , prescaler ) ;
regmap_write ( priv - > regmap , TIM_ARR , prd - 1 ) ;
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_ARPE , TIM_CR1_ARPE ) ;
/* Force master mode to update mode */
2017-05-02 14:33:45 +02:00
if ( stm32_timer_is_trgo2_name ( trig - > name ) )
regmap_update_bits ( priv - > regmap , TIM_CR2 , TIM_CR2_MMS2 ,
0x2 < < TIM_CR2_MMS2_SHIFT ) ;
else
regmap_update_bits ( priv - > regmap , TIM_CR2 , TIM_CR2_MMS ,
0x2 < < TIM_CR2_MMS_SHIFT ) ;
2017-01-20 10:15:07 +01:00
/* Make sure that registers are updated */
regmap_update_bits ( priv - > regmap , TIM_EGR , TIM_EGR_UG , TIM_EGR_UG ) ;
/* Enable controller */
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_CEN , TIM_CR1_CEN ) ;
2020-02-14 17:23:57 +01:00
mutex_unlock ( & priv - > lock ) ;
2017-01-20 10:15:07 +01:00
return 0 ;
}
2020-02-14 17:46:35 +01:00
static void stm32_timer_stop ( struct stm32_timer_trigger * priv ,
struct iio_trigger * trig )
2017-01-20 10:15:07 +01:00
{
2020-02-14 17:23:57 +01:00
u32 ccer ;
2017-01-20 10:15:07 +01:00
regmap_read ( priv - > regmap , TIM_CCER , & ccer ) ;
if ( ccer & TIM_CCER_CCXE )
return ;
2020-02-14 17:23:57 +01:00
mutex_lock ( & priv - > lock ) ;
2017-01-20 10:15:07 +01:00
/* Stop timer */
2017-09-18 12:05:31 +02:00
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_ARPE , 0 ) ;
2017-01-20 10:15:07 +01:00
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_CEN , 0 ) ;
regmap_write ( priv - > regmap , TIM_PSC , 0 ) ;
regmap_write ( priv - > regmap , TIM_ARR , 0 ) ;
2020-02-14 17:46:35 +01:00
/* Force disable master mode */
if ( stm32_timer_is_trgo2_name ( trig - > name ) )
regmap_update_bits ( priv - > regmap , TIM_CR2 , TIM_CR2_MMS2 , 0 ) ;
else
regmap_update_bits ( priv - > regmap , TIM_CR2 , TIM_CR2_MMS , 0 ) ;
2017-01-20 10:15:07 +01:00
/* Make sure that registers are updated */
regmap_update_bits ( priv - > regmap , TIM_EGR , TIM_EGR_UG , TIM_EGR_UG ) ;
2020-02-14 17:23:57 +01:00
2020-03-03 15:59:44 +01:00
if ( priv - > enabled ) {
priv - > enabled = false ;
2020-02-14 17:23:57 +01:00
clk_disable ( priv - > clk ) ;
}
mutex_unlock ( & priv - > lock ) ;
2017-01-20 10:15:07 +01:00
}
static ssize_t stm32_tt_store_frequency ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t len )
{
struct iio_trigger * trig = to_iio_trigger ( dev ) ;
struct stm32_timer_trigger * priv = iio_trigger_get_drvdata ( trig ) ;
unsigned int freq ;
int ret ;
ret = kstrtouint ( buf , 10 , & freq ) ;
if ( ret )
return ret ;
if ( freq = = 0 ) {
2020-02-14 17:46:35 +01:00
stm32_timer_stop ( priv , trig ) ;
2017-01-20 10:15:07 +01:00
} else {
2017-05-02 14:33:45 +02:00
ret = stm32_timer_start ( priv , trig , freq ) ;
2017-01-20 10:15:07 +01:00
if ( ret )
return ret ;
}
return len ;
}
static ssize_t stm32_tt_read_frequency ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct iio_trigger * trig = to_iio_trigger ( dev ) ;
struct stm32_timer_trigger * priv = iio_trigger_get_drvdata ( trig ) ;
u32 psc , arr , cr1 ;
unsigned long long freq = 0 ;
regmap_read ( priv - > regmap , TIM_CR1 , & cr1 ) ;
regmap_read ( priv - > regmap , TIM_PSC , & psc ) ;
regmap_read ( priv - > regmap , TIM_ARR , & arr ) ;
2017-04-07 13:53:46 +02:00
if ( cr1 & TIM_CR1_CEN ) {
2017-01-20 10:15:07 +01:00
freq = ( unsigned long long ) clk_get_rate ( priv - > clk ) ;
2017-04-07 13:53:46 +02:00
do_div ( freq , psc + 1 ) ;
do_div ( freq , arr + 1 ) ;
2017-01-20 10:15:07 +01:00
}
return sprintf ( buf , " %d \n " , ( unsigned int ) freq ) ;
}
static IIO_DEV_ATTR_SAMP_FREQ ( 0660 ,
stm32_tt_read_frequency ,
stm32_tt_store_frequency ) ;
2017-05-02 14:33:45 +02:00
# define MASTER_MODE_MAX 7
# define MASTER_MODE2_MAX 15
2017-01-20 10:15:07 +01:00
static char * master_mode_table [ ] = {
" reset " ,
" enable " ,
" update " ,
" compare_pulse " ,
" OC1REF " ,
" OC2REF " ,
" OC3REF " ,
2017-05-02 14:33:45 +02:00
" OC4REF " ,
/* Master mode selection 2 only */
" OC5REF " ,
" OC6REF " ,
" compare_pulse_OC4REF " ,
" compare_pulse_OC6REF " ,
" compare_pulse_OC4REF_r_or_OC6REF_r " ,
" compare_pulse_OC4REF_r_or_OC6REF_f " ,
" compare_pulse_OC5REF_r_or_OC6REF_r " ,
" compare_pulse_OC5REF_r_or_OC6REF_f " ,
2017-01-20 10:15:07 +01:00
} ;
static ssize_t stm32_tt_show_master_mode ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
2017-04-04 09:47:51 +02:00
struct stm32_timer_trigger * priv = dev_get_drvdata ( dev ) ;
2017-05-02 14:33:45 +02:00
struct iio_trigger * trig = to_iio_trigger ( dev ) ;
2017-01-20 10:15:07 +01:00
u32 cr2 ;
regmap_read ( priv - > regmap , TIM_CR2 , & cr2 ) ;
2017-05-02 14:33:45 +02:00
if ( stm32_timer_is_trgo2_name ( trig - > name ) )
cr2 = ( cr2 & TIM_CR2_MMS2 ) > > TIM_CR2_MMS2_SHIFT ;
else
cr2 = ( cr2 & TIM_CR2_MMS ) > > TIM_CR2_MMS_SHIFT ;
2017-01-20 10:15:07 +01:00
2021-04-12 16:39:11 +08:00
return sysfs_emit ( buf , " %s \n " , master_mode_table [ cr2 ] ) ;
2017-01-20 10:15:07 +01:00
}
static ssize_t stm32_tt_store_master_mode ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t len )
{
2017-04-04 09:47:51 +02:00
struct stm32_timer_trigger * priv = dev_get_drvdata ( dev ) ;
2017-05-02 14:33:45 +02:00
struct iio_trigger * trig = to_iio_trigger ( dev ) ;
u32 mask , shift , master_mode_max ;
2017-01-20 10:15:07 +01:00
int i ;
2017-05-02 14:33:45 +02:00
if ( stm32_timer_is_trgo2_name ( trig - > name ) ) {
mask = TIM_CR2_MMS2 ;
shift = TIM_CR2_MMS2_SHIFT ;
master_mode_max = MASTER_MODE2_MAX ;
} else {
mask = TIM_CR2_MMS ;
shift = TIM_CR2_MMS_SHIFT ;
master_mode_max = MASTER_MODE_MAX ;
}
for ( i = 0 ; i < = master_mode_max ; i + + ) {
2017-01-20 10:15:07 +01:00
if ( ! strncmp ( master_mode_table [ i ] , buf ,
strlen ( master_mode_table [ i ] ) ) ) {
2020-02-14 17:23:57 +01:00
mutex_lock ( & priv - > lock ) ;
2020-03-03 15:59:44 +01:00
if ( ! priv - > enabled ) {
2020-02-14 17:23:57 +01:00
/* Clock should be enabled first */
2020-03-03 15:59:44 +01:00
priv - > enabled = true ;
2020-02-14 17:23:57 +01:00
clk_enable ( priv - > clk ) ;
}
2017-05-02 14:33:45 +02:00
regmap_update_bits ( priv - > regmap , TIM_CR2 , mask ,
i < < shift ) ;
2020-02-14 17:23:57 +01:00
mutex_unlock ( & priv - > lock ) ;
2017-01-20 10:15:07 +01:00
return len ;
}
}
return - EINVAL ;
}
2017-05-02 14:33:45 +02:00
static ssize_t stm32_tt_show_master_mode_avail ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct iio_trigger * trig = to_iio_trigger ( dev ) ;
unsigned int i , master_mode_max ;
size_t len = 0 ;
if ( stm32_timer_is_trgo2_name ( trig - > name ) )
master_mode_max = MASTER_MODE2_MAX ;
else
master_mode_max = MASTER_MODE_MAX ;
for ( i = 0 ; i < = master_mode_max ; i + + )
len + = scnprintf ( buf + len , PAGE_SIZE - len ,
" %s " , master_mode_table [ i ] ) ;
/* replace trailing space by newline */
buf [ len - 1 ] = ' \n ' ;
return len ;
}
static IIO_DEVICE_ATTR ( master_mode_available , 0444 ,
stm32_tt_show_master_mode_avail , NULL , 0 ) ;
2017-01-20 10:15:07 +01:00
static IIO_DEVICE_ATTR ( master_mode , 0660 ,
stm32_tt_show_master_mode ,
stm32_tt_store_master_mode ,
0 ) ;
static struct attribute * stm32_trigger_attrs [ ] = {
& iio_dev_attr_sampling_frequency . dev_attr . attr ,
& iio_dev_attr_master_mode . dev_attr . attr ,
2017-05-02 14:33:45 +02:00
& iio_dev_attr_master_mode_available . dev_attr . attr ,
2017-01-20 10:15:07 +01:00
NULL ,
} ;
static const struct attribute_group stm32_trigger_attr_group = {
. attrs = stm32_trigger_attrs ,
} ;
static const struct attribute_group * stm32_trigger_attr_groups [ ] = {
& stm32_trigger_attr_group ,
NULL ,
} ;
static const struct iio_trigger_ops timer_trigger_ops = {
} ;
2020-02-14 17:23:57 +01:00
static void stm32_unregister_iio_triggers ( struct stm32_timer_trigger * priv )
{
struct iio_trigger * tr ;
list_for_each_entry ( tr , & priv - > tr_list , alloc_list )
iio_trigger_unregister ( tr ) ;
}
static int stm32_register_iio_triggers ( struct stm32_timer_trigger * priv )
2017-01-20 10:15:07 +01:00
{
int ret ;
const char * const * cur = priv - > triggers ;
2020-02-14 17:23:57 +01:00
INIT_LIST_HEAD ( & priv - > tr_list ) ;
2017-01-20 10:15:07 +01:00
while ( cur & & * cur ) {
struct iio_trigger * trig ;
2017-08-03 11:14:14 +02:00
bool cur_is_trgo = stm32_timer_is_trgo_name ( * cur ) ;
2017-05-02 14:33:45 +02:00
bool cur_is_trgo2 = stm32_timer_is_trgo2_name ( * cur ) ;
if ( cur_is_trgo2 & & ! priv - > has_trgo2 ) {
cur + + ;
continue ;
}
2017-01-20 10:15:07 +01:00
trig = devm_iio_trigger_alloc ( priv - > dev , " %s " , * cur ) ;
if ( ! trig )
return - ENOMEM ;
trig - > dev . parent = priv - > dev - > parent ;
trig - > ops = & timer_trigger_ops ;
/*
* sampling frequency and master mode attributes
2017-08-03 11:14:14 +02:00
* should only be available on trgo / trgo2 triggers
2017-01-20 10:15:07 +01:00
*/
2017-08-03 11:14:14 +02:00
if ( cur_is_trgo | | cur_is_trgo2 )
2017-01-20 10:15:07 +01:00
trig - > dev . groups = stm32_trigger_attr_groups ;
iio_trigger_set_drvdata ( trig , priv ) ;
2020-02-14 17:23:57 +01:00
ret = iio_trigger_register ( trig ) ;
if ( ret ) {
stm32_unregister_iio_triggers ( priv ) ;
2017-01-20 10:15:07 +01:00
return ret ;
2020-02-14 17:23:57 +01:00
}
list_add_tail ( & trig - > alloc_list , & priv - > tr_list ) ;
2017-01-20 10:15:07 +01:00
cur + + ;
}
return 0 ;
}
2017-04-04 09:47:51 +02:00
static int stm32_counter_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
2017-07-27 18:19:00 +02:00
u32 dat ;
2017-04-04 09:47:51 +02:00
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
2017-07-27 18:19:00 +02:00
regmap_read ( priv - > regmap , TIM_CNT , & dat ) ;
* val = dat ;
return IIO_VAL_INT ;
2017-04-04 09:47:51 +02:00
2017-07-27 18:19:00 +02:00
case IIO_CHAN_INFO_ENABLE :
regmap_read ( priv - > regmap , TIM_CR1 , & dat ) ;
* val = ( dat & TIM_CR1_CEN ) ? 1 : 0 ;
2017-04-04 09:47:51 +02:00
return IIO_VAL_INT ;
2017-07-27 18:19:00 +02:00
case IIO_CHAN_INFO_SCALE :
regmap_read ( priv - > regmap , TIM_SMCR , & dat ) ;
dat & = TIM_SMCR_SMS ;
2017-04-04 09:47:51 +02:00
* val = 1 ;
* val2 = 0 ;
/* in quadrature case scale = 0.25 */
2017-07-27 18:19:00 +02:00
if ( dat = = 3 )
2017-04-04 09:47:51 +02:00
* val2 = 2 ;
return IIO_VAL_FRACTIONAL_LOG2 ;
}
return - EINVAL ;
}
static int stm32_counter_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val , int val2 , long mask )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
2017-07-27 18:18:58 +02:00
return regmap_write ( priv - > regmap , TIM_CNT , val ) ;
2017-04-04 09:47:51 +02:00
case IIO_CHAN_INFO_SCALE :
/* fixed scale */
return - EINVAL ;
2017-07-27 18:19:00 +02:00
case IIO_CHAN_INFO_ENABLE :
2020-02-14 17:23:57 +01:00
mutex_lock ( & priv - > lock ) ;
2017-07-27 18:19:00 +02:00
if ( val ) {
2020-03-03 15:59:44 +01:00
if ( ! priv - > enabled ) {
priv - > enabled = true ;
2017-07-27 18:19:00 +02:00
clk_enable ( priv - > clk ) ;
2020-02-14 17:23:57 +01:00
}
2017-07-27 18:19:00 +02:00
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_CEN ,
TIM_CR1_CEN ) ;
} else {
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_CEN ,
0 ) ;
2020-03-03 15:59:44 +01:00
if ( priv - > enabled ) {
priv - > enabled = false ;
2017-07-27 18:19:00 +02:00
clk_disable ( priv - > clk ) ;
2020-02-14 17:23:57 +01:00
}
2017-07-27 18:19:00 +02:00
}
2020-02-14 17:23:57 +01:00
mutex_unlock ( & priv - > lock ) ;
2017-07-27 18:19:00 +02:00
return 0 ;
2017-04-04 09:47:51 +02:00
}
return - EINVAL ;
}
2017-04-27 15:29:16 +02:00
static int stm32_counter_validate_trigger ( struct iio_dev * indio_dev ,
struct iio_trigger * trig )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
const char * const * cur = priv - > valids ;
unsigned int i = 0 ;
if ( ! is_stm32_timer_trigger ( trig ) )
return - EINVAL ;
while ( cur & & * cur ) {
if ( ! strncmp ( trig - > name , * cur , strlen ( trig - > name ) ) ) {
regmap_update_bits ( priv - > regmap ,
TIM_SMCR , TIM_SMCR_TS ,
i < < TIM_SMCR_TS_SHIFT ) ;
return 0 ;
}
cur + + ;
i + + ;
}
return - EINVAL ;
}
2017-04-04 09:47:51 +02:00
static const struct iio_info stm32_trigger_info = {
2017-04-27 15:29:16 +02:00
. validate_trigger = stm32_counter_validate_trigger ,
2017-04-04 09:47:51 +02:00
. read_raw = stm32_counter_read_raw ,
. write_raw = stm32_counter_write_raw
} ;
2017-04-27 15:29:16 +02:00
static const char * const stm32_trigger_modes [ ] = {
" trigger " ,
} ;
static int stm32_set_trigger_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan ,
unsigned int mode )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
regmap_update_bits ( priv - > regmap , TIM_SMCR , TIM_SMCR_SMS , TIM_SMCR_SMS ) ;
return 0 ;
}
static int stm32_get_trigger_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
u32 smcr ;
regmap_read ( priv - > regmap , TIM_SMCR , & smcr ) ;
2017-08-03 11:22:17 +02:00
return ( smcr & TIM_SMCR_SMS ) = = TIM_SMCR_SMS ? 0 : - EINVAL ;
2017-04-27 15:29:16 +02:00
}
static const struct iio_enum stm32_trigger_mode_enum = {
. items = stm32_trigger_modes ,
. num_items = ARRAY_SIZE ( stm32_trigger_modes ) ,
. set = stm32_set_trigger_mode ,
. get = stm32_get_trigger_mode
} ;
2017-04-04 09:47:52 +02:00
static const char * const stm32_enable_modes [ ] = {
" always " ,
" gated " ,
" triggered " ,
} ;
static int stm32_enable_mode2sms ( int mode )
{
switch ( mode ) {
case 0 :
return 0 ;
case 1 :
return 5 ;
case 2 :
return 6 ;
}
return - EINVAL ;
}
static int stm32_set_enable_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan ,
unsigned int mode )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
int sms = stm32_enable_mode2sms ( mode ) ;
if ( sms < 0 )
return sms ;
2017-07-27 18:19:00 +02:00
/*
* Triggered mode sets CEN bit automatically by hardware . So , first
* enable counter clock , so it can use it . Keeps it in sync with CEN .
*/
2020-02-14 17:23:57 +01:00
mutex_lock ( & priv - > lock ) ;
2020-03-03 15:59:44 +01:00
if ( sms = = 6 & & ! priv - > enabled ) {
2020-02-14 17:23:57 +01:00
clk_enable ( priv - > clk ) ;
2020-03-03 15:59:44 +01:00
priv - > enabled = true ;
2017-07-27 18:19:00 +02:00
}
2020-02-14 17:23:57 +01:00
mutex_unlock ( & priv - > lock ) ;
2017-04-04 09:47:52 +02:00
regmap_update_bits ( priv - > regmap , TIM_SMCR , TIM_SMCR_SMS , sms ) ;
return 0 ;
}
static int stm32_sms2enable_mode ( int mode )
{
switch ( mode ) {
case 0 :
return 0 ;
case 5 :
return 1 ;
case 6 :
return 2 ;
}
return - EINVAL ;
}
static int stm32_get_enable_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
u32 smcr ;
regmap_read ( priv - > regmap , TIM_SMCR , & smcr ) ;
smcr & = TIM_SMCR_SMS ;
return stm32_sms2enable_mode ( smcr ) ;
}
static const struct iio_enum stm32_enable_mode_enum = {
. items = stm32_enable_modes ,
. num_items = ARRAY_SIZE ( stm32_enable_modes ) ,
. set = stm32_set_enable_mode ,
. get = stm32_get_enable_mode
} ;
2017-04-04 09:47:51 +02:00
static ssize_t stm32_count_get_preset ( struct iio_dev * indio_dev ,
uintptr_t private ,
const struct iio_chan_spec * chan ,
char * buf )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
u32 arr ;
regmap_read ( priv - > regmap , TIM_ARR , & arr ) ;
return snprintf ( buf , PAGE_SIZE , " %u \n " , arr ) ;
}
static ssize_t stm32_count_set_preset ( struct iio_dev * indio_dev ,
uintptr_t private ,
const struct iio_chan_spec * chan ,
const char * buf , size_t len )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
unsigned int preset ;
int ret ;
ret = kstrtouint ( buf , 0 , & preset ) ;
if ( ret )
return ret ;
2017-09-18 12:05:30 +02:00
/* TIMx_ARR register shouldn't be buffered (ARPE=0) */
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_ARPE , 0 ) ;
2017-04-04 09:47:51 +02:00
regmap_write ( priv - > regmap , TIM_ARR , preset ) ;
return len ;
}
static const struct iio_chan_spec_ext_info stm32_trigger_count_info [ ] = {
{
. name = " preset " ,
. shared = IIO_SEPARATE ,
. read = stm32_count_get_preset ,
. write = stm32_count_set_preset
} ,
2017-04-04 09:47:52 +02:00
IIO_ENUM ( " enable_mode " , IIO_SEPARATE , & stm32_enable_mode_enum ) ,
2021-11-19 10:56:27 +02:00
IIO_ENUM_AVAILABLE ( " enable_mode " , IIO_SHARED_BY_TYPE , & stm32_enable_mode_enum ) ,
2017-04-27 15:29:16 +02:00
IIO_ENUM ( " trigger_mode " , IIO_SEPARATE , & stm32_trigger_mode_enum ) ,
2021-11-19 10:56:27 +02:00
IIO_ENUM_AVAILABLE ( " trigger_mode " , IIO_SHARED_BY_TYPE , & stm32_trigger_mode_enum ) ,
2017-04-04 09:47:51 +02:00
{ }
} ;
static const struct iio_chan_spec stm32_trigger_channel = {
. type = IIO_COUNT ,
. channel = 0 ,
2017-07-27 18:19:00 +02:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_ENABLE ) |
BIT ( IIO_CHAN_INFO_SCALE ) ,
2017-04-04 09:47:51 +02:00
. ext_info = stm32_trigger_count_info ,
. indexed = 1
} ;
static struct stm32_timer_trigger * stm32_setup_counter_device ( struct device * dev )
{
struct iio_dev * indio_dev ;
int ret ;
indio_dev = devm_iio_device_alloc ( dev ,
sizeof ( struct stm32_timer_trigger ) ) ;
if ( ! indio_dev )
return NULL ;
indio_dev - > name = dev_name ( dev ) ;
indio_dev - > info = & stm32_trigger_info ;
2017-04-27 15:29:16 +02:00
indio_dev - > modes = INDIO_HARDWARE_TRIGGERED ;
2017-04-04 09:47:51 +02:00
indio_dev - > num_channels = 1 ;
indio_dev - > channels = & stm32_trigger_channel ;
ret = devm_iio_device_register ( dev , indio_dev ) ;
if ( ret )
return NULL ;
return iio_priv ( indio_dev ) ;
}
2017-01-20 10:15:07 +01:00
/**
* is_stm32_timer_trigger
* @ trig : trigger to be checked
*
* return true if the trigger is a valid stm32 iio timer trigger
* either return false
*/
bool is_stm32_timer_trigger ( struct iio_trigger * trig )
{
return ( trig - > ops = = & timer_trigger_ops ) ;
}
EXPORT_SYMBOL ( is_stm32_timer_trigger ) ;
2017-05-02 14:33:45 +02:00
static void stm32_timer_detect_trgo2 ( struct stm32_timer_trigger * priv )
{
u32 val ;
/*
* Master mode selection 2 bits can only be written and read back when
* timer supports it .
*/
regmap_update_bits ( priv - > regmap , TIM_CR2 , TIM_CR2_MMS2 , TIM_CR2_MMS2 ) ;
regmap_read ( priv - > regmap , TIM_CR2 , & val ) ;
regmap_update_bits ( priv - > regmap , TIM_CR2 , TIM_CR2_MMS2 , 0 ) ;
priv - > has_trgo2 = ! ! val ;
}
2017-01-20 10:15:07 +01:00
static int stm32_timer_trigger_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct stm32_timer_trigger * priv ;
struct stm32_timers * ddata = dev_get_drvdata ( pdev - > dev . parent ) ;
2017-08-03 11:14:13 +02:00
const struct stm32_timer_trigger_cfg * cfg ;
2017-01-20 10:15:07 +01:00
unsigned int index ;
int ret ;
2022-02-02 22:41:12 +02:00
ret = device_property_read_u32 ( dev , " reg " , & index ) ;
if ( ret )
return ret ;
2017-01-20 10:15:07 +01:00
2022-02-02 22:41:12 +02:00
cfg = device_get_match_data ( dev ) ;
2017-08-03 11:14:13 +02:00
2017-04-04 09:47:51 +02:00
if ( index > = ARRAY_SIZE ( triggers_table ) | |
2017-08-03 11:14:13 +02:00
index > = cfg - > num_valids_table )
2017-01-20 10:15:07 +01:00
return - EINVAL ;
2017-04-04 09:47:51 +02:00
/* Create an IIO device only if we have triggers to be validated */
2017-08-03 11:14:13 +02:00
if ( * cfg - > valids_table [ index ] )
2017-04-04 09:47:51 +02:00
priv = stm32_setup_counter_device ( dev ) ;
else
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
2017-01-20 10:15:07 +01:00
if ( ! priv )
return - ENOMEM ;
priv - > dev = dev ;
priv - > regmap = ddata - > regmap ;
priv - > clk = ddata - > clk ;
priv - > max_arr = ddata - > max_arr ;
priv - > triggers = triggers_table [ index ] ;
2017-08-03 11:14:13 +02:00
priv - > valids = cfg - > valids_table [ index ] ;
2017-05-02 14:33:45 +02:00
stm32_timer_detect_trgo2 ( priv ) ;
2020-02-14 17:23:57 +01:00
mutex_init ( & priv - > lock ) ;
2017-01-20 10:15:07 +01:00
2020-02-14 17:23:57 +01:00
ret = stm32_register_iio_triggers ( priv ) ;
2017-01-20 10:15:07 +01:00
if ( ret )
return ret ;
platform_set_drvdata ( pdev , priv ) ;
return 0 ;
}
2020-02-14 17:23:57 +01:00
static int stm32_timer_trigger_remove ( struct platform_device * pdev )
{
struct stm32_timer_trigger * priv = platform_get_drvdata ( pdev ) ;
u32 val ;
/* Unregister triggers before everything can be safely turned off */
stm32_unregister_iio_triggers ( priv ) ;
/* Check if nobody else use the timer, then disable it */
regmap_read ( priv - > regmap , TIM_CCER , & val ) ;
if ( ! ( val & TIM_CCER_CCXE ) )
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_CEN , 0 ) ;
2020-03-03 15:59:44 +01:00
if ( priv - > enabled )
2020-02-14 17:23:57 +01:00
clk_disable ( priv - > clk ) ;
return 0 ;
}
2022-01-30 19:31:47 +00:00
static int stm32_timer_trigger_suspend ( struct device * dev )
2020-03-03 15:59:45 +01:00
{
struct stm32_timer_trigger * priv = dev_get_drvdata ( dev ) ;
/* Only take care of enabled timer: don't disturb other MFD child */
if ( priv - > enabled ) {
/* Backup registers that may get lost in low power mode */
regmap_read ( priv - > regmap , TIM_CR1 , & priv - > bak . cr1 ) ;
regmap_read ( priv - > regmap , TIM_CR2 , & priv - > bak . cr2 ) ;
regmap_read ( priv - > regmap , TIM_PSC , & priv - > bak . psc ) ;
regmap_read ( priv - > regmap , TIM_ARR , & priv - > bak . arr ) ;
regmap_read ( priv - > regmap , TIM_CNT , & priv - > bak . cnt ) ;
regmap_read ( priv - > regmap , TIM_SMCR , & priv - > bak . smcr ) ;
/* Disable the timer */
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_CEN , 0 ) ;
clk_disable ( priv - > clk ) ;
}
return 0 ;
}
2022-01-30 19:31:47 +00:00
static int stm32_timer_trigger_resume ( struct device * dev )
2020-03-03 15:59:45 +01:00
{
struct stm32_timer_trigger * priv = dev_get_drvdata ( dev ) ;
int ret ;
if ( priv - > enabled ) {
ret = clk_enable ( priv - > clk ) ;
if ( ret )
return ret ;
/* restore master/slave modes */
regmap_write ( priv - > regmap , TIM_SMCR , priv - > bak . smcr ) ;
regmap_write ( priv - > regmap , TIM_CR2 , priv - > bak . cr2 ) ;
/* restore sampling_frequency (trgo / trgo2 triggers) */
regmap_write ( priv - > regmap , TIM_PSC , priv - > bak . psc ) ;
regmap_write ( priv - > regmap , TIM_ARR , priv - > bak . arr ) ;
regmap_write ( priv - > regmap , TIM_CNT , priv - > bak . cnt ) ;
/* Also re-enables the timer */
regmap_write ( priv - > regmap , TIM_CR1 , priv - > bak . cr1 ) ;
}
return 0 ;
}
2022-01-30 19:31:47 +00:00
static DEFINE_SIMPLE_DEV_PM_OPS ( stm32_timer_trigger_pm_ops ,
stm32_timer_trigger_suspend ,
stm32_timer_trigger_resume ) ;
2020-03-03 15:59:45 +01:00
2017-08-03 11:14:13 +02:00
static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
. valids_table = valids_table ,
. num_valids_table = ARRAY_SIZE ( valids_table ) ,
} ;
static const struct stm32_timer_trigger_cfg stm32h7_timer_trg_cfg = {
. valids_table = stm32h7_valids_table ,
. num_valids_table = ARRAY_SIZE ( stm32h7_valids_table ) ,
} ;
2017-01-20 10:15:07 +01:00
static const struct of_device_id stm32_trig_of_match [ ] = {
2017-08-03 11:14:13 +02:00
{
. compatible = " st,stm32-timer-trigger " ,
. data = ( void * ) & stm32_timer_trg_cfg ,
} , {
. compatible = " st,stm32h7-timer-trigger " ,
. data = ( void * ) & stm32h7_timer_trg_cfg ,
} ,
2017-01-20 10:15:07 +01:00
{ /* end node */ } ,
} ;
MODULE_DEVICE_TABLE ( of , stm32_trig_of_match ) ;
static struct platform_driver stm32_timer_trigger_driver = {
. probe = stm32_timer_trigger_probe ,
2020-02-14 17:23:57 +01:00
. remove = stm32_timer_trigger_remove ,
2017-01-20 10:15:07 +01:00
. driver = {
. name = " stm32-timer-trigger " ,
. of_match_table = stm32_trig_of_match ,
2022-01-30 19:31:47 +00:00
. pm = pm_sleep_ptr ( & stm32_timer_trigger_pm_ops ) ,
2017-01-20 10:15:07 +01:00
} ,
} ;
module_platform_driver ( stm32_timer_trigger_driver ) ;
2021-11-25 18:28:48 +00:00
MODULE_ALIAS ( " platform:stm32-timer-trigger " ) ;
2017-01-20 10:15:07 +01:00
MODULE_DESCRIPTION ( " STMicroelectronics STM32 Timer Trigger driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;