Linux Audio

Check our new training course

Loading...
v6.2
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Counter driver for the ACCES 104-QUAD-8
   4 * Copyright (C) 2016 William Breathitt Gray
   5 *
   6 * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4.
   7 */
   8#include <linux/bitops.h>
   9#include <linux/counter.h>
  10#include <linux/device.h>
  11#include <linux/errno.h>
  12#include <linux/io.h>
  13#include <linux/ioport.h>
  14#include <linux/interrupt.h>
  15#include <linux/isa.h>
  16#include <linux/kernel.h>
  17#include <linux/list.h>
  18#include <linux/module.h>
  19#include <linux/moduleparam.h>
  20#include <linux/types.h>
  21#include <linux/spinlock.h>
  22
  23#define QUAD8_EXTENT 32
  24
  25static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
  26static unsigned int num_quad8;
  27module_param_hw_array(base, uint, ioport, &num_quad8, 0);
  28MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
  29
  30static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
  31static unsigned int num_irq;
  32module_param_hw_array(irq, uint, irq, &num_irq, 0);
  33MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
  34
  35#define QUAD8_NUM_COUNTERS 8
  36
  37/**
  38 * struct channel_reg - channel register structure
  39 * @data:	Count data
  40 * @control:	Channel flags and control
  41 */
  42struct channel_reg {
  43	u8 data;
  44	u8 control;
  45};
  46
  47/**
  48 * struct quad8_reg - device register structure
  49 * @channel:		quadrature counter data and control
  50 * @interrupt_status:	channel interrupt status
  51 * @channel_oper:	enable/reset counters and interrupt functions
  52 * @index_interrupt:	enable channel interrupts
  53 * @reserved:		reserved for Factory Use
  54 * @index_input_levels:	index signal logical input level
  55 * @cable_status:	differential encoder cable status
  56 */
  57struct quad8_reg {
  58	struct channel_reg channel[QUAD8_NUM_COUNTERS];
  59	u8 interrupt_status;
  60	u8 channel_oper;
  61	u8 index_interrupt;
  62	u8 reserved[3];
  63	u8 index_input_levels;
  64	u8 cable_status;
  65};
  66
  67/**
  68 * struct quad8 - device private data structure
  69 * @lock:		lock to prevent clobbering device states during R/W ops
  70 * @counter:		instance of the counter_device
  71 * @fck_prescaler:	array of filter clock prescaler configurations
  72 * @preset:		array of preset values
  73 * @count_mode:		array of count mode configurations
  74 * @quadrature_mode:	array of quadrature mode configurations
  75 * @quadrature_scale:	array of quadrature mode scale configurations
  76 * @ab_enable:		array of A and B inputs enable configurations
  77 * @preset_enable:	array of set_to_preset_on_index attribute configurations
  78 * @irq_trigger:	array of current IRQ trigger function configurations
  79 * @synchronous_mode:	array of index function synchronous mode configurations
  80 * @index_polarity:	array of index function polarity configurations
  81 * @cable_fault_enable:	differential encoder cable status enable configurations
  82 * @reg:		I/O address offset for the device registers
  83 */
  84struct quad8 {
  85	spinlock_t lock;
 
  86	unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
  87	unsigned int preset[QUAD8_NUM_COUNTERS];
  88	unsigned int count_mode[QUAD8_NUM_COUNTERS];
  89	unsigned int quadrature_mode[QUAD8_NUM_COUNTERS];
  90	unsigned int quadrature_scale[QUAD8_NUM_COUNTERS];
  91	unsigned int ab_enable[QUAD8_NUM_COUNTERS];
  92	unsigned int preset_enable[QUAD8_NUM_COUNTERS];
  93	unsigned int irq_trigger[QUAD8_NUM_COUNTERS];
  94	unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
  95	unsigned int index_polarity[QUAD8_NUM_COUNTERS];
  96	unsigned int cable_fault_enable;
  97	struct quad8_reg __iomem *reg;
  98};
  99
 
 
 
 100/* Borrow Toggle flip-flop */
 101#define QUAD8_FLAG_BT BIT(0)
 102/* Carry Toggle flip-flop */
 103#define QUAD8_FLAG_CT BIT(1)
 104/* Error flag */
 105#define QUAD8_FLAG_E BIT(4)
 106/* Up/Down flag */
 107#define QUAD8_FLAG_UD BIT(5)
 108/* Reset and Load Signal Decoders */
 109#define QUAD8_CTR_RLD 0x00
 110/* Counter Mode Register */
 111#define QUAD8_CTR_CMR 0x20
 112/* Input / Output Control Register */
 113#define QUAD8_CTR_IOR 0x40
 114/* Index Control Register */
 115#define QUAD8_CTR_IDR 0x60
 116/* Reset Byte Pointer (three byte data pointer) */
 117#define QUAD8_RLD_RESET_BP 0x01
 118/* Reset Counter */
 119#define QUAD8_RLD_RESET_CNTR 0x02
 120/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
 121#define QUAD8_RLD_RESET_FLAGS 0x04
 122/* Reset Error flag */
 123#define QUAD8_RLD_RESET_E 0x06
 124/* Preset Register to Counter */
 125#define QUAD8_RLD_PRESET_CNTR 0x08
 126/* Transfer Counter to Output Latch */
 127#define QUAD8_RLD_CNTR_OUT 0x10
 128/* Transfer Preset Register LSB to FCK Prescaler */
 129#define QUAD8_RLD_PRESET_PSC 0x18
 
 130#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
 131#define QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC 0x04
 132#define QUAD8_CMR_QUADRATURE_X1 0x08
 133#define QUAD8_CMR_QUADRATURE_X2 0x10
 134#define QUAD8_CMR_QUADRATURE_X4 0x18
 135
 136static int quad8_signal_read(struct counter_device *counter,
 137			     struct counter_signal *signal,
 138			     enum counter_signal_level *level)
 139{
 140	const struct quad8 *const priv = counter_priv(counter);
 141	unsigned int state;
 142
 143	/* Only Index signal levels can be read */
 144	if (signal->id < 16)
 145		return -EINVAL;
 146
 147	state = ioread8(&priv->reg->index_input_levels) & BIT(signal->id - 16);
 
 148
 149	*level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
 150
 151	return 0;
 152}
 153
 154static int quad8_count_read(struct counter_device *counter,
 155			    struct counter_count *count, u64 *val)
 156{
 157	struct quad8 *const priv = counter_priv(counter);
 158	struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
 159	unsigned int flags;
 160	unsigned int borrow;
 161	unsigned int carry;
 162	unsigned long irqflags;
 163	int i;
 164
 165	flags = ioread8(&chan->control);
 166	borrow = flags & QUAD8_FLAG_BT;
 167	carry = !!(flags & QUAD8_FLAG_CT);
 168
 169	/* Borrow XOR Carry effectively doubles count range */
 170	*val = (unsigned long)(borrow ^ carry) << 24;
 171
 172	spin_lock_irqsave(&priv->lock, irqflags);
 173
 174	/* Reset Byte Pointer; transfer Counter to Output Latch */
 175	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
 176		 &chan->control);
 177
 178	for (i = 0; i < 3; i++)
 179		*val |= (unsigned long)ioread8(&chan->data) << (8 * i);
 180
 181	spin_unlock_irqrestore(&priv->lock, irqflags);
 182
 183	return 0;
 184}
 185
 186static int quad8_count_write(struct counter_device *counter,
 187			     struct counter_count *count, u64 val)
 188{
 189	struct quad8 *const priv = counter_priv(counter);
 190	struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
 191	unsigned long irqflags;
 192	int i;
 193
 194	/* Only 24-bit values are supported */
 195	if (val > 0xFFFFFF)
 196		return -ERANGE;
 197
 198	spin_lock_irqsave(&priv->lock, irqflags);
 199
 200	/* Reset Byte Pointer */
 201	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
 202
 203	/* Counter can only be set via Preset Register */
 204	for (i = 0; i < 3; i++)
 205		iowrite8(val >> (8 * i), &chan->data);
 206
 207	/* Transfer Preset Register to Counter */
 208	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, &chan->control);
 209
 210	/* Reset Byte Pointer */
 211	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
 212
 213	/* Set Preset Register back to original value */
 214	val = priv->preset[count->id];
 215	for (i = 0; i < 3; i++)
 216		iowrite8(val >> (8 * i), &chan->data);
 217
 218	/* Reset Borrow, Carry, Compare, and Sign flags */
 219	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
 220	/* Reset Error flag */
 221	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
 222
 223	spin_unlock_irqrestore(&priv->lock, irqflags);
 224
 225	return 0;
 226}
 227
 228static const enum counter_function quad8_count_functions_list[] = {
 229	COUNTER_FUNCTION_PULSE_DIRECTION,
 230	COUNTER_FUNCTION_QUADRATURE_X1_A,
 231	COUNTER_FUNCTION_QUADRATURE_X2_A,
 232	COUNTER_FUNCTION_QUADRATURE_X4,
 233};
 234
 235static int quad8_function_get(const struct quad8 *const priv, const size_t id,
 236			      enum counter_function *const function)
 237{
 238	if (!priv->quadrature_mode[id]) {
 239		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
 240		return 0;
 241	}
 242
 243	switch (priv->quadrature_scale[id]) {
 244	case 0:
 245		*function = COUNTER_FUNCTION_QUADRATURE_X1_A;
 246		return 0;
 247	case 1:
 248		*function = COUNTER_FUNCTION_QUADRATURE_X2_A;
 249		return 0;
 250	case 2:
 251		*function = COUNTER_FUNCTION_QUADRATURE_X4;
 252		return 0;
 253	default:
 254		/* should never reach this path */
 255		return -EINVAL;
 256	}
 257}
 258
 259static int quad8_function_read(struct counter_device *counter,
 260			       struct counter_count *count,
 261			       enum counter_function *function)
 262{
 263	struct quad8 *const priv = counter_priv(counter);
 264	unsigned long irqflags;
 265	int retval;
 266
 267	spin_lock_irqsave(&priv->lock, irqflags);
 268
 269	retval = quad8_function_get(priv, count->id, function);
 
 
 
 
 
 
 
 
 
 
 
 
 
 270
 271	spin_unlock_irqrestore(&priv->lock, irqflags);
 272
 273	return retval;
 274}
 275
 276static int quad8_function_write(struct counter_device *counter,
 277				struct counter_count *count,
 278				enum counter_function function)
 279{
 280	struct quad8 *const priv = counter_priv(counter);
 281	const int id = count->id;
 282	unsigned int *const quadrature_mode = priv->quadrature_mode + id;
 283	unsigned int *const scale = priv->quadrature_scale + id;
 284	unsigned int *const synchronous_mode = priv->synchronous_mode + id;
 285	u8 __iomem *const control = &priv->reg->channel[id].control;
 286	unsigned long irqflags;
 287	unsigned int mode_cfg;
 288	unsigned int idr_cfg;
 289
 290	spin_lock_irqsave(&priv->lock, irqflags);
 291
 292	mode_cfg = priv->count_mode[id] << 1;
 293	idr_cfg = priv->index_polarity[id] << 1;
 294
 295	if (function == COUNTER_FUNCTION_PULSE_DIRECTION) {
 296		*quadrature_mode = 0;
 297
 298		/* Quadrature scaling only available in quadrature mode */
 299		*scale = 0;
 300
 301		/* Synchronous function not supported in non-quadrature mode */
 302		if (*synchronous_mode) {
 303			*synchronous_mode = 0;
 304			/* Disable synchronous function mode */
 305			iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
 306		}
 307	} else {
 308		*quadrature_mode = 1;
 309
 310		switch (function) {
 311		case COUNTER_FUNCTION_QUADRATURE_X1_A:
 312			*scale = 0;
 313			mode_cfg |= QUAD8_CMR_QUADRATURE_X1;
 314			break;
 315		case COUNTER_FUNCTION_QUADRATURE_X2_A:
 316			*scale = 1;
 317			mode_cfg |= QUAD8_CMR_QUADRATURE_X2;
 318			break;
 319		case COUNTER_FUNCTION_QUADRATURE_X4:
 320			*scale = 2;
 321			mode_cfg |= QUAD8_CMR_QUADRATURE_X4;
 322			break;
 323		default:
 324			/* should never reach this path */
 325			spin_unlock_irqrestore(&priv->lock, irqflags);
 326			return -EINVAL;
 327		}
 328	}
 329
 330	/* Load mode configuration to Counter Mode Register */
 331	iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
 332
 333	spin_unlock_irqrestore(&priv->lock, irqflags);
 334
 335	return 0;
 336}
 337
 338static int quad8_direction_read(struct counter_device *counter,
 339				struct counter_count *count,
 340				enum counter_count_direction *direction)
 341{
 342	const struct quad8 *const priv = counter_priv(counter);
 343	unsigned int ud_flag;
 344	u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
 345
 346	/* U/D flag: nonzero = up, zero = down */
 347	ud_flag = ioread8(flag_addr) & QUAD8_FLAG_UD;
 348
 349	*direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD :
 350		COUNTER_COUNT_DIRECTION_BACKWARD;
 351
 352	return 0;
 353}
 354
 
 
 
 
 
 
 
 355static const enum counter_synapse_action quad8_index_actions_list[] = {
 356	COUNTER_SYNAPSE_ACTION_NONE,
 357	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
 358};
 359
 360static const enum counter_synapse_action quad8_synapse_actions_list[] = {
 361	COUNTER_SYNAPSE_ACTION_NONE,
 362	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
 363	COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
 364	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
 365};
 366
 367static int quad8_action_read(struct counter_device *counter,
 368			     struct counter_count *count,
 369			     struct counter_synapse *synapse,
 370			     enum counter_synapse_action *action)
 371{
 372	struct quad8 *const priv = counter_priv(counter);
 373	unsigned long irqflags;
 374	int err;
 375	enum counter_function function;
 376	const size_t signal_a_id = count->synapses[0].signal->id;
 377	enum counter_count_direction direction;
 378
 379	/* Handle Index signals */
 380	if (synapse->signal->id >= 16) {
 381		if (priv->preset_enable[count->id])
 382			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
 383		else
 384			*action = COUNTER_SYNAPSE_ACTION_NONE;
 385
 386		return 0;
 387	}
 388
 389	spin_lock_irqsave(&priv->lock, irqflags);
 390
 391	/* Get Count function and direction atomically */
 392	err = quad8_function_get(priv, count->id, &function);
 393	if (err) {
 394		spin_unlock_irqrestore(&priv->lock, irqflags);
 395		return err;
 396	}
 397	err = quad8_direction_read(counter, count, &direction);
 398	if (err) {
 399		spin_unlock_irqrestore(&priv->lock, irqflags);
 400		return err;
 401	}
 402
 403	spin_unlock_irqrestore(&priv->lock, irqflags);
 404
 405	/* Default action mode */
 406	*action = COUNTER_SYNAPSE_ACTION_NONE;
 407
 408	/* Determine action mode based on current count function mode */
 409	switch (function) {
 410	case COUNTER_FUNCTION_PULSE_DIRECTION:
 411		if (synapse->signal->id == signal_a_id)
 412			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
 413		return 0;
 414	case COUNTER_FUNCTION_QUADRATURE_X1_A:
 415		if (synapse->signal->id == signal_a_id) {
 
 
 416			if (direction == COUNTER_COUNT_DIRECTION_FORWARD)
 417				*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
 418			else
 419				*action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE;
 420		}
 421		return 0;
 422	case COUNTER_FUNCTION_QUADRATURE_X2_A:
 423		if (synapse->signal->id == signal_a_id)
 424			*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
 425		return 0;
 426	case COUNTER_FUNCTION_QUADRATURE_X4:
 427		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
 428		return 0;
 429	default:
 430		/* should never reach this path */
 431		return -EINVAL;
 432	}
 433}
 434
 435enum {
 436	QUAD8_EVENT_CARRY = 0,
 437	QUAD8_EVENT_COMPARE = 1,
 438	QUAD8_EVENT_CARRY_BORROW = 2,
 439	QUAD8_EVENT_INDEX = 3,
 440};
 441
 442static int quad8_events_configure(struct counter_device *counter)
 443{
 444	struct quad8 *const priv = counter_priv(counter);
 445	unsigned long irq_enabled = 0;
 446	unsigned long irqflags;
 447	struct counter_event_node *event_node;
 448	unsigned int next_irq_trigger;
 449	unsigned long ior_cfg;
 450
 451	spin_lock_irqsave(&priv->lock, irqflags);
 452
 453	list_for_each_entry(event_node, &counter->events_list, l) {
 454		switch (event_node->event) {
 455		case COUNTER_EVENT_OVERFLOW:
 456			next_irq_trigger = QUAD8_EVENT_CARRY;
 457			break;
 458		case COUNTER_EVENT_THRESHOLD:
 459			next_irq_trigger = QUAD8_EVENT_COMPARE;
 460			break;
 461		case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
 462			next_irq_trigger = QUAD8_EVENT_CARRY_BORROW;
 463			break;
 464		case COUNTER_EVENT_INDEX:
 465			next_irq_trigger = QUAD8_EVENT_INDEX;
 466			break;
 467		default:
 468			/* should never reach this path */
 469			spin_unlock_irqrestore(&priv->lock, irqflags);
 470			return -EINVAL;
 471		}
 472
 473		/* Enable IRQ line */
 474		irq_enabled |= BIT(event_node->channel);
 475
 476		/* Skip configuration if it is the same as previously set */
 477		if (priv->irq_trigger[event_node->channel] == next_irq_trigger)
 478			continue;
 479
 480		/* Save new IRQ function configuration */
 481		priv->irq_trigger[event_node->channel] = next_irq_trigger;
 482
 483		/* Load configuration to I/O Control Register */
 484		ior_cfg = priv->ab_enable[event_node->channel] |
 485			  priv->preset_enable[event_node->channel] << 1 |
 486			  priv->irq_trigger[event_node->channel] << 3;
 487		iowrite8(QUAD8_CTR_IOR | ior_cfg,
 488			 &priv->reg->channel[event_node->channel].control);
 489	}
 490
 491	iowrite8(irq_enabled, &priv->reg->index_interrupt);
 492
 493	spin_unlock_irqrestore(&priv->lock, irqflags);
 494
 495	return 0;
 496}
 497
 498static int quad8_watch_validate(struct counter_device *counter,
 499				const struct counter_watch *watch)
 500{
 501	struct counter_event_node *event_node;
 502
 503	if (watch->channel > QUAD8_NUM_COUNTERS - 1)
 504		return -EINVAL;
 505
 506	switch (watch->event) {
 507	case COUNTER_EVENT_OVERFLOW:
 508	case COUNTER_EVENT_THRESHOLD:
 509	case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
 510	case COUNTER_EVENT_INDEX:
 511		list_for_each_entry(event_node, &counter->next_events_list, l)
 512			if (watch->channel == event_node->channel &&
 513				watch->event != event_node->event)
 514				return -EINVAL;
 515		return 0;
 516	default:
 517		return -EINVAL;
 518	}
 519}
 520
 521static const struct counter_ops quad8_ops = {
 522	.signal_read = quad8_signal_read,
 523	.count_read = quad8_count_read,
 524	.count_write = quad8_count_write,
 525	.function_read = quad8_function_read,
 526	.function_write = quad8_function_write,
 527	.action_read = quad8_action_read,
 528	.events_configure = quad8_events_configure,
 529	.watch_validate = quad8_watch_validate,
 530};
 531
 532static const char *const quad8_index_polarity_modes[] = {
 533	"negative",
 534	"positive"
 535};
 536
 537static int quad8_index_polarity_get(struct counter_device *counter,
 538				    struct counter_signal *signal,
 539				    u32 *index_polarity)
 540{
 541	const struct quad8 *const priv = counter_priv(counter);
 542	const size_t channel_id = signal->id - 16;
 543
 544	*index_polarity = priv->index_polarity[channel_id];
 545
 546	return 0;
 547}
 548
 549static int quad8_index_polarity_set(struct counter_device *counter,
 550				    struct counter_signal *signal,
 551				    u32 index_polarity)
 552{
 553	struct quad8 *const priv = counter_priv(counter);
 554	const size_t channel_id = signal->id - 16;
 555	u8 __iomem *const control = &priv->reg->channel[channel_id].control;
 556	unsigned long irqflags;
 557	unsigned int idr_cfg = index_polarity << 1;
 558
 559	spin_lock_irqsave(&priv->lock, irqflags);
 560
 561	idr_cfg |= priv->synchronous_mode[channel_id];
 562
 563	priv->index_polarity[channel_id] = index_polarity;
 564
 565	/* Load Index Control configuration to Index Control Register */
 566	iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
 567
 568	spin_unlock_irqrestore(&priv->lock, irqflags);
 569
 570	return 0;
 571}
 572
 573static int quad8_polarity_read(struct counter_device *counter,
 574			       struct counter_signal *signal,
 575			       enum counter_signal_polarity *polarity)
 576{
 577	int err;
 578	u32 index_polarity;
 579
 580	err = quad8_index_polarity_get(counter, signal, &index_polarity);
 581	if (err)
 582		return err;
 583
 584	*polarity = (index_polarity) ? COUNTER_SIGNAL_POLARITY_POSITIVE :
 585		COUNTER_SIGNAL_POLARITY_NEGATIVE;
 586
 587	return 0;
 588}
 589
 590static int quad8_polarity_write(struct counter_device *counter,
 591				struct counter_signal *signal,
 592				enum counter_signal_polarity polarity)
 593{
 594	const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ? 1 : 0;
 595
 596	return quad8_index_polarity_set(counter, signal, pol);
 597}
 598
 599static const char *const quad8_synchronous_modes[] = {
 600	"non-synchronous",
 601	"synchronous"
 602};
 603
 604static int quad8_synchronous_mode_get(struct counter_device *counter,
 605				      struct counter_signal *signal,
 606				      u32 *synchronous_mode)
 607{
 608	const struct quad8 *const priv = counter_priv(counter);
 609	const size_t channel_id = signal->id - 16;
 610
 611	*synchronous_mode = priv->synchronous_mode[channel_id];
 612
 613	return 0;
 614}
 615
 616static int quad8_synchronous_mode_set(struct counter_device *counter,
 617				      struct counter_signal *signal,
 618				      u32 synchronous_mode)
 619{
 620	struct quad8 *const priv = counter_priv(counter);
 621	const size_t channel_id = signal->id - 16;
 622	u8 __iomem *const control = &priv->reg->channel[channel_id].control;
 623	unsigned long irqflags;
 624	unsigned int idr_cfg = synchronous_mode;
 625
 626	spin_lock_irqsave(&priv->lock, irqflags);
 627
 628	idr_cfg |= priv->index_polarity[channel_id] << 1;
 629
 630	/* Index function must be non-synchronous in non-quadrature mode */
 631	if (synchronous_mode && !priv->quadrature_mode[channel_id]) {
 632		spin_unlock_irqrestore(&priv->lock, irqflags);
 633		return -EINVAL;
 634	}
 635
 636	priv->synchronous_mode[channel_id] = synchronous_mode;
 637
 638	/* Load Index Control configuration to Index Control Register */
 639	iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
 640
 641	spin_unlock_irqrestore(&priv->lock, irqflags);
 642
 643	return 0;
 644}
 645
 646static int quad8_count_floor_read(struct counter_device *counter,
 647				  struct counter_count *count, u64 *floor)
 
 
 
 
 
 
 
 648{
 649	/* Only a floor of 0 is supported */
 650	*floor = 0;
 651
 652	return 0;
 653}
 654
 655static int quad8_count_mode_read(struct counter_device *counter,
 656				 struct counter_count *count,
 657				 enum counter_count_mode *cnt_mode)
 658{
 659	const struct quad8 *const priv = counter_priv(counter);
 660
 661	/* Map 104-QUAD-8 count mode to Generic Counter count mode */
 662	switch (priv->count_mode[count->id]) {
 663	case 0:
 664		*cnt_mode = COUNTER_COUNT_MODE_NORMAL;
 665		break;
 666	case 1:
 667		*cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT;
 668		break;
 669	case 2:
 670		*cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE;
 671		break;
 672	case 3:
 673		*cnt_mode = COUNTER_COUNT_MODE_MODULO_N;
 674		break;
 675	}
 676
 677	return 0;
 678}
 679
 680static int quad8_count_mode_write(struct counter_device *counter,
 681				  struct counter_count *count,
 682				  enum counter_count_mode cnt_mode)
 683{
 684	struct quad8 *const priv = counter_priv(counter);
 685	unsigned int count_mode;
 686	unsigned int mode_cfg;
 687	u8 __iomem *const control = &priv->reg->channel[count->id].control;
 688	unsigned long irqflags;
 689
 690	/* Map Generic Counter count mode to 104-QUAD-8 count mode */
 691	switch (cnt_mode) {
 692	case COUNTER_COUNT_MODE_NORMAL:
 693		count_mode = 0;
 694		break;
 695	case COUNTER_COUNT_MODE_RANGE_LIMIT:
 696		count_mode = 1;
 697		break;
 698	case COUNTER_COUNT_MODE_NON_RECYCLE:
 699		count_mode = 2;
 700		break;
 701	case COUNTER_COUNT_MODE_MODULO_N:
 702		count_mode = 3;
 703		break;
 704	default:
 705		/* should never reach this path */
 706		return -EINVAL;
 707	}
 708
 709	spin_lock_irqsave(&priv->lock, irqflags);
 710
 711	priv->count_mode[count->id] = count_mode;
 712
 713	/* Set count mode configuration value */
 714	mode_cfg = count_mode << 1;
 715
 716	/* Add quadrature mode configuration */
 717	if (priv->quadrature_mode[count->id])
 718		mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3;
 719
 720	/* Load mode configuration to Counter Mode Register */
 721	iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
 722
 723	spin_unlock_irqrestore(&priv->lock, irqflags);
 724
 725	return 0;
 726}
 727
 728static int quad8_count_enable_read(struct counter_device *counter,
 729				   struct counter_count *count, u8 *enable)
 
 
 
 
 
 
 
 730{
 731	const struct quad8 *const priv = counter_priv(counter);
 732
 733	*enable = priv->ab_enable[count->id];
 734
 735	return 0;
 
 
 
 
 
 
 
 
 736}
 737
 738static int quad8_count_enable_write(struct counter_device *counter,
 739				    struct counter_count *count, u8 enable)
 740{
 741	struct quad8 *const priv = counter_priv(counter);
 742	u8 __iomem *const control = &priv->reg->channel[count->id].control;
 743	unsigned long irqflags;
 
 744	unsigned int ior_cfg;
 745
 746	spin_lock_irqsave(&priv->lock, irqflags);
 
 
 
 
 747
 748	priv->ab_enable[count->id] = enable;
 749
 750	ior_cfg = enable | priv->preset_enable[count->id] << 1 |
 751		  priv->irq_trigger[count->id] << 3;
 752
 753	/* Load I/O control configuration */
 754	iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
 755
 756	spin_unlock_irqrestore(&priv->lock, irqflags);
 757
 758	return 0;
 759}
 760
 761static const char *const quad8_noise_error_states[] = {
 762	"No excessive noise is present at the count inputs",
 763	"Excessive noise is present at the count inputs"
 764};
 765
 766static int quad8_error_noise_get(struct counter_device *counter,
 767				 struct counter_count *count, u32 *noise_error)
 768{
 769	const struct quad8 *const priv = counter_priv(counter);
 770	u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
 771
 772	*noise_error = !!(ioread8(flag_addr) & QUAD8_FLAG_E);
 773
 774	return 0;
 775}
 776
 777static int quad8_count_preset_read(struct counter_device *counter,
 778				   struct counter_count *count, u64 *preset)
 779{
 780	const struct quad8 *const priv = counter_priv(counter);
 
 781
 782	*preset = priv->preset[count->id];
 
 
 
 783
 784	return 0;
 785}
 786
 787static void quad8_preset_register_set(struct quad8 *const priv, const int id,
 788				      const unsigned int preset)
 789{
 790	struct channel_reg __iomem *const chan = priv->reg->channel + id;
 791	int i;
 792
 793	priv->preset[id] = preset;
 794
 795	/* Reset Byte Pointer */
 796	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
 797
 798	/* Set Preset Register */
 799	for (i = 0; i < 3; i++)
 800		iowrite8(preset >> (8 * i), &chan->data);
 801}
 802
 803static int quad8_count_preset_write(struct counter_device *counter,
 804				    struct counter_count *count, u64 preset)
 805{
 806	struct quad8 *const priv = counter_priv(counter);
 807	unsigned long irqflags;
 
 
 
 
 
 808
 809	/* Only 24-bit values are supported */
 810	if (preset > 0xFFFFFF)
 811		return -ERANGE;
 812
 813	spin_lock_irqsave(&priv->lock, irqflags);
 814
 815	quad8_preset_register_set(priv, count->id, preset);
 816
 817	spin_unlock_irqrestore(&priv->lock, irqflags);
 818
 819	return 0;
 820}
 821
 822static int quad8_count_ceiling_read(struct counter_device *counter,
 823				    struct counter_count *count, u64 *ceiling)
 824{
 825	struct quad8 *const priv = counter_priv(counter);
 826	unsigned long irqflags;
 827
 828	spin_lock_irqsave(&priv->lock, irqflags);
 829
 830	/* Range Limit and Modulo-N count modes use preset value as ceiling */
 831	switch (priv->count_mode[count->id]) {
 832	case 1:
 833	case 3:
 834		*ceiling = priv->preset[count->id];
 835		break;
 836	default:
 837		/* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
 838		*ceiling = 0x1FFFFFF;
 839		break;
 840	}
 841
 842	spin_unlock_irqrestore(&priv->lock, irqflags);
 843
 844	return 0;
 
 845}
 846
 847static int quad8_count_ceiling_write(struct counter_device *counter,
 848				     struct counter_count *count, u64 ceiling)
 849{
 850	struct quad8 *const priv = counter_priv(counter);
 851	unsigned long irqflags;
 
 
 
 
 
 852
 853	/* Only 24-bit values are supported */
 854	if (ceiling > 0xFFFFFF)
 855		return -ERANGE;
 856
 857	spin_lock_irqsave(&priv->lock, irqflags);
 858
 859	/* Range Limit and Modulo-N count modes use preset value as ceiling */
 860	switch (priv->count_mode[count->id]) {
 861	case 1:
 862	case 3:
 863		quad8_preset_register_set(priv, count->id, ceiling);
 864		spin_unlock_irqrestore(&priv->lock, irqflags);
 865		return 0;
 866	}
 867
 868	spin_unlock_irqrestore(&priv->lock, irqflags);
 869
 870	return -EINVAL;
 871}
 872
 873static int quad8_count_preset_enable_read(struct counter_device *counter,
 874					  struct counter_count *count,
 875					  u8 *preset_enable)
 876{
 877	const struct quad8 *const priv = counter_priv(counter);
 878
 879	*preset_enable = !priv->preset_enable[count->id];
 880
 881	return 0;
 882}
 883
 884static int quad8_count_preset_enable_write(struct counter_device *counter,
 885					   struct counter_count *count,
 886					   u8 preset_enable)
 887{
 888	struct quad8 *const priv = counter_priv(counter);
 889	u8 __iomem *const control = &priv->reg->channel[count->id].control;
 890	unsigned long irqflags;
 891	unsigned int ior_cfg;
 892
 
 
 
 
 893	/* Preset enable is active low in Input/Output Control register */
 894	preset_enable = !preset_enable;
 895
 896	spin_lock_irqsave(&priv->lock, irqflags);
 897
 898	priv->preset_enable[count->id] = preset_enable;
 899
 900	ior_cfg = priv->ab_enable[count->id] | preset_enable << 1 |
 901		  priv->irq_trigger[count->id] << 3;
 902
 903	/* Load I/O control configuration to Input / Output Control Register */
 904	iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
 905
 906	spin_unlock_irqrestore(&priv->lock, irqflags);
 907
 908	return 0;
 909}
 910
 911static int quad8_signal_cable_fault_read(struct counter_device *counter,
 912					 struct counter_signal *signal,
 913					 u8 *cable_fault)
 914{
 915	struct quad8 *const priv = counter_priv(counter);
 916	const size_t channel_id = signal->id / 2;
 917	unsigned long irqflags;
 918	bool disabled;
 919	unsigned int status;
 
 920
 921	spin_lock_irqsave(&priv->lock, irqflags);
 922
 923	disabled = !(priv->cable_fault_enable & BIT(channel_id));
 924
 925	if (disabled) {
 926		spin_unlock_irqrestore(&priv->lock, irqflags);
 927		return -EINVAL;
 928	}
 929
 930	/* Logic 0 = cable fault */
 931	status = ioread8(&priv->reg->cable_status);
 932
 933	spin_unlock_irqrestore(&priv->lock, irqflags);
 934
 935	/* Mask respective channel and invert logic */
 936	*cable_fault = !(status & BIT(channel_id));
 937
 938	return 0;
 939}
 940
 941static int quad8_signal_cable_fault_enable_read(struct counter_device *counter,
 942						struct counter_signal *signal,
 943						u8 *enable)
 944{
 945	const struct quad8 *const priv = counter_priv(counter);
 946	const size_t channel_id = signal->id / 2;
 
 947
 948	*enable = !!(priv->cable_fault_enable & BIT(channel_id));
 949
 950	return 0;
 951}
 952
 953static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,
 954						 struct counter_signal *signal,
 955						 u8 enable)
 956{
 957	struct quad8 *const priv = counter_priv(counter);
 958	const size_t channel_id = signal->id / 2;
 959	unsigned long irqflags;
 
 960	unsigned int cable_fault_enable;
 961
 962	spin_lock_irqsave(&priv->lock, irqflags);
 
 
 
 
 963
 964	if (enable)
 965		priv->cable_fault_enable |= BIT(channel_id);
 966	else
 967		priv->cable_fault_enable &= ~BIT(channel_id);
 968
 969	/* Enable is active low in Differential Encoder Cable Status register */
 970	cable_fault_enable = ~priv->cable_fault_enable;
 971
 972	iowrite8(cable_fault_enable, &priv->reg->cable_status);
 973
 974	spin_unlock_irqrestore(&priv->lock, irqflags);
 975
 976	return 0;
 977}
 978
 979static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
 980					   struct counter_signal *signal,
 981					   u8 *prescaler)
 982{
 983	const struct quad8 *const priv = counter_priv(counter);
 984
 985	*prescaler = priv->fck_prescaler[signal->id / 2];
 986
 987	return 0;
 988}
 989
 990static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
 991					    struct counter_signal *signal,
 992					    u8 prescaler)
 993{
 994	struct quad8 *const priv = counter_priv(counter);
 995	const size_t channel_id = signal->id / 2;
 996	struct channel_reg __iomem *const chan = priv->reg->channel + channel_id;
 997	unsigned long irqflags;
 
 
 
 
 
 998
 999	spin_lock_irqsave(&priv->lock, irqflags);
1000
1001	priv->fck_prescaler[channel_id] = prescaler;
1002
1003	/* Reset Byte Pointer */
1004	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
1005
1006	/* Set filter clock factor */
1007	iowrite8(prescaler, &chan->data);
1008	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
1009		 &chan->control);
1010
1011	spin_unlock_irqrestore(&priv->lock, irqflags);
1012
1013	return 0;
1014}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1015
1016static struct counter_comp quad8_signal_ext[] = {
1017	COUNTER_COMP_SIGNAL_BOOL("cable_fault", quad8_signal_cable_fault_read,
1018				 NULL),
1019	COUNTER_COMP_SIGNAL_BOOL("cable_fault_enable",
1020				 quad8_signal_cable_fault_enable_read,
1021				 quad8_signal_cable_fault_enable_write),
1022	COUNTER_COMP_SIGNAL_U8("filter_clock_prescaler",
1023			       quad8_signal_fck_prescaler_read,
1024			       quad8_signal_fck_prescaler_write)
1025};
1026
1027static const enum counter_signal_polarity quad8_polarities[] = {
1028	COUNTER_SIGNAL_POLARITY_POSITIVE,
1029	COUNTER_SIGNAL_POLARITY_NEGATIVE,
1030};
1031
1032static DEFINE_COUNTER_AVAILABLE(quad8_polarity_available, quad8_polarities);
1033
1034static DEFINE_COUNTER_ENUM(quad8_index_pol_enum, quad8_index_polarity_modes);
1035static DEFINE_COUNTER_ENUM(quad8_synch_mode_enum, quad8_synchronous_modes);
1036
1037static struct counter_comp quad8_index_ext[] = {
1038	COUNTER_COMP_SIGNAL_ENUM("index_polarity", quad8_index_polarity_get,
1039				 quad8_index_polarity_set,
1040				 quad8_index_pol_enum),
1041	COUNTER_COMP_POLARITY(quad8_polarity_read, quad8_polarity_write,
1042			      quad8_polarity_available),
1043	COUNTER_COMP_SIGNAL_ENUM("synchronous_mode", quad8_synchronous_mode_get,
1044				 quad8_synchronous_mode_set,
1045				 quad8_synch_mode_enum),
1046};
1047
1048#define QUAD8_QUAD_SIGNAL(_id, _name) {		\
1049	.id = (_id),				\
1050	.name = (_name),			\
1051	.ext = quad8_signal_ext,		\
1052	.num_ext = ARRAY_SIZE(quad8_signal_ext)	\
1053}
1054
1055#define	QUAD8_INDEX_SIGNAL(_id, _name) {	\
1056	.id = (_id),				\
1057	.name = (_name),			\
1058	.ext = quad8_index_ext,			\
1059	.num_ext = ARRAY_SIZE(quad8_index_ext)	\
1060}
1061
1062static struct counter_signal quad8_signals[] = {
1063	QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"),
1064	QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"),
1065	QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"),
1066	QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"),
1067	QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"),
1068	QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"),
1069	QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"),
1070	QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"),
1071	QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"),
1072	QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"),
1073	QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"),
1074	QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"),
1075	QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"),
1076	QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"),
1077	QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"),
1078	QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"),
1079	QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"),
1080	QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"),
1081	QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"),
1082	QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"),
1083	QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"),
1084	QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"),
1085	QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"),
1086	QUAD8_INDEX_SIGNAL(23, "Channel 8 Index")
1087};
1088
1089#define QUAD8_COUNT_SYNAPSES(_id) {					\
1090	{								\
1091		.actions_list = quad8_synapse_actions_list,		\
1092		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
1093		.signal = quad8_signals + 2 * (_id)			\
1094	},								\
1095	{								\
1096		.actions_list = quad8_synapse_actions_list,		\
1097		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
1098		.signal = quad8_signals + 2 * (_id) + 1			\
1099	},								\
1100	{								\
1101		.actions_list = quad8_index_actions_list,		\
1102		.num_actions = ARRAY_SIZE(quad8_index_actions_list),	\
1103		.signal = quad8_signals + 2 * (_id) + 16		\
1104	}								\
1105}
1106
1107static struct counter_synapse quad8_count_synapses[][3] = {
1108	QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1),
1109	QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3),
1110	QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5),
1111	QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7)
1112};
1113
1114static const enum counter_count_mode quad8_cnt_modes[] = {
1115	COUNTER_COUNT_MODE_NORMAL,
1116	COUNTER_COUNT_MODE_RANGE_LIMIT,
1117	COUNTER_COUNT_MODE_NON_RECYCLE,
1118	COUNTER_COUNT_MODE_MODULO_N,
1119};
1120
1121static DEFINE_COUNTER_AVAILABLE(quad8_count_mode_available, quad8_cnt_modes);
1122
1123static DEFINE_COUNTER_ENUM(quad8_error_noise_enum, quad8_noise_error_states);
1124
1125static struct counter_comp quad8_count_ext[] = {
1126	COUNTER_COMP_CEILING(quad8_count_ceiling_read,
1127			     quad8_count_ceiling_write),
1128	COUNTER_COMP_FLOOR(quad8_count_floor_read, NULL),
1129	COUNTER_COMP_COUNT_MODE(quad8_count_mode_read, quad8_count_mode_write,
1130				quad8_count_mode_available),
1131	COUNTER_COMP_DIRECTION(quad8_direction_read),
1132	COUNTER_COMP_ENABLE(quad8_count_enable_read, quad8_count_enable_write),
1133	COUNTER_COMP_COUNT_ENUM("error_noise", quad8_error_noise_get, NULL,
1134				quad8_error_noise_enum),
1135	COUNTER_COMP_PRESET(quad8_count_preset_read, quad8_count_preset_write),
1136	COUNTER_COMP_PRESET_ENABLE(quad8_count_preset_enable_read,
1137				   quad8_count_preset_enable_write),
 
 
 
 
 
 
 
 
 
1138};
1139
1140#define QUAD8_COUNT(_id, _cntname) {					\
1141	.id = (_id),							\
1142	.name = (_cntname),						\
1143	.functions_list = quad8_count_functions_list,			\
1144	.num_functions = ARRAY_SIZE(quad8_count_functions_list),	\
1145	.synapses = quad8_count_synapses[(_id)],			\
1146	.num_synapses =	2,						\
1147	.ext = quad8_count_ext,						\
1148	.num_ext = ARRAY_SIZE(quad8_count_ext)				\
1149}
1150
1151static struct counter_count quad8_counts[] = {
1152	QUAD8_COUNT(0, "Channel 1 Count"),
1153	QUAD8_COUNT(1, "Channel 2 Count"),
1154	QUAD8_COUNT(2, "Channel 3 Count"),
1155	QUAD8_COUNT(3, "Channel 4 Count"),
1156	QUAD8_COUNT(4, "Channel 5 Count"),
1157	QUAD8_COUNT(5, "Channel 6 Count"),
1158	QUAD8_COUNT(6, "Channel 7 Count"),
1159	QUAD8_COUNT(7, "Channel 8 Count")
1160};
1161
1162static irqreturn_t quad8_irq_handler(int irq, void *private)
1163{
1164	struct counter_device *counter = private;
1165	struct quad8 *const priv = counter_priv(counter);
1166	unsigned long irq_status;
1167	unsigned long channel;
1168	u8 event;
1169
1170	irq_status = ioread8(&priv->reg->interrupt_status);
1171	if (!irq_status)
1172		return IRQ_NONE;
1173
1174	for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
1175		switch (priv->irq_trigger[channel]) {
1176		case QUAD8_EVENT_CARRY:
1177			event = COUNTER_EVENT_OVERFLOW;
1178				break;
1179		case QUAD8_EVENT_COMPARE:
1180			event = COUNTER_EVENT_THRESHOLD;
1181				break;
1182		case QUAD8_EVENT_CARRY_BORROW:
1183			event = COUNTER_EVENT_OVERFLOW_UNDERFLOW;
1184				break;
1185		case QUAD8_EVENT_INDEX:
1186			event = COUNTER_EVENT_INDEX;
1187				break;
1188		default:
1189			/* should never reach this path */
1190			WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n",
1191				  priv->irq_trigger[channel], channel);
1192			continue;
1193		}
1194
1195		counter_push_event(counter, event, channel);
1196	}
1197
1198	/* Clear pending interrupts on device */
1199	iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
1200
1201	return IRQ_HANDLED;
1202}
1203
1204static void quad8_init_counter(struct channel_reg __iomem *const chan)
1205{
1206	unsigned long i;
1207
1208	/* Reset Byte Pointer */
1209	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
1210	/* Reset filter clock factor */
1211	iowrite8(0, &chan->data);
1212	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
1213		 &chan->control);
1214	/* Reset Byte Pointer */
1215	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
1216	/* Reset Preset Register */
1217	for (i = 0; i < 3; i++)
1218		iowrite8(0x00, &chan->data);
1219	/* Reset Borrow, Carry, Compare, and Sign flags */
1220	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
1221	/* Reset Error flag */
1222	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
1223	/* Binary encoding; Normal count; non-quadrature mode */
1224	iowrite8(QUAD8_CTR_CMR, &chan->control);
1225	/* Disable A and B inputs; preset on index; FLG1 as Carry */
1226	iowrite8(QUAD8_CTR_IOR, &chan->control);
1227	/* Disable index function; negative index polarity */
1228	iowrite8(QUAD8_CTR_IDR, &chan->control);
1229}
1230
1231static int quad8_probe(struct device *dev, unsigned int id)
1232{
1233	struct counter_device *counter;
1234	struct quad8 *priv;
1235	unsigned long i;
1236	int err;
1237
1238	if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
1239		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
1240			base[id], base[id] + QUAD8_EXTENT);
1241		return -EBUSY;
1242	}
1243
1244	counter = devm_counter_alloc(dev, sizeof(*priv));
1245	if (!counter)
1246		return -ENOMEM;
1247	priv = counter_priv(counter);
1248
1249	priv->reg = devm_ioport_map(dev, base[id], QUAD8_EXTENT);
1250	if (!priv->reg)
1251		return -ENOMEM;
1252
1253	/* Initialize Counter device and driver data */
1254	counter->name = dev_name(dev);
1255	counter->parent = dev;
1256	counter->ops = &quad8_ops;
1257	counter->counts = quad8_counts;
1258	counter->num_counts = ARRAY_SIZE(quad8_counts);
1259	counter->signals = quad8_signals;
1260	counter->num_signals = ARRAY_SIZE(quad8_signals);
 
 
1261
1262	spin_lock_init(&priv->lock);
 
