2 * STM32 Low-Power Timer Encoder and Counter driver
4 * Copyright (C) STMicroelectronics 2017
6 * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
8 * Inspired by 104-quad-8 and stm32-timer-trigger drivers.
10 * License terms: GNU General Public License (GPL), version 2
13 #include <linux/bitfield.h>
14 #include <linux/iio/iio.h>
15 #include <linux/mfd/stm32-lptimer.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
19 struct stm32_lptim_cnt
{
21 struct regmap
*regmap
;
28 static int stm32_lptim_is_enabled(struct stm32_lptim_cnt
*priv
)
33 ret
= regmap_read(priv
->regmap
, STM32_LPTIM_CR
, &val
);
37 return FIELD_GET(STM32_LPTIM_ENABLE
, val
);
40 static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt
*priv
,
46 val
= FIELD_PREP(STM32_LPTIM_ENABLE
, enable
);
47 ret
= regmap_write(priv
->regmap
, STM32_LPTIM_CR
, val
);
52 clk_disable(priv
->clk
);
56 /* LP timer must be enabled before writing CMP & ARR */
57 ret
= regmap_write(priv
->regmap
, STM32_LPTIM_ARR
, priv
->preset
);
61 ret
= regmap_write(priv
->regmap
, STM32_LPTIM_CMP
, 0);
65 /* ensure CMP & ARR registers are properly written */
66 ret
= regmap_read_poll_timeout(priv
->regmap
, STM32_LPTIM_ISR
, val
,
67 (val
& STM32_LPTIM_CMPOK_ARROK
),
72 ret
= regmap_write(priv
->regmap
, STM32_LPTIM_ICR
,
73 STM32_LPTIM_CMPOKCF_ARROKCF
);
77 ret
= clk_enable(priv
->clk
);
79 regmap_write(priv
->regmap
, STM32_LPTIM_CR
, 0);
83 /* Start LP timer in continuous mode */
84 return regmap_update_bits(priv
->regmap
, STM32_LPTIM_CR
,
85 STM32_LPTIM_CNTSTRT
, STM32_LPTIM_CNTSTRT
);
88 static int stm32_lptim_setup(struct stm32_lptim_cnt
*priv
, int enable
)
90 u32 mask
= STM32_LPTIM_ENC
| STM32_LPTIM_COUNTMODE
|
91 STM32_LPTIM_CKPOL
| STM32_LPTIM_PRESC
;
94 /* Setup LP timer encoder/counter and polarity, without prescaler */
95 if (priv
->quadrature_mode
)
96 val
= enable
? STM32_LPTIM_ENC
: 0;
98 val
= enable
? STM32_LPTIM_COUNTMODE
: 0;
99 val
|= FIELD_PREP(STM32_LPTIM_CKPOL
, enable
? priv
->polarity
: 0);
101 return regmap_update_bits(priv
->regmap
, STM32_LPTIM_CFGR
, mask
, val
);
104 static int stm32_lptim_write_raw(struct iio_dev
*indio_dev
,
105 struct iio_chan_spec
const *chan
,
106 int val
, int val2
, long mask
)
108 struct stm32_lptim_cnt
*priv
= iio_priv(indio_dev
);
112 case IIO_CHAN_INFO_ENABLE
:
113 if (val
< 0 || val
> 1)
116 /* Check nobody uses the timer, or already disabled/enabled */
117 ret
= stm32_lptim_is_enabled(priv
);
118 if ((ret
< 0) || (!ret
&& !val
))
123 ret
= stm32_lptim_setup(priv
, val
);
126 return stm32_lptim_set_enable_state(priv
, val
);
133 static int stm32_lptim_read_raw(struct iio_dev
*indio_dev
,
134 struct iio_chan_spec
const *chan
,
135 int *val
, int *val2
, long mask
)
137 struct stm32_lptim_cnt
*priv
= iio_priv(indio_dev
);
142 case IIO_CHAN_INFO_RAW
:
143 ret
= regmap_read(priv
->regmap
, STM32_LPTIM_CNT
, &dat
);
149 case IIO_CHAN_INFO_ENABLE
:
150 ret
= stm32_lptim_is_enabled(priv
);
156 case IIO_CHAN_INFO_SCALE
:
157 /* Non-quadrature mode: scale = 1 */
160 if (priv
->quadrature_mode
) {
162 * Quadrature encoder mode:
163 * - both edges, quarter cycle, scale is 0.25
164 * - either rising/falling edge scale is 0.5
166 if (priv
->polarity
> 1)
171 return IIO_VAL_FRACTIONAL_LOG2
;
178 static const struct iio_info stm32_lptim_cnt_iio_info
= {
179 .read_raw
= stm32_lptim_read_raw
,
180 .write_raw
= stm32_lptim_write_raw
,
181 .driver_module
= THIS_MODULE
,
184 static const char *const stm32_lptim_quadrature_modes
[] = {
189 static int stm32_lptim_get_quadrature_mode(struct iio_dev
*indio_dev
,
190 const struct iio_chan_spec
*chan
)
192 struct stm32_lptim_cnt
*priv
= iio_priv(indio_dev
);
194 return priv
->quadrature_mode
;
197 static int stm32_lptim_set_quadrature_mode(struct iio_dev
*indio_dev
,
198 const struct iio_chan_spec
*chan
,
201 struct stm32_lptim_cnt
*priv
= iio_priv(indio_dev
);
203 if (stm32_lptim_is_enabled(priv
))
206 priv
->quadrature_mode
= type
;
211 static const struct iio_enum stm32_lptim_quadrature_mode_en
= {
212 .items
= stm32_lptim_quadrature_modes
,
213 .num_items
= ARRAY_SIZE(stm32_lptim_quadrature_modes
),
214 .get
= stm32_lptim_get_quadrature_mode
,
215 .set
= stm32_lptim_set_quadrature_mode
,
218 static const char * const stm32_lptim_cnt_polarity
[] = {
219 "rising-edge", "falling-edge", "both-edges",
222 static int stm32_lptim_cnt_get_polarity(struct iio_dev
*indio_dev
,
223 const struct iio_chan_spec
*chan
)
225 struct stm32_lptim_cnt
*priv
= iio_priv(indio_dev
);
227 return priv
->polarity
;
230 static int stm32_lptim_cnt_set_polarity(struct iio_dev
*indio_dev
,
231 const struct iio_chan_spec
*chan
,
234 struct stm32_lptim_cnt
*priv
= iio_priv(indio_dev
);
236 if (stm32_lptim_is_enabled(priv
))
239 priv
->polarity
= type
;
244 static const struct iio_enum stm32_lptim_cnt_polarity_en
= {
245 .items
= stm32_lptim_cnt_polarity
,
246 .num_items
= ARRAY_SIZE(stm32_lptim_cnt_polarity
),
247 .get
= stm32_lptim_cnt_get_polarity
,
248 .set
= stm32_lptim_cnt_set_polarity
,
251 static ssize_t
stm32_lptim_cnt_get_preset(struct iio_dev
*indio_dev
,
253 const struct iio_chan_spec
*chan
,
256 struct stm32_lptim_cnt
*priv
= iio_priv(indio_dev
);
258 return snprintf(buf
, PAGE_SIZE
, "%u\n", priv
->preset
);
261 static ssize_t
stm32_lptim_cnt_set_preset(struct iio_dev
*indio_dev
,
263 const struct iio_chan_spec
*chan
,
264 const char *buf
, size_t len
)
266 struct stm32_lptim_cnt
*priv
= iio_priv(indio_dev
);
269 if (stm32_lptim_is_enabled(priv
))
272 ret
= kstrtouint(buf
, 0, &priv
->preset
);
276 if (priv
->preset
> STM32_LPTIM_MAX_ARR
)
282 /* LP timer with encoder */
283 static const struct iio_chan_spec_ext_info stm32_lptim_enc_ext_info
[] = {
286 .shared
= IIO_SEPARATE
,
287 .read
= stm32_lptim_cnt_get_preset
,
288 .write
= stm32_lptim_cnt_set_preset
,
290 IIO_ENUM("polarity", IIO_SEPARATE
, &stm32_lptim_cnt_polarity_en
),
291 IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en
),
292 IIO_ENUM("quadrature_mode", IIO_SEPARATE
,
293 &stm32_lptim_quadrature_mode_en
),
294 IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_lptim_quadrature_mode_en
),
298 static const struct iio_chan_spec stm32_lptim_enc_channels
= {
301 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
) |
302 BIT(IIO_CHAN_INFO_ENABLE
) |
303 BIT(IIO_CHAN_INFO_SCALE
),
304 .ext_info
= stm32_lptim_enc_ext_info
,
308 /* LP timer without encoder (counter only) */
309 static const struct iio_chan_spec_ext_info stm32_lptim_cnt_ext_info
[] = {
312 .shared
= IIO_SEPARATE
,
313 .read
= stm32_lptim_cnt_get_preset
,
314 .write
= stm32_lptim_cnt_set_preset
,
316 IIO_ENUM("polarity", IIO_SEPARATE
, &stm32_lptim_cnt_polarity_en
),
317 IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en
),
321 static const struct iio_chan_spec stm32_lptim_cnt_channels
= {
324 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
) |
325 BIT(IIO_CHAN_INFO_ENABLE
) |
326 BIT(IIO_CHAN_INFO_SCALE
),
327 .ext_info
= stm32_lptim_cnt_ext_info
,
331 static int stm32_lptim_cnt_probe(struct platform_device
*pdev
)
333 struct stm32_lptimer
*ddata
= dev_get_drvdata(pdev
->dev
.parent
);
334 struct stm32_lptim_cnt
*priv
;
335 struct iio_dev
*indio_dev
;
337 if (IS_ERR_OR_NULL(ddata
))
340 indio_dev
= devm_iio_device_alloc(&pdev
->dev
, sizeof(*priv
));
344 priv
= iio_priv(indio_dev
);
345 priv
->dev
= &pdev
->dev
;
346 priv
->regmap
= ddata
->regmap
;
347 priv
->clk
= ddata
->clk
;
348 priv
->preset
= STM32_LPTIM_MAX_ARR
;
350 indio_dev
->name
= dev_name(&pdev
->dev
);
351 indio_dev
->dev
.parent
= &pdev
->dev
;
352 indio_dev
->dev
.of_node
= pdev
->dev
.of_node
;
353 indio_dev
->info
= &stm32_lptim_cnt_iio_info
;
354 if (ddata
->has_encoder
)
355 indio_dev
->channels
= &stm32_lptim_enc_channels
;
357 indio_dev
->channels
= &stm32_lptim_cnt_channels
;
358 indio_dev
->num_channels
= 1;
360 platform_set_drvdata(pdev
, priv
);
362 return devm_iio_device_register(&pdev
->dev
, indio_dev
);
365 static const struct of_device_id stm32_lptim_cnt_of_match
[] = {
366 { .compatible
= "st,stm32-lptimer-counter", },
369 MODULE_DEVICE_TABLE(of
, stm32_lptim_cnt_of_match
);
371 static struct platform_driver stm32_lptim_cnt_driver
= {
372 .probe
= stm32_lptim_cnt_probe
,
374 .name
= "stm32-lptimer-counter",
375 .of_match_table
= stm32_lptim_cnt_of_match
,
378 module_platform_driver(stm32_lptim_cnt_driver
);
380 MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
381 MODULE_ALIAS("platform:stm32-lptimer-counter");
382 MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver");
383 MODULE_LICENSE("GPL v2");