18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * STM32 Low-Power Timer Encoder and Counter driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics 2017 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Fabrice Gasnier <fabrice.gasnier@st.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Inspired by 104-quad-8 and stm32-timer-trigger drivers. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 148c2ecf20Sopenharmony_ci#include <linux/counter.h> 158c2ecf20Sopenharmony_ci#include <linux/mfd/stm32-lptimer.h> 168c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct stm32_lptim_cnt { 228c2ecf20Sopenharmony_ci struct counter_device counter; 238c2ecf20Sopenharmony_ci struct device *dev; 248c2ecf20Sopenharmony_ci struct regmap *regmap; 258c2ecf20Sopenharmony_ci struct clk *clk; 268c2ecf20Sopenharmony_ci u32 ceiling; 278c2ecf20Sopenharmony_ci u32 polarity; 288c2ecf20Sopenharmony_ci u32 quadrature_mode; 298c2ecf20Sopenharmony_ci bool enabled; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci u32 val; 358c2ecf20Sopenharmony_ci int ret; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci ret = regmap_read(priv->regmap, STM32_LPTIM_CR, &val); 388c2ecf20Sopenharmony_ci if (ret) 398c2ecf20Sopenharmony_ci return ret; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return FIELD_GET(STM32_LPTIM_ENABLE, val); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, 458c2ecf20Sopenharmony_ci int enable) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int ret; 488c2ecf20Sopenharmony_ci u32 val; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci val = FIELD_PREP(STM32_LPTIM_ENABLE, enable); 518c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, STM32_LPTIM_CR, val); 528c2ecf20Sopenharmony_ci if (ret) 538c2ecf20Sopenharmony_ci return ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (!enable) { 568c2ecf20Sopenharmony_ci clk_disable(priv->clk); 578c2ecf20Sopenharmony_ci priv->enabled = false; 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* LP timer must be enabled before writing CMP & ARR */ 628c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, priv->ceiling); 638c2ecf20Sopenharmony_ci if (ret) 648c2ecf20Sopenharmony_ci return ret; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, 0); 678c2ecf20Sopenharmony_ci if (ret) 688c2ecf20Sopenharmony_ci return ret; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* ensure CMP & ARR registers are properly written */ 718c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, 728c2ecf20Sopenharmony_ci (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK, 738c2ecf20Sopenharmony_ci 100, 1000); 748c2ecf20Sopenharmony_ci if (ret) 758c2ecf20Sopenharmony_ci return ret; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, 788c2ecf20Sopenharmony_ci STM32_LPTIM_CMPOKCF_ARROKCF); 798c2ecf20Sopenharmony_ci if (ret) 808c2ecf20Sopenharmony_ci return ret; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = clk_enable(priv->clk); 838c2ecf20Sopenharmony_ci if (ret) { 848c2ecf20Sopenharmony_ci regmap_write(priv->regmap, STM32_LPTIM_CR, 0); 858c2ecf20Sopenharmony_ci return ret; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci priv->enabled = true; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* Start LP timer in continuous mode */ 908c2ecf20Sopenharmony_ci return regmap_update_bits(priv->regmap, STM32_LPTIM_CR, 918c2ecf20Sopenharmony_ci STM32_LPTIM_CNTSTRT, STM32_LPTIM_CNTSTRT); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci u32 mask = STM32_LPTIM_ENC | STM32_LPTIM_COUNTMODE | 978c2ecf20Sopenharmony_ci STM32_LPTIM_CKPOL | STM32_LPTIM_PRESC; 988c2ecf20Sopenharmony_ci u32 val; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Setup LP timer encoder/counter and polarity, without prescaler */ 1018c2ecf20Sopenharmony_ci if (priv->quadrature_mode) 1028c2ecf20Sopenharmony_ci val = enable ? STM32_LPTIM_ENC : 0; 1038c2ecf20Sopenharmony_ci else 1048c2ecf20Sopenharmony_ci val = enable ? STM32_LPTIM_COUNTMODE : 0; 1058c2ecf20Sopenharmony_ci val |= FIELD_PREP(STM32_LPTIM_CKPOL, enable ? priv->polarity : 0); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/** 1118c2ecf20Sopenharmony_ci * enum stm32_lptim_cnt_function - enumerates LPTimer counter & encoder modes 1128c2ecf20Sopenharmony_ci * @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges 1138c2ecf20Sopenharmony_ci * @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature) 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * In non-quadrature mode, device counts up on active edge. 1168c2ecf20Sopenharmony_ci * In quadrature mode, encoder counting scenarios are as follows: 1178c2ecf20Sopenharmony_ci * +---------+----------+--------------------+--------------------+ 1188c2ecf20Sopenharmony_ci * | Active | Level on | IN1 signal | IN2 signal | 1198c2ecf20Sopenharmony_ci * | edge | opposite +----------+---------+----------+---------+ 1208c2ecf20Sopenharmony_ci * | | signal | Rising | Falling | Rising | Falling | 1218c2ecf20Sopenharmony_ci * +---------+----------+----------+---------+----------+---------+ 1228c2ecf20Sopenharmony_ci * | Rising | High -> | Down | - | Up | - | 1238c2ecf20Sopenharmony_ci * | edge | Low -> | Up | - | Down | - | 1248c2ecf20Sopenharmony_ci * +---------+----------+----------+---------+----------+---------+ 1258c2ecf20Sopenharmony_ci * | Falling | High -> | - | Up | - | Down | 1268c2ecf20Sopenharmony_ci * | edge | Low -> | - | Down | - | Up | 1278c2ecf20Sopenharmony_ci * +---------+----------+----------+---------+----------+---------+ 1288c2ecf20Sopenharmony_ci * | Both | High -> | Down | Up | Up | Down | 1298c2ecf20Sopenharmony_ci * | edges | Low -> | Up | Down | Down | Up | 1308c2ecf20Sopenharmony_ci * +---------+----------+----------+---------+----------+---------+ 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cienum stm32_lptim_cnt_function { 1338c2ecf20Sopenharmony_ci STM32_LPTIM_COUNTER_INCREASE, 1348c2ecf20Sopenharmony_ci STM32_LPTIM_ENCODER_BOTH_EDGE, 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic enum counter_count_function stm32_lptim_cnt_functions[] = { 1388c2ecf20Sopenharmony_ci [STM32_LPTIM_COUNTER_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE, 1398c2ecf20Sopenharmony_ci [STM32_LPTIM_ENCODER_BOTH_EDGE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cienum stm32_lptim_synapse_action { 1438c2ecf20Sopenharmony_ci STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE, 1448c2ecf20Sopenharmony_ci STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE, 1458c2ecf20Sopenharmony_ci STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES, 1468c2ecf20Sopenharmony_ci STM32_LPTIM_SYNAPSE_ACTION_NONE, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = { 1508c2ecf20Sopenharmony_ci /* Index must match with stm32_lptim_cnt_polarity[] (priv->polarity) */ 1518c2ecf20Sopenharmony_ci [STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE, 1528c2ecf20Sopenharmony_ci [STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE, 1538c2ecf20Sopenharmony_ci [STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES, 1548c2ecf20Sopenharmony_ci [STM32_LPTIM_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE, 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int stm32_lptim_cnt_read(struct counter_device *counter, 1588c2ecf20Sopenharmony_ci struct counter_count *count, unsigned long *val) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 1618c2ecf20Sopenharmony_ci u32 cnt; 1628c2ecf20Sopenharmony_ci int ret; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &cnt); 1658c2ecf20Sopenharmony_ci if (ret) 1668c2ecf20Sopenharmony_ci return ret; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci *val = cnt; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int stm32_lptim_cnt_function_get(struct counter_device *counter, 1748c2ecf20Sopenharmony_ci struct counter_count *count, 1758c2ecf20Sopenharmony_ci size_t *function) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (!priv->quadrature_mode) { 1808c2ecf20Sopenharmony_ci *function = STM32_LPTIM_COUNTER_INCREASE; 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (priv->polarity == STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES) { 1858c2ecf20Sopenharmony_ci *function = STM32_LPTIM_ENCODER_BOTH_EDGE; 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return -EINVAL; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int stm32_lptim_cnt_function_set(struct counter_device *counter, 1938c2ecf20Sopenharmony_ci struct counter_count *count, 1948c2ecf20Sopenharmony_ci size_t function) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (stm32_lptim_is_enabled(priv)) 1998c2ecf20Sopenharmony_ci return -EBUSY; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci switch (function) { 2028c2ecf20Sopenharmony_ci case STM32_LPTIM_COUNTER_INCREASE: 2038c2ecf20Sopenharmony_ci priv->quadrature_mode = 0; 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci case STM32_LPTIM_ENCODER_BOTH_EDGE: 2068c2ecf20Sopenharmony_ci priv->quadrature_mode = 1; 2078c2ecf20Sopenharmony_ci priv->polarity = STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES; 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return -EINVAL; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic ssize_t stm32_lptim_cnt_enable_read(struct counter_device *counter, 2158c2ecf20Sopenharmony_ci struct counter_count *count, 2168c2ecf20Sopenharmony_ci void *private, char *buf) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 2198c2ecf20Sopenharmony_ci int ret; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ret = stm32_lptim_is_enabled(priv); 2228c2ecf20Sopenharmony_ci if (ret < 0) 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", ret); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic ssize_t stm32_lptim_cnt_enable_write(struct counter_device *counter, 2298c2ecf20Sopenharmony_ci struct counter_count *count, 2308c2ecf20Sopenharmony_ci void *private, 2318c2ecf20Sopenharmony_ci const char *buf, size_t len) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 2348c2ecf20Sopenharmony_ci bool enable; 2358c2ecf20Sopenharmony_ci int ret; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ret = kstrtobool(buf, &enable); 2388c2ecf20Sopenharmony_ci if (ret) 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* Check nobody uses the timer, or already disabled/enabled */ 2428c2ecf20Sopenharmony_ci ret = stm32_lptim_is_enabled(priv); 2438c2ecf20Sopenharmony_ci if ((ret < 0) || (!ret && !enable)) 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci if (enable && ret) 2468c2ecf20Sopenharmony_ci return -EBUSY; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci ret = stm32_lptim_setup(priv, enable); 2498c2ecf20Sopenharmony_ci if (ret) 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci ret = stm32_lptim_set_enable_state(priv, enable); 2538c2ecf20Sopenharmony_ci if (ret) 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return len; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic ssize_t stm32_lptim_cnt_ceiling_read(struct counter_device *counter, 2608c2ecf20Sopenharmony_ci struct counter_count *count, 2618c2ecf20Sopenharmony_ci void *private, char *buf) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%u\n", priv->ceiling); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter, 2698c2ecf20Sopenharmony_ci struct counter_count *count, 2708c2ecf20Sopenharmony_ci void *private, 2718c2ecf20Sopenharmony_ci const char *buf, size_t len) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 2748c2ecf20Sopenharmony_ci unsigned int ceiling; 2758c2ecf20Sopenharmony_ci int ret; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (stm32_lptim_is_enabled(priv)) 2788c2ecf20Sopenharmony_ci return -EBUSY; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = kstrtouint(buf, 0, &ceiling); 2818c2ecf20Sopenharmony_ci if (ret) 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (ceiling > STM32_LPTIM_MAX_ARR) 2858c2ecf20Sopenharmony_ci return -EINVAL; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci priv->ceiling = ceiling; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return len; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic const struct counter_count_ext stm32_lptim_cnt_ext[] = { 2938c2ecf20Sopenharmony_ci { 2948c2ecf20Sopenharmony_ci .name = "enable", 2958c2ecf20Sopenharmony_ci .read = stm32_lptim_cnt_enable_read, 2968c2ecf20Sopenharmony_ci .write = stm32_lptim_cnt_enable_write 2978c2ecf20Sopenharmony_ci }, 2988c2ecf20Sopenharmony_ci { 2998c2ecf20Sopenharmony_ci .name = "ceiling", 3008c2ecf20Sopenharmony_ci .read = stm32_lptim_cnt_ceiling_read, 3018c2ecf20Sopenharmony_ci .write = stm32_lptim_cnt_ceiling_write 3028c2ecf20Sopenharmony_ci }, 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int stm32_lptim_cnt_action_get(struct counter_device *counter, 3068c2ecf20Sopenharmony_ci struct counter_count *count, 3078c2ecf20Sopenharmony_ci struct counter_synapse *synapse, 3088c2ecf20Sopenharmony_ci size_t *action) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 3118c2ecf20Sopenharmony_ci size_t function; 3128c2ecf20Sopenharmony_ci int err; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci err = stm32_lptim_cnt_function_get(counter, count, &function); 3158c2ecf20Sopenharmony_ci if (err) 3168c2ecf20Sopenharmony_ci return err; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci switch (function) { 3198c2ecf20Sopenharmony_ci case STM32_LPTIM_COUNTER_INCREASE: 3208c2ecf20Sopenharmony_ci /* LP Timer acts as up-counter on input 1 */ 3218c2ecf20Sopenharmony_ci if (synapse->signal->id == count->synapses[0].signal->id) 3228c2ecf20Sopenharmony_ci *action = priv->polarity; 3238c2ecf20Sopenharmony_ci else 3248c2ecf20Sopenharmony_ci *action = STM32_LPTIM_SYNAPSE_ACTION_NONE; 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci case STM32_LPTIM_ENCODER_BOTH_EDGE: 3278c2ecf20Sopenharmony_ci *action = priv->polarity; 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return -EINVAL; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int stm32_lptim_cnt_action_set(struct counter_device *counter, 3358c2ecf20Sopenharmony_ci struct counter_count *count, 3368c2ecf20Sopenharmony_ci struct counter_synapse *synapse, 3378c2ecf20Sopenharmony_ci size_t action) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *const priv = counter->priv; 3408c2ecf20Sopenharmony_ci size_t function; 3418c2ecf20Sopenharmony_ci int err; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (stm32_lptim_is_enabled(priv)) 3448c2ecf20Sopenharmony_ci return -EBUSY; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci err = stm32_lptim_cnt_function_get(counter, count, &function); 3478c2ecf20Sopenharmony_ci if (err) 3488c2ecf20Sopenharmony_ci return err; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* only set polarity when in counter mode (on input 1) */ 3518c2ecf20Sopenharmony_ci if (function == STM32_LPTIM_COUNTER_INCREASE 3528c2ecf20Sopenharmony_ci && synapse->signal->id == count->synapses[0].signal->id) { 3538c2ecf20Sopenharmony_ci switch (action) { 3548c2ecf20Sopenharmony_ci case STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE: 3558c2ecf20Sopenharmony_ci case STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE: 3568c2ecf20Sopenharmony_ci case STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES: 3578c2ecf20Sopenharmony_ci priv->polarity = action; 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return -EINVAL; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic const struct counter_ops stm32_lptim_cnt_ops = { 3668c2ecf20Sopenharmony_ci .count_read = stm32_lptim_cnt_read, 3678c2ecf20Sopenharmony_ci .function_get = stm32_lptim_cnt_function_get, 3688c2ecf20Sopenharmony_ci .function_set = stm32_lptim_cnt_function_set, 3698c2ecf20Sopenharmony_ci .action_get = stm32_lptim_cnt_action_get, 3708c2ecf20Sopenharmony_ci .action_set = stm32_lptim_cnt_action_set, 3718c2ecf20Sopenharmony_ci}; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic struct counter_signal stm32_lptim_cnt_signals[] = { 3748c2ecf20Sopenharmony_ci { 3758c2ecf20Sopenharmony_ci .id = 0, 3768c2ecf20Sopenharmony_ci .name = "Channel 1 Quadrature A" 3778c2ecf20Sopenharmony_ci }, 3788c2ecf20Sopenharmony_ci { 3798c2ecf20Sopenharmony_ci .id = 1, 3808c2ecf20Sopenharmony_ci .name = "Channel 1 Quadrature B" 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci}; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic struct counter_synapse stm32_lptim_cnt_synapses[] = { 3858c2ecf20Sopenharmony_ci { 3868c2ecf20Sopenharmony_ci .actions_list = stm32_lptim_cnt_synapse_actions, 3878c2ecf20Sopenharmony_ci .num_actions = ARRAY_SIZE(stm32_lptim_cnt_synapse_actions), 3888c2ecf20Sopenharmony_ci .signal = &stm32_lptim_cnt_signals[0] 3898c2ecf20Sopenharmony_ci }, 3908c2ecf20Sopenharmony_ci { 3918c2ecf20Sopenharmony_ci .actions_list = stm32_lptim_cnt_synapse_actions, 3928c2ecf20Sopenharmony_ci .num_actions = ARRAY_SIZE(stm32_lptim_cnt_synapse_actions), 3938c2ecf20Sopenharmony_ci .signal = &stm32_lptim_cnt_signals[1] 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci}; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/* LP timer with encoder */ 3988c2ecf20Sopenharmony_cistatic struct counter_count stm32_lptim_enc_counts = { 3998c2ecf20Sopenharmony_ci .id = 0, 4008c2ecf20Sopenharmony_ci .name = "LPTimer Count", 4018c2ecf20Sopenharmony_ci .functions_list = stm32_lptim_cnt_functions, 4028c2ecf20Sopenharmony_ci .num_functions = ARRAY_SIZE(stm32_lptim_cnt_functions), 4038c2ecf20Sopenharmony_ci .synapses = stm32_lptim_cnt_synapses, 4048c2ecf20Sopenharmony_ci .num_synapses = ARRAY_SIZE(stm32_lptim_cnt_synapses), 4058c2ecf20Sopenharmony_ci .ext = stm32_lptim_cnt_ext, 4068c2ecf20Sopenharmony_ci .num_ext = ARRAY_SIZE(stm32_lptim_cnt_ext) 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* LP timer without encoder (counter only) */ 4108c2ecf20Sopenharmony_cistatic struct counter_count stm32_lptim_in1_counts = { 4118c2ecf20Sopenharmony_ci .id = 0, 4128c2ecf20Sopenharmony_ci .name = "LPTimer Count", 4138c2ecf20Sopenharmony_ci .functions_list = stm32_lptim_cnt_functions, 4148c2ecf20Sopenharmony_ci .num_functions = 1, 4158c2ecf20Sopenharmony_ci .synapses = stm32_lptim_cnt_synapses, 4168c2ecf20Sopenharmony_ci .num_synapses = 1, 4178c2ecf20Sopenharmony_ci .ext = stm32_lptim_cnt_ext, 4188c2ecf20Sopenharmony_ci .num_ext = ARRAY_SIZE(stm32_lptim_cnt_ext) 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int stm32_lptim_cnt_probe(struct platform_device *pdev) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); 4248c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *priv; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(ddata)) 4278c2ecf20Sopenharmony_ci return -EINVAL; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 4308c2ecf20Sopenharmony_ci if (!priv) 4318c2ecf20Sopenharmony_ci return -ENOMEM; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci priv->dev = &pdev->dev; 4348c2ecf20Sopenharmony_ci priv->regmap = ddata->regmap; 4358c2ecf20Sopenharmony_ci priv->clk = ddata->clk; 4368c2ecf20Sopenharmony_ci priv->ceiling = STM32_LPTIM_MAX_ARR; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Initialize Counter device */ 4398c2ecf20Sopenharmony_ci priv->counter.name = dev_name(&pdev->dev); 4408c2ecf20Sopenharmony_ci priv->counter.parent = &pdev->dev; 4418c2ecf20Sopenharmony_ci priv->counter.ops = &stm32_lptim_cnt_ops; 4428c2ecf20Sopenharmony_ci if (ddata->has_encoder) { 4438c2ecf20Sopenharmony_ci priv->counter.counts = &stm32_lptim_enc_counts; 4448c2ecf20Sopenharmony_ci priv->counter.num_signals = ARRAY_SIZE(stm32_lptim_cnt_signals); 4458c2ecf20Sopenharmony_ci } else { 4468c2ecf20Sopenharmony_ci priv->counter.counts = &stm32_lptim_in1_counts; 4478c2ecf20Sopenharmony_ci priv->counter.num_signals = 1; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci priv->counter.num_counts = 1; 4508c2ecf20Sopenharmony_ci priv->counter.signals = stm32_lptim_cnt_signals; 4518c2ecf20Sopenharmony_ci priv->counter.priv = priv; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return devm_counter_register(&pdev->dev, &priv->counter); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4598c2ecf20Sopenharmony_cistatic int stm32_lptim_cnt_suspend(struct device *dev) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *priv = dev_get_drvdata(dev); 4628c2ecf20Sopenharmony_ci int ret; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Only take care of enabled counter: don't disturb other MFD child */ 4658c2ecf20Sopenharmony_ci if (priv->enabled) { 4668c2ecf20Sopenharmony_ci ret = stm32_lptim_setup(priv, 0); 4678c2ecf20Sopenharmony_ci if (ret) 4688c2ecf20Sopenharmony_ci return ret; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ret = stm32_lptim_set_enable_state(priv, 0); 4718c2ecf20Sopenharmony_ci if (ret) 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* Force enable state for later resume */ 4758c2ecf20Sopenharmony_ci priv->enabled = true; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return pinctrl_pm_select_sleep_state(dev); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int stm32_lptim_cnt_resume(struct device *dev) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct stm32_lptim_cnt *priv = dev_get_drvdata(dev); 4848c2ecf20Sopenharmony_ci int ret; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci ret = pinctrl_pm_select_default_state(dev); 4878c2ecf20Sopenharmony_ci if (ret) 4888c2ecf20Sopenharmony_ci return ret; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (priv->enabled) { 4918c2ecf20Sopenharmony_ci priv->enabled = false; 4928c2ecf20Sopenharmony_ci ret = stm32_lptim_setup(priv, 1); 4938c2ecf20Sopenharmony_ci if (ret) 4948c2ecf20Sopenharmony_ci return ret; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ret = stm32_lptim_set_enable_state(priv, 1); 4978c2ecf20Sopenharmony_ci if (ret) 4988c2ecf20Sopenharmony_ci return ret; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci#endif 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend, 5068c2ecf20Sopenharmony_ci stm32_lptim_cnt_resume); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic const struct of_device_id stm32_lptim_cnt_of_match[] = { 5098c2ecf20Sopenharmony_ci { .compatible = "st,stm32-lptimer-counter", }, 5108c2ecf20Sopenharmony_ci {}, 5118c2ecf20Sopenharmony_ci}; 5128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_lptim_cnt_of_match); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic struct platform_driver stm32_lptim_cnt_driver = { 5158c2ecf20Sopenharmony_ci .probe = stm32_lptim_cnt_probe, 5168c2ecf20Sopenharmony_ci .driver = { 5178c2ecf20Sopenharmony_ci .name = "stm32-lptimer-counter", 5188c2ecf20Sopenharmony_ci .of_match_table = stm32_lptim_cnt_of_match, 5198c2ecf20Sopenharmony_ci .pm = &stm32_lptim_cnt_pm_ops, 5208c2ecf20Sopenharmony_ci }, 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_cimodule_platform_driver(stm32_lptim_cnt_driver); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciMODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); 5258c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:stm32-lptimer-counter"); 5268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver"); 5278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 528