1263
1264	/* Reset Index/Interrupt Register */
1265	iowrite8(0x00, &priv->reg->index_interrupt);
1266	/* Reset all counters and disable interrupt function */
1267	iowrite8(QUAD8_CHAN_OP_RESET_COUNTERS, &priv->reg->channel_oper);
1268	/* Set initial configuration for all counters */
1269	for (i = 0; i < QUAD8_NUM_COUNTERS; i++)
1270		quad8_init_counter(priv->reg->channel + i);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1271	/* Disable Differential Encoder Cable Status for all channels */
1272	iowrite8(0xFF, &priv->reg->cable_status);
1273	/* Enable all counters and enable interrupt function */
1274	iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
1275
1276	err = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
1277			       IRQF_SHARED, counter->name, counter);
1278	if (err)
1279		return err;
1280
1281	err = devm_counter_add(dev, counter);
1282	if (err < 0)
1283		return dev_err_probe(dev, err, "Failed to add counter\n");
1284
1285	return 0;
1286}
1287
1288static struct isa_driver quad8_driver = {
1289	.probe = quad8_probe,
1290	.driver = {
1291		.name = "104-quad-8"
1292	}
1293};
1294
1295module_isa_driver_with_irq(quad8_driver, num_quad8, num_irq);
1296
1297MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1298MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
1299MODULE_LICENSE("GPL v2");
1300MODULE_IMPORT_NS(COUNTER);
v5.14.15
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Counter driver for the ACCES 104-QUAD-8
   4 * Copyright (C) 2016 William Breathitt Gray
   5 *
   6 * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4.
   7 */
   8#include <linux/bitops.h>
   9#include <linux/counter.h>
  10#include <linux/device.h>
  11#include <linux/errno.h>
  12#include <linux/io.h>
  13#include <linux/ioport.h>
 
  14#include <linux/isa.h>
  15#include <linux/kernel.h>
 
  16#include <linux/module.h>
  17#include <linux/moduleparam.h>
  18#include <linux/types.h>
 
  19
  20#define QUAD8_EXTENT 32
  21
  22static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
  23static unsigned int num_quad8;
  24module_param_hw_array(base, uint, ioport, &num_quad8, 0);
  25MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
  26
 
 
 
 
 
  27#define QUAD8_NUM_COUNTERS 8
  28
  29/**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  30 * struct quad8 - device private data structure
 
  31 * @counter:		instance of the counter_device
  32 * @fck_prescaler:	array of filter clock prescaler configurations
  33 * @preset:		array of preset values
  34 * @count_mode:		array of count mode configurations
  35 * @quadrature_mode:	array of quadrature mode configurations
  36 * @quadrature_scale:	array of quadrature mode scale configurations
  37 * @ab_enable:		array of A and B inputs enable configurations
  38 * @preset_enable:	array of set_to_preset_on_index attribute configurations
 
  39 * @synchronous_mode:	array of index function synchronous mode configurations
  40 * @index_polarity:	array of index function polarity configurations
  41 * @cable_fault_enable:	differential encoder cable status enable configurations
  42 * @base:		base port address of the device
  43 */
  44struct quad8 {
  45	struct mutex lock;
  46	struct counter_device counter;
  47	unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
  48	unsigned int preset[QUAD8_NUM_COUNTERS];
  49	unsigned int count_mode[QUAD8_NUM_COUNTERS];
  50	unsigned int quadrature_mode[QUAD8_NUM_COUNTERS];
  51	unsigned int quadrature_scale[QUAD8_NUM_COUNTERS];
  52	unsigned int ab_enable[QUAD8_NUM_COUNTERS];
  53	unsigned int preset_enable[QUAD8_NUM_COUNTERS];
 
  54	unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
  55	unsigned int index_polarity[QUAD8_NUM_COUNTERS];
  56	unsigned int cable_fault_enable;
  57	unsigned int base;
  58};
  59
  60#define QUAD8_REG_CHAN_OP 0x11
  61#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
  62#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17
  63/* Borrow Toggle flip-flop */
  64#define QUAD8_FLAG_BT BIT(0)
  65/* Carry Toggle flip-flop */
  66#define QUAD8_FLAG_CT BIT(1)
  67/* Error flag */
  68#define QUAD8_FLAG_E BIT(4)
  69/* Up/Down flag */
  70#define QUAD8_FLAG_UD BIT(5)
  71/* Reset and Load Signal Decoders */
  72#define QUAD8_CTR_RLD 0x00
  73/* Counter Mode Register */
  74#define QUAD8_CTR_CMR 0x20
  75/* Input / Output Control Register */
  76#define QUAD8_CTR_IOR 0x40
  77/* Index Control Register */
  78#define QUAD8_CTR_IDR 0x60
  79/* Reset Byte Pointer (three byte data pointer) */
  80#define QUAD8_RLD_RESET_BP 0x01
  81/* Reset Counter */
  82#define QUAD8_RLD_RESET_CNTR 0x02
  83/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
  84#define QUAD8_RLD_RESET_FLAGS 0x04
  85/* Reset Error flag */
  86#define QUAD8_RLD_RESET_E 0x06
  87/* Preset Register to Counter */
  88#define QUAD8_RLD_PRESET_CNTR 0x08
  89/* Transfer Counter to Output Latch */
  90#define QUAD8_RLD_CNTR_OUT 0x10
  91/* Transfer Preset Register LSB to FCK Prescaler */
  92#define QUAD8_RLD_PRESET_PSC 0x18
  93#define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00
  94#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
 
  95#define QUAD8_CMR_QUADRATURE_X1 0x08
  96#define QUAD8_CMR_QUADRATURE_X2 0x10
  97#define QUAD8_CMR_QUADRATURE_X4 0x18
  98
  99static int quad8_signal_read(struct counter_device *counter,
 100	struct counter_signal *signal, enum counter_signal_value *val)
 
 101{
 102	const struct quad8 *const priv = counter->priv;
 103	unsigned int state;
 104
 105	/* Only Index signal levels can be read */
 106	if (signal->id < 16)
 107		return -EINVAL;
 108
 109	state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
 110		& BIT(signal->id - 16);
 111
 112	*val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
 113
 114	return 0;
 115}
 116
 117static int quad8_count_read(struct counter_device *counter,
 118	struct counter_count *count, unsigned long *val)
 119{
 120	struct quad8 *const priv = counter->priv;
 121	const int base_offset = priv->base + 2 * count->id;
 122	unsigned int flags;
 123	unsigned int borrow;
 124	unsigned int carry;
 
 125	int i;
 126
 127	flags = inb(base_offset + 1);
 128	borrow = flags & QUAD8_FLAG_BT;
 129	carry = !!(flags & QUAD8_FLAG_CT);
 130
 131	/* Borrow XOR Carry effectively doubles count range */
 132	*val = (unsigned long)(borrow ^ carry) << 24;
 133
 134	mutex_lock(&priv->lock);
 135
 136	/* Reset Byte Pointer; transfer Counter to Output Latch */
 137	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
 138	     base_offset + 1);
 139
 140	for (i = 0; i < 3; i++)
 141		*val |= (unsigned long)inb(base_offset) << (8 * i);
 142
 143	mutex_unlock(&priv->lock);
 144
 145	return 0;
 146}
 147
 148static int quad8_count_write(struct counter_device *counter,
 149	struct counter_count *count, unsigned long val)
 150{
 151	struct quad8 *const priv = counter->priv;
 152	const int base_offset = priv->base + 2 * count->id;
 
 153	int i;
 154
 155	/* Only 24-bit values are supported */
 156	if (val > 0xFFFFFF)
 157		return -EINVAL;
 158
 159	mutex_lock(&priv->lock);
 160
 161	/* Reset Byte Pointer */
 162	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 163
 164	/* Counter can only be set via Preset Register */
 165	for (i = 0; i < 3; i++)
 166		outb(val >> (8 * i), base_offset);
 167
 168	/* Transfer Preset Register to Counter */
 169	outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
 170
 171	/* Reset Byte Pointer */
 172	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 173
 174	/* Set Preset Register back to original value */
 175	val = priv->preset[count->id];
 176	for (i = 0; i < 3; i++)
 177		outb(val >> (8 * i), base_offset);
 178
 179	/* Reset Borrow, Carry, Compare, and Sign flags */
 180	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
 181	/* Reset Error flag */
 182	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
 183
 184	mutex_unlock(&priv->lock);
 185
 186	return 0;
 187}
 188
 189enum quad8_count_function {
 190	QUAD8_COUNT_FUNCTION_PULSE_DIRECTION = 0,
 191	QUAD8_COUNT_FUNCTION_QUADRATURE_X1,
 192	QUAD8_COUNT_FUNCTION_QUADRATURE_X2,
 193	QUAD8_COUNT_FUNCTION_QUADRATURE_X4
 194};
 195
 196static const enum counter_count_function quad8_count_functions_list[] = {
 197	[QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
 198	[QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A,
 199	[QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
 200	[QUAD8_COUNT_FUNCTION_QUADRATURE_X4] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4
 201};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 202
 203static int quad8_function_get(struct counter_device *counter,
 204	struct counter_count *count, size_t *function)
 
 205{
 206	struct quad8 *const priv = counter->priv;
 207	const int id = count->id;
 
 208
 209	mutex_lock(&priv->lock);
 210
 211	if (priv->quadrature_mode[id])
 212		switch (priv->quadrature_scale[id]) {
 213		case 0:
 214			*function = QUAD8_COUNT_FUNCTION_QUADRATURE_X1;
 215			break;
 216		case 1:
 217			*function = QUAD8_COUNT_FUNCTION_QUADRATURE_X2;
 218			break;
 219		case 2:
 220			*function = QUAD8_COUNT_FUNCTION_QUADRATURE_X4;
 221			break;
 222		}
 223	else
 224		*function = QUAD8_COUNT_FUNCTION_PULSE_DIRECTION;
 225
 226	mutex_unlock(&priv->lock);
 227
 228	return 0;
 229}
 230
 231static int quad8_function_set(struct counter_device *counter,
 232	struct counter_count *count, size_t function)
 
 233{
 234	struct quad8 *const priv = counter->priv;
 235	const int id = count->id;
 236	unsigned int *const quadrature_mode = priv->quadrature_mode + id;
 237	unsigned int *const scale = priv->quadrature_scale + id;
 238	unsigned int *const synchronous_mode = priv->synchronous_mode + id;
 239	const int base_offset = priv->base + 2 * id + 1;
 
 240	unsigned int mode_cfg;
 241	unsigned int idr_cfg;
 242
 243	mutex_lock(&priv->lock);
 244
 245	mode_cfg = priv->count_mode[id] << 1;
 246	idr_cfg = priv->index_polarity[id] << 1;
 247
 248	if (function == QUAD8_COUNT_FUNCTION_PULSE_DIRECTION) {
 249		*quadrature_mode = 0;
 250
 251		/* Quadrature scaling only available in quadrature mode */
 252		*scale = 0;
 253
 254		/* Synchronous function not supported in non-quadrature mode */
 255		if (*synchronous_mode) {
 256			*synchronous_mode = 0;
 257			/* Disable synchronous function mode */
 258			outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 259		}
 260	} else {
 261		*quadrature_mode = 1;
 262
 263		switch (function) {
 264		case QUAD8_COUNT_FUNCTION_QUADRATURE_X1:
 265			*scale = 0;
 266			mode_cfg |= QUAD8_CMR_QUADRATURE_X1;
 267			break;
 268		case QUAD8_COUNT_FUNCTION_QUADRATURE_X2:
 269			*scale = 1;
 270			mode_cfg |= QUAD8_CMR_QUADRATURE_X2;
 271			break;
 272		case QUAD8_COUNT_FUNCTION_QUADRATURE_X4:
 273			*scale = 2;
 274			mode_cfg |= QUAD8_CMR_QUADRATURE_X4;
 275			break;
 
 
 
 
 276		}
 277	}
 278
 279	/* Load mode configuration to Counter Mode Register */
 280	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 281
 282	mutex_unlock(&priv->lock);
 283
 284	return 0;
 285}
 286
 287static void quad8_direction_get(struct counter_device *counter,
 288	struct counter_count *count, enum counter_count_direction *direction)
 
 289{
 290	const struct quad8 *const priv = counter->priv;
 291	unsigned int ud_flag;
 292	const unsigned int flag_addr = priv->base + 2 * count->id + 1;
 293
 294	/* U/D flag: nonzero = up, zero = down */
 295	ud_flag = inb(flag_addr) & QUAD8_FLAG_UD;
 296
 297	*direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD :
 298		COUNTER_COUNT_DIRECTION_BACKWARD;
 
 
 299}
 300
 301enum quad8_synapse_action {
 302	QUAD8_SYNAPSE_ACTION_NONE = 0,
 303	QUAD8_SYNAPSE_ACTION_RISING_EDGE,
 304	QUAD8_SYNAPSE_ACTION_FALLING_EDGE,
 305	QUAD8_SYNAPSE_ACTION_BOTH_EDGES
 306};
 307
 308static const enum counter_synapse_action quad8_index_actions_list[] = {
 309	[QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
 310	[QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
 311};
 312
 313static const enum counter_synapse_action quad8_synapse_actions_list[] = {
 314	[QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
 315	[QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
 316	[QUAD8_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
 317	[QUAD8_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES
 318};
 319
 320static int quad8_action_get(struct counter_device *counter,
 321	struct counter_count *count, struct counter_synapse *synapse,
 322	size_t *action)
 
 323{
 324	struct quad8 *const priv = counter->priv;
 
 325	int err;
 326	size_t function = 0;
 327	const size_t signal_a_id = count->synapses[0].signal->id;
 328	enum counter_count_direction direction;
 329
 330	/* Handle Index signals */
 331	if (synapse->signal->id >= 16) {
 332		if (priv->preset_enable[count->id])
 333			*action = QUAD8_SYNAPSE_ACTION_RISING_EDGE;
 334		else
 335			*action = QUAD8_SYNAPSE_ACTION_NONE;
 336
 337		return 0;
 338	}
 339
 340	err = quad8_function_get(counter, count, &function);
 341	if (err)
 
 
 
 
 
 
 
 
 
 342		return err;
 
 
 
 343
 344	/* Default action mode */
 345	*action = QUAD8_SYNAPSE_ACTION_NONE;
 346
 347	/* Determine action mode based on current count function mode */
 348	switch (function) {
 349	case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION:
 350		if (synapse->signal->id == signal_a_id)
 351			*action = QUAD8_SYNAPSE_ACTION_RISING_EDGE;
 352		break;
 353	case QUAD8_COUNT_FUNCTION_QUADRATURE_X1:
 354		if (synapse->signal->id == signal_a_id) {
 355			quad8_direction_get(counter, count, &direction);
 356
 357			if (direction == COUNTER_COUNT_DIRECTION_FORWARD)
 358				*action = QUAD8_SYNAPSE_ACTION_RISING_EDGE;
 359			else
 360				*action = QUAD8_SYNAPSE_ACTION_FALLING_EDGE;
 361		}
 362		break;
 363	case QUAD8_COUNT_FUNCTION_QUADRATURE_X2:
 364		if (synapse->signal->id == signal_a_id)
 365			*action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES;
 366		break;
 367	case QUAD8_COUNT_FUNCTION_QUADRATURE_X4:
 368		*action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES;
 369		break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 370	}
 371
 
 
 
 
 372	return 0;
 373}
 374
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 375static const struct counter_ops quad8_ops = {
 376	.signal_read = quad8_signal_read,
 377	.count_read = quad8_count_read,
 378	.count_write = quad8_count_write,
 379	.function_get = quad8_function_get,
 380	.function_set = quad8_function_set,
 381	.action_get = quad8_action_get
 
 
 382};
 383
 384static const char *const quad8_index_polarity_modes[] = {
 385	"negative",
 386	"positive"
 387};
 388
 389static int quad8_index_polarity_get(struct counter_device *counter,
 390	struct counter_signal *signal, size_t *index_polarity)
 
 391{
 392	const struct quad8 *const priv = counter->priv;
 393	const size_t channel_id = signal->id - 16;
 394
 395	*index_polarity = priv->index_polarity[channel_id];
 396
 397	return 0;
 398}
 399
 400static int quad8_index_polarity_set(struct counter_device *counter,
 401	struct counter_signal *signal, size_t index_polarity)
 
 402{
 403	struct quad8 *const priv = counter->priv;
 404	const size_t channel_id = signal->id - 16;
 405	const int base_offset = priv->base + 2 * channel_id + 1;
 
 406	unsigned int idr_cfg = index_polarity << 1;
 407
 408	mutex_lock(&priv->lock);
 409
 410	idr_cfg |= priv->synchronous_mode[channel_id];
 411
 412	priv->index_polarity[channel_id] = index_polarity;
 413
 414	/* Load Index Control configuration to Index Control Register */
 415	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 416
 417	mutex_unlock(&priv->lock);
 
 418
 419	return 0;
 420}
 421
 422static struct counter_signal_enum_ext quad8_index_pol_enum = {
 423	.items = quad8_index_polarity_modes,
 424	.num_items = ARRAY_SIZE(quad8_index_polarity_modes),
 425	.get = quad8_index_polarity_get,
 426	.set = quad8_index_polarity_set
 427};
 
 
 428
 429static const char *const quad8_synchronous_modes[] = {
 430	"non-synchronous",
 431	"synchronous"
 432};
 433
 434static int quad8_synchronous_mode_get(struct counter_device *counter,
 435	struct counter_signal *signal, size_t *synchronous_mode)
 
 436{
 437	const struct quad8 *const priv = counter->priv;
 438	const size_t channel_id = signal->id - 16;
 439
 440	*synchronous_mode = priv->synchronous_mode[channel_id];
 441
 442	return 0;
 443}
 444
 445static int quad8_synchronous_mode_set(struct counter_device *counter,
 446	struct counter_signal *signal, size_t synchronous_mode)
 
 447{
 448	struct quad8 *const priv = counter->priv;
 449	const size_t channel_id = signal->id - 16;
 450	const int base_offset = priv->base + 2 * channel_id + 1;
 
 451	unsigned int idr_cfg = synchronous_mode;
 452
 453	mutex_lock(&priv->lock);
 454
 455	idr_cfg |= priv->index_polarity[channel_id] << 1;
 456
 457	/* Index function must be non-synchronous in non-quadrature mode */
 458	if (synchronous_mode && !priv->quadrature_mode[channel_id]) {
 459		mutex_unlock(&priv->lock);
 460		return -EINVAL;
 461	}
 462
 463	priv->synchronous_mode[channel_id] = synchronous_mode;
 464
 465	/* Load Index Control configuration to Index Control Register */
 466	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 467
 468	mutex_unlock(&priv->lock);
 469
 470	return 0;
 471}
 472
 473static struct counter_signal_enum_ext quad8_syn_mode_enum = {
 474	.items = quad8_synchronous_modes,
 475	.num_items = ARRAY_SIZE(quad8_synchronous_modes),
 476	.get = quad8_synchronous_mode_get,
 477	.set = quad8_synchronous_mode_set
 478};
 479
 480static ssize_t quad8_count_floor_read(struct counter_device *counter,
 481	struct counter_count *count, void *private, char *buf)
 482{
 483	/* Only a floor of 0 is supported */
 484	return sprintf(buf, "0\n");
 
 
 485}
 486
 487static int quad8_count_mode_get(struct counter_device *counter,
 488	struct counter_count *count, size_t *cnt_mode)
 
 489{
 490	const struct quad8 *const priv = counter->priv;
 491
 492	/* Map 104-QUAD-8 count mode to Generic Counter count mode */
 493	switch (priv->count_mode[count->id]) {
 494	case 0:
 495		*cnt_mode = COUNTER_COUNT_MODE_NORMAL;
 496		break;
 497	case 1:
 498		*cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT;
 499		break;
 500	case 2:
 501		*cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE;
 502		break;
 503	case 3:
 504		*cnt_mode = COUNTER_COUNT_MODE_MODULO_N;
 505		break;
 506	}
 507
 508	return 0;
 509}
 510
 511static int quad8_count_mode_set(struct counter_device *counter,
 512	struct counter_count *count, size_t cnt_mode)
 
 513{
 514	struct quad8 *const priv = counter->priv;
 
 515	unsigned int mode_cfg;
 516	const int base_offset = priv->base + 2 * count->id + 1;
 
 517
 518	/* Map Generic Counter count mode to 104-QUAD-8 count mode */
 519	switch (cnt_mode) {
 520	case COUNTER_COUNT_MODE_NORMAL:
 521		cnt_mode = 0;
 522		break;
 523	case COUNTER_COUNT_MODE_RANGE_LIMIT:
 524		cnt_mode = 1;
 525		break;
 526	case COUNTER_COUNT_MODE_NON_RECYCLE:
 527		cnt_mode = 2;
 528		break;
 529	case COUNTER_COUNT_MODE_MODULO_N:
 530		cnt_mode = 3;
 531		break;
 
 
 
 532	}
 533
 534	mutex_lock(&priv->lock);
 535
 536	priv->count_mode[count->id] = cnt_mode;
 537
 538	/* Set count mode configuration value */
 539	mode_cfg = cnt_mode << 1;
 540
 541	/* Add quadrature mode configuration */
 542	if (priv->quadrature_mode[count->id])
 543		mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3;
 544
 545	/* Load mode configuration to Counter Mode Register */
 546	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 547
 548	mutex_unlock(&priv->lock);
 549
 550	return 0;
 551}
 552
 553static struct counter_count_enum_ext quad8_cnt_mode_enum = {
 554	.items = counter_count_mode_str,
 555	.num_items = ARRAY_SIZE(counter_count_mode_str),
 556	.get = quad8_count_mode_get,
 557	.set = quad8_count_mode_set
 558};
 559
 560static ssize_t quad8_count_direction_read(struct counter_device *counter,
 561	struct counter_count *count, void *priv, char *buf)
 562{
 563	enum counter_count_direction dir;
 564
 565	quad8_direction_get(counter, count, &dir);
 566
 567	return sprintf(buf, "%s\n", counter_count_direction_str[dir]);
 568}
 569
 570static ssize_t quad8_count_enable_read(struct counter_device *counter,
 571	struct counter_count *count, void *private, char *buf)
 572{
 573	const struct quad8 *const priv = counter->priv;
 574
 575	return sprintf(buf, "%u\n", priv->ab_enable[count->id]);
 576}
 577
 578static ssize_t quad8_count_enable_write(struct counter_device *counter,
 579	struct counter_count *count, void *private, const char *buf, size_t len)
 580{
 581	struct quad8 *const priv = counter->priv;
 582	const int base_offset = priv->base + 2 * count->id;
 583	int err;
 584	bool ab_enable;
 585	unsigned int ior_cfg;
 586
 587	err = kstrtobool(buf, &ab_enable);
 588	if (err)
 589		return err;
 590
 591	mutex_lock(&priv->lock);
 592
 593	priv->ab_enable[count->id] = ab_enable;
 594
 595	ior_cfg = ab_enable | priv->preset_enable[count->id] << 1;
 
 596
 597	/* Load I/O control configuration */
 598	outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
 599
 600	mutex_unlock(&priv->lock);
 601
 602	return len;
 603}
 604
 605static const char *const quad8_noise_error_states[] = {
 606	"No excessive noise is present at the count inputs",
 607	"Excessive noise is present at the count inputs"
 608};
 609
 610static int quad8_error_noise_get(struct counter_device *counter,
 611	struct counter_count *count, size_t *noise_error)
 612{
 613	const struct quad8 *const priv = counter->priv;
 614	const int base_offset = priv->base + 2 * count->id + 1;
 615
 616	*noise_error = !!(inb(base_offset) & QUAD8_FLAG_E);
 617
 618	return 0;
 619}
 620
 621static struct counter_count_enum_ext quad8_error_noise_enum = {
 622	.items = quad8_noise_error_states,
 623	.num_items = ARRAY_SIZE(quad8_noise_error_states),
 624	.get = quad8_error_noise_get
 625};
 626
 627static ssize_t quad8_count_preset_read(struct counter_device *counter,
 628	struct counter_count *count, void *private, char *buf)
 629{
 630	const struct quad8 *const priv = counter->priv;
 631
 632	return sprintf(buf, "%u\n", priv->preset[count->id]);
 633}
 634
 635static void quad8_preset_register_set(struct quad8 *const priv, const int id,
 636				      const unsigned int preset)
 637{
 638	const unsigned int base_offset = priv->base + 2 * id;
 639	int i;
 640
 641	priv->preset[id] = preset;
 642
 643	/* Reset Byte Pointer */
 644	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 645
 646	/* Set Preset Register */
 647	for (i = 0; i < 3; i++)
 648		outb(preset >> (8 * i), base_offset);
 649}
 650
 651static ssize_t quad8_count_preset_write(struct counter_device *counter,
 652	struct counter_count *count, void *private, const char *buf, size_t len)
 653{
 654	struct quad8 *const priv = counter->priv;
 655	unsigned int preset;
 656	int ret;
 657
 658	ret = kstrtouint(buf, 0, &preset);
 659	if (ret)
 660		return ret;
 661
 662	/* Only 24-bit values are supported */
 663	if (preset > 0xFFFFFF)
 664		return -EINVAL;
 665
 666	mutex_lock(&priv->lock);
 667
 668	quad8_preset_register_set(priv, count->id, preset);
 669
 670	mutex_unlock(&priv->lock);
 671
 672	return len;
 673}
 674
 675static ssize_t quad8_count_ceiling_read(struct counter_device *counter,
 676	struct counter_count *count, void *private, char *buf)
 677{
 678	struct quad8 *const priv = counter->priv;
 
 679
 680	mutex_lock(&priv->lock);
 681
 682	/* Range Limit and Modulo-N count modes use preset value as ceiling */
 683	switch (priv->count_mode[count->id]) {
 684	case 1:
 685	case 3:
 686		mutex_unlock(&priv->lock);
 687		return sprintf(buf, "%u\n", priv->preset[count->id]);
 
 
 
 
 688	}
 689
 690	mutex_unlock(&priv->lock);
 691
 692	/* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
 693	return sprintf(buf, "33554431\n");
 694}
 695
 696static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
 697	struct counter_count *count, void *private, const char *buf, size_t len)
 698{
 699	struct quad8 *const priv = counter->priv;
 700	unsigned int ceiling;
 701	int ret;
 702
 703	ret = kstrtouint(buf, 0, &ceiling);
 704	if (ret)
 705		return ret;
 706
 707	/* Only 24-bit values are supported */
 708	if (ceiling > 0xFFFFFF)
 709		return -EINVAL;
 710
 711	mutex_lock(&priv->lock);
 712
 713	/* Range Limit and Modulo-N count modes use preset value as ceiling */
 714	switch (priv->count_mode[count->id]) {
 715	case 1:
 716	case 3:
 717		quad8_preset_register_set(priv, count->id, ceiling);
 718		mutex_unlock(&priv->lock);
 719		return len;
 720	}
 721
 722	mutex_unlock(&priv->lock);
 723
 724	return -EINVAL;
 725}
 726
 727static ssize_t quad8_count_preset_enable_read(struct counter_device *counter,
 728	struct counter_count *count, void *private, char *buf)
 
 729{
 730	const struct quad8 *const priv = counter->priv;
 
 
 731
 732	return sprintf(buf, "%u\n", !priv->preset_enable[count->id]);
 733}
 734
 735static ssize_t quad8_count_preset_enable_write(struct counter_device *counter,
 736	struct counter_count *count, void *private, const char *buf, size_t len)
 737{
 738	struct quad8 *const priv = counter->priv;
 739	const int base_offset = priv->base + 2 * count->id + 1;
 740	bool preset_enable;
 741	int ret;
 742	unsigned int ior_cfg;
 743
 744	ret = kstrtobool(buf, &preset_enable);
 745	if (ret)
 746		return ret;
 747
 748	/* Preset enable is active low in Input/Output Control register */
 749	preset_enable = !preset_enable;
 750
 751	mutex_lock(&priv->lock);
 752
 753	priv->preset_enable[count->id] = preset_enable;
 754
 755	ior_cfg = priv->ab_enable[count->id] | (unsigned int)preset_enable << 1;
 
 756
 757	/* Load I/O control configuration to Input / Output Control Register */
 758	outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
 759
 760	mutex_unlock(&priv->lock);
 761
 762	return len;
 763}
 764
 765static ssize_t quad8_signal_cable_fault_read(struct counter_device *counter,
 766					     struct counter_signal *signal,
 767					     void *private, char *buf)
 768{
 769	struct quad8 *const priv = counter->priv;
 770	const size_t channel_id = signal->id / 2;
 
 771	bool disabled;
 772	unsigned int status;
 773	unsigned int fault;
 774
 775	mutex_lock(&priv->lock);
 776
 777	disabled = !(priv->cable_fault_enable & BIT(channel_id));
 778
 779	if (disabled) {
 780		mutex_unlock(&priv->lock);
 781		return -EINVAL;
 782	}
 783
 784	/* Logic 0 = cable fault */
 785	status = inb(priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS);
 786
 787	mutex_unlock(&priv->lock);
 788
 789	/* Mask respective channel and invert logic */
 790	fault = !(status & BIT(channel_id));
 791
 792	return sprintf(buf, "%u\n", fault);
 793}
 794
 795static ssize_t quad8_signal_cable_fault_enable_read(
 796	struct counter_device *counter, struct counter_signal *signal,
 797	void *private, char *buf)
 798{
 799	const struct quad8 *const priv = counter->priv;
 800	const size_t channel_id = signal->id / 2;
 801	const unsigned int enb = !!(priv->cable_fault_enable & BIT(channel_id));
 802
 803	return sprintf(buf, "%u\n", enb);
 
 
 804}
 805
 806static ssize_t quad8_signal_cable_fault_enable_write(
 807	struct counter_device *counter, struct counter_signal *signal,
 808	void *private, const char *buf, size_t len)
 809{
 810	struct quad8 *const priv = counter->priv;
 811	const size_t channel_id = signal->id / 2;
 812	bool enable;
 813	int ret;
 814	unsigned int cable_fault_enable;
 815
 816	ret = kstrtobool(buf, &enable);
 817	if (ret)
 818		return ret;
 819
 820	mutex_lock(&priv->lock);
 821
 822	if (enable)
 823		priv->cable_fault_enable |= BIT(channel_id);
 824	else
 825		priv->cable_fault_enable &= ~BIT(channel_id);
 826
 827	/* Enable is active low in Differential Encoder Cable Status register */
 828	cable_fault_enable = ~priv->cable_fault_enable;
 829
 830	outb(cable_fault_enable, priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS);
 831
 832	mutex_unlock(&priv->lock);
 833
 834	return len;
 835}
 836
 837static ssize_t quad8_signal_fck_prescaler_read(struct counter_device *counter,
 838	struct counter_signal *signal, void *private, char *buf)
 
 839{
 840	const struct quad8 *const priv = counter->priv;
 841	const size_t channel_id = signal->id / 2;
 
 842
 843	return sprintf(buf, "%u\n", priv->fck_prescaler[channel_id]);
 844}
 845
 846static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter,
 847	struct counter_signal *signal, void *private, const char *buf,
 848	size_t len)
 849{
 850	struct quad8 *const priv = counter->priv;
 851	const size_t channel_id = signal->id / 2;
 852	const int base_offset = priv->base + 2 * channel_id;
 853	u8 prescaler;
 854	int ret;
 855
 856	ret = kstrtou8(buf, 0, &prescaler);
 857	if (ret)
 858		return ret;
 859
 860	mutex_lock(&priv->lock);
 861
 862	priv->fck_prescaler[channel_id] = prescaler;
 863
 864	/* Reset Byte Pointer */
 865	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 866
 867	/* Set filter clock factor */
 868	outb(prescaler, base_offset);
 869	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
 870	     base_offset + 1);
 871
 872	mutex_unlock(&priv->lock);
 873
 874	return len;
 875}
 876
 877static const struct counter_signal_ext quad8_signal_ext[] = {
 878	{
 879		.name = "cable_fault",
 880		.read = quad8_signal_cable_fault_read
 881	},
 882	{
 883		.name = "cable_fault_enable",
 884		.read = quad8_signal_cable_fault_enable_read,
 885		.write = quad8_signal_cable_fault_enable_write
 886	},
 887	{
 888		.name = "filter_clock_prescaler",
 889		.read = quad8_signal_fck_prescaler_read,
 890		.write = quad8_signal_fck_prescaler_write
 891	}
 892};
 893
 894static const struct counter_signal_ext quad8_index_ext[] = {
 895	COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum),
 896	COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity",	&quad8_index_pol_enum),
 897	COUNTER_SIGNAL_ENUM("synchronous_mode", &quad8_syn_mode_enum),
 898	COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 899};
 900
 901#define QUAD8_QUAD_SIGNAL(_id, _name) {		\
 902	.id = (_id),				\
 903	.name = (_name),			\
 904	.ext = quad8_signal_ext,		\
 905	.num_ext = ARRAY_SIZE(quad8_signal_ext)	\
 906}
 907
 908#define	QUAD8_INDEX_SIGNAL(_id, _name) {	\
 909	.id = (_id),				\
 910	.name = (_name),			\
 911	.ext = quad8_index_ext,			\
 912	.num_ext = ARRAY_SIZE(quad8_index_ext)	\
 913}
 914
 915static struct counter_signal quad8_signals[] = {
 916	QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"),
 917	QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"),
 918	QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"),
 919	QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"),
 920	QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"),
 921	QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"),
 922	QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"),
 923	QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"),
 924	QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"),
 925	QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"),
 926	QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"),
 927	QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"),
 928	QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"),
 929	QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"),
 930	QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"),
 931	QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"),
 932	QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"),
 933	QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"),
 934	QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"),
 935	QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"),
 936	QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"),
 937	QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"),
 938	QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"),
 939	QUAD8_INDEX_SIGNAL(23, "Channel 8 Index")
 940};
 941
 942#define QUAD8_COUNT_SYNAPSES(_id) {					\
 943	{								\
 944		.actions_list = quad8_synapse_actions_list,		\
 945		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
 946		.signal = quad8_signals + 2 * (_id)			\
 947	},								\
 948	{								\
 949		.actions_list = quad8_synapse_actions_list,		\
 950		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
 951		.signal = quad8_signals + 2 * (_id) + 1			\
 952	},								\
 953	{								\
 954		.actions_list = quad8_index_actions_list,		\
 955		.num_actions = ARRAY_SIZE(quad8_index_actions_list),	\
 956		.signal = quad8_signals + 2 * (_id) + 16		\
 957	}								\
 958}
 959
 960static struct counter_synapse quad8_count_synapses[][3] = {
 961	QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1),
 962	QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3),
 963	QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5),
 964	QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7)
 965};
 966
 967static const struct counter_count_ext quad8_count_ext[] = {
 968	{
 969		.name = "ceiling",
 970		.read = quad8_count_ceiling_read,
 971		.write = quad8_count_ceiling_write
 972	},
 973	{
 974		.name = "floor",
 975		.read = quad8_count_floor_read
 976	},
 977	COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum),
 978	COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum),
 979	{
 980		.name = "direction",
 981		.read = quad8_count_direction_read
 982	},
 983	{
 984		.name = "enable",
 985		.read = quad8_count_enable_read,
 986		.write = quad8_count_enable_write
 987	},
 988	COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum),
 989	COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum),
 990	{
 991		.name = "preset",
 992		.read = quad8_count_preset_read,
 993		.write = quad8_count_preset_write
 994	},
 995	{
 996		.name = "preset_enable",
 997		.read = quad8_count_preset_enable_read,
 998		.write = quad8_count_preset_enable_write
 999	}
