diff options
Diffstat (limited to 'drivers/iio/trigger/stm32-timer-trigger.c')
| -rw-r--r-- | drivers/iio/trigger/stm32-timer-trigger.c | 444 |
1 files changed, 298 insertions, 146 deletions
diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index d22bc56dd9fc..3b9a3a6cbb25 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -1,18 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) STMicroelectronics 2016 * * Author: Benjamin Gaignard <benjamin.gaignard@st.com> * - * License terms: GNU General Public License (GPL), version 2 */ +#include <linux/export.h> #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/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/property.h> #define MAX_TRIGGERS 7 #define MAX_VALIDS 5 @@ -28,9 +31,17 @@ 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,}, + { TIM13_OC1,}, + { TIM14_OC1,}, + { TIM15_TRGO,}, + { TIM16_OC1,}, + { TIM17_OC1,}, + { }, /* timer 18 */ + { }, /* timer 19 */ + { TIM20_TRGO, TIM20_TRGO2, TIM20_OC1, TIM20_OC2, TIM20_OC3, }, }; /* List the triggers accepted by each timer */ @@ -43,20 +54,58 @@ 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, TIM13_OC1, TIM14_OC1,}, +}; + +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,}, + { TIM4_TRGO, TIM5_TRGO, TIM13_OC1, TIM14_OC1,}, + { }, /* timer 13 */ + { }, /* timer 14 */ + { TIM1_TRGO, TIM3_TRGO, TIM16_OC1, TIM17_OC1,}, + { }, /* timer 16 */ + { }, /* timer 17 */ +}; + +struct stm32_timer_trigger_regs { + u32 cr1; + u32 cr2; + u32 psc; + u32 arr; + u32 cnt; + u32 smcr; }; struct stm32_timer_trigger { struct device *dev; struct regmap *regmap; struct clk *clk; + bool enabled; u32 max_arr; const void *triggers; const void *valids; bool has_trgo2; + struct mutex lock; /* concurrent sysfs configuration */ + struct list_head tr_list; + struct stm32_timer_trigger_regs bak; +}; + +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) @@ -64,13 +113,18 @@ 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) { unsigned long long prd, div; - int prescaler = 0; - u32 ccer, cr1; + int prescaler = 0, ret; + u32 ccer; /* Period and prescaler values depends of clock rate */ div = (unsigned long long)clk_get_rate(priv->clk); @@ -100,13 +154,17 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, if (ccer & TIM_CCER_CCXE) return -EBUSY; - regmap_read(priv->regmap, TIM_CR1, &cr1); - if (!(cr1 & TIM_CR1_CEN)) - clk_enable(priv->clk); + guard(mutex)(&priv->lock); + if (!priv->enabled) { + priv->enabled = true; + ret = clk_enable(priv->clk); + if (ret) + return ret; + } 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); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); /* Force master mode to update mode */ if (stm32_timer_is_trgo2_name(trig->name)) @@ -117,33 +175,44 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, 0x2 << TIM_CR2_MMS_SHIFT); /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); /* Enable controller */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); return 0; } -static void stm32_timer_stop(struct stm32_timer_trigger *priv) +static void stm32_timer_stop(struct stm32_timer_trigger *priv, + struct iio_trigger *trig) { - u32 ccer, cr1; + u32 ccer; 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); - + mutex_lock(&priv->lock); /* Stop timer */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); regmap_write(priv->regmap, TIM_PSC, 0); regmap_write(priv->regmap, TIM_ARR, 0); + /* Force disable master mode */ + if (stm32_timer_is_trgo2_name(trig->name)) + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); + else + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS); + /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); + + if (priv->enabled) { + priv->enabled = false; + clk_disable(priv->clk); + } + mutex_unlock(&priv->lock); } static ssize_t stm32_tt_store_frequency(struct device *dev, @@ -160,7 +229,7 @@ static ssize_t stm32_tt_store_frequency(struct device *dev, return ret; if (freq == 0) { - stm32_timer_stop(priv); + stm32_timer_stop(priv, trig); } else { ret = stm32_timer_start(priv, trig, freq); if (ret) @@ -233,7 +302,7 @@ static ssize_t stm32_tt_show_master_mode(struct device *dev, else cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT; - return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]); + return sysfs_emit(buf, "%s\n", master_mode_table[cr2]); } static ssize_t stm32_tt_store_master_mode(struct device *dev, @@ -243,7 +312,7 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, 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; + int i, ret; if (stm32_timer_is_trgo2_name(trig->name)) { mask = TIM_CR2_MMS2; @@ -258,11 +327,16 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, for (i = 0; i <= master_mode_max; i++) { if (!strncmp(master_mode_table[i], buf, strlen(master_mode_table[i]))) { + guard(mutex)(&priv->lock); + if (!priv->enabled) { + /* Clock should be enabled first */ + priv->enabled = true; + ret = clk_enable(priv->clk); + if (ret) + return ret; + } 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); return len; } } @@ -318,16 +392,26 @@ static const struct attribute_group *stm32_trigger_attr_groups[] = { }; static const struct iio_trigger_ops timer_trigger_ops = { - .owner = THIS_MODULE, }; -static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) +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) { int ret; const char * const *cur = priv->triggers; + INIT_LIST_HEAD(&priv->tr_list); + 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) { @@ -344,17 +428,20 @@ 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); - ret = devm_iio_trigger_register(priv->dev, trig); - if (ret) + ret = iio_trigger_register(trig); + if (ret) { + stm32_unregister_iio_triggers(priv); return ret; + } + + list_add_tail(&trig->alloc_list, &priv->tr_list); cur++; } @@ -366,34 +453,32 @@ static int stm32_counter_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct stm32_timer_trigger *priv = iio_priv(indio_dev); + u32 dat; switch (mask) { case IIO_CHAN_INFO_RAW: - { - u32 cnt; - - regmap_read(priv->regmap, TIM_CNT, &cnt); - *val = cnt; + regmap_read(priv->regmap, TIM_CNT, &dat); + *val = dat; + return IIO_VAL_INT; + case IIO_CHAN_INFO_ENABLE: + regmap_read(priv->regmap, TIM_CR1, &dat); + *val = (dat & TIM_CR1_CEN) ? 1 : 0; return IIO_VAL_INT; - } - case IIO_CHAN_INFO_SCALE: - { - u32 smcr; - regmap_read(priv->regmap, TIM_SMCR, &smcr); - smcr &= TIM_SMCR_SMS; + case IIO_CHAN_INFO_SCALE: + regmap_read(priv->regmap, TIM_SMCR, &dat); + dat &= TIM_SMCR_SMS; *val = 1; *val2 = 0; /* in quadrature case scale = 0.25 */ - if (smcr == 3) + if (dat == 3) *val2 = 2; return IIO_VAL_FRACTIONAL_LOG2; } - } return -EINVAL; } @@ -403,18 +488,39 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct stm32_timer_trigger *priv = iio_priv(indio_dev); + int ret; switch (mask) { case IIO_CHAN_INFO_RAW: - regmap_write(priv->regmap, TIM_CNT, val); + return regmap_write(priv->regmap, TIM_CNT, val); - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* fixed scale */ return -EINVAL; - } - return -EINVAL; + case IIO_CHAN_INFO_ENABLE: { + guard(mutex)(&priv->lock); + if (val) { + if (!priv->enabled) { + priv->enabled = true; + ret = clk_enable(priv->clk); + if (ret) + return ret; + } + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); + } else { + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); + if (priv->enabled) { + priv->enabled = false; + clk_disable(priv->clk); + } + } + + return 0; + } + default: + return -EINVAL; + } } static int stm32_counter_validate_trigger(struct iio_dev *indio_dev, @@ -442,7 +548,6 @@ static int stm32_counter_validate_trigger(struct iio_dev *indio_dev, } 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 @@ -458,7 +563,7 @@ static int stm32_set_trigger_mode(struct iio_dev *indio_dev, { struct stm32_timer_trigger *priv = iio_priv(indio_dev); - regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, TIM_SMCR_SMS); + regmap_set_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS); return 0; } @@ -471,7 +576,7 @@ static int stm32_get_trigger_mode(struct iio_dev *indio_dev, regmap_read(priv->regmap, TIM_SMCR, &smcr); - return smcr == TIM_SMCR_SMS ? 0 : -EINVAL; + return (smcr & TIM_SMCR_SMS) == TIM_SMCR_SMS ? 0 : -EINVAL; } static const struct iio_enum stm32_trigger_mode_enum = { @@ -507,9 +612,23 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev, { struct stm32_timer_trigger *priv = iio_priv(indio_dev); int sms = stm32_enable_mode2sms(mode); + int ret; if (sms < 0) return sms; + /* + * Triggered mode sets CEN bit automatically by hardware. So, first + * enable counter clock, so it can use it. Keeps it in sync with CEN. + */ + scoped_guard(mutex, &priv->lock) { + if (sms == 6 && !priv->enabled) { + ret = clk_enable(priv->clk); + if (ret) + return ret; + + priv->enabled = true; + } + } regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms); @@ -549,76 +668,6 @@ static const struct iio_enum stm32_enable_mode_enum = { .get = stm32_get_enable_mode }; -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, @@ -645,8 +694,9 @@ static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev, if (ret) return ret; + /* TIMx_ARR register shouldn't be buffered (ARPE=0) */ + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); regmap_write(priv->regmap, TIM_ARR, preset); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE); return len; } @@ -658,21 +708,19 @@ static const struct iio_chan_spec_ext_info stm32_trigger_count_info[] = { .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), IIO_ENUM("enable_mode", IIO_SEPARATE, &stm32_enable_mode_enum), - IIO_ENUM_AVAILABLE("enable_mode", &stm32_enable_mode_enum), + IIO_ENUM_AVAILABLE("enable_mode", IIO_SHARED_BY_TYPE, &stm32_enable_mode_enum), IIO_ENUM("trigger_mode", IIO_SEPARATE, &stm32_trigger_mode_enum), - IIO_ENUM_AVAILABLE("trigger_mode", &stm32_trigger_mode_enum), - {} + IIO_ENUM_AVAILABLE("trigger_mode", IIO_SHARED_BY_TYPE, &stm32_trigger_mode_enum), + { } }; 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), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_ENABLE) | + BIT(IIO_CHAN_INFO_SCALE), .ext_info = stm32_trigger_count_info, .indexed = 1 }; @@ -688,12 +736,10 @@ static struct stm32_timer_trigger *stm32_setup_counter_device(struct device *dev return NULL; 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; ret = devm_iio_device_register(dev, indio_dev); if (ret) @@ -723,9 +769,9 @@ static void stm32_timer_detect_trgo2(struct stm32_timer_trigger *priv) * 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_set_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); regmap_read(priv->regmap, TIM_CR2, &val); - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); + regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2); priv->has_trgo2 = !!val; } @@ -734,18 +780,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; + ret = device_property_read_u32(dev, "reg", &index); + if (ret) + return ret; + + cfg = device_get_match_data(dev); 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 && *cfg->valids_table[index]) priv = stm32_setup_counter_device(dev); else priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -758,10 +808,12 @@ 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]; + if (cfg->valids_table && *cfg->valids_table[index]) + priv->valids = cfg->valids_table[index]; stm32_timer_detect_trgo2(priv); + mutex_init(&priv->lock); - ret = stm32_setup_iio_triggers(priv); + ret = stm32_register_iio_triggers(priv); if (ret) return ret; @@ -770,21 +822,121 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) return 0; } +static void 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_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); + + if (priv->enabled) + clk_disable(priv->clk); +} + +static int stm32_timer_trigger_suspend(struct device *dev) +{ + 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_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); + clk_disable(priv->clk); + } + + return 0; +} + +static int stm32_timer_trigger_resume(struct device *dev) +{ + 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; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops, + stm32_timer_trigger_suspend, + stm32_timer_trigger_resume); + +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 stm32_timer_trigger_cfg stm32mp25_timer_trg_cfg = { + /* + * valids_table not used: counter framework is now superseding the deprecated IIO + * counter interface (IIO_COUNT), so don't support it. num_valids_table is only + * kept here to register the IIO HW triggers. valids_table should be moved at some + * point to the stm32-timer-cnt driver instead. + */ + .num_valids_table = ARRAY_SIZE(triggers_table), +}; + static const struct of_device_id stm32_trig_of_match[] = { - { .compatible = "st,stm32-timer-trigger", }, - { /* end node */ }, + { + .compatible = "st,stm32-timer-trigger", + .data = (void *)&stm32_timer_trg_cfg, + }, { + .compatible = "st,stm32h7-timer-trigger", + .data = (void *)&stm32h7_timer_trg_cfg, + }, { + .compatible = "st,stm32mp25-timer-trigger", + .data = (void *)&stm32mp25_timer_trg_cfg, + }, + { } }; MODULE_DEVICE_TABLE(of, stm32_trig_of_match); static struct platform_driver stm32_timer_trigger_driver = { .probe = stm32_timer_trigger_probe, + .remove = stm32_timer_trigger_remove, .driver = { .name = "stm32-timer-trigger", .of_match_table = stm32_trig_of_match, + .pm = pm_sleep_ptr(&stm32_timer_trigger_pm_ops), }, }; module_platform_driver(stm32_timer_trigger_driver); -MODULE_ALIAS("platform: stm32-timer-trigger"); +MODULE_ALIAS("platform:stm32-timer-trigger"); MODULE_DESCRIPTION("STMicroelectronics STM32 Timer Trigger driver"); MODULE_LICENSE("GPL v2"); |
