diff options
Diffstat (limited to 'drivers/iio/trigger/stm32-timer-trigger.c')
| -rw-r--r-- | drivers/iio/trigger/stm32-timer-trigger.c | 174 | 
1 files changed, 160 insertions, 14 deletions
| diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 25248d644e7c..d22bc56dd9fc 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -14,19 +14,19 @@  #include <linux/module.h>  #include <linux/platform_device.h> -#define MAX_TRIGGERS 6 +#define MAX_TRIGGERS 7  #define MAX_VALIDS 5  /* List the triggers created by each timer */  static const void *triggers_table[][MAX_TRIGGERS] = { -	{ TIM1_TRGO, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,}, +	{ TIM1_TRGO, TIM1_TRGO2, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,},  	{ 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,}, -	{ TIM8_TRGO, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,}, +	{ TIM8_TRGO, TIM8_TRGO2, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,},  	{ TIM9_TRGO, TIM9_CH1, TIM9_CH2,},  	{ }, /* timer 10 */  	{ }, /* timer 11 */ @@ -56,9 +56,16 @@ struct stm32_timer_trigger {  	u32 max_arr;  	const void *triggers;  	const void *valids; +	bool has_trgo2;  }; +static bool stm32_timer_is_trgo2_name(const char *name) +{ +	return !!strstr(name, "trgo2"); +} +  static int stm32_timer_start(struct stm32_timer_trigger *priv, +			     struct iio_trigger *trig,  			     unsigned int frequency)  {  	unsigned long long prd, div; @@ -102,7 +109,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,  	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);  	/* Force master mode to update mode */ -	regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0x20); +	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);  	/* Make sure that registers are updated */  	regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); @@ -150,7 +162,7 @@ static ssize_t stm32_tt_store_frequency(struct device *dev,  	if (freq == 0) {  		stm32_timer_stop(priv);  	} else { -		ret = stm32_timer_start(priv, freq); +		ret = stm32_timer_start(priv, trig, freq);  		if (ret)  			return ret;  	} @@ -183,6 +195,9 @@ static IIO_DEV_ATTR_SAMP_FREQ(0660,  			      stm32_tt_read_frequency,  			      stm32_tt_store_frequency); +#define MASTER_MODE_MAX		7 +#define MASTER_MODE2_MAX	15 +  static char *master_mode_table[] = {  	"reset",  	"enable", @@ -191,7 +206,16 @@ static char *master_mode_table[] = {  	"OC1REF",  	"OC2REF",  	"OC3REF", -	"OC4REF" +	"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",  };  static ssize_t stm32_tt_show_master_mode(struct device *dev, @@ -199,10 +223,15 @@ static ssize_t stm32_tt_show_master_mode(struct device *dev,  					 char *buf)  {  	struct stm32_timer_trigger *priv = dev_get_drvdata(dev); +	struct iio_trigger *trig = to_iio_trigger(dev);  	u32 cr2;  	regmap_read(priv->regmap, TIM_CR2, &cr2); -	cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT; + +	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;  	return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]);  } @@ -212,13 +241,25 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,  					  const char *buf, size_t len)  {  	struct stm32_timer_trigger *priv = dev_get_drvdata(dev); +	struct iio_trigger *trig = to_iio_trigger(dev); +	u32 mask, shift, master_mode_max;  	int i; -	for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) { +	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++) {  		if (!strncmp(master_mode_table[i], buf,  			     strlen(master_mode_table[i]))) { -			regmap_update_bits(priv->regmap, TIM_CR2, -					   TIM_CR2_MMS, i << TIM_CR2_MMS_SHIFT); +			regmap_update_bits(priv->regmap, TIM_CR2, mask, +					   i << shift);  			/* Make sure that registers are updated */  			regmap_update_bits(priv->regmap, TIM_EGR,  					   TIM_EGR_UG, TIM_EGR_UG); @@ -229,8 +270,31 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,  	return -EINVAL;  } -static IIO_CONST_ATTR(master_mode_available, -	"reset enable update compare_pulse OC1REF OC2REF OC3REF OC4REF"); +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);  static IIO_DEVICE_ATTR(master_mode, 0660,  		       stm32_tt_show_master_mode, @@ -240,7 +304,7 @@ static IIO_DEVICE_ATTR(master_mode, 0660,  static struct attribute *stm32_trigger_attrs[] = {  	&iio_dev_attr_sampling_frequency.dev_attr.attr,  	&iio_dev_attr_master_mode.dev_attr.attr, -	&iio_const_attr_master_mode_available.dev_attr.attr, +	&iio_dev_attr_master_mode_available.dev_attr.attr,  	NULL,  }; @@ -264,6 +328,12 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)  	while (cur && *cur) {  		struct iio_trigger *trig; +		bool cur_is_trgo2 = stm32_timer_is_trgo2_name(*cur); + +		if (cur_is_trgo2 && !priv->has_trgo2) { +			cur++; +			continue; +		}  		trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);  		if  (!trig) @@ -277,7 +347,7 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)  		 * should only be available on trgo trigger which  		 * is always the first in the list.  		 */ -		if (cur == priv->triggers) +		if (cur == priv->triggers || cur_is_trgo2)  			trig->dev.groups = stm32_trigger_attr_groups;  		iio_trigger_set_drvdata(trig, priv); @@ -347,12 +417,70 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,  	return -EINVAL;  } +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; +} +  static const struct iio_info stm32_trigger_info = {  	.driver_module = THIS_MODULE, +	.validate_trigger = stm32_counter_validate_trigger,  	.read_raw = stm32_counter_read_raw,  	.write_raw = stm32_counter_write_raw  }; +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); + +	return smcr == TIM_SMCR_SMS ? 0 : -EINVAL; +} + +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 +}; +  static const char *const stm32_enable_modes[] = {  	"always",  	"gated", @@ -536,6 +664,8 @@ static const struct iio_chan_spec_ext_info stm32_trigger_count_info[] = {  	IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_quadrature_mode_enum),  	IIO_ENUM("enable_mode", IIO_SEPARATE, &stm32_enable_mode_enum),  	IIO_ENUM_AVAILABLE("enable_mode", &stm32_enable_mode_enum), +	IIO_ENUM("trigger_mode", IIO_SEPARATE, &stm32_trigger_mode_enum), +	IIO_ENUM_AVAILABLE("trigger_mode", &stm32_trigger_mode_enum),  	{}  }; @@ -560,6 +690,7 @@ static struct stm32_timer_trigger *stm32_setup_counter_device(struct device *dev  	indio_dev->name = dev_name(dev);  	indio_dev->dev.parent = dev;  	indio_dev->info = &stm32_trigger_info; +	indio_dev->modes = INDIO_HARDWARE_TRIGGERED;  	indio_dev->num_channels = 1;  	indio_dev->channels = &stm32_trigger_channel;  	indio_dev->dev.of_node = dev->of_node; @@ -584,6 +715,20 @@ bool is_stm32_timer_trigger(struct iio_trigger *trig)  }  EXPORT_SYMBOL(is_stm32_timer_trigger); +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; +} +  static int stm32_timer_trigger_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; @@ -614,6 +759,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)  	priv->max_arr = ddata->max_arr;  	priv->triggers = triggers_table[index];  	priv->valids = valids_table[index]; +	stm32_timer_detect_trgo2(priv);  	ret = stm32_setup_iio_triggers(priv);  	if (ret) |