1000};
1001
1002#define QUAD8_COUNT(_id, _cntname) {					\
1003	.id = (_id),							\
1004	.name = (_cntname),						\
1005	.functions_list = quad8_count_functions_list,			\
1006	.num_functions = ARRAY_SIZE(quad8_count_functions_list),	\
1007	.synapses = quad8_count_synapses[(_id)],			\
1008	.num_synapses =	2,						\
1009	.ext = quad8_count_ext,						\
1010	.num_ext = ARRAY_SIZE(quad8_count_ext)				\
1011}
1012
1013static struct counter_count quad8_counts[] = {
1014	QUAD8_COUNT(0, "Channel 1 Count"),
1015	QUAD8_COUNT(1, "Channel 2 Count"),
1016	QUAD8_COUNT(2, "Channel 3 Count"),
1017	QUAD8_COUNT(3, "Channel 4 Count"),
1018	QUAD8_COUNT(4, "Channel 5 Count"),
1019	QUAD8_COUNT(5, "Channel 6 Count"),
1020	QUAD8_COUNT(6, "Channel 7 Count"),
1021	QUAD8_COUNT(7, "Channel 8 Count")
1022};
1023
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1024static int quad8_probe(struct device *dev, unsigned int id)
1025{
 
1026	struct quad8 *priv;
1027	int i, j;
1028	unsigned int base_offset;
1029
1030	if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
1031		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
1032			base[id], base[id] + QUAD8_EXTENT);
1033		return -EBUSY;
1034	}
1035
1036	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1037	if (!priv)
 
 
 
 
 
