cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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");