524 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * STM32 Low-Power Timer Encoder and Counter driver4 *5 * Copyright (C) STMicroelectronics 20176 *7 * Author: Fabrice Gasnier <fabrice.gasnier@st.com>8 *9 * Inspired by 104-quad-8 and stm32-timer-trigger drivers.10 *11 */12 13#include <linux/bitfield.h>14#include <linux/counter.h>15#include <linux/mfd/stm32-lptimer.h>16#include <linux/mod_devicetable.h>17#include <linux/module.h>18#include <linux/pinctrl/consumer.h>19#include <linux/platform_device.h>20#include <linux/types.h>21 22struct stm32_lptim_cnt {23 struct device *dev;24 struct regmap *regmap;25 struct clk *clk;26 u32 ceiling;27 u32 polarity;28 u32 quadrature_mode;29 bool enabled;30};31 32static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv)33{34 u32 val;35 int ret;36 37 ret = regmap_read(priv->regmap, STM32_LPTIM_CR, &val);38 if (ret)39 return ret;40 41 return FIELD_GET(STM32_LPTIM_ENABLE, val);42}43 44static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,45 int enable)46{47 int ret;48 u32 val;49 50 val = FIELD_PREP(STM32_LPTIM_ENABLE, enable);51 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, val);52 if (ret)53 return ret;54 55 if (!enable) {56 clk_disable(priv->clk);57 priv->enabled = false;58 return 0;59 }60 61 /* LP timer must be enabled before writing CMP & ARR */62 ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, priv->ceiling);63 if (ret)64 return ret;65 66 ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, 0);67 if (ret)68 return ret;69 70 /* ensure CMP & ARR registers are properly written */71 ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val,72 (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK,73 100, 1000);74 if (ret)75 return ret;76 77 ret = regmap_write(priv->regmap, STM32_LPTIM_ICR,78 STM32_LPTIM_CMPOKCF_ARROKCF);79 if (ret)80 return ret;81 82 ret = clk_enable(priv->clk);83 if (ret) {84 regmap_write(priv->regmap, STM32_LPTIM_CR, 0);85 return ret;86 }87 priv->enabled = true;88 89 /* Start LP timer in continuous mode */90 return regmap_update_bits(priv->regmap, STM32_LPTIM_CR,91 STM32_LPTIM_CNTSTRT, STM32_LPTIM_CNTSTRT);92}93 94static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable)95{96 u32 mask = STM32_LPTIM_ENC | STM32_LPTIM_COUNTMODE |97 STM32_LPTIM_CKPOL | STM32_LPTIM_PRESC;98 u32 val;99 100 /* Setup LP timer encoder/counter and polarity, without prescaler */101 if (priv->quadrature_mode)102 val = enable ? STM32_LPTIM_ENC : 0;103 else104 val = enable ? STM32_LPTIM_COUNTMODE : 0;105 val |= FIELD_PREP(STM32_LPTIM_CKPOL, enable ? priv->polarity : 0);106 107 return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val);108}109 110/*111 * In non-quadrature mode, device counts up on active edge.112 * In quadrature mode, encoder counting scenarios are as follows:113 * +---------+----------+--------------------+--------------------+114 * | Active | Level on | IN1 signal | IN2 signal |115 * | edge | opposite +----------+---------+----------+---------+116 * | | signal | Rising | Falling | Rising | Falling |117 * +---------+----------+----------+---------+----------+---------+118 * | Rising | High -> | Down | - | Up | - |119 * | edge | Low -> | Up | - | Down | - |120 * +---------+----------+----------+---------+----------+---------+121 * | Falling | High -> | - | Up | - | Down |122 * | edge | Low -> | - | Down | - | Up |123 * +---------+----------+----------+---------+----------+---------+124 * | Both | High -> | Down | Up | Up | Down |125 * | edges | Low -> | Up | Down | Down | Up |126 * +---------+----------+----------+---------+----------+---------+127 */128static const enum counter_function stm32_lptim_cnt_functions[] = {129 COUNTER_FUNCTION_INCREASE,130 COUNTER_FUNCTION_QUADRATURE_X4,131};132 133static const enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {134 COUNTER_SYNAPSE_ACTION_RISING_EDGE,135 COUNTER_SYNAPSE_ACTION_FALLING_EDGE,136 COUNTER_SYNAPSE_ACTION_BOTH_EDGES,137 COUNTER_SYNAPSE_ACTION_NONE,138};139 140static int stm32_lptim_cnt_read(struct counter_device *counter,141 struct counter_count *count, u64 *val)142{143 struct stm32_lptim_cnt *const priv = counter_priv(counter);144 u32 cnt;145 int ret;146 147 ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &cnt);148 if (ret)149 return ret;150 151 *val = cnt;152 153 return 0;154}155 156static int stm32_lptim_cnt_function_read(struct counter_device *counter,157 struct counter_count *count,158 enum counter_function *function)159{160 struct stm32_lptim_cnt *const priv = counter_priv(counter);161 162 if (!priv->quadrature_mode) {163 *function = COUNTER_FUNCTION_INCREASE;164 return 0;165 }166 167 if (priv->polarity == STM32_LPTIM_CKPOL_BOTH_EDGES) {168 *function = COUNTER_FUNCTION_QUADRATURE_X4;169 return 0;170 }171 172 return -EINVAL;173}174 175static int stm32_lptim_cnt_function_write(struct counter_device *counter,176 struct counter_count *count,177 enum counter_function function)178{179 struct stm32_lptim_cnt *const priv = counter_priv(counter);180 181 if (stm32_lptim_is_enabled(priv))182 return -EBUSY;183 184 switch (function) {185 case COUNTER_FUNCTION_INCREASE:186 priv->quadrature_mode = 0;187 return 0;188 case COUNTER_FUNCTION_QUADRATURE_X4:189 priv->quadrature_mode = 1;190 priv->polarity = STM32_LPTIM_CKPOL_BOTH_EDGES;191 return 0;192 default:193 /* should never reach this path */194 return -EINVAL;195 }196}197 198static int stm32_lptim_cnt_enable_read(struct counter_device *counter,199 struct counter_count *count,200 u8 *enable)201{202 struct stm32_lptim_cnt *const priv = counter_priv(counter);203 int ret;204 205 ret = stm32_lptim_is_enabled(priv);206 if (ret < 0)207 return ret;208 209 *enable = ret;210 211 return 0;212}213 214static int stm32_lptim_cnt_enable_write(struct counter_device *counter,215 struct counter_count *count,216 u8 enable)217{218 struct stm32_lptim_cnt *const priv = counter_priv(counter);219 int ret;220 221 /* Check nobody uses the timer, or already disabled/enabled */222 ret = stm32_lptim_is_enabled(priv);223 if ((ret < 0) || (!ret && !enable))224 return ret;225 if (enable && ret)226 return -EBUSY;227 228 ret = stm32_lptim_setup(priv, enable);229 if (ret)230 return ret;231 232 ret = stm32_lptim_set_enable_state(priv, enable);233 if (ret)234 return ret;235 236 return 0;237}238 239static int stm32_lptim_cnt_ceiling_read(struct counter_device *counter,240 struct counter_count *count,241 u64 *ceiling)242{243 struct stm32_lptim_cnt *const priv = counter_priv(counter);244 245 *ceiling = priv->ceiling;246 247 return 0;248}249 250static int stm32_lptim_cnt_ceiling_write(struct counter_device *counter,251 struct counter_count *count,252 u64 ceiling)253{254 struct stm32_lptim_cnt *const priv = counter_priv(counter);255 256 if (stm32_lptim_is_enabled(priv))257 return -EBUSY;258 259 if (ceiling > STM32_LPTIM_MAX_ARR)260 return -ERANGE;261 262 priv->ceiling = ceiling;263 264 return 0;265}266 267static struct counter_comp stm32_lptim_cnt_ext[] = {268 COUNTER_COMP_ENABLE(stm32_lptim_cnt_enable_read,269 stm32_lptim_cnt_enable_write),270 COUNTER_COMP_CEILING(stm32_lptim_cnt_ceiling_read,271 stm32_lptim_cnt_ceiling_write),272};273 274static int stm32_lptim_cnt_action_read(struct counter_device *counter,275 struct counter_count *count,276 struct counter_synapse *synapse,277 enum counter_synapse_action *action)278{279 struct stm32_lptim_cnt *const priv = counter_priv(counter);280 enum counter_function function;281 int err;282 283 err = stm32_lptim_cnt_function_read(counter, count, &function);284 if (err)285 return err;286 287 switch (function) {288 case COUNTER_FUNCTION_INCREASE:289 /* LP Timer acts as up-counter on input 1 */290 if (synapse->signal->id != count->synapses[0].signal->id) {291 *action = COUNTER_SYNAPSE_ACTION_NONE;292 return 0;293 }294 295 switch (priv->polarity) {296 case STM32_LPTIM_CKPOL_RISING_EDGE:297 *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;298 return 0;299 case STM32_LPTIM_CKPOL_FALLING_EDGE:300 *action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE;301 return 0;302 case STM32_LPTIM_CKPOL_BOTH_EDGES:303 *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;304 return 0;305 default:306 /* should never reach this path */307 return -EINVAL;308 }309 case COUNTER_FUNCTION_QUADRATURE_X4:310 *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;311 return 0;312 default:313 /* should never reach this path */314 return -EINVAL;315 }316}317 318static int stm32_lptim_cnt_action_write(struct counter_device *counter,319 struct counter_count *count,320 struct counter_synapse *synapse,321 enum counter_synapse_action action)322{323 struct stm32_lptim_cnt *const priv = counter_priv(counter);324 enum counter_function function;325 int err;326 327 if (stm32_lptim_is_enabled(priv))328 return -EBUSY;329 330 err = stm32_lptim_cnt_function_read(counter, count, &function);331 if (err)332 return err;333 334 /* only set polarity when in counter mode (on input 1) */335 if (function != COUNTER_FUNCTION_INCREASE336 || synapse->signal->id != count->synapses[0].signal->id)337 return -EINVAL;338 339 switch (action) {340 case COUNTER_SYNAPSE_ACTION_RISING_EDGE:341 priv->polarity = STM32_LPTIM_CKPOL_RISING_EDGE;342 return 0;343 case COUNTER_SYNAPSE_ACTION_FALLING_EDGE:344 priv->polarity = STM32_LPTIM_CKPOL_FALLING_EDGE;345 return 0;346 case COUNTER_SYNAPSE_ACTION_BOTH_EDGES:347 priv->polarity = STM32_LPTIM_CKPOL_BOTH_EDGES;348 return 0;349 default:350 return -EINVAL;351 }352}353 354static const struct counter_ops stm32_lptim_cnt_ops = {355 .count_read = stm32_lptim_cnt_read,356 .function_read = stm32_lptim_cnt_function_read,357 .function_write = stm32_lptim_cnt_function_write,358 .action_read = stm32_lptim_cnt_action_read,359 .action_write = stm32_lptim_cnt_action_write,360};361 362static struct counter_signal stm32_lptim_cnt_signals[] = {363 {364 .id = 0,365 .name = "Channel 1 Quadrature A"366 },367 {368 .id = 1,369 .name = "Channel 1 Quadrature B"370 }371};372 373static struct counter_synapse stm32_lptim_cnt_synapses[] = {374 {375 .actions_list = stm32_lptim_cnt_synapse_actions,376 .num_actions = ARRAY_SIZE(stm32_lptim_cnt_synapse_actions),377 .signal = &stm32_lptim_cnt_signals[0]378 },379 {380 .actions_list = stm32_lptim_cnt_synapse_actions,381 .num_actions = ARRAY_SIZE(stm32_lptim_cnt_synapse_actions),382 .signal = &stm32_lptim_cnt_signals[1]383 }384};385 386/* LP timer with encoder */387static struct counter_count stm32_lptim_enc_counts = {388 .id = 0,389 .name = "LPTimer Count",390 .functions_list = stm32_lptim_cnt_functions,391 .num_functions = ARRAY_SIZE(stm32_lptim_cnt_functions),392 .synapses = stm32_lptim_cnt_synapses,393 .num_synapses = ARRAY_SIZE(stm32_lptim_cnt_synapses),394 .ext = stm32_lptim_cnt_ext,395 .num_ext = ARRAY_SIZE(stm32_lptim_cnt_ext)396};397 398/* LP timer without encoder (counter only) */399static struct counter_count stm32_lptim_in1_counts = {400 .id = 0,401 .name = "LPTimer Count",402 .functions_list = stm32_lptim_cnt_functions,403 .num_functions = 1,404 .synapses = stm32_lptim_cnt_synapses,405 .num_synapses = 1,406 .ext = stm32_lptim_cnt_ext,407 .num_ext = ARRAY_SIZE(stm32_lptim_cnt_ext)408};409 410static int stm32_lptim_cnt_probe(struct platform_device *pdev)411{412 struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);413 struct counter_device *counter;414 struct stm32_lptim_cnt *priv;415 int ret;416 417 if (IS_ERR_OR_NULL(ddata))418 return -EINVAL;419 420 counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));421 if (!counter)422 return -ENOMEM;423 priv = counter_priv(counter);424 425 priv->dev = &pdev->dev;426 priv->regmap = ddata->regmap;427 priv->clk = ddata->clk;428 priv->ceiling = STM32_LPTIM_MAX_ARR;429 430 /* Initialize Counter device */431 counter->name = dev_name(&pdev->dev);432 counter->parent = &pdev->dev;433 counter->ops = &stm32_lptim_cnt_ops;434 if (ddata->has_encoder) {435 counter->counts = &stm32_lptim_enc_counts;436 counter->num_signals = ARRAY_SIZE(stm32_lptim_cnt_signals);437 } else {438 counter->counts = &stm32_lptim_in1_counts;439 counter->num_signals = 1;440 }441 counter->num_counts = 1;442 counter->signals = stm32_lptim_cnt_signals;443 444 platform_set_drvdata(pdev, priv);445 446 ret = devm_counter_add(&pdev->dev, counter);447 if (ret < 0)448 return dev_err_probe(&pdev->dev, ret, "Failed to add counter\n");449 450 return 0;451}452 453#ifdef CONFIG_PM_SLEEP454static int stm32_lptim_cnt_suspend(struct device *dev)455{456 struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);457 int ret;458 459 /* Only take care of enabled counter: don't disturb other MFD child */460 if (priv->enabled) {461 ret = stm32_lptim_setup(priv, 0);462 if (ret)463 return ret;464 465 ret = stm32_lptim_set_enable_state(priv, 0);466 if (ret)467 return ret;468 469 /* Force enable state for later resume */470 priv->enabled = true;471 }472 473 return pinctrl_pm_select_sleep_state(dev);474}475 476static int stm32_lptim_cnt_resume(struct device *dev)477{478 struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);479 int ret;480 481 ret = pinctrl_pm_select_default_state(dev);482 if (ret)483 return ret;484 485 if (priv->enabled) {486 priv->enabled = false;487 ret = stm32_lptim_setup(priv, 1);488 if (ret)489 return ret;490 491 ret = stm32_lptim_set_enable_state(priv, 1);492 if (ret)493 return ret;494 }495 496 return 0;497}498#endif499 500static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend,501 stm32_lptim_cnt_resume);502 503static const struct of_device_id stm32_lptim_cnt_of_match[] = {504 { .compatible = "st,stm32-lptimer-counter", },505 {},506};507MODULE_DEVICE_TABLE(of, stm32_lptim_cnt_of_match);508 509static struct platform_driver stm32_lptim_cnt_driver = {510 .probe = stm32_lptim_cnt_probe,511 .driver = {512 .name = "stm32-lptimer-counter",513 .of_match_table = stm32_lptim_cnt_of_match,514 .pm = &stm32_lptim_cnt_pm_ops,515 },516};517module_platform_driver(stm32_lptim_cnt_driver);518 519MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");520MODULE_ALIAS("platform:stm32-lptimer-counter");521MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver");522MODULE_LICENSE("GPL v2");523MODULE_IMPORT_NS(COUNTER);524