1038		return -ENOMEM;
1039
1040	/* Initialize Counter device and driver data */
1041	priv->counter.name = dev_name(dev);
1042	priv->counter.parent = dev;
1043	priv->counter.ops = &quad8_ops;
1044	priv->counter.counts = quad8_counts;
1045	priv->counter.num_counts = ARRAY_SIZE(quad8_counts);
1046	priv->counter.signals = quad8_signals;
1047	priv->counter.num_signals = ARRAY_SIZE(quad8_signals);
1048	priv->counter.priv = priv;
1049	priv->base = base[id];
1050
1051	/* Initialize mutex */
1052	mutex_init(&priv->lock);
1053
 
 
1054	/* Reset all counters and disable interrupt function */
1055	outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
1056	/* Set initial configuration for all counters */
1057	for (i = 0; i < QUAD8_NUM_COUNTERS; i++) {
1058		base_offset = base[id] + 2 * i;
1059		/* Reset Byte Pointer */
1060		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
1061		/* Reset filter clock factor */
1062		outb(0, base_offset);
1063		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
1064		     base_offset + 1);
1065		/* Reset Byte Pointer */
1066		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
1067		/* Reset Preset Register */
1068		for (j = 0; j < 3; j++)
1069			outb(0x00, base_offset);
1070		/* Reset Borrow, Carry, Compare, and Sign flags */
1071		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
1072		/* Reset Error flag */
1073		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
1074		/* Binary encoding; Normal count; non-quadrature mode */
1075		outb(QUAD8_CTR_CMR, base_offset + 1);
1076		/* Disable A and B inputs; preset on index; FLG1 as Carry */
1077		outb(QUAD8_CTR_IOR, base_offset + 1);
1078		/* Disable index function; negative index polarity */
1079		outb(QUAD8_CTR_IDR, base_offset + 1);
1080	}
1081	/* Disable Differential Encoder Cable Status for all channels */
1082	outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS);
1083	/* Enable all counters */
1084	outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
1085
1086	return devm_counter_register(dev, &priv->counter);
 
 
 
 
 
 
 
 
 
1087}
1088
1089static struct isa_driver quad8_driver = {
1090	.probe = quad8_probe,
1091	.driver = {
1092		.name = "104-quad-8"
1093	}
1094};
1095
1096module_isa_driver(quad8_driver, num_quad8);
1097
1098MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1099MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
1100MODULE_LICENSE("GPL v2");