mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 09:04:39 +02:00
counter: 104-quad-8: Migrate to the regmap API
The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. With regmap we get boundary checks, read-write permissions, operation synchronization locks, and more for free. Most important of all, rather than rolling our own we utilize implementations that are known to work and gain from any future improvements and fixes that come. Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/1f1f7920d2be94aedb6fdf49f429fe6137c8cb24.1681753140.git.william.gray@linaro.org/ Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
This commit is contained in:
parent
142c8622b5
commit
98ffe02529
|
|
@ -9,7 +9,7 @@
|
||||||
#include <linux/bits.h>
|
#include <linux/bits.h>
|
||||||
#include <linux/counter.h>
|
#include <linux/counter.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/err.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
|
@ -18,8 +18,9 @@
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/types.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
|
|
@ -37,35 +38,13 @@ MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
|
||||||
|
|
||||||
#define QUAD8_NUM_COUNTERS 8
|
#define QUAD8_NUM_COUNTERS 8
|
||||||
|
|
||||||
/**
|
#define QUAD8_DATA(_channel) ((_channel) * 2)
|
||||||
* struct channel_reg - channel register structure
|
#define QUAD8_CONTROL(_channel) (QUAD8_DATA(_channel) + 1)
|
||||||
* @data: Count data
|
#define QUAD8_INTERRUPT_STATUS 0x10
|
||||||
* @control: Channel flags and control
|
#define QUAD8_CHANNEL_OPERATION 0x11
|
||||||
*/
|
#define QUAD8_INDEX_INTERRUPT 0x12
|
||||||
struct channel_reg {
|
#define QUAD8_INDEX_INPUT_LEVELS 0x16
|
||||||
u8 data;
|
#define QUAD8_CABLE_STATUS 0x17
|
||||||
u8 control;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct quad8_reg - device register structure
|
|
||||||
* @channel: quadrature counter data and control
|
|
||||||
* @interrupt_status: channel interrupt status
|
|
||||||
* @channel_oper: enable/reset counters and interrupt functions
|
|
||||||
* @index_interrupt: enable channel interrupts
|
|
||||||
* @reserved: reserved for Factory Use
|
|
||||||
* @index_input_levels: index signal logical input level
|
|
||||||
* @cable_status: differential encoder cable status
|
|
||||||
*/
|
|
||||||
struct quad8_reg {
|
|
||||||
struct channel_reg channel[QUAD8_NUM_COUNTERS];
|
|
||||||
u8 interrupt_status;
|
|
||||||
u8 channel_oper;
|
|
||||||
u8 index_interrupt;
|
|
||||||
u8 reserved[3];
|
|
||||||
u8 index_input_levels;
|
|
||||||
u8 cable_status;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct quad8 - device private data structure
|
* struct quad8 - device private data structure
|
||||||
|
|
@ -76,7 +55,7 @@ struct quad8_reg {
|
||||||
* @fck_prescaler: array of filter clock prescaler configurations
|
* @fck_prescaler: array of filter clock prescaler configurations
|
||||||
* @preset: array of preset values
|
* @preset: array of preset values
|
||||||
* @cable_fault_enable: differential encoder cable status enable configurations
|
* @cable_fault_enable: differential encoder cable status enable configurations
|
||||||
* @reg: I/O address offset for the device registers
|
* @map: regmap for the device
|
||||||
*/
|
*/
|
||||||
struct quad8 {
|
struct quad8 {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
|
@ -86,7 +65,30 @@ struct quad8 {
|
||||||
unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
|
unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
|
||||||
unsigned int preset[QUAD8_NUM_COUNTERS];
|
unsigned int preset[QUAD8_NUM_COUNTERS];
|
||||||
unsigned int cable_fault_enable;
|
unsigned int cable_fault_enable;
|
||||||
struct quad8_reg __iomem *reg;
|
struct regmap *map;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regmap_range quad8_wr_ranges[] = {
|
||||||
|
regmap_reg_range(0x0, 0xF), regmap_reg_range(0x11, 0x12), regmap_reg_range(0x17, 0x17),
|
||||||
|
};
|
||||||
|
static const struct regmap_range quad8_rd_ranges[] = {
|
||||||
|
regmap_reg_range(0x0, 0x12), regmap_reg_range(0x16, 0x18),
|
||||||
|
};
|
||||||
|
static const struct regmap_access_table quad8_wr_table = {
|
||||||
|
.yes_ranges = quad8_wr_ranges,
|
||||||
|
.n_yes_ranges = ARRAY_SIZE(quad8_wr_ranges),
|
||||||
|
};
|
||||||
|
static const struct regmap_access_table quad8_rd_table = {
|
||||||
|
.yes_ranges = quad8_rd_ranges,
|
||||||
|
.n_yes_ranges = ARRAY_SIZE(quad8_rd_ranges),
|
||||||
|
};
|
||||||
|
static const struct regmap_config quad8_regmap_config = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.reg_stride = 1,
|
||||||
|
.val_bits = 8,
|
||||||
|
.io_port = true,
|
||||||
|
.wr_table = &quad8_wr_table,
|
||||||
|
.rd_table = &quad8_rd_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Error flag */
|
/* Error flag */
|
||||||
|
|
@ -202,12 +204,12 @@ struct quad8 {
|
||||||
/* Each Counter is 24 bits wide */
|
/* Each Counter is 24 bits wide */
|
||||||
#define LS7267_CNTR_MAX GENMASK(23, 0)
|
#define LS7267_CNTR_MAX GENMASK(23, 0)
|
||||||
|
|
||||||
static __always_inline void quad8_control_register_update(struct quad8 *const priv, u8 *const buf,
|
static __always_inline int quad8_control_register_update(struct regmap *const map, u8 *const buf,
|
||||||
const size_t channel, const u8 val,
|
const size_t channel, const u8 val,
|
||||||
const u8 field)
|
const u8 field)
|
||||||
{
|
{
|
||||||
u8p_replace_bits(&buf[channel], val, field);
|
u8p_replace_bits(&buf[channel], val, field);
|
||||||
iowrite8(buf[channel], &priv->reg->channel[channel].control);
|
return regmap_write(map, QUAD8_CONTROL(channel), buf[channel]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_signal_read(struct counter_device *counter,
|
static int quad8_signal_read(struct counter_device *counter,
|
||||||
|
|
@ -215,15 +217,17 @@ static int quad8_signal_read(struct counter_device *counter,
|
||||||
enum counter_signal_level *level)
|
enum counter_signal_level *level)
|
||||||
{
|
{
|
||||||
const struct quad8 *const priv = counter_priv(counter);
|
const struct quad8 *const priv = counter_priv(counter);
|
||||||
unsigned int state;
|
int ret;
|
||||||
|
|
||||||
/* Only Index signal levels can be read */
|
/* Only Index signal levels can be read */
|
||||||
if (signal->id < 16)
|
if (signal->id < 16)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
state = ioread8(&priv->reg->index_input_levels) & BIT(signal->id - 16);
|
ret = regmap_test_bits(priv->map, QUAD8_INDEX_INPUT_LEVELS, BIT(signal->id - 16));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
*level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
|
*level = (ret) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -232,48 +236,56 @@ static int quad8_count_read(struct counter_device *counter,
|
||||||
struct counter_count *count, u64 *val)
|
struct counter_count *count, u64 *val)
|
||||||
{
|
{
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
|
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
u8 value[3];
|
u8 value[3];
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
iowrite8(SELECT_RLD | RESET_BP | TRANSFER_CNTR_TO_OL, &chan->control);
|
ret = regmap_write(priv->map, QUAD8_CONTROL(count->id),
|
||||||
ioread8_rep(&chan->data, value, sizeof(value));
|
SELECT_RLD | RESET_BP | TRANSFER_CNTR_TO_OL);
|
||||||
|
if (ret)
|
||||||
|
goto exit_unlock;
|
||||||
|
ret = regmap_noinc_read(priv->map, QUAD8_DATA(count->id), value, sizeof(value));
|
||||||
|
|
||||||
|
exit_unlock:
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
*val = get_unaligned_le24(value);
|
*val = get_unaligned_le24(value);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quad8_preset_register_set(struct quad8 *const priv, const size_t id,
|
static int quad8_preset_register_set(struct quad8 *const priv, const size_t id,
|
||||||
const unsigned long preset)
|
const unsigned long preset)
|
||||||
{
|
{
|
||||||
struct channel_reg __iomem *const chan = priv->reg->channel + id;
|
|
||||||
u8 value[3];
|
u8 value[3];
|
||||||
|
int ret;
|
||||||
|
|
||||||
put_unaligned_le24(preset, value);
|
put_unaligned_le24(preset, value);
|
||||||
|
|
||||||
iowrite8(SELECT_RLD | RESET_BP, &chan->control);
|
ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BP);
|
||||||
iowrite8_rep(&chan->data, value, sizeof(value));
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
return regmap_noinc_write(priv->map, QUAD8_DATA(id), value, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quad8_flag_register_reset(struct quad8 *const priv, const size_t id)
|
static int quad8_flag_register_reset(struct quad8 *const priv, const size_t id)
|
||||||
{
|
{
|
||||||
struct channel_reg __iomem *const chan = priv->reg->channel + id;
|
int ret;
|
||||||
|
|
||||||
iowrite8(SELECT_RLD | RESET_BT_CT_CPT_S_IDX, &chan->control);
|
ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BT_CT_CPT_S_IDX);
|
||||||
iowrite8(SELECT_RLD | RESET_E, &chan->control);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
return regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_E);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_count_write(struct counter_device *counter,
|
static int quad8_count_write(struct counter_device *counter,
|
||||||
struct counter_count *count, u64 val)
|
struct counter_count *count, u64 val)
|
||||||
{
|
{
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
|
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (val > LS7267_CNTR_MAX)
|
if (val > LS7267_CNTR_MAX)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
@ -281,17 +293,24 @@ static int quad8_count_write(struct counter_device *counter,
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
/* Counter can only be set via Preset Register */
|
/* Counter can only be set via Preset Register */
|
||||||
quad8_preset_register_set(priv, count->id, val);
|
ret = quad8_preset_register_set(priv, count->id, val);
|
||||||
iowrite8(SELECT_RLD | TRANSFER_PR_TO_CNTR, &chan->control);
|
if (ret)
|
||||||
|
goto exit_unlock;
|
||||||
|
ret = regmap_write(priv->map, QUAD8_CONTROL(count->id), SELECT_RLD | TRANSFER_PR_TO_CNTR);
|
||||||
|
if (ret)
|
||||||
|
goto exit_unlock;
|
||||||
|
|
||||||
quad8_flag_register_reset(priv, count->id);
|
ret = quad8_flag_register_reset(priv, count->id);
|
||||||
|
if (ret)
|
||||||
|
goto exit_unlock;
|
||||||
|
|
||||||
/* Set Preset Register back to original value */
|
/* Set Preset Register back to original value */
|
||||||
quad8_preset_register_set(priv, count->id, priv->preset[count->id]);
|
ret = quad8_preset_register_set(priv, count->id, priv->preset[count->id]);
|
||||||
|
|
||||||
|
exit_unlock:
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const enum counter_function quad8_count_functions_list[] = {
|
static const enum counter_function quad8_count_functions_list[] = {
|
||||||
|
|
@ -349,6 +368,7 @@ static int quad8_function_write(struct counter_device *counter,
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
unsigned int mode_cfg;
|
unsigned int mode_cfg;
|
||||||
bool synchronous_mode;
|
bool synchronous_mode;
|
||||||
|
int ret;
|
||||||
|
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case COUNTER_FUNCTION_PULSE_DIRECTION:
|
case COUNTER_FUNCTION_PULSE_DIRECTION:
|
||||||
|
|
@ -372,14 +392,19 @@ static int quad8_function_write(struct counter_device *counter,
|
||||||
|
|
||||||
/* Synchronous function not supported in non-quadrature mode */
|
/* Synchronous function not supported in non-quadrature mode */
|
||||||
synchronous_mode = u8_get_bits(priv->idr[id], INDEX_MODE) == ENABLE_INDEX_MODE;
|
synchronous_mode = u8_get_bits(priv->idr[id], INDEX_MODE) == ENABLE_INDEX_MODE;
|
||||||
if (synchronous_mode && mode_cfg == NON_QUADRATURE)
|
if (synchronous_mode && mode_cfg == NON_QUADRATURE) {
|
||||||
quad8_control_register_update(priv, priv->idr, id, DISABLE_INDEX_MODE, INDEX_MODE);
|
ret = quad8_control_register_update(priv->map, priv->idr, id, DISABLE_INDEX_MODE,
|
||||||
|
INDEX_MODE);
|
||||||
|
if (ret)
|
||||||
|
goto exit_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
quad8_control_register_update(priv, priv->cmr, id, mode_cfg, QUADRATURE_MODE);
|
ret = quad8_control_register_update(priv->map, priv->cmr, id, mode_cfg, QUADRATURE_MODE);
|
||||||
|
|
||||||
|
exit_unlock:
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_direction_read(struct counter_device *counter,
|
static int quad8_direction_read(struct counter_device *counter,
|
||||||
|
|
@ -387,10 +412,12 @@ static int quad8_direction_read(struct counter_device *counter,
|
||||||
enum counter_count_direction *direction)
|
enum counter_count_direction *direction)
|
||||||
{
|
{
|
||||||
const struct quad8 *const priv = counter_priv(counter);
|
const struct quad8 *const priv = counter_priv(counter);
|
||||||
u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
|
unsigned int flag;
|
||||||
u8 flag;
|
int ret;
|
||||||
|
|
||||||
flag = ioread8(flag_addr);
|
ret = regmap_read(priv->map, QUAD8_CONTROL(count->id), &flag);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
*direction = (u8_get_bits(flag, FLAG_UD) == UP) ? COUNTER_COUNT_DIRECTION_FORWARD :
|
*direction = (u8_get_bits(flag, FLAG_UD) == UP) ? COUNTER_COUNT_DIRECTION_FORWARD :
|
||||||
COUNTER_COUNT_DIRECTION_BACKWARD;
|
COUNTER_COUNT_DIRECTION_BACKWARD;
|
||||||
|
|
||||||
|
|
@ -481,6 +508,7 @@ static int quad8_events_configure(struct counter_device *counter)
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
struct counter_event_node *event_node;
|
struct counter_event_node *event_node;
|
||||||
u8 flg_pins;
|
u8 flg_pins;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
|
|
@ -500,8 +528,8 @@ static int quad8_events_configure(struct counter_device *counter)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* should never reach this path */
|
/* should never reach this path */
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
ret = -EINVAL;
|
||||||
return -EINVAL;
|
goto exit_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ line */
|
/* Enable IRQ line */
|
||||||
|
|
@ -512,15 +540,18 @@ static int quad8_events_configure(struct counter_device *counter)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Save new IRQ function configuration */
|
/* Save new IRQ function configuration */
|
||||||
quad8_control_register_update(priv, priv->ior, event_node->channel, flg_pins,
|
ret = quad8_control_register_update(priv->map, priv->ior, event_node->channel,
|
||||||
FLG_PINS);
|
flg_pins, FLG_PINS);
|
||||||
|
if (ret)
|
||||||
|
goto exit_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
iowrite8(irq_enabled, &priv->reg->index_interrupt);
|
ret = regmap_write(priv->map, QUAD8_INDEX_INTERRUPT, irq_enabled);
|
||||||
|
|
||||||
|
exit_unlock:
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_watch_validate(struct counter_device *counter,
|
static int quad8_watch_validate(struct counter_device *counter,
|
||||||
|
|
@ -581,14 +612,16 @@ static int quad8_index_polarity_set(struct counter_device *counter,
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
const size_t channel_id = signal->id - 16;
|
const size_t channel_id = signal->id - 16;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
quad8_control_register_update(priv, priv->idr, channel_id, index_polarity, INDEX_POLARITY);
|
ret = quad8_control_register_update(priv->map, priv->idr, channel_id, index_polarity,
|
||||||
|
INDEX_POLARITY);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_polarity_read(struct counter_device *counter,
|
static int quad8_polarity_read(struct counter_device *counter,
|
||||||
|
|
@ -643,21 +676,24 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,
|
||||||
const size_t channel_id = signal->id - 16;
|
const size_t channel_id = signal->id - 16;
|
||||||
u8 quadrature_mode;
|
u8 quadrature_mode;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
/* Index function must be non-synchronous in non-quadrature mode */
|
/* Index function must be non-synchronous in non-quadrature mode */
|
||||||
quadrature_mode = u8_get_bits(priv->idr[channel_id], QUADRATURE_MODE);
|
quadrature_mode = u8_get_bits(priv->idr[channel_id], QUADRATURE_MODE);
|
||||||
if (synchronous_mode && quadrature_mode == NON_QUADRATURE) {
|
if (synchronous_mode && quadrature_mode == NON_QUADRATURE) {
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
ret = -EINVAL;
|
||||||
return -EINVAL;
|
goto exit_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
quad8_control_register_update(priv, priv->idr, channel_id, synchronous_mode, INDEX_MODE);
|
ret = quad8_control_register_update(priv->map, priv->idr, channel_id, synchronous_mode,
|
||||||
|
INDEX_MODE);
|
||||||
|
|
||||||
|
exit_unlock:
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_count_floor_read(struct counter_device *counter,
|
static int quad8_count_floor_read(struct counter_device *counter,
|
||||||
|
|
@ -700,6 +736,7 @@ static int quad8_count_mode_write(struct counter_device *counter,
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
unsigned int count_mode;
|
unsigned int count_mode;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
switch (cnt_mode) {
|
switch (cnt_mode) {
|
||||||
case COUNTER_COUNT_MODE_NORMAL:
|
case COUNTER_COUNT_MODE_NORMAL:
|
||||||
|
|
@ -721,11 +758,12 @@ static int quad8_count_mode_write(struct counter_device *counter,
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
quad8_control_register_update(priv, priv->cmr, count->id, count_mode, COUNT_MODE);
|
ret = quad8_control_register_update(priv->map, priv->cmr, count->id, count_mode,
|
||||||
|
COUNT_MODE);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_count_enable_read(struct counter_device *counter,
|
static int quad8_count_enable_read(struct counter_device *counter,
|
||||||
|
|
@ -743,14 +781,15 @@ static int quad8_count_enable_write(struct counter_device *counter,
|
||||||
{
|
{
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
quad8_control_register_update(priv, priv->ior, count->id, enable, AB_GATE);
|
ret = quad8_control_register_update(priv->map, priv->ior, count->id, enable, AB_GATE);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *const quad8_noise_error_states[] = {
|
static const char *const quad8_noise_error_states[] = {
|
||||||
|
|
@ -762,10 +801,12 @@ static int quad8_error_noise_get(struct counter_device *counter,
|
||||||
struct counter_count *count, u32 *noise_error)
|
struct counter_count *count, u32 *noise_error)
|
||||||
{
|
{
|
||||||
const struct quad8 *const priv = counter_priv(counter);
|
const struct quad8 *const priv = counter_priv(counter);
|
||||||
u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
|
unsigned int flag;
|
||||||
u8 flag;
|
int ret;
|
||||||
|
|
||||||
flag = ioread8(flag_addr);
|
ret = regmap_read(priv->map, QUAD8_CONTROL(count->id), &flag);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
*noise_error = u8_get_bits(flag, FLAG_E);
|
*noise_error = u8_get_bits(flag, FLAG_E);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -786,6 +827,7 @@ static int quad8_count_preset_write(struct counter_device *counter,
|
||||||
{
|
{
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (preset > LS7267_CNTR_MAX)
|
if (preset > LS7267_CNTR_MAX)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
@ -793,11 +835,11 @@ static int quad8_count_preset_write(struct counter_device *counter,
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
priv->preset[count->id] = preset;
|
priv->preset[count->id] = preset;
|
||||||
quad8_preset_register_set(priv, count->id, preset);
|
ret = quad8_preset_register_set(priv, count->id, preset);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_count_ceiling_read(struct counter_device *counter,
|
static int quad8_count_ceiling_read(struct counter_device *counter,
|
||||||
|
|
@ -829,6 +871,7 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
|
||||||
{
|
{
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (ceiling > LS7267_CNTR_MAX)
|
if (ceiling > LS7267_CNTR_MAX)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
@ -840,14 +883,16 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
|
||||||
case RANGE_LIMIT:
|
case RANGE_LIMIT:
|
||||||
case MODULO_N:
|
case MODULO_N:
|
||||||
priv->preset[count->id] = ceiling;
|
priv->preset[count->id] = ceiling;
|
||||||
quad8_preset_register_set(priv, count->id, ceiling);
|
ret = quad8_preset_register_set(priv, count->id, ceiling);
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
break;
|
||||||
return 0;
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return -EINVAL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_count_preset_enable_read(struct counter_device *counter,
|
static int quad8_count_preset_enable_read(struct counter_device *counter,
|
||||||
|
|
@ -868,15 +913,17 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,
|
||||||
{
|
{
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
/* Preset enable is active low in Input/Output Control register */
|
/* Preset enable is active low in Input/Output Control register */
|
||||||
quad8_control_register_update(priv, priv->ior, count->id, !preset_enable, LOAD_PIN);
|
ret = quad8_control_register_update(priv->map, priv->ior, count->id, !preset_enable,
|
||||||
|
LOAD_PIN);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_signal_cable_fault_read(struct counter_device *counter,
|
static int quad8_signal_cable_fault_read(struct counter_device *counter,
|
||||||
|
|
@ -887,7 +934,7 @@ static int quad8_signal_cable_fault_read(struct counter_device *counter,
|
||||||
const size_t channel_id = signal->id / 2;
|
const size_t channel_id = signal->id / 2;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
bool disabled;
|
bool disabled;
|
||||||
unsigned int status;
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
|
|
@ -898,13 +945,16 @@ static int quad8_signal_cable_fault_read(struct counter_device *counter,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Logic 0 = cable fault */
|
ret = regmap_test_bits(priv->map, QUAD8_CABLE_STATUS, BIT(channel_id));
|
||||||
status = ioread8(&priv->reg->cable_status);
|
if (ret < 0) {
|
||||||
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
/* Mask respective channel and invert logic */
|
/* Logic 0 = cable fault */
|
||||||
*cable_fault = !(status & BIT(channel_id));
|
*cable_fault = !ret;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -929,6 +979,7 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,
|
||||||
const size_t channel_id = signal->id / 2;
|
const size_t channel_id = signal->id / 2;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
unsigned int cable_fault_enable;
|
unsigned int cable_fault_enable;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
|
|
@ -940,11 +991,11 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,
|
||||||
/* Enable is active low in Differential Encoder Cable Status register */
|
/* Enable is active low in Differential Encoder Cable Status register */
|
||||||
cable_fault_enable = ~priv->cable_fault_enable;
|
cable_fault_enable = ~priv->cable_fault_enable;
|
||||||
|
|
||||||
iowrite8(cable_fault_enable, &priv->reg->cable_status);
|
ret = regmap_write(priv->map, QUAD8_CABLE_STATUS, cable_fault_enable);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
|
static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
|
||||||
|
|
@ -958,14 +1009,18 @@ static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quad8_filter_clock_prescaler_set(struct quad8 *const priv, const size_t id,
|
static int quad8_filter_clock_prescaler_set(struct quad8 *const priv, const size_t id,
|
||||||
const u8 prescaler)
|
const u8 prescaler)
|
||||||
{
|
{
|
||||||
struct channel_reg __iomem *const chan = priv->reg->channel + id;
|
int ret;
|
||||||
|
|
||||||
iowrite8(SELECT_RLD | RESET_BP, &chan->control);
|
ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BP);
|
||||||
iowrite8(prescaler, &chan->data);
|
if (ret)
|
||||||
iowrite8(SELECT_RLD | TRANSFER_PR0_TO_PSC, &chan->control);
|
return ret;
|
||||||
|
ret = regmap_write(priv->map, QUAD8_DATA(id), prescaler);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
return regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | TRANSFER_PR0_TO_PSC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
|
static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
|
||||||
|
|
@ -975,15 +1030,16 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
const size_t channel_id = signal->id / 2;
|
const size_t channel_id = signal->id / 2;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, irqflags);
|
spin_lock_irqsave(&priv->lock, irqflags);
|
||||||
|
|
||||||
priv->fck_prescaler[channel_id] = prescaler;
|
priv->fck_prescaler[channel_id] = prescaler;
|
||||||
quad8_filter_clock_prescaler_set(priv, channel_id, prescaler);
|
ret = quad8_filter_clock_prescaler_set(priv, channel_id, prescaler);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, irqflags);
|
spin_unlock_irqrestore(&priv->lock, irqflags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct counter_comp quad8_signal_ext[] = {
|
static struct counter_comp quad8_signal_ext[] = {
|
||||||
|
|
@ -1136,15 +1192,20 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
|
||||||
{
|
{
|
||||||
struct counter_device *counter = private;
|
struct counter_device *counter = private;
|
||||||
struct quad8 *const priv = counter_priv(counter);
|
struct quad8 *const priv = counter_priv(counter);
|
||||||
|
unsigned int status;
|
||||||
unsigned long irq_status;
|
unsigned long irq_status;
|
||||||
unsigned long channel;
|
unsigned long channel;
|
||||||
unsigned int flg_pins;
|
unsigned int flg_pins;
|
||||||
u8 event;
|
u8 event;
|
||||||
|
int ret;
|
||||||
|
|
||||||
irq_status = ioread8(&priv->reg->interrupt_status);
|
ret = regmap_read(priv->map, QUAD8_INTERRUPT_STATUS, &status);
|
||||||
if (!irq_status)
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
if (!status)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
irq_status = status;
|
||||||
for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
|
for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
|
||||||
flg_pins = u8_get_bits(priv->ior[channel], FLG_PINS);
|
flg_pins = u8_get_bits(priv->ior[channel], FLG_PINS);
|
||||||
switch (flg_pins) {
|
switch (flg_pins) {
|
||||||
|
|
@ -1170,42 +1231,54 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
|
||||||
counter_push_event(counter, event, channel);
|
counter_push_event(counter, event, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear pending interrupts on device */
|
ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION, CLEAR_PENDING_INTERRUPTS);
|
||||||
iowrite8(CLEAR_PENDING_INTERRUPTS, &priv->reg->channel_oper);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quad8_init_counter(struct quad8 *const priv, const size_t channel)
|
static int quad8_init_counter(struct quad8 *const priv, const size_t channel)
|
||||||
{
|
{
|
||||||
struct channel_reg __iomem *const chan = priv->reg->channel + channel;
|
int ret;
|
||||||
|
|
||||||
quad8_filter_clock_prescaler_set(priv, channel, 0);
|
ret = quad8_filter_clock_prescaler_set(priv, channel, 0);
|
||||||
quad8_preset_register_set(priv, channel, 0);
|
if (ret)
|
||||||
quad8_flag_register_reset(priv, channel);
|
return ret;
|
||||||
|
ret = quad8_preset_register_set(priv, channel, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = quad8_flag_register_reset(priv, channel);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Binary encoding; Normal count; non-quadrature mode */
|
/* Binary encoding; Normal count; non-quadrature mode */
|
||||||
priv->cmr[channel] = SELECT_CMR | BINARY | u8_encode_bits(NORMAL_COUNT, COUNT_MODE) |
|
priv->cmr[channel] = SELECT_CMR | BINARY | u8_encode_bits(NORMAL_COUNT, COUNT_MODE) |
|
||||||
u8_encode_bits(NON_QUADRATURE, QUADRATURE_MODE);
|
u8_encode_bits(NON_QUADRATURE, QUADRATURE_MODE);
|
||||||
iowrite8(priv->cmr[channel], &chan->control);
|
ret = regmap_write(priv->map, QUAD8_CONTROL(channel), priv->cmr[channel]);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Disable A and B inputs; preset on index; FLG1 as Carry */
|
/* Disable A and B inputs; preset on index; FLG1 as Carry */
|
||||||
priv->ior[channel] = SELECT_IOR | DISABLE_AB | u8_encode_bits(LOAD_CNTR, LOAD_PIN) |
|
priv->ior[channel] = SELECT_IOR | DISABLE_AB | u8_encode_bits(LOAD_CNTR, LOAD_PIN) |
|
||||||
u8_encode_bits(FLG1_CARRY_FLG2_BORROW, FLG_PINS);
|
u8_encode_bits(FLG1_CARRY_FLG2_BORROW, FLG_PINS);
|
||||||
iowrite8(priv->ior[channel], &chan->control);
|
ret = regmap_write(priv->map, QUAD8_CONTROL(channel), priv->ior[channel]);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Disable index function; negative index polarity */
|
/* Disable index function; negative index polarity */
|
||||||
priv->idr[channel] = SELECT_IDR | u8_encode_bits(DISABLE_INDEX_MODE, INDEX_MODE) |
|
priv->idr[channel] = SELECT_IDR | u8_encode_bits(DISABLE_INDEX_MODE, INDEX_MODE) |
|
||||||
u8_encode_bits(NEGATIVE_INDEX_POLARITY, INDEX_POLARITY);
|
u8_encode_bits(NEGATIVE_INDEX_POLARITY, INDEX_POLARITY);
|
||||||
iowrite8(priv->idr[channel], &chan->control);
|
return regmap_write(priv->map, QUAD8_CONTROL(channel), priv->idr[channel]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int quad8_probe(struct device *dev, unsigned int id)
|
static int quad8_probe(struct device *dev, unsigned int id)
|
||||||
{
|
{
|
||||||
struct counter_device *counter;
|
struct counter_device *counter;
|
||||||
struct quad8 *priv;
|
struct quad8 *priv;
|
||||||
|
void __iomem *regs;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
int err;
|
int ret;
|
||||||
|
|
||||||
if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
|
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",
|
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
|
||||||
|
|
@ -1218,10 +1291,15 @@ static int quad8_probe(struct device *dev, unsigned int id)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
priv = counter_priv(counter);
|
priv = counter_priv(counter);
|
||||||
|
|
||||||
priv->reg = devm_ioport_map(dev, base[id], QUAD8_EXTENT);
|
regs = devm_ioport_map(dev, base[id], QUAD8_EXTENT);
|
||||||
if (!priv->reg)
|
if (!regs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->map = devm_regmap_init_mmio(dev, regs, &quad8_regmap_config);
|
||||||
|
if (IS_ERR(priv->map))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(priv->map),
|
||||||
|
"Unable to initialize register map\n");
|
||||||
|
|
||||||
/* Initialize Counter device and driver data */
|
/* Initialize Counter device and driver data */
|
||||||
counter->name = dev_name(dev);
|
counter->name = dev_name(dev);
|
||||||
counter->parent = dev;
|
counter->parent = dev;
|
||||||
|
|
@ -1234,25 +1312,38 @@ static int quad8_probe(struct device *dev, unsigned int id)
|
||||||
spin_lock_init(&priv->lock);
|
spin_lock_init(&priv->lock);
|
||||||
|
|
||||||
/* Reset Index/Interrupt Register */
|
/* Reset Index/Interrupt Register */
|
||||||
iowrite8(0x00, &priv->reg->index_interrupt);
|
ret = regmap_write(priv->map, QUAD8_INDEX_INTERRUPT, 0x00);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
/* Reset all counters and disable interrupt function */
|
/* Reset all counters and disable interrupt function */
|
||||||
iowrite8(RESET_COUNTERS | DISABLE_INTERRUPT_FUNCTION, &priv->reg->channel_oper);
|
ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION,
|
||||||
|
RESET_COUNTERS | DISABLE_INTERRUPT_FUNCTION);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
/* Set initial configuration for all counters */
|
/* Set initial configuration for all counters */
|
||||||
for (i = 0; i < QUAD8_NUM_COUNTERS; i++)
|
for (i = 0; i < QUAD8_NUM_COUNTERS; i++) {
|
||||||
quad8_init_counter(priv, i);
|
ret = quad8_init_counter(priv, i);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
/* Disable Differential Encoder Cable Status for all channels */
|
/* Disable Differential Encoder Cable Status for all channels */
|
||||||
iowrite8(0xFF, &priv->reg->cable_status);
|
ret = regmap_write(priv->map, QUAD8_CABLE_STATUS, GENMASK(7, 0));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
/* Enable all counters and enable interrupt function */
|
/* Enable all counters and enable interrupt function */
|
||||||
iowrite8(ENABLE_COUNTERS | ENABLE_INTERRUPT_FUNCTION, &priv->reg->channel_oper);
|
ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION,
|
||||||
|
ENABLE_COUNTERS | ENABLE_INTERRUPT_FUNCTION);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
err = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
|
ret = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
|
||||||
IRQF_SHARED, counter->name, counter);
|
IRQF_SHARED, counter->name, counter);
|
||||||
if (err)
|
if (ret)
|
||||||
return err;
|
return ret;
|
||||||
|
|
||||||
err = devm_counter_add(dev, counter);
|
ret = devm_counter_add(dev, counter);
|
||||||
if (err < 0)
|
if (ret < 0)
|
||||||
return dev_err_probe(dev, err, "Failed to add counter\n");
|
return dev_err_probe(dev, ret, "Failed to add counter\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ config 104_QUAD_8
|
||||||
tristate "ACCES 104-QUAD-8 driver"
|
tristate "ACCES 104-QUAD-8 driver"
|
||||||
depends on (PC104 && X86) || COMPILE_TEST
|
depends on (PC104 && X86) || COMPILE_TEST
|
||||||
select ISA_BUS_API
|
select ISA_BUS_API
|
||||||
|
select REGMAP_MMIO
|
||||||
help
|
help
|
||||||
Say yes here to build support for the ACCES 104-QUAD-8 quadrature
|
Say yes here to build support for the ACCES 104-QUAD-8 quadrature
|
||||||
encoder counter/interface device family (104-QUAD-8, 104-QUAD-4).
|
encoder counter/interface device family (104-QUAD-8, 104-QUAD-4).
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user