diff options
Diffstat (limited to 'drivers/counter/104-quad-8.c')
-rw-r--r-- | drivers/counter/104-quad-8.c | 481 |
1 files changed, 284 insertions, 197 deletions
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index 1cbd60aaed69..deed4afadb29 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -14,6 +14,7 @@ #include <linux/interrupt.h> #include <linux/isa.h> #include <linux/kernel.h> +#include <linux/list.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> @@ -27,12 +28,43 @@ module_param_hw_array(base, uint, ioport, &num_quad8, 0); MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)]; -module_param_hw_array(irq, uint, irq, NULL, 0); +static unsigned int num_irq; +module_param_hw_array(irq, uint, irq, &num_irq, 0); MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers"); #define QUAD8_NUM_COUNTERS 8 /** + * struct channel_reg - channel register structure + * @data: Count data + * @control: Channel flags and control + */ +struct channel_reg { + u8 data; + 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 * @lock: lock to prevent clobbering device states during R/W ops * @counter: instance of the counter_device @@ -44,15 +76,13 @@ MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers"); * @ab_enable: array of A and B inputs enable configurations * @preset_enable: array of set_to_preset_on_index attribute configurations * @irq_trigger: array of current IRQ trigger function configurations - * @next_irq_trigger: array of next IRQ trigger function configurations * @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 device + * @reg: I/O address offset for the device registers */ struct quad8 { spinlock_t lock; - struct counter_device counter; unsigned int fck_prescaler[QUAD8_NUM_COUNTERS]; unsigned int preset[QUAD8_NUM_COUNTERS]; unsigned int count_mode[QUAD8_NUM_COUNTERS]; @@ -61,18 +91,12 @@ struct quad8 { unsigned int ab_enable[QUAD8_NUM_COUNTERS]; unsigned int preset_enable[QUAD8_NUM_COUNTERS]; unsigned int irq_trigger[QUAD8_NUM_COUNTERS]; - unsigned int next_irq_trigger[QUAD8_NUM_COUNTERS]; unsigned int synchronous_mode[QUAD8_NUM_COUNTERS]; unsigned int index_polarity[QUAD8_NUM_COUNTERS]; unsigned int cable_fault_enable; - unsigned int base; + struct quad8_reg __iomem *reg; }; -#define QUAD8_REG_INTERRUPT_STATUS 0x10 -#define QUAD8_REG_CHAN_OP 0x11 -#define QUAD8_REG_INDEX_INTERRUPT 0x12 -#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16 -#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17 /* Borrow Toggle flip-flop */ #define QUAD8_FLAG_BT BIT(0) /* Carry Toggle flip-flop */ @@ -113,15 +137,14 @@ static int quad8_signal_read(struct counter_device *counter, struct counter_signal *signal, enum counter_signal_level *level) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); unsigned int state; /* Only Index signal levels can be read */ if (signal->id < 16) return -EINVAL; - state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) - & BIT(signal->id - 16); + state = ioread8(&priv->reg->index_input_levels) & BIT(signal->id - 16); *level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW; @@ -131,15 +154,15 @@ static int quad8_signal_read(struct counter_device *counter, static int quad8_count_read(struct counter_device *counter, struct counter_count *count, u64 *val) { - struct quad8 *const priv = counter->priv; - const int base_offset = priv->base + 2 * count->id; + struct quad8 *const priv = counter_priv(counter); + struct channel_reg __iomem *const chan = priv->reg->channel + count->id; unsigned int flags; unsigned int borrow; unsigned int carry; unsigned long irqflags; int i; - flags = inb(base_offset + 1); + flags = ioread8(&chan->control); borrow = flags & QUAD8_FLAG_BT; carry = !!(flags & QUAD8_FLAG_CT); @@ -149,11 +172,11 @@ static int quad8_count_read(struct counter_device *counter, spin_lock_irqsave(&priv->lock, irqflags); /* Reset Byte Pointer; transfer Counter to Output Latch */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, - base_offset + 1); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, + &chan->control); for (i = 0; i < 3; i++) - *val |= (unsigned long)inb(base_offset) << (8 * i); + *val |= (unsigned long)ioread8(&chan->data) << (8 * i); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -163,8 +186,8 @@ static int quad8_count_read(struct counter_device *counter, static int quad8_count_write(struct counter_device *counter, struct counter_count *count, u64 val) { - struct quad8 *const priv = counter->priv; - const int base_offset = priv->base + 2 * count->id; + struct quad8 *const priv = counter_priv(counter); + struct channel_reg __iomem *const chan = priv->reg->channel + count->id; unsigned long irqflags; int i; @@ -175,27 +198,27 @@ static int quad8_count_write(struct counter_device *counter, spin_lock_irqsave(&priv->lock, irqflags); /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control); /* Counter can only be set via Preset Register */ for (i = 0; i < 3; i++) - outb(val >> (8 * i), base_offset); + iowrite8(val >> (8 * i), &chan->data); /* Transfer Preset Register to Counter */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, &chan->control); /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control); /* Set Preset Register back to original value */ val = priv->preset[count->id]; for (i = 0; i < 3; i++) - outb(val >> (8 * i), base_offset); + iowrite8(val >> (8 * i), &chan->data); /* Reset Borrow, Carry, Compare, and Sign flags */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control); /* Reset Error flag */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -209,46 +232,57 @@ static const enum counter_function quad8_count_functions_list[] = { COUNTER_FUNCTION_QUADRATURE_X4, }; +static int quad8_function_get(const struct quad8 *const priv, const size_t id, + enum counter_function *const function) +{ + if (!priv->quadrature_mode[id]) { + *function = COUNTER_FUNCTION_PULSE_DIRECTION; + return 0; + } + + switch (priv->quadrature_scale[id]) { + case 0: + *function = COUNTER_FUNCTION_QUADRATURE_X1_A; + return 0; + case 1: + *function = COUNTER_FUNCTION_QUADRATURE_X2_A; + return 0; + case 2: + *function = COUNTER_FUNCTION_QUADRATURE_X4; + return 0; + default: + /* should never reach this path */ + return -EINVAL; + } +} + static int quad8_function_read(struct counter_device *counter, struct counter_count *count, enum counter_function *function) { - struct quad8 *const priv = counter->priv; - const int id = count->id; + struct quad8 *const priv = counter_priv(counter); unsigned long irqflags; + int retval; spin_lock_irqsave(&priv->lock, irqflags); - if (priv->quadrature_mode[id]) - switch (priv->quadrature_scale[id]) { - case 0: - *function = COUNTER_FUNCTION_QUADRATURE_X1_A; - break; - case 1: - *function = COUNTER_FUNCTION_QUADRATURE_X2_A; - break; - case 2: - *function = COUNTER_FUNCTION_QUADRATURE_X4; - break; - } - else - *function = COUNTER_FUNCTION_PULSE_DIRECTION; + retval = quad8_function_get(priv, count->id, function); spin_unlock_irqrestore(&priv->lock, irqflags); - return 0; + return retval; } static int quad8_function_write(struct counter_device *counter, struct counter_count *count, enum counter_function function) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); const int id = count->id; unsigned int *const quadrature_mode = priv->quadrature_mode + id; unsigned int *const scale = priv->quadrature_scale + id; unsigned int *const synchronous_mode = priv->synchronous_mode + id; - const int base_offset = priv->base + 2 * id + 1; + u8 __iomem *const control = &priv->reg->channel[id].control; unsigned long irqflags; unsigned int mode_cfg; unsigned int idr_cfg; @@ -268,7 +302,7 @@ static int quad8_function_write(struct counter_device *counter, if (*synchronous_mode) { *synchronous_mode = 0; /* Disable synchronous function mode */ - outb(QUAD8_CTR_IDR | idr_cfg, base_offset); + iowrite8(QUAD8_CTR_IDR | idr_cfg, control); } } else { *quadrature_mode = 1; @@ -294,7 +328,7 @@ static int quad8_function_write(struct counter_device *counter, } /* Load mode configuration to Counter Mode Register */ - outb(QUAD8_CTR_CMR | mode_cfg, base_offset); + iowrite8(QUAD8_CTR_CMR | mode_cfg, control); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -305,12 +339,12 @@ static int quad8_direction_read(struct counter_device *counter, struct counter_count *count, enum counter_count_direction *direction) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); unsigned int ud_flag; - const unsigned int flag_addr = priv->base + 2 * count->id + 1; + u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control; /* U/D flag: nonzero = up, zero = down */ - ud_flag = inb(flag_addr) & QUAD8_FLAG_UD; + ud_flag = ioread8(flag_addr) & QUAD8_FLAG_UD; *direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD : COUNTER_COUNT_DIRECTION_BACKWARD; @@ -335,7 +369,8 @@ static int quad8_action_read(struct counter_device *counter, struct counter_synapse *synapse, enum counter_synapse_action *action) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); + unsigned long irqflags; int err; enum counter_function function; const size_t signal_a_id = count->synapses[0].signal->id; @@ -351,9 +386,21 @@ static int quad8_action_read(struct counter_device *counter, return 0; } - err = quad8_function_read(counter, count, &function); - if (err) + spin_lock_irqsave(&priv->lock, irqflags); + + /* Get Count function and direction atomically */ + err = quad8_function_get(priv, count->id, &function); + if (err) { + spin_unlock_irqrestore(&priv->lock, irqflags); + return err; + } + err = quad8_direction_read(counter, count, &direction); + if (err) { + spin_unlock_irqrestore(&priv->lock, irqflags); return err; + } + + spin_unlock_irqrestore(&priv->lock, irqflags); /* Default action mode */ *action = COUNTER_SYNAPSE_ACTION_NONE; @@ -366,10 +413,6 @@ static int quad8_action_read(struct counter_device *counter, return 0; case COUNTER_FUNCTION_QUADRATURE_X1_A: if (synapse->signal->id == signal_a_id) { - err = quad8_direction_read(counter, count, &direction); - if (err) - return err; - if (direction == COUNTER_COUNT_DIRECTION_FORWARD) *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; else @@ -390,7 +433,6 @@ static int quad8_action_read(struct counter_device *counter, } enum { - QUAD8_EVENT_NONE = -1, QUAD8_EVENT_CARRY = 0, QUAD8_EVENT_COMPARE = 1, QUAD8_EVENT_CARRY_BORROW = 2, @@ -399,40 +441,54 @@ enum { static int quad8_events_configure(struct counter_device *counter) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); unsigned long irq_enabled = 0; unsigned long irqflags; - size_t channel; + struct counter_event_node *event_node; + unsigned int next_irq_trigger; unsigned long ior_cfg; - unsigned long base_offset; spin_lock_irqsave(&priv->lock, irqflags); - /* Enable interrupts for the requested channels, disable for the rest */ - for (channel = 0; channel < QUAD8_NUM_COUNTERS; channel++) { - if (priv->next_irq_trigger[channel] == QUAD8_EVENT_NONE) - continue; + list_for_each_entry(event_node, &counter->events_list, l) { + switch (event_node->event) { + case COUNTER_EVENT_OVERFLOW: + next_irq_trigger = QUAD8_EVENT_CARRY; + break; + case COUNTER_EVENT_THRESHOLD: + next_irq_trigger = QUAD8_EVENT_COMPARE; + break; + case COUNTER_EVENT_OVERFLOW_UNDERFLOW: + next_irq_trigger = QUAD8_EVENT_CARRY_BORROW; + break; + case COUNTER_EVENT_INDEX: + next_irq_trigger = QUAD8_EVENT_INDEX; + break; + default: + /* should never reach this path */ + spin_unlock_irqrestore(&priv->lock, irqflags); + return -EINVAL; + } - if (priv->irq_trigger[channel] != priv->next_irq_trigger[channel]) { - /* Save new IRQ function configuration */ - priv->irq_trigger[channel] = priv->next_irq_trigger[channel]; + /* Enable IRQ line */ + irq_enabled |= BIT(event_node->channel); - /* Load configuration to I/O Control Register */ - ior_cfg = priv->ab_enable[channel] | - priv->preset_enable[channel] << 1 | - priv->irq_trigger[channel] << 3; - base_offset = priv->base + 2 * channel + 1; - outb(QUAD8_CTR_IOR | ior_cfg, base_offset); - } + /* Skip configuration if it is the same as previously set */ + if (priv->irq_trigger[event_node->channel] == next_irq_trigger) + continue; - /* Reset next IRQ trigger function configuration */ - priv->next_irq_trigger[channel] = QUAD8_EVENT_NONE; + /* Save new IRQ function configuration */ + priv->irq_trigger[event_node->channel] = next_irq_trigger; - /* Enable IRQ line */ - irq_enabled |= BIT(channel); + /* Load configuration to I/O Control Register */ + ior_cfg = priv->ab_enable[event_node->channel] | + priv->preset_enable[event_node->channel] << 1 | + priv->irq_trigger[event_node->channel] << 3; + iowrite8(QUAD8_CTR_IOR | ior_cfg, + &priv->reg->channel[event_node->channel].control); } - outb(irq_enabled, priv->base + QUAD8_REG_INDEX_INTERRUPT); + iowrite8(irq_enabled, &priv->reg->index_interrupt); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -442,35 +498,20 @@ static int quad8_events_configure(struct counter_device *counter) static int quad8_watch_validate(struct counter_device *counter, const struct counter_watch *watch) { - struct quad8 *const priv = counter->priv; + struct counter_event_node *event_node; if (watch->channel > QUAD8_NUM_COUNTERS - 1) return -EINVAL; switch (watch->event) { case COUNTER_EVENT_OVERFLOW: - if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE) - priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_CARRY; - else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_CARRY) - return -EINVAL; - return 0; case COUNTER_EVENT_THRESHOLD: - if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE) - priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_COMPARE; - else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_COMPARE) - return -EINVAL; - return 0; case COUNTER_EVENT_OVERFLOW_UNDERFLOW: - if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE) - priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_CARRY_BORROW; - else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_CARRY_BORROW) - return -EINVAL; - return 0; case COUNTER_EVENT_INDEX: - if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE) - priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_INDEX; - else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_INDEX) - return -EINVAL; + list_for_each_entry(event_node, &counter->next_events_list, l) + if (watch->channel == event_node->channel && + watch->event != event_node->event) + return -EINVAL; return 0; default: return -EINVAL; @@ -497,7 +538,7 @@ static int quad8_index_polarity_get(struct counter_device *counter, struct counter_signal *signal, u32 *index_polarity) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); const size_t channel_id = signal->id - 16; *index_polarity = priv->index_polarity[channel_id]; @@ -509,9 +550,9 @@ static int quad8_index_polarity_set(struct counter_device *counter, struct counter_signal *signal, u32 index_polarity) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); const size_t channel_id = signal->id - 16; - const int base_offset = priv->base + 2 * channel_id + 1; + u8 __iomem *const control = &priv->reg->channel[channel_id].control; unsigned long irqflags; unsigned int idr_cfg = index_polarity << 1; @@ -522,13 +563,39 @@ static int quad8_index_polarity_set(struct counter_device *counter, priv->index_polarity[channel_id] = index_polarity; /* Load Index Control configuration to Index Control Register */ - outb(QUAD8_CTR_IDR | idr_cfg, base_offset); + iowrite8(QUAD8_CTR_IDR | idr_cfg, control); spin_unlock_irqrestore(&priv->lock, irqflags); return 0; } +static int quad8_polarity_read(struct counter_device *counter, + struct counter_signal *signal, + enum counter_signal_polarity *polarity) +{ + int err; + u32 index_polarity; + + err = quad8_index_polarity_get(counter, signal, &index_polarity); + if (err) + return err; + + *polarity = (index_polarity) ? COUNTER_SIGNAL_POLARITY_POSITIVE : + COUNTER_SIGNAL_POLARITY_NEGATIVE; + + return 0; +} + +static int quad8_polarity_write(struct counter_device *counter, + struct counter_signal *signal, + enum counter_signal_polarity polarity) +{ + const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ? 1 : 0; + + return quad8_index_polarity_set(counter, signal, pol); +} + static const char *const quad8_synchronous_modes[] = { "non-synchronous", "synchronous" @@ -538,7 +605,7 @@ static int quad8_synchronous_mode_get(struct counter_device *counter, struct counter_signal *signal, u32 *synchronous_mode) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); const size_t channel_id = signal->id - 16; *synchronous_mode = priv->synchronous_mode[channel_id]; @@ -550,9 +617,9 @@ static int quad8_synchronous_mode_set(struct counter_device *counter, struct counter_signal *signal, u32 synchronous_mode) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); const size_t channel_id = signal->id - 16; - const int base_offset = priv->base + 2 * channel_id + 1; + u8 __iomem *const control = &priv->reg->channel[channel_id].control; unsigned long irqflags; unsigned int idr_cfg = synchronous_mode; @@ -569,7 +636,7 @@ static int quad8_synchronous_mode_set(struct counter_device *counter, priv->synchronous_mode[channel_id] = synchronous_mode; /* Load Index Control configuration to Index Control Register */ - outb(QUAD8_CTR_IDR | idr_cfg, base_offset); + iowrite8(QUAD8_CTR_IDR | idr_cfg, control); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -589,7 +656,7 @@ static int quad8_count_mode_read(struct counter_device *counter, struct counter_count *count, enum counter_count_mode *cnt_mode) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); /* Map 104-QUAD-8 count mode to Generic Counter count mode */ switch (priv->count_mode[count->id]) { @@ -614,10 +681,10 @@ static int quad8_count_mode_write(struct counter_device *counter, struct counter_count *count, enum counter_count_mode cnt_mode) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); unsigned int count_mode; unsigned int mode_cfg; - const int base_offset = priv->base + 2 * count->id + 1; + u8 __iomem *const control = &priv->reg->channel[count->id].control; unsigned long irqflags; /* Map Generic Counter count mode to 104-QUAD-8 count mode */ @@ -651,7 +718,7 @@ static int quad8_count_mode_write(struct counter_device *counter, mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3; /* Load mode configuration to Counter Mode Register */ - outb(QUAD8_CTR_CMR | mode_cfg, base_offset); + iowrite8(QUAD8_CTR_CMR | mode_cfg, control); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -661,7 +728,7 @@ static int quad8_count_mode_write(struct counter_device *counter, static int quad8_count_enable_read(struct counter_device *counter, struct counter_count *count, u8 *enable) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); *enable = priv->ab_enable[count->id]; @@ -671,8 +738,8 @@ static int quad8_count_enable_read(struct counter_device *counter, static int quad8_count_enable_write(struct counter_device *counter, struct counter_count *count, u8 enable) { - struct quad8 *const priv = counter->priv; - const int base_offset = priv->base + 2 * count->id; + struct quad8 *const priv = counter_priv(counter); + u8 __iomem *const control = &priv->reg->channel[count->id].control; unsigned long irqflags; unsigned int ior_cfg; @@ -684,7 +751,7 @@ static int quad8_count_enable_write(struct counter_device *counter, priv->irq_trigger[count->id] << 3; /* Load I/O control configuration */ - outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); + iowrite8(QUAD8_CTR_IOR | ior_cfg, control); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -699,10 +766,10 @@ static const char *const quad8_noise_error_states[] = { static int quad8_error_noise_get(struct counter_device *counter, struct counter_count *count, u32 *noise_error) { - const struct quad8 *const priv = counter->priv; - const int base_offset = priv->base + 2 * count->id + 1; + const struct quad8 *const priv = counter_priv(counter); + u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control; - *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E); + *noise_error = !!(ioread8(flag_addr) & QUAD8_FLAG_E); return 0; } @@ -710,7 +777,7 @@ static int quad8_error_noise_get(struct counter_device *counter, static int quad8_count_preset_read(struct counter_device *counter, struct counter_count *count, u64 *preset) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); *preset = priv->preset[count->id]; @@ -720,23 +787,23 @@ static int quad8_count_preset_read(struct counter_device *counter, static void quad8_preset_register_set(struct quad8 *const priv, const int id, const unsigned int preset) { - const unsigned int base_offset = priv->base + 2 * id; + struct channel_reg __iomem *const chan = priv->reg->channel + id; int i; priv->preset[id] = preset; /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control); /* Set Preset Register */ for (i = 0; i < 3; i++) - outb(preset >> (8 * i), base_offset); + iowrite8(preset >> (8 * i), &chan->data); } static int quad8_count_preset_write(struct counter_device *counter, struct counter_count *count, u64 preset) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); unsigned long irqflags; /* Only 24-bit values are supported */ @@ -755,7 +822,7 @@ static int quad8_count_preset_write(struct counter_device *counter, static int quad8_count_ceiling_read(struct counter_device *counter, struct counter_count *count, u64 *ceiling) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); unsigned long irqflags; spin_lock_irqsave(&priv->lock, irqflags); @@ -780,7 +847,7 @@ static int quad8_count_ceiling_read(struct counter_device *counter, static int quad8_count_ceiling_write(struct counter_device *counter, struct counter_count *count, u64 ceiling) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); unsigned long irqflags; /* Only 24-bit values are supported */ @@ -807,7 +874,7 @@ static int quad8_count_preset_enable_read(struct counter_device *counter, struct counter_count *count, u8 *preset_enable) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); *preset_enable = !priv->preset_enable[count->id]; @@ -818,8 +885,8 @@ static int quad8_count_preset_enable_write(struct counter_device *counter, struct counter_count *count, u8 preset_enable) { - struct quad8 *const priv = counter->priv; - const int base_offset = priv->base + 2 * count->id + 1; + struct quad8 *const priv = counter_priv(counter); + u8 __iomem *const control = &priv->reg->channel[count->id].control; unsigned long irqflags; unsigned int ior_cfg; @@ -834,7 +901,7 @@ static int quad8_count_preset_enable_write(struct counter_device *counter, priv->irq_trigger[count->id] << 3; /* Load I/O control configuration to Input / Output Control Register */ - outb(QUAD8_CTR_IOR | ior_cfg, base_offset); + iowrite8(QUAD8_CTR_IOR | ior_cfg, control); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -845,7 +912,7 @@ static int quad8_signal_cable_fault_read(struct counter_device *counter, struct counter_signal *signal, u8 *cable_fault) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); const size_t channel_id = signal->id / 2; unsigned long irqflags; bool disabled; @@ -861,7 +928,7 @@ static int quad8_signal_cable_fault_read(struct counter_device *counter, } /* Logic 0 = cable fault */ - status = inb(priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS); + status = ioread8(&priv->reg->cable_status); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -875,7 +942,7 @@ static int quad8_signal_cable_fault_enable_read(struct counter_device *counter, struct counter_signal *signal, u8 *enable) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); const size_t channel_id = signal->id / 2; *enable = !!(priv->cable_fault_enable & BIT(channel_id)); @@ -887,7 +954,7 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter, struct counter_signal *signal, u8 enable) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); const size_t channel_id = signal->id / 2; unsigned long irqflags; unsigned int cable_fault_enable; @@ -902,7 +969,7 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter, /* Enable is active low in Differential Encoder Cable Status register */ cable_fault_enable = ~priv->cable_fault_enable; - outb(cable_fault_enable, priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS); + iowrite8(cable_fault_enable, &priv->reg->cable_status); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -913,7 +980,7 @@ static int quad8_signal_fck_prescaler_read(struct counter_device *counter, struct counter_signal *signal, u8 *prescaler) { - const struct quad8 *const priv = counter->priv; + const struct quad8 *const priv = counter_priv(counter); *prescaler = priv->fck_prescaler[signal->id / 2]; @@ -924,9 +991,9 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter, struct counter_signal *signal, u8 prescaler) { - struct quad8 *const priv = counter->priv; + struct quad8 *const priv = counter_priv(counter); const size_t channel_id = signal->id / 2; - const int base_offset = priv->base + 2 * channel_id; + struct channel_reg __iomem *const chan = priv->reg->channel + channel_id; unsigned long irqflags; spin_lock_irqsave(&priv->lock, irqflags); @@ -934,12 +1001,12 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter, priv->fck_prescaler[channel_id] = prescaler; /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control); /* Set filter clock factor */ - outb(prescaler, base_offset); - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, - base_offset + 1); + iowrite8(prescaler, &chan->data); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, + &chan->control); spin_unlock_irqrestore(&priv->lock, irqflags); @@ -957,6 +1024,13 @@ static struct counter_comp quad8_signal_ext[] = { quad8_signal_fck_prescaler_write) }; +static const enum counter_signal_polarity quad8_polarities[] = { + COUNTER_SIGNAL_POLARITY_POSITIVE, + COUNTER_SIGNAL_POLARITY_NEGATIVE, +}; + +static DEFINE_COUNTER_AVAILABLE(quad8_polarity_available, quad8_polarities); + static DEFINE_COUNTER_ENUM(quad8_index_pol_enum, quad8_index_polarity_modes); static DEFINE_COUNTER_ENUM(quad8_synch_mode_enum, quad8_synchronous_modes); @@ -964,6 +1038,8 @@ static struct counter_comp quad8_index_ext[] = { COUNTER_COMP_SIGNAL_ENUM("index_polarity", quad8_index_polarity_get, quad8_index_polarity_set, quad8_index_pol_enum), + COUNTER_COMP_POLARITY(quad8_polarity_read, quad8_polarity_write, + quad8_polarity_available), COUNTER_COMP_SIGNAL_ENUM("synchronous_mode", quad8_synchronous_mode_get, quad8_synchronous_mode_set, quad8_synch_mode_enum), @@ -1085,13 +1161,13 @@ static struct counter_count quad8_counts[] = { static irqreturn_t quad8_irq_handler(int irq, void *private) { - struct quad8 *const priv = private; - const unsigned long base = priv->base; + struct counter_device *counter = private; + struct quad8 *const priv = counter_priv(counter); unsigned long irq_status; unsigned long channel; u8 event; - irq_status = inb(base + QUAD8_REG_INTERRUPT_STATUS); + irq_status = ioread8(&priv->reg->interrupt_status); if (!irq_status) return IRQ_NONE; @@ -1116,20 +1192,47 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) continue; } - counter_push_event(&priv->counter, event, channel); + counter_push_event(counter, event, channel); } /* Clear pending interrupts on device */ - outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base + QUAD8_REG_CHAN_OP); + iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper); return IRQ_HANDLED; } +static void quad8_init_counter(struct channel_reg __iomem *const chan) +{ + unsigned long i; + + /* Reset Byte Pointer */ + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control); + /* Reset filter clock factor */ + iowrite8(0, &chan->data); + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, + &chan->control); + /* Reset Byte Pointer */ + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control); + /* Reset Preset Register */ + for (i = 0; i < 3; i++) + iowrite8(0x00, &chan->data); + /* Reset Borrow, Carry, Compare, and Sign flags */ + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control); + /* Reset Error flag */ + iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control); + /* Binary encoding; Normal count; non-quadrature mode */ + iowrite8(QUAD8_CTR_CMR, &chan->control); + /* Disable A and B inputs; preset on index; FLG1 as Carry */ + iowrite8(QUAD8_CTR_IOR, &chan->control); + /* Disable index function; negative index polarity */ + iowrite8(QUAD8_CTR_IDR, &chan->control); +} + static int quad8_probe(struct device *dev, unsigned int id) { + struct counter_device *counter; struct quad8 *priv; - int i, j; - unsigned int base_offset; + unsigned long i; int err; if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) { @@ -1138,65 +1241,48 @@ static int quad8_probe(struct device *dev, unsigned int id) return -EBUSY; } - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) + counter = devm_counter_alloc(dev, sizeof(*priv)); + if (!counter) + return -ENOMEM; + priv = counter_priv(counter); + + priv->reg = devm_ioport_map(dev, base[id], QUAD8_EXTENT); + if (!priv->reg) return -ENOMEM; /* Initialize Counter device and driver data */ - 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]; + counter->name = dev_name(dev); + counter->parent = dev; + counter->ops = &quad8_ops; + counter->counts = quad8_counts; + counter->num_counts = ARRAY_SIZE(quad8_counts); + counter->signals = quad8_signals; + counter->num_signals = ARRAY_SIZE(quad8_signals); spin_lock_init(&priv->lock); /* Reset Index/Interrupt Register */ - outb(0x00, base[id] + QUAD8_REG_INDEX_INTERRUPT); + iowrite8(0x00, &priv->reg->index_interrupt); /* Reset all counters and disable interrupt function */ - outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); + iowrite8(QUAD8_CHAN_OP_RESET_COUNTERS, &priv->reg->channel_oper); /* Set initial configuration for all counters */ - for (i = 0; i < QUAD8_NUM_COUNTERS; i++) { - base_offset = base[id] + 2 * i; - /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); - /* Reset filter clock factor */ - outb(0, base_offset); - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, - base_offset + 1); - /* Reset Byte Pointer */ - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); - /* Reset Preset Register */ - for (j = 0; j < 3; j++) - outb(0x00, 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); - /* Binary encoding; Normal count; non-quadrature mode */ - outb(QUAD8_CTR_CMR, base_offset + 1); - /* Disable A and B inputs; preset on index; FLG1 as Carry */ - outb(QUAD8_CTR_IOR, base_offset + 1); - /* Disable index function; negative index polarity */ - outb(QUAD8_CTR_IDR, base_offset + 1); - /* Initialize next IRQ trigger function configuration */ - priv->next_irq_trigger[i] = QUAD8_EVENT_NONE; - } + for (i = 0; i < QUAD8_NUM_COUNTERS; i++) + quad8_init_counter(priv->reg->channel + i); /* Disable Differential Encoder Cable Status for all channels */ - outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS); + iowrite8(0xFF, &priv->reg->cable_status); /* Enable all counters and enable interrupt function */ - outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base[id] + QUAD8_REG_CHAN_OP); + iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper); - err = devm_request_irq(dev, irq[id], quad8_irq_handler, IRQF_SHARED, - priv->counter.name, priv); + err = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler, + IRQF_SHARED, counter->name, counter); if (err) return err; - return devm_counter_register(dev, &priv->counter); + err = devm_counter_add(dev, counter); + if (err < 0) + return dev_err_probe(dev, err, "Failed to add counter\n"); + + return 0; } static struct isa_driver quad8_driver = { @@ -1206,8 +1292,9 @@ static struct isa_driver quad8_driver = { } }; -module_isa_driver(quad8_driver, num_quad8); +module_isa_driver_with_irq(quad8_driver, num_quad8, num_irq); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(COUNTER); |