stm32-lptimer-cnt.c (13446B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * STM32 Low-Power Timer Encoder and Counter driver 4 * 5 * Copyright (C) STMicroelectronics 2017 6 * 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), 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 else 104 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_INCREASE 336 || 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_SLEEP 454static 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#endif 499 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");