Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   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/iio/iio.h>
  13#include <linux/iio/types.h>
  14#include <linux/io.h>
  15#include <linux/ioport.h>
  16#include <linux/isa.h>
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/moduleparam.h>
  20#include <linux/types.h>
  21
  22#define QUAD8_EXTENT 32
  23
  24static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
  25static unsigned int num_quad8;
  26module_param_array(base, uint, &num_quad8, 0);
  27MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
  28
  29#define QUAD8_NUM_COUNTERS 8
  30
  31/**
  32 * struct quad8_iio - IIO device private data structure
  33 * @counter:		instance of the counter_device
  34 * @fck_prescaler:	array of filter clock prescaler configurations
  35 * @preset:		array of preset values
  36 * @count_mode:		array of count mode configurations
  37 * @quadrature_mode:	array of quadrature mode configurations
  38 * @quadrature_scale:	array of quadrature mode scale configurations
  39 * @ab_enable:		array of A and B inputs enable configurations
  40 * @preset_enable:	array of set_to_preset_on_index attribute configurations
  41 * @synchronous_mode:	array of index function synchronous mode configurations
  42 * @index_polarity:	array of index function polarity configurations
  43 * @cable_fault_enable:	differential encoder cable status enable configurations
  44 * @base:		base port address of the IIO device
  45 */
  46struct quad8_iio {
  47	struct mutex lock;
  48	struct counter_device counter;
  49	unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
  50	unsigned int preset[QUAD8_NUM_COUNTERS];
  51	unsigned int count_mode[QUAD8_NUM_COUNTERS];
  52	unsigned int quadrature_mode[QUAD8_NUM_COUNTERS];
  53	unsigned int quadrature_scale[QUAD8_NUM_COUNTERS];
  54	unsigned int ab_enable[QUAD8_NUM_COUNTERS];
  55	unsigned int preset_enable[QUAD8_NUM_COUNTERS];
  56	unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
  57	unsigned int index_polarity[QUAD8_NUM_COUNTERS];
  58	unsigned int cable_fault_enable;
  59	unsigned int base;
  60};
  61
  62#define QUAD8_REG_CHAN_OP 0x11
  63#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
  64#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17
  65/* Borrow Toggle flip-flop */
  66#define QUAD8_FLAG_BT BIT(0)
  67/* Carry Toggle flip-flop */
  68#define QUAD8_FLAG_CT BIT(1)
  69/* Error flag */
  70#define QUAD8_FLAG_E BIT(4)
  71/* Up/Down flag */
  72#define QUAD8_FLAG_UD BIT(5)
  73/* Reset and Load Signal Decoders */
  74#define QUAD8_CTR_RLD 0x00
  75/* Counter Mode Register */
  76#define QUAD8_CTR_CMR 0x20
  77/* Input / Output Control Register */
  78#define QUAD8_CTR_IOR 0x40
  79/* Index Control Register */
  80#define QUAD8_CTR_IDR 0x60
  81/* Reset Byte Pointer (three byte data pointer) */
  82#define QUAD8_RLD_RESET_BP 0x01
  83/* Reset Counter */
  84#define QUAD8_RLD_RESET_CNTR 0x02
  85/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
  86#define QUAD8_RLD_RESET_FLAGS 0x04
  87/* Reset Error flag */
  88#define QUAD8_RLD_RESET_E 0x06
  89/* Preset Register to Counter */
  90#define QUAD8_RLD_PRESET_CNTR 0x08
  91/* Transfer Counter to Output Latch */
  92#define QUAD8_RLD_CNTR_OUT 0x10
  93/* Transfer Preset Register LSB to FCK Prescaler */
  94#define QUAD8_RLD_PRESET_PSC 0x18
  95#define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00
  96#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
  97#define QUAD8_CMR_QUADRATURE_X1 0x08
  98#define QUAD8_CMR_QUADRATURE_X2 0x10
  99#define QUAD8_CMR_QUADRATURE_X4 0x18
 100
 101
 102static int quad8_read_raw(struct iio_dev *indio_dev,
 103	struct iio_chan_spec const *chan, int *val, int *val2, long mask)
 104{
 105	struct quad8_iio *const priv = iio_priv(indio_dev);
 106	const int base_offset = priv->base + 2 * chan->channel;
 107	unsigned int flags;
 108	unsigned int borrow;
 109	unsigned int carry;
 110	int i;
 111
 112	switch (mask) {
 113	case IIO_CHAN_INFO_RAW:
 114		if (chan->type == IIO_INDEX) {
 115			*val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
 116				& BIT(chan->channel));
 117			return IIO_VAL_INT;
 118		}
 119
 120		flags = inb(base_offset + 1);
 121		borrow = flags & QUAD8_FLAG_BT;
 122		carry = !!(flags & QUAD8_FLAG_CT);
 123
 124		/* Borrow XOR Carry effectively doubles count range */
 125		*val = (borrow ^ carry) << 24;
 126
 127		mutex_lock(&priv->lock);
 128
 129		/* Reset Byte Pointer; transfer Counter to Output Latch */
 130		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
 131		     base_offset + 1);
 132
 133		for (i = 0; i < 3; i++)
 134			*val |= (unsigned int)inb(base_offset) << (8 * i);
 135
 136		mutex_unlock(&priv->lock);
 137
 138		return IIO_VAL_INT;
 139	case IIO_CHAN_INFO_ENABLE:
 140		*val = priv->ab_enable[chan->channel];
 141		return IIO_VAL_INT;
 142	case IIO_CHAN_INFO_SCALE:
 143		*val = 1;
 144		*val2 = priv->quadrature_scale[chan->channel];
 145		return IIO_VAL_FRACTIONAL_LOG2;
 146	}
 147
 148	return -EINVAL;
 149}
 150
 151static int quad8_write_raw(struct iio_dev *indio_dev,
 152	struct iio_chan_spec const *chan, int val, int val2, long mask)
 153{
 154	struct quad8_iio *const priv = iio_priv(indio_dev);
 155	const int base_offset = priv->base + 2 * chan->channel;
 156	int i;
 157	unsigned int ior_cfg;
 158
 159	switch (mask) {
 160	case IIO_CHAN_INFO_RAW:
 161		if (chan->type == IIO_INDEX)
 162			return -EINVAL;
 163
 164		/* Only 24-bit values are supported */
 165		if ((unsigned int)val > 0xFFFFFF)
 166			return -EINVAL;
 167
 168		mutex_lock(&priv->lock);
 169
 170		/* Reset Byte Pointer */
 171		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 172
 173		/* Counter can only be set via Preset Register */
 174		for (i = 0; i < 3; i++)
 175			outb(val >> (8 * i), base_offset);
 176
 177		/* Transfer Preset Register to Counter */
 178		outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
 179
 180		/* Reset Byte Pointer */
 181		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 182
 183		/* Set Preset Register back to original value */
 184		val = priv->preset[chan->channel];
 185		for (i = 0; i < 3; i++)
 186			outb(val >> (8 * i), base_offset);
 187
 188		/* Reset Borrow, Carry, Compare, and Sign flags */
 189		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
 190		/* Reset Error flag */
 191		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
 192
 193		mutex_unlock(&priv->lock);
 194
 195		return 0;
 196	case IIO_CHAN_INFO_ENABLE:
 197		/* only boolean values accepted */
 198		if (val < 0 || val > 1)
 199			return -EINVAL;
 200
 201		mutex_lock(&priv->lock);
 202
 203		priv->ab_enable[chan->channel] = val;
 204
 205		ior_cfg = val | priv->preset_enable[chan->channel] << 1;
 206
 207		/* Load I/O control configuration */
 208		outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
 209
 210		mutex_unlock(&priv->lock);
 211
 212		return 0;
 213	case IIO_CHAN_INFO_SCALE:
 214		mutex_lock(&priv->lock);
 215
 216		/* Quadrature scaling only available in quadrature mode */
 217		if (!priv->quadrature_mode[chan->channel] &&
 218				(val2 || val != 1)) {
 219			mutex_unlock(&priv->lock);
 220			return -EINVAL;
 221		}
 222
 223		/* Only three gain states (1, 0.5, 0.25) */
 224		if (val == 1 && !val2)
 225			priv->quadrature_scale[chan->channel] = 0;
 226		else if (!val)
 227			switch (val2) {
 228			case 500000:
 229				priv->quadrature_scale[chan->channel] = 1;
 230				break;
 231			case 250000:
 232				priv->quadrature_scale[chan->channel] = 2;
 233				break;
 234			default:
 235				mutex_unlock(&priv->lock);
 236				return -EINVAL;
 237			}
 238		else {
 239			mutex_unlock(&priv->lock);
 240			return -EINVAL;
 241		}
 242
 243		mutex_unlock(&priv->lock);
 244		return 0;
 245	}
 246
 247	return -EINVAL;
 248}
 249
 250static const struct iio_info quad8_info = {
 251	.read_raw = quad8_read_raw,
 252	.write_raw = quad8_write_raw
 253};
 254
 255static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private,
 256	const struct iio_chan_spec *chan, char *buf)
 257{
 258	const struct quad8_iio *const priv = iio_priv(indio_dev);
 259
 260	return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]);
 261}
 262
 263static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private,
 264	const struct iio_chan_spec *chan, const char *buf, size_t len)
 265{
 266	struct quad8_iio *const priv = iio_priv(indio_dev);
 267	const int base_offset = priv->base + 2 * chan->channel;
 268	unsigned int preset;
 269	int ret;
 270	int i;
 271
 272	ret = kstrtouint(buf, 0, &preset);
 273	if (ret)
 274		return ret;
 275
 276	/* Only 24-bit values are supported */
 277	if (preset > 0xFFFFFF)
 278		return -EINVAL;
 279
 280	mutex_lock(&priv->lock);
 281
 282	priv->preset[chan->channel] = preset;
 283
 284	/* Reset Byte Pointer */
 285	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 286
 287	/* Set Preset Register */
 288	for (i = 0; i < 3; i++)
 289		outb(preset >> (8 * i), base_offset);
 290
 291	mutex_unlock(&priv->lock);
 292
 293	return len;
 294}
 295
 296static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev,
 297	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
 298{
 299	const struct quad8_iio *const priv = iio_priv(indio_dev);
 300
 301	return snprintf(buf, PAGE_SIZE, "%u\n",
 302		!priv->preset_enable[chan->channel]);
 303}
 304
 305static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev,
 306	uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
 307	size_t len)
 308{
 309	struct quad8_iio *const priv = iio_priv(indio_dev);
 310	const int base_offset = priv->base + 2 * chan->channel + 1;
 311	bool preset_enable;
 312	int ret;
 313	unsigned int ior_cfg;
 314
 315	ret = kstrtobool(buf, &preset_enable);
 316	if (ret)
 317		return ret;
 318
 319	/* Preset enable is active low in Input/Output Control register */
 320	preset_enable = !preset_enable;
 321
 322	mutex_lock(&priv->lock);
 323
 324	priv->preset_enable[chan->channel] = preset_enable;
 325
 326	ior_cfg = priv->ab_enable[chan->channel] |
 327		(unsigned int)preset_enable << 1;
 328
 329	/* Load I/O control configuration to Input / Output Control Register */
 330	outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
 331
 332	mutex_unlock(&priv->lock);
 333
 334	return len;
 335}
 336
 337static const char *const quad8_noise_error_states[] = {
 338	"No excessive noise is present at the count inputs",
 339	"Excessive noise is present at the count inputs"
 340};
 341
 342static int quad8_get_noise_error(struct iio_dev *indio_dev,
 343	const struct iio_chan_spec *chan)
 344{
 345	struct quad8_iio *const priv = iio_priv(indio_dev);
 346	const int base_offset = priv->base + 2 * chan->channel + 1;
 347
 348	return !!(inb(base_offset) & QUAD8_FLAG_E);
 349}
 350
 351static const struct iio_enum quad8_noise_error_enum = {
 352	.items = quad8_noise_error_states,
 353	.num_items = ARRAY_SIZE(quad8_noise_error_states),
 354	.get = quad8_get_noise_error
 355};
 356
 357static const char *const quad8_count_direction_states[] = {
 358	"down",
 359	"up"
 360};
 361
 362static int quad8_get_count_direction(struct iio_dev *indio_dev,
 363	const struct iio_chan_spec *chan)
 364{
 365	struct quad8_iio *const priv = iio_priv(indio_dev);
 366	const int base_offset = priv->base + 2 * chan->channel + 1;
 367
 368	return !!(inb(base_offset) & QUAD8_FLAG_UD);
 369}
 370
 371static const struct iio_enum quad8_count_direction_enum = {
 372	.items = quad8_count_direction_states,
 373	.num_items = ARRAY_SIZE(quad8_count_direction_states),
 374	.get = quad8_get_count_direction
 375};
 376
 377static const char *const quad8_count_modes[] = {
 378	"normal",
 379	"range limit",
 380	"non-recycle",
 381	"modulo-n"
 382};
 383
 384static int quad8_set_count_mode(struct iio_dev *indio_dev,
 385	const struct iio_chan_spec *chan, unsigned int cnt_mode)
 386{
 387	struct quad8_iio *const priv = iio_priv(indio_dev);
 388	unsigned int mode_cfg = cnt_mode << 1;
 389	const int base_offset = priv->base + 2 * chan->channel + 1;
 390
 391	mutex_lock(&priv->lock);
 392
 393	priv->count_mode[chan->channel] = cnt_mode;
 394
 395	/* Add quadrature mode configuration */
 396	if (priv->quadrature_mode[chan->channel])
 397		mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3;
 398
 399	/* Load mode configuration to Counter Mode Register */
 400	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 401
 402	mutex_unlock(&priv->lock);
 403
 404	return 0;
 405}
 406
 407static int quad8_get_count_mode(struct iio_dev *indio_dev,
 408	const struct iio_chan_spec *chan)
 409{
 410	const struct quad8_iio *const priv = iio_priv(indio_dev);
 411
 412	return priv->count_mode[chan->channel];
 413}
 414
 415static const struct iio_enum quad8_count_mode_enum = {
 416	.items = quad8_count_modes,
 417	.num_items = ARRAY_SIZE(quad8_count_modes),
 418	.set = quad8_set_count_mode,
 419	.get = quad8_get_count_mode
 420};
 421
 422static const char *const quad8_synchronous_modes[] = {
 423	"non-synchronous",
 424	"synchronous"
 425};
 426
 427static int quad8_set_synchronous_mode(struct iio_dev *indio_dev,
 428	const struct iio_chan_spec *chan, unsigned int synchronous_mode)
 429{
 430	struct quad8_iio *const priv = iio_priv(indio_dev);
 431	const int base_offset = priv->base + 2 * chan->channel + 1;
 432	unsigned int idr_cfg = synchronous_mode;
 433
 434	mutex_lock(&priv->lock);
 435
 436	idr_cfg |= priv->index_polarity[chan->channel] << 1;
 437
 438	/* Index function must be non-synchronous in non-quadrature mode */
 439	if (synchronous_mode && !priv->quadrature_mode[chan->channel]) {
 440		mutex_unlock(&priv->lock);
 441		return -EINVAL;
 442	}
 443
 444	priv->synchronous_mode[chan->channel] = synchronous_mode;
 445
 446	/* Load Index Control configuration to Index Control Register */
 447	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 448
 449	mutex_unlock(&priv->lock);
 450
 451	return 0;
 452}
 453
 454static int quad8_get_synchronous_mode(struct iio_dev *indio_dev,
 455	const struct iio_chan_spec *chan)
 456{
 457	const struct quad8_iio *const priv = iio_priv(indio_dev);
 458
 459	return priv->synchronous_mode[chan->channel];
 460}
 461
 462static const struct iio_enum quad8_synchronous_mode_enum = {
 463	.items = quad8_synchronous_modes,
 464	.num_items = ARRAY_SIZE(quad8_synchronous_modes),
 465	.set = quad8_set_synchronous_mode,
 466	.get = quad8_get_synchronous_mode
 467};
 468
 469static const char *const quad8_quadrature_modes[] = {
 470	"non-quadrature",
 471	"quadrature"
 472};
 473
 474static int quad8_set_quadrature_mode(struct iio_dev *indio_dev,
 475	const struct iio_chan_spec *chan, unsigned int quadrature_mode)
 476{
 477	struct quad8_iio *const priv = iio_priv(indio_dev);
 478	const int base_offset = priv->base + 2 * chan->channel + 1;
 479	unsigned int mode_cfg;
 480
 481	mutex_lock(&priv->lock);
 482
 483	mode_cfg = priv->count_mode[chan->channel] << 1;
 484
 485	if (quadrature_mode)
 486		mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3;
 487	else {
 488		/* Quadrature scaling only available in quadrature mode */
 489		priv->quadrature_scale[chan->channel] = 0;
 490
 491		/* Synchronous function not supported in non-quadrature mode */
 492		if (priv->synchronous_mode[chan->channel])
 493			quad8_set_synchronous_mode(indio_dev, chan, 0);
 494	}
 495
 496	priv->quadrature_mode[chan->channel] = quadrature_mode;
 497
 498	/* Load mode configuration to Counter Mode Register */
 499	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 500
 501	mutex_unlock(&priv->lock);
 502
 503	return 0;
 504}
 505
 506static int quad8_get_quadrature_mode(struct iio_dev *indio_dev,
 507	const struct iio_chan_spec *chan)
 508{
 509	const struct quad8_iio *const priv = iio_priv(indio_dev);
 510
 511	return priv->quadrature_mode[chan->channel];
 512}
 513
 514static const struct iio_enum quad8_quadrature_mode_enum = {
 515	.items = quad8_quadrature_modes,
 516	.num_items = ARRAY_SIZE(quad8_quadrature_modes),
 517	.set = quad8_set_quadrature_mode,
 518	.get = quad8_get_quadrature_mode
 519};
 520
 521static const char *const quad8_index_polarity_modes[] = {
 522	"negative",
 523	"positive"
 524};
 525
 526static int quad8_set_index_polarity(struct iio_dev *indio_dev,
 527	const struct iio_chan_spec *chan, unsigned int index_polarity)
 528{
 529	struct quad8_iio *const priv = iio_priv(indio_dev);
 530	const int base_offset = priv->base + 2 * chan->channel + 1;
 531	unsigned int idr_cfg = index_polarity << 1;
 532
 533	mutex_lock(&priv->lock);
 534
 535	idr_cfg |= priv->synchronous_mode[chan->channel];
 536
 537	priv->index_polarity[chan->channel] = index_polarity;
 538
 539	/* Load Index Control configuration to Index Control Register */
 540	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 541
 542	mutex_unlock(&priv->lock);
 543
 544	return 0;
 545}
 546
 547static int quad8_get_index_polarity(struct iio_dev *indio_dev,
 548	const struct iio_chan_spec *chan)
 549{
 550	const struct quad8_iio *const priv = iio_priv(indio_dev);
 551
 552	return priv->index_polarity[chan->channel];
 553}
 554
 555static const struct iio_enum quad8_index_polarity_enum = {
 556	.items = quad8_index_polarity_modes,
 557	.num_items = ARRAY_SIZE(quad8_index_polarity_modes),
 558	.set = quad8_set_index_polarity,
 559	.get = quad8_get_index_polarity
 560};
 561
 562static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = {
 563	{
 564		.name = "preset",
 565		.shared = IIO_SEPARATE,
 566		.read = quad8_read_preset,
 567		.write = quad8_write_preset
 568	},
 569	{
 570		.name = "set_to_preset_on_index",
 571		.shared = IIO_SEPARATE,
 572		.read = quad8_read_set_to_preset_on_index,
 573		.write = quad8_write_set_to_preset_on_index
 574	},
 575	IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum),
 576	IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum),
 577	IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum),
 578	IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum),
 579	IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum),
 580	IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum),
 581	IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum),
 582	IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum),
 583	{}
 584};
 585
 586static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = {
 587	IIO_ENUM("synchronous_mode", IIO_SEPARATE,
 588		&quad8_synchronous_mode_enum),
 589	IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum),
 590	IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum),
 591	IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum),
 592	{}
 593};
 594
 595#define QUAD8_COUNT_CHAN(_chan) {					\
 596	.type = IIO_COUNT,						\
 597	.channel = (_chan),						\
 598	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
 599		BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE),	\
 600	.ext_info = quad8_count_ext_info,				\
 601	.indexed = 1							\
 602}
 603
 604#define QUAD8_INDEX_CHAN(_chan) {			\
 605	.type = IIO_INDEX,				\
 606	.channel = (_chan),				\
 607	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
 608	.ext_info = quad8_index_ext_info,		\
 609	.indexed = 1					\
 610}
 611
 612static const struct iio_chan_spec quad8_channels[] = {
 613	QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0),
 614	QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1),
 615	QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2),
 616	QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3),
 617	QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4),
 618	QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5),
 619	QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6),
 620	QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7)
 621};
 622
 623static int quad8_signal_read(struct counter_device *counter,
 624	struct counter_signal *signal, enum counter_signal_value *val)
 625{
 626	const struct quad8_iio *const priv = counter->priv;
 627	unsigned int state;
 628
 629	/* Only Index signal levels can be read */
 630	if (signal->id < 16)
 631		return -EINVAL;
 632
 633	state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
 634		& BIT(signal->id - 16);
 635
 636	*val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
 637
 638	return 0;
 639}
 640
 641static int quad8_count_read(struct counter_device *counter,
 642	struct counter_count *count, unsigned long *val)
 643{
 644	struct quad8_iio *const priv = counter->priv;
 645	const int base_offset = priv->base + 2 * count->id;
 646	unsigned int flags;
 647	unsigned int borrow;
 648	unsigned int carry;
 649	int i;
 650
 651	flags = inb(base_offset + 1);
 652	borrow = flags & QUAD8_FLAG_BT;
 653	carry = !!(flags & QUAD8_FLAG_CT);
 654
 655	/* Borrow XOR Carry effectively doubles count range */
 656	*val = (unsigned long)(borrow ^ carry) << 24;
 657
 658	mutex_lock(&priv->lock);
 659
 660	/* Reset Byte Pointer; transfer Counter to Output Latch */
 661	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
 662	     base_offset + 1);
 663
 664	for (i = 0; i < 3; i++)
 665		*val |= (unsigned long)inb(base_offset) << (8 * i);
 666
 667	mutex_unlock(&priv->lock);
 668
 669	return 0;
 670}
 671
 672static int quad8_count_write(struct counter_device *counter,
 673	struct counter_count *count, unsigned long val)
 674{
 675	struct quad8_iio *const priv = counter->priv;
 676	const int base_offset = priv->base + 2 * count->id;
 677	int i;
 678
 679	/* Only 24-bit values are supported */
 680	if (val > 0xFFFFFF)
 681		return -EINVAL;
 682
 683	mutex_lock(&priv->lock);
 684
 685	/* Reset Byte Pointer */
 686	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 687
 688	/* Counter can only be set via Preset Register */
 689	for (i = 0; i < 3; i++)
 690		outb(val >> (8 * i), base_offset);
 691
 692	/* Transfer Preset Register to Counter */
 693	outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
 694
 695	/* Reset Byte Pointer */
 696	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 697
 698	/* Set Preset Register back to original value */
 699	val = priv->preset[count->id];
 700	for (i = 0; i < 3; i++)
 701		outb(val >> (8 * i), base_offset);
 702
 703	/* Reset Borrow, Carry, Compare, and Sign flags */
 704	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
 705	/* Reset Error flag */
 706	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
 707
 708	mutex_unlock(&priv->lock);
 709
 710	return 0;
 711}
 712
 713enum quad8_count_function {
 714	QUAD8_COUNT_FUNCTION_PULSE_DIRECTION = 0,
 715	QUAD8_COUNT_FUNCTION_QUADRATURE_X1,
 716	QUAD8_COUNT_FUNCTION_QUADRATURE_X2,
 717	QUAD8_COUNT_FUNCTION_QUADRATURE_X4
 718};
 719
 720static enum counter_count_function quad8_count_functions_list[] = {
 721	[QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
 722	[QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A,
 723	[QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
 724	[QUAD8_COUNT_FUNCTION_QUADRATURE_X4] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4
 725};
 726
 727static int quad8_function_get(struct counter_device *counter,
 728	struct counter_count *count, size_t *function)
 729{
 730	struct quad8_iio *const priv = counter->priv;
 731	const int id = count->id;
 732
 733	mutex_lock(&priv->lock);
 734
 735	if (priv->quadrature_mode[id])
 736		switch (priv->quadrature_scale[id]) {
 737		case 0:
 738			*function = QUAD8_COUNT_FUNCTION_QUADRATURE_X1;
 739			break;
 740		case 1:
 741			*function = QUAD8_COUNT_FUNCTION_QUADRATURE_X2;
 742			break;
 743		case 2:
 744			*function = QUAD8_COUNT_FUNCTION_QUADRATURE_X4;
 745			break;
 746		}
 747	else
 748		*function = QUAD8_COUNT_FUNCTION_PULSE_DIRECTION;
 749
 750	mutex_unlock(&priv->lock);
 751
 752	return 0;
 753}
 754
 755static int quad8_function_set(struct counter_device *counter,
 756	struct counter_count *count, size_t function)
 757{
 758	struct quad8_iio *const priv = counter->priv;
 759	const int id = count->id;
 760	unsigned int *const quadrature_mode = priv->quadrature_mode + id;
 761	unsigned int *const scale = priv->quadrature_scale + id;
 762	unsigned int *const synchronous_mode = priv->synchronous_mode + id;
 763	const int base_offset = priv->base + 2 * id + 1;
 764	unsigned int mode_cfg;
 765	unsigned int idr_cfg;
 766
 767	mutex_lock(&priv->lock);
 768
 769	mode_cfg = priv->count_mode[id] << 1;
 770	idr_cfg = priv->index_polarity[id] << 1;
 771
 772	if (function == QUAD8_COUNT_FUNCTION_PULSE_DIRECTION) {
 773		*quadrature_mode = 0;
 774
 775		/* Quadrature scaling only available in quadrature mode */
 776		*scale = 0;
 777
 778		/* Synchronous function not supported in non-quadrature mode */
 779		if (*synchronous_mode) {
 780			*synchronous_mode = 0;
 781			/* Disable synchronous function mode */
 782			outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 783		}
 784	} else {
 785		*quadrature_mode = 1;
 786
 787		switch (function) {
 788		case QUAD8_COUNT_FUNCTION_QUADRATURE_X1:
 789			*scale = 0;
 790			mode_cfg |= QUAD8_CMR_QUADRATURE_X1;
 791			break;
 792		case QUAD8_COUNT_FUNCTION_QUADRATURE_X2:
 793			*scale = 1;
 794			mode_cfg |= QUAD8_CMR_QUADRATURE_X2;
 795			break;
 796		case QUAD8_COUNT_FUNCTION_QUADRATURE_X4:
 797			*scale = 2;
 798			mode_cfg |= QUAD8_CMR_QUADRATURE_X4;
 799			break;
 800		}
 801	}
 802
 803	/* Load mode configuration to Counter Mode Register */
 804	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 805
 806	mutex_unlock(&priv->lock);
 807
 808	return 0;
 809}
 810
 811static void quad8_direction_get(struct counter_device *counter,
 812	struct counter_count *count, enum counter_count_direction *direction)
 813{
 814	const struct quad8_iio *const priv = counter->priv;
 815	unsigned int ud_flag;
 816	const unsigned int flag_addr = priv->base + 2 * count->id + 1;
 817
 818	/* U/D flag: nonzero = up, zero = down */
 819	ud_flag = inb(flag_addr) & QUAD8_FLAG_UD;
 820
 821	*direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD :
 822		COUNTER_COUNT_DIRECTION_BACKWARD;
 823}
 824
 825enum quad8_synapse_action {
 826	QUAD8_SYNAPSE_ACTION_NONE = 0,
 827	QUAD8_SYNAPSE_ACTION_RISING_EDGE,
 828	QUAD8_SYNAPSE_ACTION_FALLING_EDGE,
 829	QUAD8_SYNAPSE_ACTION_BOTH_EDGES
 830};
 831
 832static enum counter_synapse_action quad8_index_actions_list[] = {
 833	[QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
 834	[QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
 835};
 836
 837static enum counter_synapse_action quad8_synapse_actions_list[] = {
 838	[QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
 839	[QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
 840	[QUAD8_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
 841	[QUAD8_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES
 842};
 843
 844static int quad8_action_get(struct counter_device *counter,
 845	struct counter_count *count, struct counter_synapse *synapse,
 846	size_t *action)
 847{
 848	struct quad8_iio *const priv = counter->priv;
 849	int err;
 850	size_t function = 0;
 851	const size_t signal_a_id = count->synapses[0].signal->id;
 852	enum counter_count_direction direction;
 853
 854	/* Handle Index signals */
 855	if (synapse->signal->id >= 16) {
 856		if (priv->preset_enable[count->id])
 857			*action = QUAD8_SYNAPSE_ACTION_RISING_EDGE;
 858		else
 859			*action = QUAD8_SYNAPSE_ACTION_NONE;
 860
 861		return 0;
 862	}
 863
 864	err = quad8_function_get(counter, count, &function);
 865	if (err)
 866		return err;
 867
 868	/* Default action mode */
 869	*action = QUAD8_SYNAPSE_ACTION_NONE;
 870
 871	/* Determine action mode based on current count function mode */
 872	switch (function) {
 873	case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION:
 874		if (synapse->signal->id == signal_a_id)
 875			*action = QUAD8_SYNAPSE_ACTION_RISING_EDGE;
 876		break;
 877	case QUAD8_COUNT_FUNCTION_QUADRATURE_X1:
 878		if (synapse->signal->id == signal_a_id) {
 879			quad8_direction_get(counter, count, &direction);
 880
 881			if (direction == COUNTER_COUNT_DIRECTION_FORWARD)
 882				*action = QUAD8_SYNAPSE_ACTION_RISING_EDGE;
 883			else
 884				*action = QUAD8_SYNAPSE_ACTION_FALLING_EDGE;
 885		}
 886		break;
 887	case QUAD8_COUNT_FUNCTION_QUADRATURE_X2:
 888		if (synapse->signal->id == signal_a_id)
 889			*action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES;
 890		break;
 891	case QUAD8_COUNT_FUNCTION_QUADRATURE_X4:
 892		*action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES;
 893		break;
 894	}
 895
 896	return 0;
 897}
 898
 899static const struct counter_ops quad8_ops = {
 900	.signal_read = quad8_signal_read,
 901	.count_read = quad8_count_read,
 902	.count_write = quad8_count_write,
 903	.function_get = quad8_function_get,
 904	.function_set = quad8_function_set,
 905	.action_get = quad8_action_get
 906};
 907
 908static int quad8_index_polarity_get(struct counter_device *counter,
 909	struct counter_signal *signal, size_t *index_polarity)
 910{
 911	const struct quad8_iio *const priv = counter->priv;
 912	const size_t channel_id = signal->id - 16;
 913
 914	*index_polarity = priv->index_polarity[channel_id];
 915
 916	return 0;
 917}
 918
 919static int quad8_index_polarity_set(struct counter_device *counter,
 920	struct counter_signal *signal, size_t index_polarity)
 921{
 922	struct quad8_iio *const priv = counter->priv;
 923	const size_t channel_id = signal->id - 16;
 924	const int base_offset = priv->base + 2 * channel_id + 1;
 925	unsigned int idr_cfg = index_polarity << 1;
 926
 927	mutex_lock(&priv->lock);
 928
 929	idr_cfg |= priv->synchronous_mode[channel_id];
 930
 931	priv->index_polarity[channel_id] = index_polarity;
 932
 933	/* Load Index Control configuration to Index Control Register */
 934	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 935
 936	mutex_unlock(&priv->lock);
 937
 938	return 0;
 939}
 940
 941static struct counter_signal_enum_ext quad8_index_pol_enum = {
 942	.items = quad8_index_polarity_modes,
 943	.num_items = ARRAY_SIZE(quad8_index_polarity_modes),
 944	.get = quad8_index_polarity_get,
 945	.set = quad8_index_polarity_set
 946};
 947
 948static int quad8_synchronous_mode_get(struct counter_device *counter,
 949	struct counter_signal *signal, size_t *synchronous_mode)
 950{
 951	const struct quad8_iio *const priv = counter->priv;
 952	const size_t channel_id = signal->id - 16;
 953
 954	*synchronous_mode = priv->synchronous_mode[channel_id];
 955
 956	return 0;
 957}
 958
 959static int quad8_synchronous_mode_set(struct counter_device *counter,
 960	struct counter_signal *signal, size_t synchronous_mode)
 961{
 962	struct quad8_iio *const priv = counter->priv;
 963	const size_t channel_id = signal->id - 16;
 964	const int base_offset = priv->base + 2 * channel_id + 1;
 965	unsigned int idr_cfg = synchronous_mode;
 966
 967	mutex_lock(&priv->lock);
 968
 969	idr_cfg |= priv->index_polarity[channel_id] << 1;
 970
 971	/* Index function must be non-synchronous in non-quadrature mode */
 972	if (synchronous_mode && !priv->quadrature_mode[channel_id]) {
 973		mutex_unlock(&priv->lock);
 974		return -EINVAL;
 975	}
 976
 977	priv->synchronous_mode[channel_id] = synchronous_mode;
 978
 979	/* Load Index Control configuration to Index Control Register */
 980	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 981
 982	mutex_unlock(&priv->lock);
 983
 984	return 0;
 985}
 986
 987static struct counter_signal_enum_ext quad8_syn_mode_enum = {
 988	.items = quad8_synchronous_modes,
 989	.num_items = ARRAY_SIZE(quad8_synchronous_modes),
 990	.get = quad8_synchronous_mode_get,
 991	.set = quad8_synchronous_mode_set
 992};
 993
 994static ssize_t quad8_count_floor_read(struct counter_device *counter,
 995	struct counter_count *count, void *private, char *buf)
 996{
 997	/* Only a floor of 0 is supported */
 998	return sprintf(buf, "0\n");
 999}
1000
1001static int quad8_count_mode_get(struct counter_device *counter,
1002	struct counter_count *count, size_t *cnt_mode)
1003{
1004	const struct quad8_iio *const priv = counter->priv;
1005
1006	/* Map 104-QUAD-8 count mode to Generic Counter count mode */
1007	switch (priv->count_mode[count->id]) {
1008	case 0:
1009		*cnt_mode = COUNTER_COUNT_MODE_NORMAL;
1010		break;
1011	case 1:
1012		*cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT;
1013		break;
1014	case 2:
1015		*cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE;
1016		break;
1017	case 3:
1018		*cnt_mode = COUNTER_COUNT_MODE_MODULO_N;
1019		break;
1020	}
1021
1022	return 0;
1023}
1024
1025static int quad8_count_mode_set(struct counter_device *counter,
1026	struct counter_count *count, size_t cnt_mode)
1027{
1028	struct quad8_iio *const priv = counter->priv;
1029	unsigned int mode_cfg;
1030	const int base_offset = priv->base + 2 * count->id + 1;
1031
1032	/* Map Generic Counter count mode to 104-QUAD-8 count mode */
1033	switch (cnt_mode) {
1034	case COUNTER_COUNT_MODE_NORMAL:
1035		cnt_mode = 0;
1036		break;
1037	case COUNTER_COUNT_MODE_RANGE_LIMIT:
1038		cnt_mode = 1;
1039		break;
1040	case COUNTER_COUNT_MODE_NON_RECYCLE:
1041		cnt_mode = 2;
1042		break;
1043	case COUNTER_COUNT_MODE_MODULO_N:
1044		cnt_mode = 3;
1045		break;
1046	}
1047
1048	mutex_lock(&priv->lock);
1049
1050	priv->count_mode[count->id] = cnt_mode;
1051
1052	/* Set count mode configuration value */
1053	mode_cfg = cnt_mode << 1;
1054
1055	/* Add quadrature mode configuration */
1056	if (priv->quadrature_mode[count->id])
1057		mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3;
1058
1059	/* Load mode configuration to Counter Mode Register */
1060	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
1061
1062	mutex_unlock(&priv->lock);
1063
1064	return 0;
1065}
1066
1067static struct counter_count_enum_ext quad8_cnt_mode_enum = {
1068	.items = counter_count_mode_str,
1069	.num_items = ARRAY_SIZE(counter_count_mode_str),
1070	.get = quad8_count_mode_get,
1071	.set = quad8_count_mode_set
1072};
1073
1074static ssize_t quad8_count_direction_read(struct counter_device *counter,
1075	struct counter_count *count, void *priv, char *buf)
1076{
1077	enum counter_count_direction dir;
1078
1079	quad8_direction_get(counter, count, &dir);
1080
1081	return sprintf(buf, "%s\n", counter_count_direction_str[dir]);
1082}
1083
1084static ssize_t quad8_count_enable_read(struct counter_device *counter,
1085	struct counter_count *count, void *private, char *buf)
1086{
1087	const struct quad8_iio *const priv = counter->priv;
1088
1089	return sprintf(buf, "%u\n", priv->ab_enable[count->id]);
1090}
1091
1092static ssize_t quad8_count_enable_write(struct counter_device *counter,
1093	struct counter_count *count, void *private, const char *buf, size_t len)
1094{
1095	struct quad8_iio *const priv = counter->priv;
1096	const int base_offset = priv->base + 2 * count->id;
1097	int err;
1098	bool ab_enable;
1099	unsigned int ior_cfg;
1100
1101	err = kstrtobool(buf, &ab_enable);
1102	if (err)
1103		return err;
1104
1105	mutex_lock(&priv->lock);
1106
1107	priv->ab_enable[count->id] = ab_enable;
1108
1109	ior_cfg = ab_enable | priv->preset_enable[count->id] << 1;
1110
1111	/* Load I/O control configuration */
1112	outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
1113
1114	mutex_unlock(&priv->lock);
1115
1116	return len;
1117}
1118
1119static int quad8_error_noise_get(struct counter_device *counter,
1120	struct counter_count *count, size_t *noise_error)
1121{
1122	const struct quad8_iio *const priv = counter->priv;
1123	const int base_offset = priv->base + 2 * count->id + 1;
1124
1125	*noise_error = !!(inb(base_offset) & QUAD8_FLAG_E);
1126
1127	return 0;
1128}
1129
1130static struct counter_count_enum_ext quad8_error_noise_enum = {
1131	.items = quad8_noise_error_states,
1132	.num_items = ARRAY_SIZE(quad8_noise_error_states),
1133	.get = quad8_error_noise_get
1134};
1135
1136static ssize_t quad8_count_preset_read(struct counter_device *counter,
1137	struct counter_count *count, void *private, char *buf)
1138{
1139	const struct quad8_iio *const priv = counter->priv;
1140
1141	return sprintf(buf, "%u\n", priv->preset[count->id]);
1142}
1143
1144static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id,
1145		unsigned int preset)
1146{
1147	const unsigned int base_offset = quad8iio->base + 2 * id;
1148	int i;
1149
1150	quad8iio->preset[id] = preset;
1151
1152	/* Reset Byte Pointer */
1153	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
1154
1155	/* Set Preset Register */
1156	for (i = 0; i < 3; i++)
1157		outb(preset >> (8 * i), base_offset);
1158}
1159
1160static ssize_t quad8_count_preset_write(struct counter_device *counter,
1161	struct counter_count *count, void *private, const char *buf, size_t len)
1162{
1163	struct quad8_iio *const priv = counter->priv;
1164	unsigned int preset;
1165	int ret;
1166
1167	ret = kstrtouint(buf, 0, &preset);
1168	if (ret)
1169		return ret;
1170
1171	/* Only 24-bit values are supported */
1172	if (preset > 0xFFFFFF)
1173		return -EINVAL;
1174
1175	mutex_lock(&priv->lock);
1176
1177	quad8_preset_register_set(priv, count->id, preset);
1178
1179	mutex_unlock(&priv->lock);
1180
1181	return len;
1182}
1183
1184static ssize_t quad8_count_ceiling_read(struct counter_device *counter,
1185	struct counter_count *count, void *private, char *buf)
1186{
1187	struct quad8_iio *const priv = counter->priv;
1188
1189	mutex_lock(&priv->lock);
1190
1191	/* Range Limit and Modulo-N count modes use preset value as ceiling */
1192	switch (priv->count_mode[count->id]) {
1193	case 1:
1194	case 3:
1195		mutex_unlock(&priv->lock);
1196		return sprintf(buf, "%u\n", priv->preset[count->id]);
1197	}
1198
1199	mutex_unlock(&priv->lock);
1200
1201	/* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
1202	return sprintf(buf, "33554431\n");
1203}
1204
1205static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
1206	struct counter_count *count, void *private, const char *buf, size_t len)
1207{
1208	struct quad8_iio *const priv = counter->priv;
1209	unsigned int ceiling;
1210	int ret;
1211
1212	ret = kstrtouint(buf, 0, &ceiling);
1213	if (ret)
1214		return ret;
1215
1216	/* Only 24-bit values are supported */
1217	if (ceiling > 0xFFFFFF)
1218		return -EINVAL;
1219
1220	mutex_lock(&priv->lock);
1221
1222	/* Range Limit and Modulo-N count modes use preset value as ceiling */
1223	switch (priv->count_mode[count->id]) {
1224	case 1:
1225	case 3:
1226		quad8_preset_register_set(priv, count->id, ceiling);
1227		break;
1228	}
1229
1230	mutex_unlock(&priv->lock);
1231
1232	return len;
1233}
1234
1235static ssize_t quad8_count_preset_enable_read(struct counter_device *counter,
1236	struct counter_count *count, void *private, char *buf)
1237{
1238	const struct quad8_iio *const priv = counter->priv;
1239
1240	return sprintf(buf, "%u\n", !priv->preset_enable[count->id]);
1241}
1242
1243static ssize_t quad8_count_preset_enable_write(struct counter_device *counter,
1244	struct counter_count *count, void *private, const char *buf, size_t len)
1245{
1246	struct quad8_iio *const priv = counter->priv;
1247	const int base_offset = priv->base + 2 * count->id + 1;
1248	bool preset_enable;
1249	int ret;
1250	unsigned int ior_cfg;
1251
1252	ret = kstrtobool(buf, &preset_enable);
1253	if (ret)
1254		return ret;
1255
1256	/* Preset enable is active low in Input/Output Control register */
1257	preset_enable = !preset_enable;
1258
1259	mutex_lock(&priv->lock);
1260
1261	priv->preset_enable[count->id] = preset_enable;
1262
1263	ior_cfg = priv->ab_enable[count->id] | (unsigned int)preset_enable << 1;
1264
1265	/* Load I/O control configuration to Input / Output Control Register */
1266	outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
1267
1268	mutex_unlock(&priv->lock);
1269
1270	return len;
1271}
1272
1273static ssize_t quad8_signal_cable_fault_read(struct counter_device *counter,
1274					     struct counter_signal *signal,
1275					     void *private, char *buf)
1276{
1277	struct quad8_iio *const priv = counter->priv;
1278	const size_t channel_id = signal->id / 2;
1279	bool disabled;
1280	unsigned int status;
1281	unsigned int fault;
1282
1283	mutex_lock(&priv->lock);
1284
1285	disabled = !(priv->cable_fault_enable & BIT(channel_id));
1286
1287	if (disabled) {
1288		mutex_unlock(&priv->lock);
1289		return -EINVAL;
1290	}
1291
1292	/* Logic 0 = cable fault */
1293	status = inb(priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS);
1294
1295	mutex_unlock(&priv->lock);
1296
1297	/* Mask respective channel and invert logic */
1298	fault = !(status & BIT(channel_id));
1299
1300	return sprintf(buf, "%u\n", fault);
1301}
1302
1303static ssize_t quad8_signal_cable_fault_enable_read(
1304	struct counter_device *counter, struct counter_signal *signal,
1305	void *private, char *buf)
1306{
1307	const struct quad8_iio *const priv = counter->priv;
1308	const size_t channel_id = signal->id / 2;
1309	const unsigned int enb = !!(priv->cable_fault_enable & BIT(channel_id));
1310
1311	return sprintf(buf, "%u\n", enb);
1312}
1313
1314static ssize_t quad8_signal_cable_fault_enable_write(
1315	struct counter_device *counter, struct counter_signal *signal,
1316	void *private, const char *buf, size_t len)
1317{
1318	struct quad8_iio *const priv = counter->priv;
1319	const size_t channel_id = signal->id / 2;
1320	bool enable;
1321	int ret;
1322	unsigned int cable_fault_enable;
1323
1324	ret = kstrtobool(buf, &enable);
1325	if (ret)
1326		return ret;
1327
1328	mutex_lock(&priv->lock);
1329
1330	if (enable)
1331		priv->cable_fault_enable |= BIT(channel_id);
1332	else
1333		priv->cable_fault_enable &= ~BIT(channel_id);
1334
1335	/* Enable is active low in Differential Encoder Cable Status register */
1336	cable_fault_enable = ~priv->cable_fault_enable;
1337
1338	outb(cable_fault_enable, priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS);
1339
1340	mutex_unlock(&priv->lock);
1341
1342	return len;
1343}
1344
1345static ssize_t quad8_signal_fck_prescaler_read(struct counter_device *counter,
1346	struct counter_signal *signal, void *private, char *buf)
1347{
1348	const struct quad8_iio *const priv = counter->priv;
1349	const size_t channel_id = signal->id / 2;
1350
1351	return sprintf(buf, "%u\n", priv->fck_prescaler[channel_id]);
1352}
1353
1354static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter,
1355	struct counter_signal *signal, void *private, const char *buf,
1356	size_t len)
1357{
1358	struct quad8_iio *const priv = counter->priv;
1359	const size_t channel_id = signal->id / 2;
1360	const int base_offset = priv->base + 2 * channel_id;
1361	u8 prescaler;
1362	int ret;
1363
1364	ret = kstrtou8(buf, 0, &prescaler);
1365	if (ret)
1366		return ret;
1367
1368	mutex_lock(&priv->lock);
1369
1370	priv->fck_prescaler[channel_id] = prescaler;
1371
1372	/* Reset Byte Pointer */
1373	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
1374
1375	/* Set filter clock factor */
1376	outb(prescaler, base_offset);
1377	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
1378	     base_offset + 1);
1379
1380	mutex_unlock(&priv->lock);
1381
1382	return len;
1383}
1384
1385static const struct counter_signal_ext quad8_signal_ext[] = {
1386	{
1387		.name = "cable_fault",
1388		.read = quad8_signal_cable_fault_read
1389	},
1390	{
1391		.name = "cable_fault_enable",
1392		.read = quad8_signal_cable_fault_enable_read,
1393		.write = quad8_signal_cable_fault_enable_write
1394	},
1395	{
1396		.name = "filter_clock_prescaler",
1397		.read = quad8_signal_fck_prescaler_read,
1398		.write = quad8_signal_fck_prescaler_write
1399	}
1400};
1401
1402static const struct counter_signal_ext quad8_index_ext[] = {
1403	COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum),
1404	COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity",	&quad8_index_pol_enum),
1405	COUNTER_SIGNAL_ENUM("synchronous_mode", &quad8_syn_mode_enum),
1406	COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum)
1407};
1408
1409#define QUAD8_QUAD_SIGNAL(_id, _name) {		\
1410	.id = (_id),				\
1411	.name = (_name),			\
1412	.ext = quad8_signal_ext,		\
1413	.num_ext = ARRAY_SIZE(quad8_signal_ext)	\
1414}
1415
1416#define	QUAD8_INDEX_SIGNAL(_id, _name) {	\
1417	.id = (_id),				\
1418	.name = (_name),			\
1419	.ext = quad8_index_ext,			\
1420	.num_ext = ARRAY_SIZE(quad8_index_ext)	\
1421}
1422
1423static struct counter_signal quad8_signals[] = {
1424	QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"),
1425	QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"),
1426	QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"),
1427	QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"),
1428	QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"),
1429	QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"),
1430	QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"),
1431	QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"),
1432	QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"),
1433	QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"),
1434	QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"),
1435	QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"),
1436	QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"),
1437	QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"),
1438	QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"),
1439	QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"),
1440	QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"),
1441	QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"),
1442	QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"),
1443	QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"),
1444	QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"),
1445	QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"),
1446	QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"),
1447	QUAD8_INDEX_SIGNAL(23, "Channel 8 Index")
1448};
1449
1450#define QUAD8_COUNT_SYNAPSES(_id) {					\
1451	{								\
1452		.actions_list = quad8_synapse_actions_list,		\
1453		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
1454		.signal = quad8_signals + 2 * (_id)			\
1455	},								\
1456	{								\
1457		.actions_list = quad8_synapse_actions_list,		\
1458		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
1459		.signal = quad8_signals + 2 * (_id) + 1			\
1460	},								\
1461	{								\
1462		.actions_list = quad8_index_actions_list,		\
1463		.num_actions = ARRAY_SIZE(quad8_index_actions_list),	\
1464		.signal = quad8_signals + 2 * (_id) + 16		\
1465	}								\
1466}
1467
1468static struct counter_synapse quad8_count_synapses[][3] = {
1469	QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1),
1470	QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3),
1471	QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5),
1472	QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7)
1473};
1474
1475static const struct counter_count_ext quad8_count_ext[] = {
1476	{
1477		.name = "ceiling",
1478		.read = quad8_count_ceiling_read,
1479		.write = quad8_count_ceiling_write
1480	},
1481	{
1482		.name = "floor",
1483		.read = quad8_count_floor_read
1484	},
1485	COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum),
1486	COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum),
1487	{
1488		.name = "direction",
1489		.read = quad8_count_direction_read
1490	},
1491	{
1492		.name = "enable",
1493		.read = quad8_count_enable_read,
1494		.write = quad8_count_enable_write
1495	},
1496	COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum),
1497	COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum),
1498	{
1499		.name = "preset",
1500		.read = quad8_count_preset_read,
1501		.write = quad8_count_preset_write
1502	},
1503	{
1504		.name = "preset_enable",
1505		.read = quad8_count_preset_enable_read,
1506		.write = quad8_count_preset_enable_write
1507	}
1508};
1509
1510#define QUAD8_COUNT(_id, _cntname) {					\
1511	.id = (_id),							\
1512	.name = (_cntname),						\
1513	.functions_list = quad8_count_functions_list,			\
1514	.num_functions = ARRAY_SIZE(quad8_count_functions_list),	\
1515	.synapses = quad8_count_synapses[(_id)],			\
1516	.num_synapses =	2,						\
1517	.ext = quad8_count_ext,						\
1518	.num_ext = ARRAY_SIZE(quad8_count_ext)				\
1519}
1520
1521static struct counter_count quad8_counts[] = {
1522	QUAD8_COUNT(0, "Channel 1 Count"),
1523	QUAD8_COUNT(1, "Channel 2 Count"),
1524	QUAD8_COUNT(2, "Channel 3 Count"),
1525	QUAD8_COUNT(3, "Channel 4 Count"),
1526	QUAD8_COUNT(4, "Channel 5 Count"),
1527	QUAD8_COUNT(5, "Channel 6 Count"),
1528	QUAD8_COUNT(6, "Channel 7 Count"),
1529	QUAD8_COUNT(7, "Channel 8 Count")
1530};
1531
1532static int quad8_probe(struct device *dev, unsigned int id)
1533{
1534	struct iio_dev *indio_dev;
1535	struct quad8_iio *quad8iio;
1536	int i, j;
1537	unsigned int base_offset;
1538	int err;
1539
1540	if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
1541		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
1542			base[id], base[id] + QUAD8_EXTENT);
1543		return -EBUSY;
1544	}
1545
1546	/* Allocate IIO device; this also allocates driver data structure */
1547	indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio));
1548	if (!indio_dev)
1549		return -ENOMEM;
1550
1551	/* Initialize IIO device */
1552	indio_dev->info = &quad8_info;
1553	indio_dev->modes = INDIO_DIRECT_MODE;
1554	indio_dev->num_channels = ARRAY_SIZE(quad8_channels);
1555	indio_dev->channels = quad8_channels;
1556	indio_dev->name = dev_name(dev);
1557
1558	/* Initialize Counter device and driver data */
1559	quad8iio = iio_priv(indio_dev);
1560	quad8iio->counter.name = dev_name(dev);
1561	quad8iio->counter.parent = dev;
1562	quad8iio->counter.ops = &quad8_ops;
1563	quad8iio->counter.counts = quad8_counts;
1564	quad8iio->counter.num_counts = ARRAY_SIZE(quad8_counts);
1565	quad8iio->counter.signals = quad8_signals;
1566	quad8iio->counter.num_signals = ARRAY_SIZE(quad8_signals);
1567	quad8iio->counter.priv = quad8iio;
1568	quad8iio->base = base[id];
1569
1570	/* Initialize mutex */
1571	mutex_init(&quad8iio->lock);
1572
1573	/* Reset all counters and disable interrupt function */
1574	outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
1575	/* Set initial configuration for all counters */
1576	for (i = 0; i < QUAD8_NUM_COUNTERS; i++) {
1577		base_offset = base[id] + 2 * i;
1578		/* Reset Byte Pointer */
1579		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
1580		/* Reset filter clock factor */
1581		outb(0, base_offset);
1582		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
1583		     base_offset + 1);
1584		/* Reset Byte Pointer */
1585		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
1586		/* Reset Preset Register */
1587		for (j = 0; j < 3; j++)
1588			outb(0x00, base_offset);
1589		/* Reset Borrow, Carry, Compare, and Sign flags */
1590		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
1591		/* Reset Error flag */
1592		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
1593		/* Binary encoding; Normal count; non-quadrature mode */
1594		outb(QUAD8_CTR_CMR, base_offset + 1);
1595		/* Disable A and B inputs; preset on index; FLG1 as Carry */
1596		outb(QUAD8_CTR_IOR, base_offset + 1);
1597		/* Disable index function; negative index polarity */
1598		outb(QUAD8_CTR_IDR, base_offset + 1);
1599	}
1600	/* Disable Differential Encoder Cable Status for all channels */
1601	outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS);
1602	/* Enable all counters */
1603	outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
1604
1605	/* Register IIO device */
1606	err = devm_iio_device_register(dev, indio_dev);
1607	if (err)
1608		return err;
1609
1610	/* Register Counter device */
1611	return devm_counter_register(dev, &quad8iio->counter);
1612}
1613
1614static struct isa_driver quad8_driver = {
1615	.probe = quad8_probe,
1616	.driver = {
1617		.name = "104-quad-8"
1618	}
1619};
1620
1621module_isa_driver(quad8_driver, num_quad8);
1622
1623MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1624MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver");
1625MODULE_LICENSE("GPL v2");