linux/drivers/iio/counter/stm32-lptimer-cnt.c
<<
>>
Prefs
   1/*
   2 * STM32 Low-Power Timer Encoder and Counter driver
   3 *
   4 * Copyright (C) STMicroelectronics 2017
   5 *
   6 * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
   7 *
   8 * Inspired by 104-quad-8 and stm32-timer-trigger drivers.
   9 *
  10 * License terms:  GNU General Public License (GPL), version 2
  11 */
  12
  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>
  18
  19struct stm32_lptim_cnt {
  20        struct device *dev;
  21        struct regmap *regmap;
  22        struct clk *clk;
  23        u32 preset;
  24        u32 polarity;
  25        u32 quadrature_mode;
  26};
  27
  28static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv)
  29{
  30        u32 val;
  31        int ret;
  32
  33        ret = regmap_read(priv->regmap, STM32_LPTIM_CR, &val);
  34        if (ret)
  35                return ret;
  36
  37        return FIELD_GET(STM32_LPTIM_ENABLE, val);
  38}
  39
  40static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
  41                                        int enable)
  42{
  43        int ret;
  44        u32 val;
  45
  46        val = FIELD_PREP(STM32_LPTIM_ENABLE, enable);
  47        ret = regmap_write(priv->regmap, STM32_LPTIM_CR, val);
  48        if (ret)
  49                return ret;
  50
  51        if (!enable) {
  52                clk_disable(priv->clk);
  53                return 0;
  54        }
  55
  56        /* LP timer must be enabled before writing CMP & ARR */
  57        ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, priv->preset);
  58        if (ret)
  59                return ret;
  60
  61        ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, 0);
  62        if (ret)
  63                return ret;
  64
  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),
  68                                       100, 1000);
  69        if (ret)
  70                return ret;
  71
  72        ret = regmap_write(priv->regmap, STM32_LPTIM_ICR,
  73                           STM32_LPTIM_CMPOKCF_ARROKCF);
  74        if (ret)
  75                return ret;
  76
  77        ret = clk_enable(priv->clk);
  78        if (ret) {
  79                regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
  80                return ret;
  81        }
  82
  83        /* Start LP timer in continuous mode */
  84        return regmap_update_bits(priv->regmap, STM32_LPTIM_CR,
  85                                  STM32_LPTIM_CNTSTRT, STM32_LPTIM_CNTSTRT);
  86}
  87
  88static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable)
  89{
  90        u32 mask = STM32_LPTIM_ENC | STM32_LPTIM_COUNTMODE |
  91                   STM32_LPTIM_CKPOL | STM32_LPTIM_PRESC;
  92        u32 val;
  93
  94        /* Setup LP timer encoder/counter and polarity, without prescaler */
  95        if (priv->quadrature_mode)
  96                val = enable ? STM32_LPTIM_ENC : 0;
  97        else
  98                val = enable ? STM32_LPTIM_COUNTMODE : 0;
  99        val |= FIELD_PREP(STM32_LPTIM_CKPOL, enable ? priv->polarity : 0);
 100
 101        return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val);
 102}
 103
 104static int stm32_lptim_write_raw(struct iio_dev *indio_dev,
 105                                 struct iio_chan_spec const *chan,
 106                                 int val, int val2, long mask)
 107{
 108        struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
 109        int ret;
 110
 111        switch (mask) {
 112        case IIO_CHAN_INFO_ENABLE:
 113                if (val < 0 || val > 1)
 114                        return -EINVAL;
 115
 116                /* Check nobody uses the timer, or already disabled/enabled */
 117                ret = stm32_lptim_is_enabled(priv);
 118                if ((ret < 0) || (!ret && !val))
 119                        return ret;
 120                if (val && ret)
 121                        return -EBUSY;
 122
 123                ret = stm32_lptim_setup(priv, val);
 124                if (ret)
 125                        return ret;
 126                return stm32_lptim_set_enable_state(priv, val);
 127
 128        default:
 129                return -EINVAL;
 130        }
 131}
 132
 133static int stm32_lptim_read_raw(struct iio_dev *indio_dev,
 134                                struct iio_chan_spec const *chan,
 135                                int *val, int *val2, long mask)
 136{
 137        struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
 138        u32 dat;
 139        int ret;
 140
 141        switch (mask) {
 142        case IIO_CHAN_INFO_RAW:
 143                ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &dat);
 144                if (ret)
 145                        return ret;
 146                *val = dat;
 147                return IIO_VAL_INT;
 148
 149        case IIO_CHAN_INFO_ENABLE:
 150                ret = stm32_lptim_is_enabled(priv);
 151                if (ret < 0)
 152                        return ret;
 153                *val = ret;
 154                return IIO_VAL_INT;
 155
 156        case IIO_CHAN_INFO_SCALE:
 157                /* Non-quadrature mode: scale = 1 */
 158                *val = 1;
 159                *val2 = 0;
 160                if (priv->quadrature_mode) {
 161                        /*
 162                         * Quadrature encoder mode:
 163                         * - both edges, quarter cycle, scale is 0.25
 164                         * - either rising/falling edge scale is 0.5
 165                         */
 166                        if (priv->polarity > 1)
 167                                *val2 = 2;
 168                        else
 169                                *val2 = 1;
 170                }
 171                return IIO_VAL_FRACTIONAL_LOG2;
 172
 173        default:
 174                return -EINVAL;
 175        }
 176}
 177
 178static 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,
 182};
 183
 184static const char *const stm32_lptim_quadrature_modes[] = {
 185        "non-quadrature",
 186        "quadrature",
 187};
 188
 189static int stm32_lptim_get_quadrature_mode(struct iio_dev *indio_dev,
 190                                           const struct iio_chan_spec *chan)
 191{
 192        struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
 193
 194        return priv->quadrature_mode;
 195}
 196
 197static int stm32_lptim_set_quadrature_mode(struct iio_dev *indio_dev,
 198                                           const struct iio_chan_spec *chan,
 199                                           unsigned int type)
 200{
 201        struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
 202
 203        if (stm32_lptim_is_enabled(priv))
 204                return -EBUSY;
 205
 206        priv->quadrature_mode = type;
 207
 208        return 0;
 209}
 210
 211static 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,
 216};
 217
 218static const char * const stm32_lptim_cnt_polarity[] = {
 219        "rising-edge", "falling-edge", "both-edges",
 220};
 221
 222static int stm32_lptim_cnt_get_polarity(struct iio_dev *indio_dev,
 223                                        const struct iio_chan_spec *chan)
 224{
 225        struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
 226
 227        return priv->polarity;
 228}
 229
 230static int stm32_lptim_cnt_set_polarity(struct iio_dev *indio_dev,
 231                                        const struct iio_chan_spec *chan,
 232                                        unsigned int type)
 233{
 234        struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
 235
 236        if (stm32_lptim_is_enabled(priv))
 237                return -EBUSY;
 238
 239        priv->polarity = type;
 240
 241        return 0;
 242}
 243
 244static 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,
 249};
 250
 251static ssize_t stm32_lptim_cnt_get_preset(struct iio_dev *indio_dev,
 252                                          uintptr_t private,
 253                                          const struct iio_chan_spec *chan,
 254                                          char *buf)
 255{
 256        struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
 257
 258        return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset);
 259}
 260
 261static ssize_t stm32_lptim_cnt_set_preset(struct iio_dev *indio_dev,
 262                                          uintptr_t private,
 263                                          const struct iio_chan_spec *chan,
 264                                          const char *buf, size_t len)
 265{
 266        struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
 267        int ret;
 268
 269        if (stm32_lptim_is_enabled(priv))
 270                return -EBUSY;
 271
 272        ret = kstrtouint(buf, 0, &priv->preset);
 273        if (ret)
 274                return ret;
 275
 276        if (priv->preset > STM32_LPTIM_MAX_ARR)
 277                return -EINVAL;
 278
 279        return len;
 280}
 281
 282/* LP timer with encoder */
 283static const struct iio_chan_spec_ext_info stm32_lptim_enc_ext_info[] = {
 284        {
 285                .name = "preset",
 286                .shared = IIO_SEPARATE,
 287                .read = stm32_lptim_cnt_get_preset,
 288                .write = stm32_lptim_cnt_set_preset,
 289        },
 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),
 295        {}
 296};
 297
 298static const struct iio_chan_spec stm32_lptim_enc_channels = {
 299        .type = IIO_COUNT,
 300        .channel = 0,
 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,
 305        .indexed = 1,
 306};
 307
 308/* LP timer without encoder (counter only) */
 309static const struct iio_chan_spec_ext_info stm32_lptim_cnt_ext_info[] = {
 310        {
 311                .name = "preset",
 312                .shared = IIO_SEPARATE,
 313                .read = stm32_lptim_cnt_get_preset,
 314                .write = stm32_lptim_cnt_set_preset,
 315        },
 316        IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en),
 317        IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en),
 318        {}
 319};
 320
 321static const struct iio_chan_spec stm32_lptim_cnt_channels = {
 322        .type = IIO_COUNT,
 323        .channel = 0,
 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,
 328        .indexed = 1,
 329};
 330
 331static int stm32_lptim_cnt_probe(struct platform_device *pdev)
 332{
 333        struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
 334        struct stm32_lptim_cnt *priv;
 335        struct iio_dev *indio_dev;
 336
 337        if (IS_ERR_OR_NULL(ddata))
 338                return -EINVAL;
 339
 340        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
 341        if (!indio_dev)
 342                return -ENOMEM;
 343
 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;
 349
 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;
 356        else
 357                indio_dev->channels = &stm32_lptim_cnt_channels;
 358        indio_dev->num_channels = 1;
 359
 360        platform_set_drvdata(pdev, priv);
 361
 362        return devm_iio_device_register(&pdev->dev, indio_dev);
 363}
 364
 365static const struct of_device_id stm32_lptim_cnt_of_match[] = {
 366        { .compatible = "st,stm32-lptimer-counter", },
 367        {},
 368};
 369MODULE_DEVICE_TABLE(of, stm32_lptim_cnt_of_match);
 370
 371static struct platform_driver stm32_lptim_cnt_driver = {
 372        .probe = stm32_lptim_cnt_probe,
 373        .driver = {
 374                .name = "stm32-lptimer-counter",
 375                .of_match_table = stm32_lptim_cnt_of_match,
 376        },
 377};
 378module_platform_driver(stm32_lptim_cnt_driver);
 379
 380MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
 381MODULE_ALIAS("platform:stm32-lptimer-counter");
 382MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver");
 383MODULE_LICENSE("GPL v2");
 384