diff options
Diffstat (limited to 'drivers/counter')
-rw-r--r-- | drivers/counter/104-quad-8.c | 653 | ||||
-rw-r--r-- | drivers/counter/Kconfig | 14 | ||||
-rw-r--r-- | drivers/counter/Makefile | 1 | ||||
-rw-r--r-- | drivers/counter/interrupt-cnt.c | 244 | ||||
-rw-r--r-- | drivers/counter/stm32-lptimer-cnt.c | 297 |
5 files changed, 357 insertions, 852 deletions
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index 78766b6ec271..9691f8612be8 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -9,8 +9,6 @@ #include <linux/counter.h> #include <linux/device.h> #include <linux/errno.h> -#include <linux/iio/iio.h> -#include <linux/iio/types.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/isa.h> @@ -29,7 +27,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); #define QUAD8_NUM_COUNTERS 8 /** - * struct quad8_iio - IIO device private data structure + * struct quad8 - device private data structure * @counter: instance of the counter_device * @fck_prescaler: array of filter clock prescaler configurations * @preset: array of preset values @@ -41,9 +39,9 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); * @synchronous_mode: array of index function synchronous mode configurations * @index_polarity: array of index function polarity configurations * @cable_fault_enable: differential encoder cable status enable configurations - * @base: base port address of the IIO device + * @base: base port address of the device */ -struct quad8_iio { +struct quad8 { struct mutex lock; struct counter_device counter; unsigned int fck_prescaler[QUAD8_NUM_COUNTERS]; @@ -98,532 +96,10 @@ struct quad8_iio { #define QUAD8_CMR_QUADRATURE_X2 0x10 #define QUAD8_CMR_QUADRATURE_X4 0x18 - -static int quad8_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int *val, int *val2, long mask) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel; - unsigned int flags; - unsigned int borrow; - unsigned int carry; - int i; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - if (chan->type == IIO_INDEX) { - *val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) - & BIT(chan->channel)); - return IIO_VAL_INT; - } - - flags = inb(base_offset + 1); - borrow = flags & QUAD8_FLAG_BT; - carry = !!(flags & QUAD8_FLAG_CT); - - /* Borrow XOR Carry effectively doubles count range */ - *val = (borrow ^ carry) << 24; - - mutex_lock(&priv->lock); - - /* Reset Byte Pointer; transfer Counter to Output Latch */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, - base_offset + 1); - - for (i = 0; i < 3; i++) - *val |= (unsigned int)inb(base_offset) << (8 * i); - - mutex_unlock(&priv->lock); - - return IIO_VAL_INT; - case IIO_CHAN_INFO_ENABLE: - *val = priv->ab_enable[chan->channel]; - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 1; - *val2 = priv->quadrature_scale[chan->channel]; - return IIO_VAL_FRACTIONAL_LOG2; - } - - return -EINVAL; -} - -static int quad8_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int val, int val2, long mask) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel; - int i; - unsigned int ior_cfg; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - if (chan->type == IIO_INDEX) - return -EINVAL; - - /* Only 24-bit values are supported */ - if ((unsigned int)val > 0xFFFFFF) - return -EINVAL; - - mutex_lock(&priv->lock); - - /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); - - /* Counter can only be set via Preset Register */ - for (i = 0; i < 3; i++) - outb(val >> (8 * i), base_offset); - - /* Transfer Preset Register to Counter */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); - - /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); - - /* Set Preset Register back to original value */ - val = priv->preset[chan->channel]; - for (i = 0; i < 3; i++) - outb(val >> (8 * i), base_offset); - - /* Reset Borrow, Carry, Compare, and Sign flags */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); - /* Reset Error flag */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); - - mutex_unlock(&priv->lock); - - return 0; - case IIO_CHAN_INFO_ENABLE: - /* only boolean values accepted */ - if (val < 0 || val > 1) - return -EINVAL; - - mutex_lock(&priv->lock); - - priv->ab_enable[chan->channel] = val; - - ior_cfg = val | priv->preset_enable[chan->channel] << 1; - - /* Load I/O control configuration */ - outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); - - mutex_unlock(&priv->lock); - - return 0; - case IIO_CHAN_INFO_SCALE: - mutex_lock(&priv->lock); - - /* Quadrature scaling only available in quadrature mode */ - if (!priv->quadrature_mode[chan->channel] && - (val2 || val != 1)) { - mutex_unlock(&priv->lock); - return -EINVAL; - } - - /* Only three gain states (1, 0.5, 0.25) */ - if (val == 1 && !val2) - priv->quadrature_scale[chan->channel] = 0; - else if (!val) - switch (val2) { - case 500000: - priv->quadrature_scale[chan->channel] = 1; - break; - case 250000: - priv->quadrature_scale[chan->channel] = 2; - break; - default: - mutex_unlock(&priv->lock); - return -EINVAL; - } - else { - mutex_unlock(&priv->lock); - return -EINVAL; - } - - mutex_unlock(&priv->lock); - return 0; - } - - return -EINVAL; -} - -static const struct iio_info quad8_info = { - .read_raw = quad8_read_raw, - .write_raw = quad8_write_raw -}; - -static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private, - const struct iio_chan_spec *chan, char *buf) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]); -} - -static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private, - const struct iio_chan_spec *chan, const char *buf, size_t len) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel; - unsigned int preset; - int ret; - int i; - - ret = kstrtouint(buf, 0, &preset); - if (ret) - return ret; - - /* Only 24-bit values are supported */ - if (preset > 0xFFFFFF) - return -EINVAL; - - mutex_lock(&priv->lock); - - priv->preset[chan->channel] = preset; - - /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); - - /* Set Preset Register */ - for (i = 0; i < 3; i++) - outb(preset >> (8 * i), base_offset); - - mutex_unlock(&priv->lock); - - return len; -} - -static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, char *buf) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", - !priv->preset_enable[chan->channel]); -} - -static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, const char *buf, - size_t len) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - bool preset_enable; - int ret; - unsigned int ior_cfg; - - ret = kstrtobool(buf, &preset_enable); - if (ret) - return ret; - - /* Preset enable is active low in Input/Output Control register */ - preset_enable = !preset_enable; - - mutex_lock(&priv->lock); - - priv->preset_enable[chan->channel] = preset_enable; - - ior_cfg = priv->ab_enable[chan->channel] | - (unsigned int)preset_enable << 1; - - /* Load I/O control configuration to Input / Output Control Register */ - outb(QUAD8_CTR_IOR | ior_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return len; -} - -static const char *const quad8_noise_error_states[] = { - "No excessive noise is present at the count inputs", - "Excessive noise is present at the count inputs" -}; - -static int quad8_get_noise_error(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - - return !!(inb(base_offset) & QUAD8_FLAG_E); -} - -static const struct iio_enum quad8_noise_error_enum = { - .items = quad8_noise_error_states, - .num_items = ARRAY_SIZE(quad8_noise_error_states), - .get = quad8_get_noise_error -}; - -static const char *const quad8_count_direction_states[] = { - "down", - "up" -}; - -static int quad8_get_count_direction(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - - return !!(inb(base_offset) & QUAD8_FLAG_UD); -} - -static const struct iio_enum quad8_count_direction_enum = { - .items = quad8_count_direction_states, - .num_items = ARRAY_SIZE(quad8_count_direction_states), - .get = quad8_get_count_direction -}; - -static const char *const quad8_count_modes[] = { - "normal", - "range limit", - "non-recycle", - "modulo-n" -}; - -static int quad8_set_count_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int cnt_mode) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - unsigned int mode_cfg = cnt_mode << 1; - const int base_offset = priv->base + 2 * chan->channel + 1; - - mutex_lock(&priv->lock); - - priv->count_mode[chan->channel] = cnt_mode; - - /* Add quadrature mode configuration */ - if (priv->quadrature_mode[chan->channel]) - mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; - - /* Load mode configuration to Counter Mode Register */ - outb(QUAD8_CTR_CMR | mode_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int quad8_get_count_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return priv->count_mode[chan->channel]; -} - -static const struct iio_enum quad8_count_mode_enum = { - .items = quad8_count_modes, - .num_items = ARRAY_SIZE(quad8_count_modes), - .set = quad8_set_count_mode, - .get = quad8_get_count_mode -}; - -static const char *const quad8_synchronous_modes[] = { - "non-synchronous", - "synchronous" -}; - -static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int synchronous_mode) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - unsigned int idr_cfg = synchronous_mode; - - mutex_lock(&priv->lock); - - idr_cfg |= priv->index_polarity[chan->channel] << 1; - - /* Index function must be non-synchronous in non-quadrature mode */ - if (synchronous_mode && !priv->quadrature_mode[chan->channel]) { - mutex_unlock(&priv->lock); - return -EINVAL; - } - - priv->synchronous_mode[chan->channel] = synchronous_mode; - - /* Load Index Control configuration to Index Control Register */ - outb(QUAD8_CTR_IDR | idr_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int quad8_get_synchronous_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return priv->synchronous_mode[chan->channel]; -} - -static const struct iio_enum quad8_synchronous_mode_enum = { - .items = quad8_synchronous_modes, - .num_items = ARRAY_SIZE(quad8_synchronous_modes), - .set = quad8_set_synchronous_mode, - .get = quad8_get_synchronous_mode -}; - -static const char *const quad8_quadrature_modes[] = { - "non-quadrature", - "quadrature" -}; - -static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int quadrature_mode) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - unsigned int mode_cfg; - - mutex_lock(&priv->lock); - - mode_cfg = priv->count_mode[chan->channel] << 1; - - if (quadrature_mode) - mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; - else { - /* Quadrature scaling only available in quadrature mode */ - priv->quadrature_scale[chan->channel] = 0; - - /* Synchronous function not supported in non-quadrature mode */ - if (priv->synchronous_mode[chan->channel]) - quad8_set_synchronous_mode(indio_dev, chan, 0); - } - - priv->quadrature_mode[chan->channel] = quadrature_mode; - - /* Load mode configuration to Counter Mode Register */ - outb(QUAD8_CTR_CMR | mode_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int quad8_get_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return priv->quadrature_mode[chan->channel]; -} - -static const struct iio_enum quad8_quadrature_mode_enum = { - .items = quad8_quadrature_modes, - .num_items = ARRAY_SIZE(quad8_quadrature_modes), - .set = quad8_set_quadrature_mode, - .get = quad8_get_quadrature_mode -}; - -static const char *const quad8_index_polarity_modes[] = { - "negative", - "positive" -}; - -static int quad8_set_index_polarity(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int index_polarity) -{ - struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel + 1; - unsigned int idr_cfg = index_polarity << 1; - - mutex_lock(&priv->lock); - - idr_cfg |= priv->synchronous_mode[chan->channel]; - - priv->index_polarity[chan->channel] = index_polarity; - - /* Load Index Control configuration to Index Control Register */ - outb(QUAD8_CTR_IDR | idr_cfg, base_offset); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int quad8_get_index_polarity(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - const struct quad8_iio *const priv = iio_priv(indio_dev); - - return priv->index_polarity[chan->channel]; -} - -static const struct iio_enum quad8_index_polarity_enum = { - .items = quad8_index_polarity_modes, - .num_items = ARRAY_SIZE(quad8_index_polarity_modes), - .set = quad8_set_index_polarity, - .get = quad8_get_index_polarity -}; - -static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = { - { - .name = "preset", - .shared = IIO_SEPARATE, - .read = quad8_read_preset, - .write = quad8_write_preset - }, - { - .name = "set_to_preset_on_index", - .shared = IIO_SEPARATE, - .read = quad8_read_set_to_preset_on_index, - .write = quad8_write_set_to_preset_on_index - }, - IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum), - IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum), - IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum), - IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum), - IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum), - IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum), - IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum), - IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum), - {} -}; - -static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = { - IIO_ENUM("synchronous_mode", IIO_SEPARATE, - &quad8_synchronous_mode_enum), - IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum), - IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum), - IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum), - {} -}; - -#define QUAD8_COUNT_CHAN(_chan) { \ - .type = IIO_COUNT, \ - .channel = (_chan), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \ - .ext_info = quad8_count_ext_info, \ - .indexed = 1 \ -} - -#define QUAD8_INDEX_CHAN(_chan) { \ - .type = IIO_INDEX, \ - .channel = (_chan), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .ext_info = quad8_index_ext_info, \ - .indexed = 1 \ -} - -static const struct iio_chan_spec quad8_channels[] = { - QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0), - QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1), - QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2), - QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3), - QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4), - QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5), - QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6), - QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7) -}; - static int quad8_signal_read(struct counter_device *counter, struct counter_signal *signal, enum counter_signal_value *val) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; unsigned int state; /* Only Index signal levels can be read */ @@ -641,7 +117,7 @@ static int quad8_signal_read(struct counter_device *counter, static int quad8_count_read(struct counter_device *counter, struct counter_count *count, unsigned long *val) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id; unsigned int flags; unsigned int borrow; @@ -672,7 +148,7 @@ static int quad8_count_read(struct counter_device *counter, static int quad8_count_write(struct counter_device *counter, struct counter_count *count, unsigned long val) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id; int i; @@ -727,7 +203,7 @@ static enum counter_count_function quad8_count_functions_list[] = { static int quad8_function_get(struct counter_device *counter, struct counter_count *count, size_t *function) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int id = count->id; mutex_lock(&priv->lock); @@ -755,7 +231,7 @@ static int quad8_function_get(struct counter_device *counter, static int quad8_function_set(struct counter_device *counter, struct counter_count *count, size_t function) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int id = count->id; unsigned int *const quadrature_mode = priv->quadrature_mode + id; unsigned int *const scale = priv->quadrature_scale + id; @@ -811,7 +287,7 @@ static int quad8_function_set(struct counter_device *counter, static void quad8_direction_get(struct counter_device *counter, struct counter_count *count, enum counter_count_direction *direction) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; unsigned int ud_flag; const unsigned int flag_addr = priv->base + 2 * count->id + 1; @@ -845,7 +321,7 @@ static int quad8_action_get(struct counter_device *counter, struct counter_count *count, struct counter_synapse *synapse, size_t *action) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; int err; size_t function = 0; const size_t signal_a_id = count->synapses[0].signal->id; @@ -905,10 +381,15 @@ static const struct counter_ops quad8_ops = { .action_get = quad8_action_get }; +static const char *const quad8_index_polarity_modes[] = { + "negative", + "positive" +}; + static int quad8_index_polarity_get(struct counter_device *counter, struct counter_signal *signal, size_t *index_polarity) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id - 16; *index_polarity = priv->index_polarity[channel_id]; @@ -919,7 +400,7 @@ static int quad8_index_polarity_get(struct counter_device *counter, static int quad8_index_polarity_set(struct counter_device *counter, struct counter_signal *signal, size_t index_polarity) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id - 16; const int base_offset = priv->base + 2 * channel_id + 1; unsigned int idr_cfg = index_polarity << 1; @@ -945,10 +426,15 @@ static struct counter_signal_enum_ext quad8_index_pol_enum = { .set = quad8_index_polarity_set }; +static const char *const quad8_synchronous_modes[] = { + "non-synchronous", + "synchronous" +}; + static int quad8_synchronous_mode_get(struct counter_device *counter, struct counter_signal *signal, size_t *synchronous_mode) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id - 16; *synchronous_mode = priv->synchronous_mode[channel_id]; @@ -959,7 +445,7 @@ static int quad8_synchronous_mode_get(struct counter_device *counter, static int quad8_synchronous_mode_set(struct counter_device *counter, struct counter_signal *signal, size_t synchronous_mode) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id - 16; const int base_offset = priv->base + 2 * channel_id + 1; unsigned int idr_cfg = synchronous_mode; @@ -1001,7 +487,7 @@ static ssize_t quad8_count_floor_read(struct counter_device *counter, static int quad8_count_mode_get(struct counter_device *counter, struct counter_count *count, size_t *cnt_mode) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; /* Map 104-QUAD-8 count mode to Generic Counter count mode */ switch (priv->count_mode[count->id]) { @@ -1025,7 +511,7 @@ static int quad8_count_mode_get(struct counter_device *counter, static int quad8_count_mode_set(struct counter_device *counter, struct counter_count *count, size_t cnt_mode) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; unsigned int mode_cfg; const int base_offset = priv->base + 2 * count->id + 1; @@ -1084,7 +570,7 @@ static ssize_t quad8_count_direction_read(struct counter_device *counter, static ssize_t quad8_count_enable_read(struct counter_device *counter, struct counter_count *count, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; return sprintf(buf, "%u\n", priv->ab_enable[count->id]); } @@ -1092,7 +578,7 @@ static ssize_t quad8_count_enable_read(struct counter_device *counter, static ssize_t quad8_count_enable_write(struct counter_device *counter, struct counter_count *count, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id; int err; bool ab_enable; @@ -1116,10 +602,15 @@ static ssize_t quad8_count_enable_write(struct counter_device *counter, return len; } +static const char *const quad8_noise_error_states[] = { + "No excessive noise is present at the count inputs", + "Excessive noise is present at the count inputs" +}; + static int quad8_error_noise_get(struct counter_device *counter, struct counter_count *count, size_t *noise_error) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id + 1; *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E); @@ -1136,18 +627,18 @@ static struct counter_count_enum_ext quad8_error_noise_enum = { static ssize_t quad8_count_preset_read(struct counter_device *counter, struct counter_count *count, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; return sprintf(buf, "%u\n", priv->preset[count->id]); } -static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id, - unsigned int preset) +static void quad8_preset_register_set(struct quad8 *priv, int id, + unsigned int preset) { - const unsigned int base_offset = quad8iio->base + 2 * id; + const unsigned int base_offset = priv->base + 2 * id; int i; - quad8iio->preset[id] = preset; + priv->preset[id] = preset; /* Reset Byte Pointer */ outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); @@ -1160,7 +651,7 @@ static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id, static ssize_t quad8_count_preset_write(struct counter_device *counter, struct counter_count *count, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; unsigned int preset; int ret; @@ -1184,7 +675,7 @@ static ssize_t quad8_count_preset_write(struct counter_device *counter, static ssize_t quad8_count_ceiling_read(struct counter_device *counter, struct counter_count *count, void *private, char *buf) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; mutex_lock(&priv->lock); @@ -1205,7 +696,7 @@ static ssize_t quad8_count_ceiling_read(struct counter_device *counter, static ssize_t quad8_count_ceiling_write(struct counter_device *counter, struct counter_count *count, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; unsigned int ceiling; int ret; @@ -1235,7 +726,7 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter, static ssize_t quad8_count_preset_enable_read(struct counter_device *counter, struct counter_count *count, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; return sprintf(buf, "%u\n", !priv->preset_enable[count->id]); } @@ -1243,7 +734,7 @@ static ssize_t quad8_count_preset_enable_read(struct counter_device *counter, static ssize_t quad8_count_preset_enable_write(struct counter_device *counter, struct counter_count *count, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id + 1; bool preset_enable; int ret; @@ -1274,7 +765,7 @@ static ssize_t quad8_signal_cable_fault_read(struct counter_device *counter, struct counter_signal *signal, void *private, char *buf) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; bool disabled; unsigned int status; @@ -1304,7 +795,7 @@ static ssize_t quad8_signal_cable_fault_enable_read( struct counter_device *counter, struct counter_signal *signal, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; const unsigned int enb = !!(priv->cable_fault_enable & BIT(channel_id)); @@ -1315,7 +806,7 @@ static ssize_t quad8_signal_cable_fault_enable_write( struct counter_device *counter, struct counter_signal *signal, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; bool enable; int ret; @@ -1345,7 +836,7 @@ static ssize_t quad8_signal_cable_fault_enable_write( static ssize_t quad8_signal_fck_prescaler_read(struct counter_device *counter, struct counter_signal *signal, void *private, char *buf) { - const struct quad8_iio *const priv = counter->priv; + const struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; return sprintf(buf, "%u\n", priv->fck_prescaler[channel_id]); @@ -1355,7 +846,7 @@ static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter, struct counter_signal *signal, void *private, const char *buf, size_t len) { - struct quad8_iio *const priv = counter->priv; + struct quad8 *const priv = counter->priv; const size_t channel_id = signal->id / 2; const int base_offset = priv->base + 2 * channel_id; u8 prescaler; @@ -1531,11 +1022,9 @@ static struct counter_count quad8_counts[] = { static int quad8_probe(struct device *dev, unsigned int id) { - struct iio_dev *indio_dev; - struct quad8_iio *quad8iio; + struct quad8 *priv; int i, j; unsigned int base_offset; - int err; if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -1543,32 +1032,23 @@ static int quad8_probe(struct device *dev, unsigned int id) return -EBUSY; } - /* Allocate IIO device; this also allocates driver data structure */ - indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio)); - if (!indio_dev) + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - /* Initialize IIO device */ - indio_dev->info = &quad8_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->num_channels = ARRAY_SIZE(quad8_channels); - indio_dev->channels = quad8_channels; - indio_dev->name = dev_name(dev); - /* Initialize Counter device and driver data */ - quad8iio = iio_priv(indio_dev); - quad8iio->counter.name = dev_name(dev); - quad8iio->counter.parent = dev; - quad8iio->counter.ops = &quad8_ops; - quad8iio->counter.counts = quad8_counts; - quad8iio->counter.num_counts = ARRAY_SIZE(quad8_counts); - quad8iio->counter.signals = quad8_signals; - quad8iio->counter.num_signals = ARRAY_SIZE(quad8_signals); - quad8iio->counter.priv = quad8iio; - quad8iio->base = base[id]; + priv->counter.name = dev_name(dev); + priv->counter.parent = dev; + priv->counter.ops = &quad8_ops; + priv->counter.counts = quad8_counts; + priv->counter.num_counts = ARRAY_SIZE(quad8_counts); + priv->counter.signals = quad8_signals; + priv->counter.num_signals = ARRAY_SIZE(quad8_signals); + priv->counter.priv = priv; + priv->base = base[id]; /* Initialize mutex */ - mutex_init(&quad8iio->lock); + mutex_init(&priv->lock); /* Reset all counters and disable interrupt function */ outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); @@ -1602,13 +1082,8 @@ static int quad8_probe(struct device *dev, unsigned int id) /* Enable all counters */ outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); - /* Register IIO device */ - err = devm_iio_device_register(dev, indio_dev); - if (err) - return err; - /* Register Counter device */ - return devm_counter_register(dev, &quad8iio->counter); + return devm_counter_register(dev, &priv->counter); } static struct isa_driver quad8_driver = { @@ -1621,5 +1096,5 @@ static struct isa_driver quad8_driver = { module_isa_driver(quad8_driver, num_quad8); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); -MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); +MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 2de53ab0dd25..5328705aa09c 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -14,7 +14,7 @@ if COUNTER config 104_QUAD_8 tristate "ACCES 104-QUAD-8 driver" - depends on PC104 && X86 && IIO + depends on PC104 && X86 select ISA_BUS_API help Say yes here to build support for the ACCES 104-QUAD-8 quadrature @@ -29,6 +29,16 @@ config 104_QUAD_8 The base port addresses for the devices may be configured via the base array module parameter. +config INTERRUPT_CNT + tristate "Interrupt counter driver" + depends on GPIOLIB + help + Select this option to enable interrupt counter driver. Any interrupt + source can be used by this driver as the event source. + + To compile this driver as a module, choose M here: the + module will be called interrupt-cnt. + config STM32_TIMER_CNT tristate "STM32 Timer encoder counter driver" depends on MFD_STM32_TIMERS || COMPILE_TEST @@ -41,7 +51,7 @@ config STM32_TIMER_CNT config STM32_LPTIMER_CNT tristate "STM32 LP Timer encoder counter driver" - depends on (MFD_STM32_LPTIMER || COMPILE_TEST) && IIO + depends on MFD_STM32_LPTIMER || COMPILE_TEST help Select this option to enable STM32 Low-Power Timer quadrature encoder and counter driver. diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile index 0a393f71e481..cb646ed2f039 100644 --- a/drivers/counter/Makefile +++ b/drivers/counter/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_COUNTER) += counter.o obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o +obj-$(CONFIG_INTERRUPT_CNT) += interrupt-cnt.o obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o obj-$(CONFIG_TI_EQEP) += ti-eqep.o diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c new file mode 100644 index 000000000000..a99ee7996977 --- /dev/null +++ b/drivers/counter/interrupt-cnt.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> + */ + +#include <linux/counter.h> +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#define INTERRUPT_CNT_NAME "interrupt-cnt" + +struct interrupt_cnt_priv { + atomic_t count; + struct counter_device counter; + struct gpio_desc *gpio; + int irq; + bool enabled; + struct counter_signal signals; + struct counter_synapse synapses; + struct counter_count cnts; +}; + +static irqreturn_t interrupt_cnt_isr(int irq, void *dev_id) +{ + struct interrupt_cnt_priv *priv = dev_id; + + atomic_inc(&priv->count); + + return IRQ_HANDLED; +} + +static ssize_t interrupt_cnt_enable_read(struct counter_device *counter, + struct counter_count *count, + void *private, char *buf) +{ + struct interrupt_cnt_priv *priv = counter->priv; + + return sysfs_emit(buf, "%d\n", priv->enabled); +} + +static ssize_t interrupt_cnt_enable_write(struct counter_device *counter, + struct counter_count *count, + void *private, const char *buf, + size_t len) +{ + struct interrupt_cnt_priv *priv = counter->priv; + bool enable; + ssize_t ret; + + ret = kstrtobool(buf, &enable); + if (ret) + return ret; + + if (priv->enabled == enable) + return len; + + if (enable) { + priv->enabled = true; + enable_irq(priv->irq); + } else { + disable_irq(priv->irq); + priv->enabled = false; + } + + return len; +} + +static const struct counter_count_ext interrupt_cnt_ext[] = { + { + .name = "enable", + .read = interrupt_cnt_enable_read, + .write = interrupt_cnt_enable_write, + }, +}; + +static enum counter_synapse_action interrupt_cnt_synapse_actionss[] = { + COUNTER_SYNAPSE_ACTION_RISING_EDGE, +}; + +static int interrupt_cnt_action_get(struct counter_device *counter, + struct counter_count *count, + struct counter_synapse *synapse, + size_t *action) +{ + *action = 0; + + return 0; +} + +static int interrupt_cnt_read(struct counter_device *counter, + struct counter_count *count, unsigned long *val) +{ + struct interrupt_cnt_priv *priv = counter->priv; + + *val = atomic_read(&priv->count); + + return 0; +} + +static int interrupt_cnt_write(struct counter_device *counter, + struct counter_count *count, + const unsigned long val) +{ + struct interrupt_cnt_priv *priv = counter->priv; + + atomic_set(&priv->count, val); + + return 0; +} + +static enum counter_count_function interrupt_cnt_functions[] = { + COUNTER_COUNT_FUNCTION_INCREASE, +}; + +static int interrupt_cnt_function_get(struct counter_device *counter, + struct counter_count *count, + size_t *function) +{ + *function = 0; + + return 0; +} + +static int interrupt_cnt_signal_read(struct counter_device *counter, + struct counter_signal *signal, + enum counter_signal_value *val) +{ + struct interrupt_cnt_priv *priv = counter->priv; + int ret; + + if (!priv->gpio) + return -EINVAL; + + ret = gpiod_get_value(priv->gpio); + if (ret < 0) + return ret; + + *val = ret ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW; + + return 0; +} + +static const struct counter_ops interrupt_cnt_ops = { + .action_get = interrupt_cnt_action_get, + .count_read = interrupt_cnt_read, + .count_write = interrupt_cnt_write, + .function_get = interrupt_cnt_function_get, + .signal_read = interrupt_cnt_signal_read, +}; + +static int interrupt_cnt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct interrupt_cnt_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->irq = platform_get_irq_optional(pdev, 0); + if (priv->irq == -ENXIO) + priv->irq = 0; + else if (priv->irq < 0) + return dev_err_probe(dev, priv->irq, "failed to get IRQ\n"); + + priv->gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_IN); + if (IS_ERR(priv->gpio)) + return dev_err_probe(dev, PTR_ERR(priv->gpio), "failed to get GPIO\n"); + + if (!priv->irq && !priv->gpio) { + dev_err(dev, "IRQ and GPIO are not found. At least one source should be provided\n"); + return -ENODEV; + } + + if (!priv->irq) { + int irq = gpiod_to_irq(priv->gpio); + + if (irq < 0) + return dev_err_probe(dev, irq, "failed to get IRQ from GPIO\n"); + + priv->irq = irq; + } + + priv->signals.name = devm_kasprintf(dev, GFP_KERNEL, "IRQ %d", + priv->irq); + if (!priv->signals.name) + return -ENOMEM; + + priv->counter.signals = &priv->signals; + priv->counter.num_signals = 1; + + priv->synapses.actions_list = interrupt_cnt_synapse_actionss; + priv->synapses.num_actions = ARRAY_SIZE(interrupt_cnt_synapse_actionss); + priv->synapses.signal = &priv->signals; + + priv->cnts.name = "Channel 0 Count"; + priv->cnts.functions_list = interrupt_cnt_functions; + priv->cnts.num_functions = ARRAY_SIZE(interrupt_cnt_functions); + priv->cnts.synapses = &priv->synapses; + priv->cnts.num_synapses = 1; + priv->cnts.ext = interrupt_cnt_ext; + priv->cnts.num_ext = ARRAY_SIZE(interrupt_cnt_ext); + + priv->counter.priv = priv; + priv->counter.name = dev_name(dev); + priv->counter.parent = dev; + priv->counter.ops = &interrupt_cnt_ops; + priv->counter.counts = &priv->cnts; + priv->counter.num_counts = 1; + + irq_set_status_flags(priv->irq, IRQ_NOAUTOEN); + ret = devm_request_irq(dev, priv->irq, interrupt_cnt_isr, + IRQF_TRIGGER_RISING | IRQF_NO_THREAD, + dev_name(dev), priv); + if (ret) + return ret; + + return devm_counter_register(dev, &priv->counter); +} + +static const struct of_device_id interrupt_cnt_of_match[] = { + { .compatible = "interrupt-counter", }, + {} +}; +MODULE_DEVICE_TABLE(of, interrupt_cnt_of_match); + +static struct platform_driver interrupt_cnt_driver = { + .probe = interrupt_cnt_probe, + .driver = { + .name = INTERRUPT_CNT_NAME, + .of_match_table = interrupt_cnt_of_match, + }, +}; +module_platform_driver(interrupt_cnt_driver); + +MODULE_ALIAS("platform:interrupt-counter"); +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>"); +MODULE_DESCRIPTION("Interrupt counter driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c index fd6828e2d34f..937439635d53 100644 --- a/drivers/counter/stm32-lptimer-cnt.c +++ b/drivers/counter/stm32-lptimer-cnt.c @@ -12,8 +12,8 @@ #include <linux/bitfield.h> #include <linux/counter.h> -#include <linux/iio/iio.h> #include <linux/mfd/stm32-lptimer.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> @@ -107,249 +107,27 @@ static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable) return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val); } -static int stm32_lptim_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - int ret; - - switch (mask) { - case IIO_CHAN_INFO_ENABLE: - if (val < 0 || val > 1) - return -EINVAL; - - /* Check nobody uses the timer, or already disabled/enabled */ - ret = stm32_lptim_is_enabled(priv); - if ((ret < 0) || (!ret && !val)) - return ret; - if (val && ret) - return -EBUSY; - - ret = stm32_lptim_setup(priv, val); - if (ret) - return ret; - return stm32_lptim_set_enable_state(priv, val); - - default: - return -EINVAL; - } -} - -static int stm32_lptim_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - u32 dat; - int ret; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &dat); - if (ret) - return ret; - *val = dat; - return IIO_VAL_INT; - - case IIO_CHAN_INFO_ENABLE: - ret = stm32_lptim_is_enabled(priv); - if (ret < 0) - return ret; - *val = ret; - return IIO_VAL_INT; - - case IIO_CHAN_INFO_SCALE: - /* Non-quadrature mode: scale = 1 */ - *val = 1; - *val2 = 0; - if (priv->quadrature_mode) { - /* - * Quadrature encoder mode: - * - both edges, quarter cycle, scale is 0.25 - * - either rising/falling edge scale is 0.5 - */ - if (priv->polarity > 1) - *val2 = 2; - else - *val2 = 1; - } - return IIO_VAL_FRACTIONAL_LOG2; - - default: - return -EINVAL; - } -} - -static const struct iio_info stm32_lptim_cnt_iio_info = { - .read_raw = stm32_lptim_read_raw, - .write_raw = stm32_lptim_write_raw, -}; - -static const char *const stm32_lptim_quadrature_modes[] = { - "non-quadrature", - "quadrature", -}; - -static int stm32_lptim_get_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - return priv->quadrature_mode; -} - -static int stm32_lptim_set_quadrature_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int type) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - if (stm32_lptim_is_enabled(priv)) - return -EBUSY; - - priv->quadrature_mode = type; - - return 0; -} - -static const struct iio_enum stm32_lptim_quadrature_mode_en = { - .items = stm32_lptim_quadrature_modes, - .num_items = ARRAY_SIZE(stm32_lptim_quadrature_modes), - .get = stm32_lptim_get_quadrature_mode, - .set = stm32_lptim_set_quadrature_mode, -}; - -static const char * const stm32_lptim_cnt_polarity[] = { - "rising-edge", "falling-edge", "both-edges", -}; - -static int stm32_lptim_cnt_get_polarity(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - return priv->polarity; -} - -static int stm32_lptim_cnt_set_polarity(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int type) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - if (stm32_lptim_is_enabled(priv)) - return -EBUSY; - - priv->polarity = type; - - return 0; -} - -static const struct iio_enum stm32_lptim_cnt_polarity_en = { - .items = stm32_lptim_cnt_polarity, - .num_items = ARRAY_SIZE(stm32_lptim_cnt_polarity), - .get = stm32_lptim_cnt_get_polarity, - .set = stm32_lptim_cnt_set_polarity, -}; - -static ssize_t stm32_lptim_cnt_get_ceiling(struct stm32_lptim_cnt *priv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", priv->ceiling); -} - -static ssize_t stm32_lptim_cnt_set_ceiling(struct stm32_lptim_cnt *priv, - const char *buf, size_t len) -{ - int ret; - - if (stm32_lptim_is_enabled(priv)) - return -EBUSY; - - ret = kstrtouint(buf, 0, &priv->ceiling); - if (ret) - return ret; - - if (priv->ceiling > STM32_LPTIM_MAX_ARR) - return -EINVAL; - - return len; -} - -static ssize_t stm32_lptim_cnt_get_preset_iio(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - char *buf) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - return stm32_lptim_cnt_get_ceiling(priv, buf); -} - -static ssize_t stm32_lptim_cnt_set_preset_iio(struct iio_dev *indio_dev, - uintptr_t private, - const struct iio_chan_spec *chan, - const char *buf, size_t len) -{ - struct stm32_lptim_cnt *priv = iio_priv(indio_dev); - - return stm32_lptim_cnt_set_ceiling(priv, buf, len); -} - -/* LP timer with encoder */ -static const struct iio_chan_spec_ext_info stm32_lptim_enc_ext_info[] = { - { - .name = "preset", - .shared = IIO_SEPARATE, - .read = stm32_lptim_cnt_get_preset_iio, - .write = stm32_lptim_cnt_set_preset_iio, - }, - IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), - IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), - IIO_ENUM("quadrature_mode", IIO_SEPARATE, - &stm32_lptim_quadrature_mode_en), - IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_lptim_quadrature_mode_en), - {} -}; - -static const struct iio_chan_spec stm32_lptim_enc_channels = { - .type = IIO_COUNT, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_ENABLE) | - BIT(IIO_CHAN_INFO_SCALE), - .ext_info = stm32_lptim_enc_ext_info, - .indexed = 1, -}; - -/* LP timer without encoder (counter only) */ -static const struct iio_chan_spec_ext_info stm32_lptim_cnt_ext_info[] = { - { - .name = "preset", - .shared = IIO_SEPARATE, - .read = stm32_lptim_cnt_get_preset_iio, - .write = stm32_lptim_cnt_set_preset_iio, - }, - IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), - IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), - {} -}; - -static const struct iio_chan_spec stm32_lptim_cnt_channels = { - .type = IIO_COUNT, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_ENABLE) | - BIT(IIO_CHAN_INFO_SCALE), - .ext_info = stm32_lptim_cnt_ext_info, - .indexed = 1, -}; - /** * enum stm32_lptim_cnt_function - enumerates LPTimer counter & encoder modes * @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges * @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature) + * + * In non-quadrature mode, device counts up on active edge. + * In quadrature mode, encoder counting scenarios are as follows: + * +---------+----------+--------------------+--------------------+ + * | Active | Level on | IN1 signal | IN2 signal | + * | edge | opposite +----------+---------+----------+---------+ + * | | signal | Rising | Falling | Rising | Falling | + * +---------+----------+----------+---------+----------+---------+ + * | Rising | High -> | Down | - | Up | - | + * | edge | Low -> | Up | - | Down | - | + * +---------+----------+----------+---------+----------+---------+ + * | Falling | High -> | - | Up | - | Down | + * | edge | Low -> | - | Down | - | Up | + * +---------+----------+----------+---------+----------+---------+ + * | Both | High -> | Down | Up | Up | Down | + * | edges | Low -> | Up | Down | Down | Up | + * +---------+----------+----------+---------+----------+---------+ */ enum stm32_lptim_cnt_function { STM32_LPTIM_COUNTER_INCREASE, @@ -484,7 +262,7 @@ static ssize_t stm32_lptim_cnt_ceiling_read(struct counter_device *counter, { struct stm32_lptim_cnt *const priv = counter->priv; - return stm32_lptim_cnt_get_ceiling(priv, buf); + return snprintf(buf, PAGE_SIZE, "%u\n", priv->ceiling); } static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter, @@ -493,8 +271,22 @@ static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter, const char *buf, size_t len) { struct stm32_lptim_cnt *const priv = counter->priv; + unsigned int ceiling; + int ret; + + if (stm32_lptim_is_enabled(priv)) + return -EBUSY; + + ret = kstrtouint(buf, 0, &ceiling); + if (ret) + return ret; + + if (ceiling > STM32_LPTIM_MAX_ARR) + return -EINVAL; + + priv->ceiling = ceiling; - return stm32_lptim_cnt_set_ceiling(priv, buf, len); + return len; } static const struct counter_count_ext stm32_lptim_cnt_ext[] = { @@ -630,32 +422,19 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev) { struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); struct stm32_lptim_cnt *priv; - struct iio_dev *indio_dev; - int ret; if (IS_ERR_OR_NULL(ddata)) return -EINVAL; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); - if (!indio_dev) + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - priv = iio_priv(indio_dev); priv->dev = &pdev->dev; priv->regmap = ddata->regmap; priv->clk = ddata->clk; priv->ceiling = STM32_LPTIM_MAX_ARR; - /* Initialize IIO device */ - indio_dev->name = dev_name(&pdev->dev); - indio_dev->dev.of_node = pdev->dev.of_node; - indio_dev->info = &stm32_lptim_cnt_iio_info; - if (ddata->has_encoder) - indio_dev->channels = &stm32_lptim_enc_channels; - else - indio_dev->channels = &stm32_lptim_cnt_channels; - indio_dev->num_channels = 1; - /* Initialize Counter device */ priv->counter.name = dev_name(&pdev->dev); priv->counter.parent = &pdev->dev; @@ -673,10 +452,6 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - ret = devm_iio_device_register(&pdev->dev, indio_dev); - if (ret) - return ret; - return devm_counter_register(&pdev->dev, &priv->counter); } |