Commit c62f5032 authored by Ian Abbott's avatar Ian Abbott Committed by Greg Kroah-Hartman
Browse files

comedi: comedi_8254: Use a call-back function for register access



Rework the comedi_8254 module to use a call-back function for register
access.  This will make it easier to isolate the parts that will depend
on the `CONFIG_HAS_IOPORT` macro being defined and also allows the
possibility of supplying an external callback function during
initialization by a variant of the `comedi_8254_init()` and
`comedi_8254_mm_init()` functions, although that has not been
implemented yet.

The `struct comedi_8254` members have been changed to use a pointer to a
callback function and a context of type `unsigned long`.  The
`comedi_8254_init()` and `comedi_8254_mm_init()` functions use an
internal callback function and set the context to the base address of
the registers (for `comedi_8254_mm_init()` that involves converting a
`void __iomem *` to `unsigned long`).

A minor change to `dio200_subdev_8254_offset()` in the
amplc_dio200_common module has been made due to the changes in `struct
comedi_8254`.

Cc: Arnd Bergmann <arnd@kernel.org>
Cc: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: default avatarIan Abbott <abbotti@mev.co.uk>
Link: https://lore.kernel.org/r/20230913170712.111719-3-abbotti@mev.co.uk


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7b79e3d2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -149,9 +149,9 @@ static unsigned int dio200_subdev_8254_offset(struct comedi_device *dev,

	/* get the offset that was passed to comedi_8254_*_init() */
	if (dev->mmio)
		offset = i8254->mmio - dev->mmio;
		offset = (void __iomem *)i8254->context - dev->mmio;
	else
		offset = i8254->iobase - dev->iobase;
		offset = i8254->context - dev->iobase;

	/* remove the shift that was added for PCIe boards */
	if (board->is_pcie)
+124 −53
Original line number Diff line number Diff line
@@ -119,63 +119,101 @@
#include <linux/comedi/comedidev.h>
#include <linux/comedi/comedi_8254.h>

static unsigned int __i8254_read(struct comedi_8254 *i8254, unsigned int reg)
static unsigned int i8254_io8_cb(struct comedi_8254 *i8254, int dir,
				unsigned int reg, unsigned int val)
{
	unsigned int reg_offset = (reg * i8254->iosize) << i8254->regshift;
	unsigned int val;
	unsigned long iobase = i8254->context;
	unsigned int reg_offset = (reg * I8254_IO8) << i8254->regshift;

	switch (i8254->iosize) {
	default:
	case I8254_IO8:
		if (i8254->mmio)
			val = readb(i8254->mmio + reg_offset);
		else
			val = inb(i8254->iobase + reg_offset);
		break;
	case I8254_IO16:
		if (i8254->mmio)
			val = readw(i8254->mmio + reg_offset);
		else
			val = inw(i8254->iobase + reg_offset);
		break;
	case I8254_IO32:
		if (i8254->mmio)
			val = readl(i8254->mmio + reg_offset);
		else
			val = inl(i8254->iobase + reg_offset);
		break;
	if (dir) {
		outb(val, iobase + reg_offset);
		return 0;
	} else {
		return inb(iobase + reg_offset);
	}
	return val & 0xff;
}

static void __i8254_write(struct comedi_8254 *i8254,
			  unsigned int val, unsigned int reg)
static unsigned int i8254_io16_cb(struct comedi_8254 *i8254, int dir,
				  unsigned int reg, unsigned int val)
{
	unsigned int reg_offset = (reg * i8254->iosize) << i8254->regshift;
	unsigned long iobase = i8254->context;
	unsigned int reg_offset = (reg * I8254_IO16) << i8254->regshift;

	switch (i8254->iosize) {
	default:
	case I8254_IO8:
		if (i8254->mmio)
			writeb(val, i8254->mmio + reg_offset);
		else
			outb(val, i8254->iobase + reg_offset);
		break;
	case I8254_IO16:
		if (i8254->mmio)
			writew(val, i8254->mmio + reg_offset);
		else
			outw(val, i8254->iobase + reg_offset);
		break;
	case I8254_IO32:
		if (i8254->mmio)
			writel(val, i8254->mmio + reg_offset);
		else
			outl(val, i8254->iobase + reg_offset);
		break;
	if (dir) {
		outw(val, iobase + reg_offset);
		return 0;
	} else {
		return inw(iobase + reg_offset);
	}
}

static unsigned int i8254_io32_cb(struct comedi_8254 *i8254, int dir,
				  unsigned int reg, unsigned int val)
{
	unsigned long iobase = i8254->context;
	unsigned int reg_offset = (reg * I8254_IO32) << i8254->regshift;

	if (dir) {
		outl(val, iobase + reg_offset);
		return 0;
	} else {
		return inl(iobase + reg_offset);
	}
}

static unsigned int i8254_mmio8_cb(struct comedi_8254 *i8254, int dir,
				   unsigned int reg, unsigned int val)
{
	void __iomem *mmiobase = (void __iomem *)i8254->context;
	unsigned int reg_offset = (reg * I8254_IO8) << i8254->regshift;

	if (dir) {
		writeb(val, mmiobase + reg_offset);
		return 0;
	} else {
		return readb(mmiobase + reg_offset);
	}
}

static unsigned int i8254_mmio16_cb(struct comedi_8254 *i8254, int dir,
				    unsigned int reg, unsigned int val)
{
	void __iomem *mmiobase = (void __iomem *)i8254->context;
	unsigned int reg_offset = (reg * I8254_IO16) << i8254->regshift;

	if (dir) {
		writew(val, mmiobase + reg_offset);
		return 0;
	} else {
		return readw(mmiobase + reg_offset);
	}
}

static unsigned int i8254_mmio32_cb(struct comedi_8254 *i8254, int dir,
				    unsigned int reg, unsigned int val)
{
	void __iomem *mmiobase = (void __iomem *)i8254->context;
	unsigned int reg_offset = (reg * I8254_IO32) << i8254->regshift;

	if (dir) {
		writel(val, mmiobase + reg_offset);
		return 0;
	} else {
		return readl(mmiobase + reg_offset);
	}
}

static unsigned int __i8254_read(struct comedi_8254 *i8254, unsigned int reg)
{
	return 0xff & i8254->iocb(i8254, 0, reg, 0);
}

static void __i8254_write(struct comedi_8254 *i8254,
			  unsigned int val, unsigned int reg)
{
	i8254->iocb(i8254, 1, reg, val);
}

/**
 * comedi_8254_status - return the status of a counter
 * @i8254:	comedi_8254 struct for the timer
@@ -571,8 +609,8 @@ void comedi_8254_subdevice_init(struct comedi_subdevice *s,
}
EXPORT_SYMBOL_GPL(comedi_8254_subdevice_init);

static struct comedi_8254 *__i8254_init(unsigned long iobase,
					void __iomem *mmio,
static struct comedi_8254 *__i8254_init(comedi_8254_iocb_fn *iocb,
					unsigned long context,
					unsigned int osc_base,
					unsigned int iosize,
					unsigned int regshift)
@@ -585,12 +623,15 @@ static struct comedi_8254 *__i8254_init(unsigned long iobase,
	      iosize == I8254_IO32))
		return NULL;

	if (!iocb)
		return NULL;

	i8254 = kzalloc(sizeof(*i8254), GFP_KERNEL);
	if (!i8254)
		return NULL;

	i8254->iobase	= iobase;
	i8254->mmio	= mmio;
	i8254->iocb	= iocb;
	i8254->context	= context;
	i8254->iosize	= iosize;
	i8254->regshift	= regshift;

@@ -617,7 +658,22 @@ struct comedi_8254 *comedi_8254_init(unsigned long iobase,
				     unsigned int iosize,
				     unsigned int regshift)
{
	return __i8254_init(iobase, NULL, osc_base, iosize, regshift);
	comedi_8254_iocb_fn *iocb;

	switch (iosize) {
	case I8254_IO8:
		iocb = i8254_io8_cb;
		break;
	case I8254_IO16:
		iocb = i8254_io16_cb;
		break;
	case I8254_IO32:
		iocb = i8254_io32_cb;
		break;
	default:
		return NULL;
	}
	return __i8254_init(iocb, iobase, osc_base, iosize, regshift);
}
EXPORT_SYMBOL_GPL(comedi_8254_init);

@@ -634,7 +690,22 @@ struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio,
					unsigned int iosize,
					unsigned int regshift)
{
	return __i8254_init(0, mmio, osc_base, iosize, regshift);
	comedi_8254_iocb_fn *iocb;

	switch (iosize) {
	case I8254_IO8:
		iocb = i8254_mmio8_cb;
		break;
	case I8254_IO16:
		iocb = i8254_mmio16_cb;
		break;
	case I8254_IO32:
		iocb = i8254_mmio32_cb;
		break;
	default:
		return NULL;
	}
	return __i8254_init(iocb, (unsigned long)mmio, osc_base, iosize, regshift);
}
EXPORT_SYMBOL_GPL(comedi_8254_mm_init);

+18 −4
Original line number Diff line number Diff line
@@ -57,10 +57,24 @@ struct comedi_subdevice;
/* counter maps zero to 0x10000 */
#define I8254_MAX_COUNT			0x10000

struct comedi_8254;

/**
 * typedef comedi_8254_iocb_fn - call-back function type for 8254 register access
 * @i8254:		pointer to struct comedi_8254
 * @dir:		direction (0 = read, 1 = write)
 * @reg:		register number
 * @val:		value to write
 *
 * Return: Register value when reading, 0 when writing.
 */
typedef unsigned int comedi_8254_iocb_fn(struct comedi_8254 *i8254, int dir,
					 unsigned int reg, unsigned int val);

/**
 * struct comedi_8254 - private data used by this module
 * @iobase:		PIO base address of the registers (in/out)
 * @mmio:		MMIO base address of the registers (read/write)
 * @iocb:		I/O call-back function for register access
 * @context:		context for register access (e.g. a base address)
 * @iosize:		I/O size used to access the registers (b/w/l)
 * @regshift:		register gap shift
 * @osc_base:		cascaded oscillator speed in ns
@@ -76,8 +90,8 @@ struct comedi_subdevice;
 * @insn_config:	driver specific (*insn_config) callback
 */
struct comedi_8254 {
	unsigned long iobase;
	void __iomem *mmio;
	comedi_8254_iocb_fn *iocb;
	unsigned long context;
	unsigned int iosize;
	unsigned int regshift;
	unsigned int osc_base;