From 250bbbdbed93ca27c9f4d445c960a87d9f7e2044 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 20 Jun 2017 21:52:08 +0200 Subject: iio: common: st_sensors: move st_sensors_of_i2c_probe() in common code Move st_sensors_of_i2c_probe() in st_sensors_core and rename it in st_sensors_of_name_probe(). That change is necessary to add device-tree support in spi code otherwise the rest of the autodetection will fail since spi->modalias (and indio_dev->name) will be set using compatible string value that differs from standard sensor name Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- include/linux/iio/common/st_sensors.h | 12 ++++++++++++ include/linux/iio/common/st_sensors_i2c.h | 10 ---------- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include/linux/iio') diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 497f2b3a5a62..1f8211b6438b 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -325,4 +325,16 @@ ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, ssize_t st_sensors_sysfs_scale_avail(struct device *dev, struct device_attribute *attr, char *buf); +#ifdef CONFIG_OF +void st_sensors_of_name_probe(struct device *dev, + const struct of_device_id *match, + char *name, int len); +#else +static inline void st_sensors_of_name_probe(struct device *dev, + const struct of_device_id *match, + char *name, int len) +{ +} +#endif + #endif /* ST_SENSORS_H */ diff --git a/include/linux/iio/common/st_sensors_i2c.h b/include/linux/iio/common/st_sensors_i2c.h index 254de3c7dde8..0a2c25e06d1f 100644 --- a/include/linux/iio/common/st_sensors_i2c.h +++ b/include/linux/iio/common/st_sensors_i2c.h @@ -18,16 +18,6 @@ void st_sensors_i2c_configure(struct iio_dev *indio_dev, struct i2c_client *client, struct st_sensor_data *sdata); -#ifdef CONFIG_OF -void st_sensors_of_i2c_probe(struct i2c_client *client, - const struct of_device_id *match); -#else -static inline void st_sensors_of_i2c_probe(struct i2c_client *client, - const struct of_device_id *match) -{ -} -#endif - #ifdef CONFIG_ACPI int st_sensors_match_acpi_device(struct device *dev); #else -- cgit v1.2.3 From a7b8829d242b1a58107e9c02b09e93aec446d55c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 5 Jul 2017 20:30:01 +0200 Subject: iio: accel: st_accel: add SPI-3wire support Add SPI Serial Interface Mode (SIM) register information in st_sensor_settings look up table to support devices (like LSM303AGR accel sensor) that allow just SPI-3wire communication mode. SIM mode has to be configured before any other operation since it is not enabled by default and the driver is not able to read without that configuration Whilst a fairly substantial patch, the actual logic is simple and it is better to have the generic fix than a band aid. Fixes: ddc05fa28606 (iio: st-accel: add support for lsm303agr accel) Signed-off-by: Lorenzo Bianconi Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 32 +++++++++++++++++++++++++ drivers/iio/common/st_sensors/st_sensors_core.c | 29 ++++++++++++++++++++++ include/linux/iio/common/st_sensors.h | 7 ++++++ include/linux/platform_data/st_sensors_pdata.h | 2 ++ 4 files changed, 70 insertions(+) (limited to 'include/linux/iio') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 784670e2736b..2ee3ae11eb2a 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -166,6 +166,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_ihl = 0x02, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, + .sim = { + .addr = 0x23, + .value = BIT(0), + }, .multi_read_bit = true, .bootime = 2, }, @@ -234,6 +238,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_od = 0x40, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, + .sim = { + .addr = 0x23, + .value = BIT(0), + }, .multi_read_bit = true, .bootime = 2, }, @@ -316,6 +324,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .en_mask = 0x08, }, }, + .sim = { + .addr = 0x24, + .value = BIT(0), + }, .multi_read_bit = false, .bootime = 2, }, @@ -379,6 +391,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_int1 = 0x04, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, + .sim = { + .addr = 0x21, + .value = BIT(1), + }, .multi_read_bit = true, .bootime = 2, /* guess */ }, @@ -437,6 +453,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_od = 0x40, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, + .sim = { + .addr = 0x21, + .value = BIT(7), + }, .multi_read_bit = false, .bootime = 2, /* guess */ }, @@ -499,6 +519,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .addr_ihl = 0x22, .mask_ihl = 0x80, }, + .sim = { + .addr = 0x23, + .value = BIT(0), + }, .multi_read_bit = true, .bootime = 2, }, @@ -547,6 +571,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_int1 = 0x04, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, + .sim = { + .addr = 0x21, + .value = BIT(1), + }, .multi_read_bit = false, .bootime = 2, }, @@ -614,6 +642,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_ihl = 0x02, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, + .sim = { + .addr = 0x23, + .value = BIT(0), + }, .multi_read_bit = true, .bootime = 2, }, diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 79c8c7cd70d5..6e6a1ecc99dd 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -550,6 +550,31 @@ out: } EXPORT_SYMBOL(st_sensors_read_info_raw); +static int st_sensors_init_interface_mode(struct iio_dev *indio_dev, + const struct st_sensor_settings *sensor_settings) +{ + struct st_sensor_data *sdata = iio_priv(indio_dev); + struct device_node *np = sdata->dev->of_node; + struct st_sensors_platform_data *pdata; + + pdata = (struct st_sensors_platform_data *)sdata->dev->platform_data; + if (((np && of_property_read_bool(np, "spi-3wire")) || + (pdata && pdata->spi_3wire)) && sensor_settings->sim.addr) { + int err; + + err = sdata->tf->write_byte(&sdata->tb, sdata->dev, + sensor_settings->sim.addr, + sensor_settings->sim.value); + if (err < 0) { + dev_err(&indio_dev->dev, + "failed to init interface mode\n"); + return err; + } + } + + return 0; +} + int st_sensors_check_device_support(struct iio_dev *indio_dev, int num_sensors_list, const struct st_sensor_settings *sensor_settings) @@ -574,6 +599,10 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev, return -ENODEV; } + err = st_sensors_init_interface_mode(indio_dev, &sensor_settings[i]); + if (err < 0) + return err; + if (sensor_settings[i].wai_addr) { err = sdata->tf->read_byte(&sdata->tb, sdata->dev, sensor_settings[i].wai_addr, &wai); diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 497f2b3a5a62..97f1b465d04f 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -105,6 +105,11 @@ struct st_sensor_fullscale { struct st_sensor_fullscale_avl fs_avl[ST_SENSORS_FULLSCALE_AVL_MAX]; }; +struct st_sensor_sim { + u8 addr; + u8 value; +}; + /** * struct st_sensor_bdu - ST sensor device block data update * @addr: address of the register. @@ -197,6 +202,7 @@ struct st_sensor_transfer_function { * @bdu: Block data update register. * @das: Data Alignment Selection register. * @drdy_irq: Data ready register of the sensor. + * @sim: SPI serial interface mode register of the sensor. * @multi_read_bit: Use or not particular bit for [I2C/SPI] multi-read. * @bootime: samples to discard when sensor passing from power-down to power-up. */ @@ -213,6 +219,7 @@ struct st_sensor_settings { struct st_sensor_bdu bdu; struct st_sensor_das das; struct st_sensor_data_ready_irq drdy_irq; + struct st_sensor_sim sim; bool multi_read_bit; unsigned int bootime; }; diff --git a/include/linux/platform_data/st_sensors_pdata.h b/include/linux/platform_data/st_sensors_pdata.h index 79b0e4cdb814..f8274b0c6888 100644 --- a/include/linux/platform_data/st_sensors_pdata.h +++ b/include/linux/platform_data/st_sensors_pdata.h @@ -17,10 +17,12 @@ * Available only for accelerometer and pressure sensors. * Accelerometer DRDY on LSM330 available only on pin 1 (see datasheet). * @open_drain: set the interrupt line to be open drain if possible. + * @spi_3wire: enable spi-3wire mode. */ struct st_sensors_platform_data { u8 drdy_int_pin; bool open_drain; + bool spi_3wire; }; #endif /* ST_SENSORS_PDATA_H */ -- cgit v1.2.3 From 45fff14bab00eea97e0f60a2a5ba3eca97bd476a Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 3 Aug 2017 11:14:13 +0200 Subject: iio: trigger: stm32-timer: add support for STM32H7 Add support for STM32H7 timer triggers: - Add new valids_table - Introduce compatible, with configuration data - Extend up to 15 timers, available on STM32H7 Signed-off-by: Fabrice Gasnier Signed-off-by: Jonathan Cameron --- drivers/iio/trigger/stm32-timer-trigger.c | 55 +++++++++++++++++++++++++-- include/linux/iio/timer/stm32-timer-trigger.h | 2 + 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'include/linux/iio') diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index d22bc56dd9fc..33890f9ad11b 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -13,6 +13,7 @@ #include #include #include +#include #define MAX_TRIGGERS 7 #define MAX_VALIDS 5 @@ -31,6 +32,9 @@ static const void *triggers_table[][MAX_TRIGGERS] = { { }, /* timer 10 */ { }, /* timer 11 */ { TIM12_TRGO, TIM12_CH1, TIM12_CH2,}, + { }, /* timer 13 */ + { }, /* timer 14 */ + { TIM15_TRGO,}, }; /* List the triggers accepted by each timer */ @@ -49,6 +53,24 @@ static const void *valids_table[][MAX_VALIDS] = { { TIM4_TRGO, TIM5_TRGO,}, }; +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 */ + { TIM4_TRGO, TIM5_TRGO,}, + { }, /* timer 13 */ + { }, /* timer 14 */ + { TIM1_TRGO, TIM3_TRGO,}, +}; + struct stm32_timer_trigger { struct device *dev; struct regmap *regmap; @@ -59,6 +81,11 @@ struct stm32_timer_trigger { bool has_trgo2; }; +struct stm32_timer_trigger_cfg { + const void *(*valids_table)[MAX_VALIDS]; + const unsigned int num_valids_table; +}; + static bool stm32_timer_is_trgo2_name(const char *name) { return !!strstr(name, "trgo2"); @@ -734,18 +761,22 @@ 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); + const struct stm32_timer_trigger_cfg *cfg; unsigned int index; int ret; if (of_property_read_u32(dev->of_node, "reg", &index)) return -EINVAL; + cfg = (const struct stm32_timer_trigger_cfg *) + of_match_device(dev->driver->of_match_table, dev)->data; + if (index >= ARRAY_SIZE(triggers_table) || - index >= ARRAY_SIZE(valids_table)) + index >= cfg->num_valids_table) return -EINVAL; /* Create an IIO device only if we have triggers to be validated */ - if (*valids_table[index]) + if (*cfg->valids_table[index]) priv = stm32_setup_counter_device(dev); else priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -758,7 +789,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) priv->clk = ddata->clk; priv->max_arr = ddata->max_arr; priv->triggers = triggers_table[index]; - priv->valids = valids_table[index]; + priv->valids = cfg->valids_table[index]; stm32_timer_detect_trgo2(priv); ret = stm32_setup_iio_triggers(priv); @@ -770,8 +801,24 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) return 0; } +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), +}; + static const struct of_device_id stm32_trig_of_match[] = { - { .compatible = "st,stm32-timer-trigger", }, + { + .compatible = "st,stm32-timer-trigger", + .data = (void *)&stm32_timer_trg_cfg, + }, { + .compatible = "st,stm32h7-timer-trigger", + .data = (void *)&stm32h7_timer_trg_cfg, + }, { /* end node */ }, }; MODULE_DEVICE_TABLE(of, stm32_trig_of_match); diff --git a/include/linux/iio/timer/stm32-timer-trigger.h b/include/linux/iio/timer/stm32-timer-trigger.h index fa7d786ed99e..20f465353a7c 100644 --- a/include/linux/iio/timer/stm32-timer-trigger.h +++ b/include/linux/iio/timer/stm32-timer-trigger.h @@ -59,6 +59,8 @@ #define TIM12_CH1 "tim12_ch1" #define TIM12_CH2 "tim12_ch2" +#define TIM15_TRGO "tim15_trgo" + bool is_stm32_timer_trigger(struct iio_trigger *trig); #endif -- cgit v1.2.3 From 25892d6eac9cb752af95bcd539ed5e1158eba760 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 3 Aug 2017 11:14:14 +0200 Subject: iio: trigger: stm32-timer: add output compare triggers Add output compare trigger sources available on some instances. Signed-off-by: Fabrice Gasnier Signed-off-by: Jonathan Cameron --- drivers/iio/trigger/stm32-timer-trigger.c | 31 +++++++++++++++++---------- include/linux/iio/timer/stm32-timer-trigger.h | 12 +++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) (limited to 'include/linux/iio') diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 33890f9ad11b..a9bc5b603b86 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -29,12 +29,14 @@ static const void *triggers_table[][MAX_TRIGGERS] = { { TIM7_TRGO,}, { TIM8_TRGO, TIM8_TRGO2, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,}, { TIM9_TRGO, TIM9_CH1, TIM9_CH2,}, - { }, /* timer 10 */ - { }, /* timer 11 */ + { TIM10_OC1,}, + { TIM11_OC1,}, { TIM12_TRGO, TIM12_CH1, TIM12_CH2,}, - { }, /* timer 13 */ - { }, /* timer 14 */ + { TIM13_OC1,}, + { TIM14_OC1,}, { TIM15_TRGO,}, + { TIM16_OC1,}, + { TIM17_OC1,}, }; /* List the triggers accepted by each timer */ @@ -47,10 +49,10 @@ static const void *valids_table[][MAX_VALIDS] = { { }, /* timer 6 */ { }, /* timer 7 */ { TIM1_TRGO, TIM2_TRGO, TIM4_TRGO, TIM5_TRGO,}, - { TIM2_TRGO, TIM3_TRGO,}, + { TIM2_TRGO, TIM3_TRGO, TIM10_OC1, TIM11_OC1,}, { }, /* timer 10 */ { }, /* timer 11 */ - { TIM4_TRGO, TIM5_TRGO,}, + { TIM4_TRGO, TIM5_TRGO, TIM13_OC1, TIM14_OC1,}, }; static const void *stm32h7_valids_table[][MAX_VALIDS] = { @@ -65,10 +67,12 @@ static const void *stm32h7_valids_table[][MAX_VALIDS] = { { }, /* timer 9 */ { }, /* timer 10 */ { }, /* timer 11 */ - { TIM4_TRGO, TIM5_TRGO,}, + { TIM4_TRGO, TIM5_TRGO, TIM13_OC1, TIM14_OC1,}, { }, /* timer 13 */ { }, /* timer 14 */ - { TIM1_TRGO, TIM3_TRGO,}, + { TIM1_TRGO, TIM3_TRGO, TIM16_OC1, TIM17_OC1,}, + { }, /* timer 16 */ + { }, /* timer 17 */ }; struct stm32_timer_trigger { @@ -91,6 +95,11 @@ static bool stm32_timer_is_trgo2_name(const char *name) return !!strstr(name, "trgo2"); } +static bool stm32_timer_is_trgo_name(const char *name) +{ + return (!!strstr(name, "trgo") && !strstr(name, "trgo2")); +} + static int stm32_timer_start(struct stm32_timer_trigger *priv, struct iio_trigger *trig, unsigned int frequency) @@ -355,6 +364,7 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) while (cur && *cur) { struct iio_trigger *trig; + bool cur_is_trgo = stm32_timer_is_trgo_name(*cur); bool cur_is_trgo2 = stm32_timer_is_trgo2_name(*cur); if (cur_is_trgo2 && !priv->has_trgo2) { @@ -371,10 +381,9 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) /* * sampling frequency and master mode attributes - * should only be available on trgo trigger which - * is always the first in the list. + * should only be available on trgo/trgo2 triggers */ - if (cur == priv->triggers || cur_is_trgo2) + if (cur_is_trgo || cur_is_trgo2) trig->dev.groups = stm32_trigger_attr_groups; iio_trigger_set_drvdata(trig, priv); diff --git a/include/linux/iio/timer/stm32-timer-trigger.h b/include/linux/iio/timer/stm32-timer-trigger.h index 20f465353a7c..d68add80ab86 100644 --- a/include/linux/iio/timer/stm32-timer-trigger.h +++ b/include/linux/iio/timer/stm32-timer-trigger.h @@ -55,12 +55,24 @@ #define TIM9_CH1 "tim9_ch1" #define TIM9_CH2 "tim9_ch2" +#define TIM10_OC1 "tim10_oc1" + +#define TIM11_OC1 "tim11_oc1" + #define TIM12_TRGO "tim12_trgo" #define TIM12_CH1 "tim12_ch1" #define TIM12_CH2 "tim12_ch2" +#define TIM13_OC1 "tim13_oc1" + +#define TIM14_OC1 "tim14_oc1" + #define TIM15_TRGO "tim15_trgo" +#define TIM16_OC1 "tim16_oc1" + +#define TIM17_OC1 "tim17_oc1" + bool is_stm32_timer_trigger(struct iio_trigger *trig); #endif -- cgit v1.2.3 From f00fd7ae4f409abb7b2e5d099248832548199f0c Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sun, 30 Jul 2017 16:14:42 -0600 Subject: PATCH] iio: Fix some documentation warnings The kerneldoc description for the trig_readonly field of struct iio_dev lacked a colon, leading to this doc build warning: ./include/linux/iio/iio.h:603: warning: No description found for parameter 'trig_readonly' A similar issue for iio_trigger_set_immutable() in trigger.h yielded: ./include/linux/iio/trigger.h:151: warning: No description found for parameter 'indio_dev' ./include/linux/iio/trigger.h:151: warning: No description found for parameter 'trig' Fix the formatting and silence the warnings. Signed-off-by: Jonathan Corbet Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 2 +- include/linux/iio/trigger.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux/iio') diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index d68bec297a45..c380daa40c0e 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -535,7 +535,7 @@ struct iio_buffer_setup_ops { * @scan_timestamp: [INTERN] set if any buffers have requested timestamp * @scan_index_timestamp:[INTERN] cache of the index to the timestamp * @trig: [INTERN] current device trigger (buffer modes) - * @trig_readonly [INTERN] mark the current trigger immutable + * @trig_readonly: [INTERN] mark the current trigger immutable * @pollfunc: [DRIVER] function run on trigger being received * @pollfunc_event: [DRIVER] function run on events trigger being received * @channels: [DRIVER] channel specification structure table diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index ea08302f2d7b..7142d8d6e470 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -144,8 +144,8 @@ void devm_iio_trigger_unregister(struct device *dev, /** * iio_trigger_set_immutable() - set an immutable trigger on destination * - * @indio_dev - IIO device structure containing the device - * @trig - trigger to assign to device + * @indio_dev: IIO device structure containing the device + * @trig: trigger to assign to device * **/ int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig); -- cgit v1.2.3 From b01ced2b504b2592af6703533c62cb9d1cdc1c6c Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 28 Aug 2017 12:04:11 +0200 Subject: iio: trigger: Add STM32 LPTimer trigger driver Add support for LPTIMx_OUT triggers that can be found on some STM32 devices. These triggers can be used then by ADC or DAC. Typical usage is to configure LPTimer as PWM output (via pwm-stm32-lp) and have synchronised analog conversions with these triggers. Signed-off-by: Fabrice Gasnier Reviewed-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/iio/trigger/Kconfig | 11 +++ drivers/iio/trigger/Makefile | 1 + drivers/iio/trigger/stm32-lptimer-trigger.c | 118 ++++++++++++++++++++++++++ include/linux/iio/timer/stm32-lptim-trigger.h | 27 ++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/iio/trigger/stm32-lptimer-trigger.c create mode 100644 include/linux/iio/timer/stm32-lptim-trigger.h (limited to 'include/linux/iio') diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig index e4d4e63434db..a633d2c8e805 100644 --- a/drivers/iio/trigger/Kconfig +++ b/drivers/iio/trigger/Kconfig @@ -24,6 +24,17 @@ config IIO_INTERRUPT_TRIGGER To compile this driver as a module, choose M here: the module will be called iio-trig-interrupt. +config IIO_STM32_LPTIMER_TRIGGER + tristate "STM32 Low-Power Timer Trigger" + depends on MFD_STM32_LPTIMER || COMPILE_TEST + help + Select this option to enable STM32 Low-Power Timer Trigger. + This can be used as trigger source for STM32 internal ADC + and/or DAC. + + To compile this driver as a module, choose M here: the + module will be called stm32-lptimer-trigger. + config IIO_STM32_TIMER_TRIGGER tristate "STM32 Timer Trigger" depends on (ARCH_STM32 && OF && MFD_STM32_TIMERS) || COMPILE_TEST diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile index 5c4ecd380653..0a72a2a76cb2 100644 --- a/drivers/iio/trigger/Makefile +++ b/drivers/iio/trigger/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o +obj-$(CONFIG_IIO_STM32_LPTIMER_TRIGGER) += stm32-lptimer-trigger.o obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o obj-$(CONFIG_IIO_TIGHTLOOP_TRIGGER) += iio-trig-loop.o diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c new file mode 100644 index 000000000000..241eae6a4306 --- /dev/null +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c @@ -0,0 +1,118 @@ +/* + * STM32 Low-Power Timer Trigger driver + * + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier . + * + * License terms: GNU General Public License (GPL), version 2 + * + * Inspired by Benjamin Gaignard's stm32-timer-trigger driver + */ + +#include +#include +#include +#include + +/* List Low-Power Timer triggers */ +static const char * const stm32_lptim_triggers[] = { + LPTIM1_OUT, + LPTIM2_OUT, + LPTIM3_OUT, +}; + +struct stm32_lptim_trigger { + struct device *dev; + const char *trg; +}; + +static int stm32_lptim_validate_device(struct iio_trigger *trig, + struct iio_dev *indio_dev) +{ + if (indio_dev->modes & INDIO_HARDWARE_TRIGGERED) + return 0; + + return -EINVAL; +} + +static const struct iio_trigger_ops stm32_lptim_trigger_ops = { + .owner = THIS_MODULE, + .validate_device = stm32_lptim_validate_device, +}; + +/** + * is_stm32_lptim_trigger + * @trig: trigger to be checked + * + * return true if the trigger is a valid STM32 IIO Low-Power Timer Trigger + * either return false + */ +bool is_stm32_lptim_trigger(struct iio_trigger *trig) +{ + return (trig->ops == &stm32_lptim_trigger_ops); +} +EXPORT_SYMBOL(is_stm32_lptim_trigger); + +static int stm32_lptim_setup_trig(struct stm32_lptim_trigger *priv) +{ + struct iio_trigger *trig; + + trig = devm_iio_trigger_alloc(priv->dev, "%s", priv->trg); + if (!trig) + return -ENOMEM; + + trig->dev.parent = priv->dev->parent; + trig->ops = &stm32_lptim_trigger_ops; + iio_trigger_set_drvdata(trig, priv); + + return devm_iio_trigger_register(priv->dev, trig); +} + +static int stm32_lptim_trigger_probe(struct platform_device *pdev) +{ + struct stm32_lptim_trigger *priv; + u32 index; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (of_property_read_u32(pdev->dev.of_node, "reg", &index)) + return -EINVAL; + + if (index >= ARRAY_SIZE(stm32_lptim_triggers)) + return -EINVAL; + + priv->dev = &pdev->dev; + priv->trg = stm32_lptim_triggers[index]; + + ret = stm32_lptim_setup_trig(priv); + if (ret) + return ret; + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static const struct of_device_id stm32_lptim_trig_of_match[] = { + { .compatible = "st,stm32-lptimer-trigger", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_lptim_trig_of_match); + +static struct platform_driver stm32_lptim_trigger_driver = { + .probe = stm32_lptim_trigger_probe, + .driver = { + .name = "stm32-lptimer-trigger", + .of_match_table = stm32_lptim_trig_of_match, + }, +}; +module_platform_driver(stm32_lptim_trigger_driver); + +MODULE_AUTHOR("Fabrice Gasnier "); +MODULE_ALIAS("platform:stm32-lptimer-trigger"); +MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM trigger driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/iio/timer/stm32-lptim-trigger.h b/include/linux/iio/timer/stm32-lptim-trigger.h new file mode 100644 index 000000000000..34d59bfdce2d --- /dev/null +++ b/include/linux/iio/timer/stm32-lptim-trigger.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STM32_LPTIM_TRIGGER_H_ +#define _STM32_LPTIM_TRIGGER_H_ + +#include +#include + +#define LPTIM1_OUT "lptim1_out" +#define LPTIM2_OUT "lptim2_out" +#define LPTIM3_OUT "lptim3_out" + +#if IS_ENABLED(CONFIG_IIO_STM32_LPTIMER_TRIGGER) +bool is_stm32_lptim_trigger(struct iio_trigger *trig); +#else +static inline bool is_stm32_lptim_trigger(struct iio_trigger *trig) +{ + return false; +} +#endif +#endif -- cgit v1.2.3