18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics 2016 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Benjamin Gaignard <benjamin.gaignard@st.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 108c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 118c2ecf20Sopenharmony_ci#include <linux/iio/timer/stm32-timer-trigger.h> 128c2ecf20Sopenharmony_ci#include <linux/iio/trigger.h> 138c2ecf20Sopenharmony_ci#include <linux/mfd/stm32-timers.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/of_device.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define MAX_TRIGGERS 7 198c2ecf20Sopenharmony_ci#define MAX_VALIDS 5 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* List the triggers created by each timer */ 228c2ecf20Sopenharmony_cistatic const void *triggers_table[][MAX_TRIGGERS] = { 238c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM1_TRGO2, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,}, 248c2ecf20Sopenharmony_ci { TIM2_TRGO, TIM2_CH1, TIM2_CH2, TIM2_CH3, TIM2_CH4,}, 258c2ecf20Sopenharmony_ci { TIM3_TRGO, TIM3_CH1, TIM3_CH2, TIM3_CH3, TIM3_CH4,}, 268c2ecf20Sopenharmony_ci { TIM4_TRGO, TIM4_CH1, TIM4_CH2, TIM4_CH3, TIM4_CH4,}, 278c2ecf20Sopenharmony_ci { TIM5_TRGO, TIM5_CH1, TIM5_CH2, TIM5_CH3, TIM5_CH4,}, 288c2ecf20Sopenharmony_ci { TIM6_TRGO,}, 298c2ecf20Sopenharmony_ci { TIM7_TRGO,}, 308c2ecf20Sopenharmony_ci { TIM8_TRGO, TIM8_TRGO2, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,}, 318c2ecf20Sopenharmony_ci { TIM9_TRGO, TIM9_CH1, TIM9_CH2,}, 328c2ecf20Sopenharmony_ci { TIM10_OC1,}, 338c2ecf20Sopenharmony_ci { TIM11_OC1,}, 348c2ecf20Sopenharmony_ci { TIM12_TRGO, TIM12_CH1, TIM12_CH2,}, 358c2ecf20Sopenharmony_ci { TIM13_OC1,}, 368c2ecf20Sopenharmony_ci { TIM14_OC1,}, 378c2ecf20Sopenharmony_ci { TIM15_TRGO,}, 388c2ecf20Sopenharmony_ci { TIM16_OC1,}, 398c2ecf20Sopenharmony_ci { TIM17_OC1,}, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* List the triggers accepted by each timer */ 438c2ecf20Sopenharmony_cistatic const void *valids_table[][MAX_VALIDS] = { 448c2ecf20Sopenharmony_ci { TIM5_TRGO, TIM2_TRGO, TIM3_TRGO, TIM4_TRGO,}, 458c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM8_TRGO, TIM3_TRGO, TIM4_TRGO,}, 468c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM2_TRGO, TIM5_TRGO, TIM4_TRGO,}, 478c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM2_TRGO, TIM3_TRGO, TIM8_TRGO,}, 488c2ecf20Sopenharmony_ci { TIM2_TRGO, TIM3_TRGO, TIM4_TRGO, TIM8_TRGO,}, 498c2ecf20Sopenharmony_ci { }, /* timer 6 */ 508c2ecf20Sopenharmony_ci { }, /* timer 7 */ 518c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM2_TRGO, TIM4_TRGO, TIM5_TRGO,}, 528c2ecf20Sopenharmony_ci { TIM2_TRGO, TIM3_TRGO, TIM10_OC1, TIM11_OC1,}, 538c2ecf20Sopenharmony_ci { }, /* timer 10 */ 548c2ecf20Sopenharmony_ci { }, /* timer 11 */ 558c2ecf20Sopenharmony_ci { TIM4_TRGO, TIM5_TRGO, TIM13_OC1, TIM14_OC1,}, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic const void *stm32h7_valids_table[][MAX_VALIDS] = { 598c2ecf20Sopenharmony_ci { TIM15_TRGO, TIM2_TRGO, TIM3_TRGO, TIM4_TRGO,}, 608c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM8_TRGO, TIM3_TRGO, TIM4_TRGO,}, 618c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM2_TRGO, TIM15_TRGO, TIM4_TRGO,}, 628c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM2_TRGO, TIM3_TRGO, TIM8_TRGO,}, 638c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM8_TRGO, TIM3_TRGO, TIM4_TRGO,}, 648c2ecf20Sopenharmony_ci { }, /* timer 6 */ 658c2ecf20Sopenharmony_ci { }, /* timer 7 */ 668c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM2_TRGO, TIM4_TRGO, TIM5_TRGO,}, 678c2ecf20Sopenharmony_ci { }, /* timer 9 */ 688c2ecf20Sopenharmony_ci { }, /* timer 10 */ 698c2ecf20Sopenharmony_ci { }, /* timer 11 */ 708c2ecf20Sopenharmony_ci { TIM4_TRGO, TIM5_TRGO, TIM13_OC1, TIM14_OC1,}, 718c2ecf20Sopenharmony_ci { }, /* timer 13 */ 728c2ecf20Sopenharmony_ci { }, /* timer 14 */ 738c2ecf20Sopenharmony_ci { TIM1_TRGO, TIM3_TRGO, TIM16_OC1, TIM17_OC1,}, 748c2ecf20Sopenharmony_ci { }, /* timer 16 */ 758c2ecf20Sopenharmony_ci { }, /* timer 17 */ 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistruct stm32_timer_trigger_regs { 798c2ecf20Sopenharmony_ci u32 cr1; 808c2ecf20Sopenharmony_ci u32 cr2; 818c2ecf20Sopenharmony_ci u32 psc; 828c2ecf20Sopenharmony_ci u32 arr; 838c2ecf20Sopenharmony_ci u32 cnt; 848c2ecf20Sopenharmony_ci u32 smcr; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct stm32_timer_trigger { 888c2ecf20Sopenharmony_ci struct device *dev; 898c2ecf20Sopenharmony_ci struct regmap *regmap; 908c2ecf20Sopenharmony_ci struct clk *clk; 918c2ecf20Sopenharmony_ci bool enabled; 928c2ecf20Sopenharmony_ci u32 max_arr; 938c2ecf20Sopenharmony_ci const void *triggers; 948c2ecf20Sopenharmony_ci const void *valids; 958c2ecf20Sopenharmony_ci bool has_trgo2; 968c2ecf20Sopenharmony_ci struct mutex lock; /* concurrent sysfs configuration */ 978c2ecf20Sopenharmony_ci struct list_head tr_list; 988c2ecf20Sopenharmony_ci struct stm32_timer_trigger_regs bak; 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct stm32_timer_trigger_cfg { 1028c2ecf20Sopenharmony_ci const void *(*valids_table)[MAX_VALIDS]; 1038c2ecf20Sopenharmony_ci const unsigned int num_valids_table; 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic bool stm32_timer_is_trgo2_name(const char *name) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return !!strstr(name, "trgo2"); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic bool stm32_timer_is_trgo_name(const char *name) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return (!!strstr(name, "trgo") && !strstr(name, "trgo2")); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int stm32_timer_start(struct stm32_timer_trigger *priv, 1178c2ecf20Sopenharmony_ci struct iio_trigger *trig, 1188c2ecf20Sopenharmony_ci unsigned int frequency) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci unsigned long long prd, div; 1218c2ecf20Sopenharmony_ci int prescaler = 0; 1228c2ecf20Sopenharmony_ci u32 ccer; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Period and prescaler values depends of clock rate */ 1258c2ecf20Sopenharmony_ci div = (unsigned long long)clk_get_rate(priv->clk); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci do_div(div, frequency); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci prd = div; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * Increase prescaler value until we get a result that fit 1338c2ecf20Sopenharmony_ci * with auto reload register maximum value. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci while (div > priv->max_arr) { 1368c2ecf20Sopenharmony_ci prescaler++; 1378c2ecf20Sopenharmony_ci div = prd; 1388c2ecf20Sopenharmony_ci do_div(div, (prescaler + 1)); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci prd = div; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (prescaler > MAX_TIM_PSC) { 1438c2ecf20Sopenharmony_ci dev_err(priv->dev, "prescaler exceeds the maximum value\n"); 1448c2ecf20Sopenharmony_ci return -EINVAL; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Check if nobody else use the timer */ 1488c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CCER, &ccer); 1498c2ecf20Sopenharmony_ci if (ccer & TIM_CCER_CCXE) 1508c2ecf20Sopenharmony_ci return -EBUSY; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 1538c2ecf20Sopenharmony_ci if (!priv->enabled) { 1548c2ecf20Sopenharmony_ci priv->enabled = true; 1558c2ecf20Sopenharmony_ci clk_enable(priv->clk); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_PSC, prescaler); 1598c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_ARR, prd - 1); 1608c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Force master mode to update mode */ 1638c2ecf20Sopenharmony_ci if (stm32_timer_is_trgo2_name(trig->name)) 1648c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 1658c2ecf20Sopenharmony_ci 0x2 << TIM_CR2_MMS2_SHIFT); 1668c2ecf20Sopenharmony_ci else 1678c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 1688c2ecf20Sopenharmony_ci 0x2 << TIM_CR2_MMS_SHIFT); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Make sure that registers are updated */ 1718c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* Enable controller */ 1748c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); 1758c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void stm32_timer_stop(struct stm32_timer_trigger *priv, 1818c2ecf20Sopenharmony_ci struct iio_trigger *trig) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci u32 ccer; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CCER, &ccer); 1868c2ecf20Sopenharmony_ci if (ccer & TIM_CCER_CCXE) 1878c2ecf20Sopenharmony_ci return; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 1908c2ecf20Sopenharmony_ci /* Stop timer */ 1918c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); 1928c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); 1938c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_PSC, 0); 1948c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_ARR, 0); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Force disable master mode */ 1978c2ecf20Sopenharmony_ci if (stm32_timer_is_trgo2_name(trig->name)) 1988c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); 1998c2ecf20Sopenharmony_ci else 2008c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Make sure that registers are updated */ 2038c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (priv->enabled) { 2068c2ecf20Sopenharmony_ci priv->enabled = false; 2078c2ecf20Sopenharmony_ci clk_disable(priv->clk); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic ssize_t stm32_tt_store_frequency(struct device *dev, 2138c2ecf20Sopenharmony_ci struct device_attribute *attr, 2148c2ecf20Sopenharmony_ci const char *buf, size_t len) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct iio_trigger *trig = to_iio_trigger(dev); 2178c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_trigger_get_drvdata(trig); 2188c2ecf20Sopenharmony_ci unsigned int freq; 2198c2ecf20Sopenharmony_ci int ret; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ret = kstrtouint(buf, 10, &freq); 2228c2ecf20Sopenharmony_ci if (ret) 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (freq == 0) { 2268c2ecf20Sopenharmony_ci stm32_timer_stop(priv, trig); 2278c2ecf20Sopenharmony_ci } else { 2288c2ecf20Sopenharmony_ci ret = stm32_timer_start(priv, trig, freq); 2298c2ecf20Sopenharmony_ci if (ret) 2308c2ecf20Sopenharmony_ci return ret; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return len; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic ssize_t stm32_tt_read_frequency(struct device *dev, 2378c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct iio_trigger *trig = to_iio_trigger(dev); 2408c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_trigger_get_drvdata(trig); 2418c2ecf20Sopenharmony_ci u32 psc, arr, cr1; 2428c2ecf20Sopenharmony_ci unsigned long long freq = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CR1, &cr1); 2458c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_PSC, &psc); 2468c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_ARR, &arr); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (cr1 & TIM_CR1_CEN) { 2498c2ecf20Sopenharmony_ci freq = (unsigned long long)clk_get_rate(priv->clk); 2508c2ecf20Sopenharmony_ci do_div(freq, psc + 1); 2518c2ecf20Sopenharmony_ci do_div(freq, arr + 1); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", (unsigned int)freq); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic IIO_DEV_ATTR_SAMP_FREQ(0660, 2588c2ecf20Sopenharmony_ci stm32_tt_read_frequency, 2598c2ecf20Sopenharmony_ci stm32_tt_store_frequency); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci#define MASTER_MODE_MAX 7 2628c2ecf20Sopenharmony_ci#define MASTER_MODE2_MAX 15 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic char *master_mode_table[] = { 2658c2ecf20Sopenharmony_ci "reset", 2668c2ecf20Sopenharmony_ci "enable", 2678c2ecf20Sopenharmony_ci "update", 2688c2ecf20Sopenharmony_ci "compare_pulse", 2698c2ecf20Sopenharmony_ci "OC1REF", 2708c2ecf20Sopenharmony_ci "OC2REF", 2718c2ecf20Sopenharmony_ci "OC3REF", 2728c2ecf20Sopenharmony_ci "OC4REF", 2738c2ecf20Sopenharmony_ci /* Master mode selection 2 only */ 2748c2ecf20Sopenharmony_ci "OC5REF", 2758c2ecf20Sopenharmony_ci "OC6REF", 2768c2ecf20Sopenharmony_ci "compare_pulse_OC4REF", 2778c2ecf20Sopenharmony_ci "compare_pulse_OC6REF", 2788c2ecf20Sopenharmony_ci "compare_pulse_OC4REF_r_or_OC6REF_r", 2798c2ecf20Sopenharmony_ci "compare_pulse_OC4REF_r_or_OC6REF_f", 2808c2ecf20Sopenharmony_ci "compare_pulse_OC5REF_r_or_OC6REF_r", 2818c2ecf20Sopenharmony_ci "compare_pulse_OC5REF_r_or_OC6REF_f", 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic ssize_t stm32_tt_show_master_mode(struct device *dev, 2858c2ecf20Sopenharmony_ci struct device_attribute *attr, 2868c2ecf20Sopenharmony_ci char *buf) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = dev_get_drvdata(dev); 2898c2ecf20Sopenharmony_ci struct iio_trigger *trig = to_iio_trigger(dev); 2908c2ecf20Sopenharmony_ci u32 cr2; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CR2, &cr2); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (stm32_timer_is_trgo2_name(trig->name)) 2958c2ecf20Sopenharmony_ci cr2 = (cr2 & TIM_CR2_MMS2) >> TIM_CR2_MMS2_SHIFT; 2968c2ecf20Sopenharmony_ci else 2978c2ecf20Sopenharmony_ci cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic ssize_t stm32_tt_store_master_mode(struct device *dev, 3038c2ecf20Sopenharmony_ci struct device_attribute *attr, 3048c2ecf20Sopenharmony_ci const char *buf, size_t len) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = dev_get_drvdata(dev); 3078c2ecf20Sopenharmony_ci struct iio_trigger *trig = to_iio_trigger(dev); 3088c2ecf20Sopenharmony_ci u32 mask, shift, master_mode_max; 3098c2ecf20Sopenharmony_ci int i; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (stm32_timer_is_trgo2_name(trig->name)) { 3128c2ecf20Sopenharmony_ci mask = TIM_CR2_MMS2; 3138c2ecf20Sopenharmony_ci shift = TIM_CR2_MMS2_SHIFT; 3148c2ecf20Sopenharmony_ci master_mode_max = MASTER_MODE2_MAX; 3158c2ecf20Sopenharmony_ci } else { 3168c2ecf20Sopenharmony_ci mask = TIM_CR2_MMS; 3178c2ecf20Sopenharmony_ci shift = TIM_CR2_MMS_SHIFT; 3188c2ecf20Sopenharmony_ci master_mode_max = MASTER_MODE_MAX; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci for (i = 0; i <= master_mode_max; i++) { 3228c2ecf20Sopenharmony_ci if (!strncmp(master_mode_table[i], buf, 3238c2ecf20Sopenharmony_ci strlen(master_mode_table[i]))) { 3248c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 3258c2ecf20Sopenharmony_ci if (!priv->enabled) { 3268c2ecf20Sopenharmony_ci /* Clock should be enabled first */ 3278c2ecf20Sopenharmony_ci priv->enabled = true; 3288c2ecf20Sopenharmony_ci clk_enable(priv->clk); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR2, mask, 3318c2ecf20Sopenharmony_ci i << shift); 3328c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 3338c2ecf20Sopenharmony_ci return len; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic ssize_t stm32_tt_show_master_mode_avail(struct device *dev, 3418c2ecf20Sopenharmony_ci struct device_attribute *attr, 3428c2ecf20Sopenharmony_ci char *buf) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct iio_trigger *trig = to_iio_trigger(dev); 3458c2ecf20Sopenharmony_ci unsigned int i, master_mode_max; 3468c2ecf20Sopenharmony_ci size_t len = 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (stm32_timer_is_trgo2_name(trig->name)) 3498c2ecf20Sopenharmony_ci master_mode_max = MASTER_MODE2_MAX; 3508c2ecf20Sopenharmony_ci else 3518c2ecf20Sopenharmony_ci master_mode_max = MASTER_MODE_MAX; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci for (i = 0; i <= master_mode_max; i++) 3548c2ecf20Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, 3558c2ecf20Sopenharmony_ci "%s ", master_mode_table[i]); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* replace trailing space by newline */ 3588c2ecf20Sopenharmony_ci buf[len - 1] = '\n'; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return len; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(master_mode_available, 0444, 3648c2ecf20Sopenharmony_ci stm32_tt_show_master_mode_avail, NULL, 0); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(master_mode, 0660, 3678c2ecf20Sopenharmony_ci stm32_tt_show_master_mode, 3688c2ecf20Sopenharmony_ci stm32_tt_store_master_mode, 3698c2ecf20Sopenharmony_ci 0); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic struct attribute *stm32_trigger_attrs[] = { 3728c2ecf20Sopenharmony_ci &iio_dev_attr_sampling_frequency.dev_attr.attr, 3738c2ecf20Sopenharmony_ci &iio_dev_attr_master_mode.dev_attr.attr, 3748c2ecf20Sopenharmony_ci &iio_dev_attr_master_mode_available.dev_attr.attr, 3758c2ecf20Sopenharmony_ci NULL, 3768c2ecf20Sopenharmony_ci}; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic const struct attribute_group stm32_trigger_attr_group = { 3798c2ecf20Sopenharmony_ci .attrs = stm32_trigger_attrs, 3808c2ecf20Sopenharmony_ci}; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic const struct attribute_group *stm32_trigger_attr_groups[] = { 3838c2ecf20Sopenharmony_ci &stm32_trigger_attr_group, 3848c2ecf20Sopenharmony_ci NULL, 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic const struct iio_trigger_ops timer_trigger_ops = { 3888c2ecf20Sopenharmony_ci}; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic void stm32_unregister_iio_triggers(struct stm32_timer_trigger *priv) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct iio_trigger *tr; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci list_for_each_entry(tr, &priv->tr_list, alloc_list) 3958c2ecf20Sopenharmony_ci iio_trigger_unregister(tr); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int stm32_register_iio_triggers(struct stm32_timer_trigger *priv) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci int ret; 4018c2ecf20Sopenharmony_ci const char * const *cur = priv->triggers; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->tr_list); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci while (cur && *cur) { 4068c2ecf20Sopenharmony_ci struct iio_trigger *trig; 4078c2ecf20Sopenharmony_ci bool cur_is_trgo = stm32_timer_is_trgo_name(*cur); 4088c2ecf20Sopenharmony_ci bool cur_is_trgo2 = stm32_timer_is_trgo2_name(*cur); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (cur_is_trgo2 && !priv->has_trgo2) { 4118c2ecf20Sopenharmony_ci cur++; 4128c2ecf20Sopenharmony_ci continue; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur); 4168c2ecf20Sopenharmony_ci if (!trig) 4178c2ecf20Sopenharmony_ci return -ENOMEM; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci trig->dev.parent = priv->dev->parent; 4208c2ecf20Sopenharmony_ci trig->ops = &timer_trigger_ops; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * sampling frequency and master mode attributes 4248c2ecf20Sopenharmony_ci * should only be available on trgo/trgo2 triggers 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ci if (cur_is_trgo || cur_is_trgo2) 4278c2ecf20Sopenharmony_ci trig->dev.groups = stm32_trigger_attr_groups; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci iio_trigger_set_drvdata(trig, priv); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ret = iio_trigger_register(trig); 4328c2ecf20Sopenharmony_ci if (ret) { 4338c2ecf20Sopenharmony_ci stm32_unregister_iio_triggers(priv); 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci list_add_tail(&trig->alloc_list, &priv->tr_list); 4388c2ecf20Sopenharmony_ci cur++; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int stm32_counter_read_raw(struct iio_dev *indio_dev, 4458c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 4468c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 4498c2ecf20Sopenharmony_ci u32 dat; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci switch (mask) { 4528c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 4538c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CNT, &dat); 4548c2ecf20Sopenharmony_ci *val = dat; 4558c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_ENABLE: 4588c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CR1, &dat); 4598c2ecf20Sopenharmony_ci *val = (dat & TIM_CR1_CEN) ? 1 : 0; 4608c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 4638c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_SMCR, &dat); 4648c2ecf20Sopenharmony_ci dat &= TIM_SMCR_SMS; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci *val = 1; 4678c2ecf20Sopenharmony_ci *val2 = 0; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* in quadrature case scale = 0.25 */ 4708c2ecf20Sopenharmony_ci if (dat == 3) 4718c2ecf20Sopenharmony_ci *val2 = 2; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return -EINVAL; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int stm32_counter_write_raw(struct iio_dev *indio_dev, 4808c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 4818c2ecf20Sopenharmony_ci int val, int val2, long mask) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci switch (mask) { 4868c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 4878c2ecf20Sopenharmony_ci return regmap_write(priv->regmap, TIM_CNT, val); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 4908c2ecf20Sopenharmony_ci /* fixed scale */ 4918c2ecf20Sopenharmony_ci return -EINVAL; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_ENABLE: 4948c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 4958c2ecf20Sopenharmony_ci if (val) { 4968c2ecf20Sopenharmony_ci if (!priv->enabled) { 4978c2ecf20Sopenharmony_ci priv->enabled = true; 4988c2ecf20Sopenharmony_ci clk_enable(priv->clk); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 5018c2ecf20Sopenharmony_ci TIM_CR1_CEN); 5028c2ecf20Sopenharmony_ci } else { 5038c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 5048c2ecf20Sopenharmony_ci 0); 5058c2ecf20Sopenharmony_ci if (priv->enabled) { 5068c2ecf20Sopenharmony_ci priv->enabled = false; 5078c2ecf20Sopenharmony_ci clk_disable(priv->clk); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return -EINVAL; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int stm32_counter_validate_trigger(struct iio_dev *indio_dev, 5188c2ecf20Sopenharmony_ci struct iio_trigger *trig) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 5218c2ecf20Sopenharmony_ci const char * const *cur = priv->valids; 5228c2ecf20Sopenharmony_ci unsigned int i = 0; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (!is_stm32_timer_trigger(trig)) 5258c2ecf20Sopenharmony_ci return -EINVAL; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci while (cur && *cur) { 5288c2ecf20Sopenharmony_ci if (!strncmp(trig->name, *cur, strlen(trig->name))) { 5298c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, 5308c2ecf20Sopenharmony_ci TIM_SMCR, TIM_SMCR_TS, 5318c2ecf20Sopenharmony_ci i << TIM_SMCR_TS_SHIFT); 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci cur++; 5358c2ecf20Sopenharmony_ci i++; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return -EINVAL; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic const struct iio_info stm32_trigger_info = { 5428c2ecf20Sopenharmony_ci .validate_trigger = stm32_counter_validate_trigger, 5438c2ecf20Sopenharmony_ci .read_raw = stm32_counter_read_raw, 5448c2ecf20Sopenharmony_ci .write_raw = stm32_counter_write_raw 5458c2ecf20Sopenharmony_ci}; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic const char *const stm32_trigger_modes[] = { 5488c2ecf20Sopenharmony_ci "trigger", 5498c2ecf20Sopenharmony_ci}; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int stm32_set_trigger_mode(struct iio_dev *indio_dev, 5528c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 5538c2ecf20Sopenharmony_ci unsigned int mode) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, TIM_SMCR_SMS); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return 0; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic int stm32_get_trigger_mode(struct iio_dev *indio_dev, 5638c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 5668c2ecf20Sopenharmony_ci u32 smcr; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_SMCR, &smcr); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return (smcr & TIM_SMCR_SMS) == TIM_SMCR_SMS ? 0 : -EINVAL; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic const struct iio_enum stm32_trigger_mode_enum = { 5748c2ecf20Sopenharmony_ci .items = stm32_trigger_modes, 5758c2ecf20Sopenharmony_ci .num_items = ARRAY_SIZE(stm32_trigger_modes), 5768c2ecf20Sopenharmony_ci .set = stm32_set_trigger_mode, 5778c2ecf20Sopenharmony_ci .get = stm32_get_trigger_mode 5788c2ecf20Sopenharmony_ci}; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic const char *const stm32_enable_modes[] = { 5818c2ecf20Sopenharmony_ci "always", 5828c2ecf20Sopenharmony_ci "gated", 5838c2ecf20Sopenharmony_ci "triggered", 5848c2ecf20Sopenharmony_ci}; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int stm32_enable_mode2sms(int mode) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci switch (mode) { 5898c2ecf20Sopenharmony_ci case 0: 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci case 1: 5928c2ecf20Sopenharmony_ci return 5; 5938c2ecf20Sopenharmony_ci case 2: 5948c2ecf20Sopenharmony_ci return 6; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return -EINVAL; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic int stm32_set_enable_mode(struct iio_dev *indio_dev, 6018c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 6028c2ecf20Sopenharmony_ci unsigned int mode) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 6058c2ecf20Sopenharmony_ci int sms = stm32_enable_mode2sms(mode); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (sms < 0) 6088c2ecf20Sopenharmony_ci return sms; 6098c2ecf20Sopenharmony_ci /* 6108c2ecf20Sopenharmony_ci * Triggered mode sets CEN bit automatically by hardware. So, first 6118c2ecf20Sopenharmony_ci * enable counter clock, so it can use it. Keeps it in sync with CEN. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 6148c2ecf20Sopenharmony_ci if (sms == 6 && !priv->enabled) { 6158c2ecf20Sopenharmony_ci clk_enable(priv->clk); 6168c2ecf20Sopenharmony_ci priv->enabled = true; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int stm32_sms2enable_mode(int mode) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci switch (mode) { 6288c2ecf20Sopenharmony_ci case 0: 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci case 5: 6318c2ecf20Sopenharmony_ci return 1; 6328c2ecf20Sopenharmony_ci case 6: 6338c2ecf20Sopenharmony_ci return 2; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return -EINVAL; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic int stm32_get_enable_mode(struct iio_dev *indio_dev, 6408c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 6438c2ecf20Sopenharmony_ci u32 smcr; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_SMCR, &smcr); 6468c2ecf20Sopenharmony_ci smcr &= TIM_SMCR_SMS; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return stm32_sms2enable_mode(smcr); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic const struct iio_enum stm32_enable_mode_enum = { 6528c2ecf20Sopenharmony_ci .items = stm32_enable_modes, 6538c2ecf20Sopenharmony_ci .num_items = ARRAY_SIZE(stm32_enable_modes), 6548c2ecf20Sopenharmony_ci .set = stm32_set_enable_mode, 6558c2ecf20Sopenharmony_ci .get = stm32_get_enable_mode 6568c2ecf20Sopenharmony_ci}; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic ssize_t stm32_count_get_preset(struct iio_dev *indio_dev, 6598c2ecf20Sopenharmony_ci uintptr_t private, 6608c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 6618c2ecf20Sopenharmony_ci char *buf) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 6648c2ecf20Sopenharmony_ci u32 arr; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_ARR, &arr); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%u\n", arr); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic ssize_t stm32_count_set_preset(struct iio_dev *indio_dev, 6728c2ecf20Sopenharmony_ci uintptr_t private, 6738c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 6748c2ecf20Sopenharmony_ci const char *buf, size_t len) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = iio_priv(indio_dev); 6778c2ecf20Sopenharmony_ci unsigned int preset; 6788c2ecf20Sopenharmony_ci int ret; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci ret = kstrtouint(buf, 0, &preset); 6818c2ecf20Sopenharmony_ci if (ret) 6828c2ecf20Sopenharmony_ci return ret; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* TIMx_ARR register shouldn't be buffered (ARPE=0) */ 6858c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); 6868c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_ARR, preset); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return len; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info stm32_trigger_count_info[] = { 6928c2ecf20Sopenharmony_ci { 6938c2ecf20Sopenharmony_ci .name = "preset", 6948c2ecf20Sopenharmony_ci .shared = IIO_SEPARATE, 6958c2ecf20Sopenharmony_ci .read = stm32_count_get_preset, 6968c2ecf20Sopenharmony_ci .write = stm32_count_set_preset 6978c2ecf20Sopenharmony_ci }, 6988c2ecf20Sopenharmony_ci IIO_ENUM("enable_mode", IIO_SEPARATE, &stm32_enable_mode_enum), 6998c2ecf20Sopenharmony_ci IIO_ENUM_AVAILABLE("enable_mode", &stm32_enable_mode_enum), 7008c2ecf20Sopenharmony_ci IIO_ENUM("trigger_mode", IIO_SEPARATE, &stm32_trigger_mode_enum), 7018c2ecf20Sopenharmony_ci IIO_ENUM_AVAILABLE("trigger_mode", &stm32_trigger_mode_enum), 7028c2ecf20Sopenharmony_ci {} 7038c2ecf20Sopenharmony_ci}; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic const struct iio_chan_spec stm32_trigger_channel = { 7068c2ecf20Sopenharmony_ci .type = IIO_COUNT, 7078c2ecf20Sopenharmony_ci .channel = 0, 7088c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 7098c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_ENABLE) | 7108c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), 7118c2ecf20Sopenharmony_ci .ext_info = stm32_trigger_count_info, 7128c2ecf20Sopenharmony_ci .indexed = 1 7138c2ecf20Sopenharmony_ci}; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic struct stm32_timer_trigger *stm32_setup_counter_device(struct device *dev) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 7188c2ecf20Sopenharmony_ci int ret; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, 7218c2ecf20Sopenharmony_ci sizeof(struct stm32_timer_trigger)); 7228c2ecf20Sopenharmony_ci if (!indio_dev) 7238c2ecf20Sopenharmony_ci return NULL; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci indio_dev->name = dev_name(dev); 7268c2ecf20Sopenharmony_ci indio_dev->info = &stm32_trigger_info; 7278c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_HARDWARE_TRIGGERED; 7288c2ecf20Sopenharmony_ci indio_dev->num_channels = 1; 7298c2ecf20Sopenharmony_ci indio_dev->channels = &stm32_trigger_channel; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci ret = devm_iio_device_register(dev, indio_dev); 7328c2ecf20Sopenharmony_ci if (ret) 7338c2ecf20Sopenharmony_ci return NULL; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci return iio_priv(indio_dev); 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci/** 7398c2ecf20Sopenharmony_ci * is_stm32_timer_trigger 7408c2ecf20Sopenharmony_ci * @trig: trigger to be checked 7418c2ecf20Sopenharmony_ci * 7428c2ecf20Sopenharmony_ci * return true if the trigger is a valid stm32 iio timer trigger 7438c2ecf20Sopenharmony_ci * either return false 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_cibool is_stm32_timer_trigger(struct iio_trigger *trig) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci return (trig->ops == &timer_trigger_ops); 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(is_stm32_timer_trigger); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic void stm32_timer_detect_trgo2(struct stm32_timer_trigger *priv) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci u32 val; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* 7568c2ecf20Sopenharmony_ci * Master mode selection 2 bits can only be written and read back when 7578c2ecf20Sopenharmony_ci * timer supports it. 7588c2ecf20Sopenharmony_ci */ 7598c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, TIM_CR2_MMS2); 7608c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CR2, &val); 7618c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); 7628c2ecf20Sopenharmony_ci priv->has_trgo2 = !!val; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic int stm32_timer_trigger_probe(struct platform_device *pdev) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 7688c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv; 7698c2ecf20Sopenharmony_ci struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent); 7708c2ecf20Sopenharmony_ci const struct stm32_timer_trigger_cfg *cfg; 7718c2ecf20Sopenharmony_ci unsigned int index; 7728c2ecf20Sopenharmony_ci int ret; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (of_property_read_u32(dev->of_node, "reg", &index)) 7758c2ecf20Sopenharmony_ci return -EINVAL; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci cfg = (const struct stm32_timer_trigger_cfg *) 7788c2ecf20Sopenharmony_ci of_match_device(dev->driver->of_match_table, dev)->data; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (index >= ARRAY_SIZE(triggers_table) || 7818c2ecf20Sopenharmony_ci index >= cfg->num_valids_table) 7828c2ecf20Sopenharmony_ci return -EINVAL; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* Create an IIO device only if we have triggers to be validated */ 7858c2ecf20Sopenharmony_ci if (*cfg->valids_table[index]) 7868c2ecf20Sopenharmony_ci priv = stm32_setup_counter_device(dev); 7878c2ecf20Sopenharmony_ci else 7888c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (!priv) 7918c2ecf20Sopenharmony_ci return -ENOMEM; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci priv->dev = dev; 7948c2ecf20Sopenharmony_ci priv->regmap = ddata->regmap; 7958c2ecf20Sopenharmony_ci priv->clk = ddata->clk; 7968c2ecf20Sopenharmony_ci priv->max_arr = ddata->max_arr; 7978c2ecf20Sopenharmony_ci priv->triggers = triggers_table[index]; 7988c2ecf20Sopenharmony_ci priv->valids = cfg->valids_table[index]; 7998c2ecf20Sopenharmony_ci stm32_timer_detect_trgo2(priv); 8008c2ecf20Sopenharmony_ci mutex_init(&priv->lock); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci ret = stm32_register_iio_triggers(priv); 8038c2ecf20Sopenharmony_ci if (ret) 8048c2ecf20Sopenharmony_ci return ret; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci return 0; 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int stm32_timer_trigger_remove(struct platform_device *pdev) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = platform_get_drvdata(pdev); 8148c2ecf20Sopenharmony_ci u32 val; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* Unregister triggers before everything can be safely turned off */ 8178c2ecf20Sopenharmony_ci stm32_unregister_iio_triggers(priv); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Check if nobody else use the timer, then disable it */ 8208c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CCER, &val); 8218c2ecf20Sopenharmony_ci if (!(val & TIM_CCER_CCXE)) 8228c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (priv->enabled) 8258c2ecf20Sopenharmony_ci clk_disable(priv->clk); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci return 0; 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic int __maybe_unused stm32_timer_trigger_suspend(struct device *dev) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = dev_get_drvdata(dev); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Only take care of enabled timer: don't disturb other MFD child */ 8358c2ecf20Sopenharmony_ci if (priv->enabled) { 8368c2ecf20Sopenharmony_ci /* Backup registers that may get lost in low power mode */ 8378c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CR1, &priv->bak.cr1); 8388c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CR2, &priv->bak.cr2); 8398c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_PSC, &priv->bak.psc); 8408c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_ARR, &priv->bak.arr); 8418c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_CNT, &priv->bak.cnt); 8428c2ecf20Sopenharmony_ci regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Disable the timer */ 8458c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); 8468c2ecf20Sopenharmony_ci clk_disable(priv->clk); 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci return 0; 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic int __maybe_unused stm32_timer_trigger_resume(struct device *dev) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct stm32_timer_trigger *priv = dev_get_drvdata(dev); 8558c2ecf20Sopenharmony_ci int ret; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (priv->enabled) { 8588c2ecf20Sopenharmony_ci ret = clk_enable(priv->clk); 8598c2ecf20Sopenharmony_ci if (ret) 8608c2ecf20Sopenharmony_ci return ret; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci /* restore master/slave modes */ 8638c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr); 8648c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_CR2, priv->bak.cr2); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* restore sampling_frequency (trgo / trgo2 triggers) */ 8678c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_PSC, priv->bak.psc); 8688c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_ARR, priv->bak.arr); 8698c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_CNT, priv->bak.cnt); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* Also re-enables the timer */ 8728c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TIM_CR1, priv->bak.cr1); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops, 8798c2ecf20Sopenharmony_ci stm32_timer_trigger_suspend, 8808c2ecf20Sopenharmony_ci stm32_timer_trigger_resume); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = { 8838c2ecf20Sopenharmony_ci .valids_table = valids_table, 8848c2ecf20Sopenharmony_ci .num_valids_table = ARRAY_SIZE(valids_table), 8858c2ecf20Sopenharmony_ci}; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic const struct stm32_timer_trigger_cfg stm32h7_timer_trg_cfg = { 8888c2ecf20Sopenharmony_ci .valids_table = stm32h7_valids_table, 8898c2ecf20Sopenharmony_ci .num_valids_table = ARRAY_SIZE(stm32h7_valids_table), 8908c2ecf20Sopenharmony_ci}; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic const struct of_device_id stm32_trig_of_match[] = { 8938c2ecf20Sopenharmony_ci { 8948c2ecf20Sopenharmony_ci .compatible = "st,stm32-timer-trigger", 8958c2ecf20Sopenharmony_ci .data = (void *)&stm32_timer_trg_cfg, 8968c2ecf20Sopenharmony_ci }, { 8978c2ecf20Sopenharmony_ci .compatible = "st,stm32h7-timer-trigger", 8988c2ecf20Sopenharmony_ci .data = (void *)&stm32h7_timer_trg_cfg, 8998c2ecf20Sopenharmony_ci }, 9008c2ecf20Sopenharmony_ci { /* end node */ }, 9018c2ecf20Sopenharmony_ci}; 9028c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_trig_of_match); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic struct platform_driver stm32_timer_trigger_driver = { 9058c2ecf20Sopenharmony_ci .probe = stm32_timer_trigger_probe, 9068c2ecf20Sopenharmony_ci .remove = stm32_timer_trigger_remove, 9078c2ecf20Sopenharmony_ci .driver = { 9088c2ecf20Sopenharmony_ci .name = "stm32-timer-trigger", 9098c2ecf20Sopenharmony_ci .of_match_table = stm32_trig_of_match, 9108c2ecf20Sopenharmony_ci .pm = &stm32_timer_trigger_pm_ops, 9118c2ecf20Sopenharmony_ci }, 9128c2ecf20Sopenharmony_ci}; 9138c2ecf20Sopenharmony_cimodule_platform_driver(stm32_timer_trigger_driver); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:stm32-timer-trigger"); 9168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32 Timer Trigger driver"); 9178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 918