// SPDX-License-Identifier: GPL-2.0
/*
* Counter driver for the ACCES 104-QUAD-8
* Copyright (C) 2016 William Breathitt Gray
*
* This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4.
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/counter.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/unaligned.h>
#define QUAD8_EXTENT 32
static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
static unsigned int num_quad8;
module_param_hw_array(base, uint, ioport, &num_quad8, 0);
MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
static unsigned int num_irq;
module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
#define QUAD8_NUM_COUNTERS 8
#define QUAD8_DATA(_channel) ((_channel) * 2)
#define QUAD8_CONTROL(_channel) (QUAD8_DATA(_channel) + 1)
#define QUAD8_INTERRUPT_STATUS 0x10
#define QUAD8_CHANNEL_OPERATION 0x11
#define QUAD8_INDEX_INTERRUPT 0x12
#define QUAD8_INDEX_INPUT_LEVELS 0x16
#define QUAD8_CABLE_STATUS 0x17
/**
* struct quad8 - device private data structure
* @lock: lock to prevent clobbering device states during R/W ops
* @cmr: array of Counter Mode Register states
* @ior: array of Input / Output Control Register states
* @idr: array of Index Control Register states
* @fck_prescaler: array of filter clock prescaler configurations
* @preset: array of preset values
* @cable_fault_enable: differential encoder cable status enable configurations
* @map: regmap for the device
*/
struct quad8 {
spinlock_t lock;
u8 cmr[QUAD8_NUM_COUNTERS];
u8 ior[QUAD8_NUM_COUNTERS];
u8 idr[QUAD8_NUM_COUNTERS];
unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
unsigned int preset[QUAD8_NUM_COUNTERS];
unsigned int cable_fault_enable;
struct regmap *map;
};
static const struct regmap_range quad8_wr_ranges[] = {
regmap_reg_range(0x0, 0xF), regmap_reg_range(0x11, 0x12), regmap_reg_range(0x17, 0x17),
};
static const struct regmap_range quad8_rd_ranges[] = {
regmap_reg_range(0x0, 0x12), regmap_reg_range(0x16, 0x18),
};
static const struct regmap_access_table quad8_wr_table = {
.yes_ranges = quad8_wr_ranges,
.n_yes_ranges = ARRAY_SIZE(quad8_wr_ranges),
};
static const struct regmap_access_table quad8_rd_table = {
.yes_ranges = quad8_rd_ranges,
.n_yes_ranges = ARRAY_SIZE(quad8_rd_ranges),
};
static const