2017-01-20 10:15:07 +01:00
/*
* Copyright ( C ) STMicroelectronics 2016
*
* Author : Benjamin Gaignard < benjamin . gaignard @ st . com >
*
* License terms : GNU General Public License ( GPL ) , version 2
*/
# 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>
# include <linux/module.h>
# include <linux/platform_device.h>
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 , } ,
{ } , /* timer 10 */
{ } , /* timer 11 */
{ TIM12_TRGO , TIM12_CH1 , TIM12_CH2 , } ,
} ;
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 , } ,
{ TIM2_TRGO , TIM3_TRGO , } ,
{ } , /* timer 10 */
{ } , /* timer 11 */
{ TIM4_TRGO , TIM5_TRGO , } ,
} ;
2017-01-20 10:15:07 +01:00
struct stm32_timer_trigger {
struct device * dev ;
struct regmap * regmap ;
struct clk * clk ;
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 ;
2017-01-20 10:15:07 +01:00
} ;
2017-05-02 14:33:45 +02:00
static bool stm32_timer_is_trgo2_name ( const char * name )
{
return ! ! 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 ;
u32 ccer , cr1 ;
/* 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 ;
regmap_read ( priv - > regmap , TIM_CR1 , & cr1 ) ;
if ( ! ( cr1 & TIM_CR1_CEN ) )
clk_enable ( priv - > clk ) ;
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 ) ;
return 0 ;
}
static void stm32_timer_stop ( struct stm32_timer_trigger * priv )
{
u32 ccer , cr1 ;
regmap_read ( priv - > regmap , TIM_CCER , & ccer ) ;
if ( ccer & TIM_CCER_CCXE )
return ;
regmap_read ( priv - > regmap , TIM_CR1 , & cr1 ) ;
if ( cr1 & TIM_CR1_CEN )
clk_disable ( priv - > clk ) ;
/* Stop timer */
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 ) ;
/* Make sure that registers are updated */
regmap_update_bits ( priv - > regmap , TIM_EGR , TIM_EGR_UG , TIM_EGR_UG ) ;
}
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 ) {
stm32_timer_stop ( priv ) ;
} 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
return snprintf ( buf , PAGE_SIZE , " %s \n " , master_mode_table [ cr2 ] ) ;
}
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 ] ) ) ) {
2017-05-02 14:33:45 +02:00
regmap_update_bits ( priv - > regmap , TIM_CR2 , mask ,
i < < 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 ) ;
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 = {
. owner = THIS_MODULE ,
} ;
static int stm32_setup_iio_triggers ( struct stm32_timer_trigger * priv )
{
int ret ;
const char * const * cur = priv - > triggers ;
while ( cur & & * cur ) {
struct iio_trigger * trig ;
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
* should only be available on trgo trigger which
* is always the first in the list .
*/
2017-05-02 14:33:45 +02:00
if ( cur = = priv - > triggers | | cur_is_trgo2 )
2017-01-20 10:15:07 +01:00
trig - > dev . groups = stm32_trigger_attr_groups ;
iio_trigger_set_drvdata ( trig , priv ) ;
ret = devm_iio_trigger_register ( priv - > dev , trig ) ;
if ( ret )
return ret ;
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 ) ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
{
u32 cnt ;
regmap_read ( priv - > regmap , TIM_CNT , & cnt ) ;
* val = cnt ;
return IIO_VAL_INT ;
}
case IIO_CHAN_INFO_SCALE :
{
u32 smcr ;
regmap_read ( priv - > regmap , TIM_SMCR , & smcr ) ;
smcr & = TIM_SMCR_SMS ;
* val = 1 ;
* val2 = 0 ;
/* in quadrature case scale = 0.25 */
if ( smcr = = 3 )
* 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 :
regmap_write ( priv - > regmap , TIM_CNT , val ) ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
/* fixed scale */
return - EINVAL ;
}
return - EINVAL ;
}
static const struct iio_info stm32_trigger_info = {
. driver_module = THIS_MODULE ,
. read_raw = stm32_counter_read_raw ,
. write_raw = stm32_counter_write_raw
} ;
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 ;
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 const char * const stm32_quadrature_modes [ ] = {
" channel_A " ,
" channel_B " ,
" quadrature " ,
} ;
static int stm32_set_quadrature_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 , mode + 1 ) ;
return 0 ;
}
static int stm32_get_quadrature_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 smcr - 1 ;
}
static const struct iio_enum stm32_quadrature_mode_enum = {
. items = stm32_quadrature_modes ,
. num_items = ARRAY_SIZE ( stm32_quadrature_modes ) ,
. set = stm32_set_quadrature_mode ,
. get = stm32_get_quadrature_mode
} ;
static const char * const stm32_count_direction_states [ ] = {
" up " ,
" down "
} ;
static int stm32_set_count_direction ( 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_CR1 , TIM_CR1_DIR , mode ) ;
return 0 ;
}
static int stm32_get_count_direction ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
{
struct stm32_timer_trigger * priv = iio_priv ( indio_dev ) ;
u32 cr1 ;
regmap_read ( priv - > regmap , TIM_CR1 , & cr1 ) ;
return ( cr1 & TIM_CR1_DIR ) ;
}
static const struct iio_enum stm32_count_direction_enum = {
. items = stm32_count_direction_states ,
. num_items = ARRAY_SIZE ( stm32_count_direction_states ) ,
. set = stm32_set_count_direction ,
. get = stm32_get_count_direction
} ;
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 ;
regmap_write ( priv - > regmap , TIM_ARR , preset ) ;
regmap_update_bits ( priv - > regmap , TIM_CR1 , TIM_CR1_ARPE , TIM_CR1_ARPE ) ;
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
} ,
IIO_ENUM ( " count_direction " , IIO_SEPARATE , & stm32_count_direction_enum ) ,
IIO_ENUM_AVAILABLE ( " count_direction " , & stm32_count_direction_enum ) ,
IIO_ENUM ( " quadrature_mode " , IIO_SEPARATE , & stm32_quadrature_mode_enum ) ,
IIO_ENUM_AVAILABLE ( " quadrature_mode " , & stm32_quadrature_mode_enum ) ,
2017-04-04 09:47:52 +02:00
IIO_ENUM ( " enable_mode " , IIO_SEPARATE , & stm32_enable_mode_enum ) ,
IIO_ENUM_AVAILABLE ( " enable_mode " , & stm32_enable_mode_enum ) ,
2017-04-04 09:47:51 +02:00
{ }
} ;
static const struct iio_chan_spec stm32_trigger_channel = {
. type = IIO_COUNT ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | BIT ( IIO_CHAN_INFO_SCALE ) ,
. 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 - > dev . parent = dev ;
indio_dev - > info = & stm32_trigger_info ;
indio_dev - > num_channels = 1 ;
indio_dev - > channels = & stm32_trigger_channel ;
indio_dev - > dev . of_node = dev - > of_node ;
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 ) ;
unsigned int index ;
int ret ;
if ( of_property_read_u32 ( dev - > of_node , " reg " , & index ) )
return - EINVAL ;
2017-04-04 09:47:51 +02:00
if ( index > = ARRAY_SIZE ( triggers_table ) | |
index > = ARRAY_SIZE ( 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 */
if ( * valids_table [ index ] )
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-04-04 09:47:51 +02:00
priv - > valids = valids_table [ index ] ;
2017-05-02 14:33:45 +02:00
stm32_timer_detect_trgo2 ( priv ) ;
2017-01-20 10:15:07 +01:00
ret = stm32_setup_iio_triggers ( priv ) ;
if ( ret )
return ret ;
platform_set_drvdata ( pdev , priv ) ;
return 0 ;
}
static const struct of_device_id stm32_trig_of_match [ ] = {
{ . compatible = " st,stm32-timer-trigger " , } ,
{ /* end node */ } ,
} ;
MODULE_DEVICE_TABLE ( of , stm32_trig_of_match ) ;
static struct platform_driver stm32_timer_trigger_driver = {
. probe = stm32_timer_trigger_probe ,
. driver = {
. name = " stm32-timer-trigger " ,
. of_match_table = stm32_trig_of_match ,
} ,
} ;
module_platform_driver ( stm32_timer_trigger_driver ) ;
MODULE_ALIAS ( " platform: stm32-timer-trigger " ) ;
MODULE_DESCRIPTION ( " STMicroelectronics STM32 Timer Trigger driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;