linux/drivers/comedi/drivers/comedi_8254.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * comedi_8254.c
 * Generic 8254 timer/counter support
 * Copyright (C) 2014 H Hartley Sweeten <[email protected]>
 *
 * Based on 8253.h and various subdevice implementations in comedi drivers.
 *
 * COMEDI - Linux Control and Measurement Device Interface
 * Copyright (C) 2000 David A. Schleef <[email protected]>
 */

/*
 * Module: comedi_8254
 * Description: Generic 8254 timer/counter support
 * Author: H Hartley Sweeten <[email protected]>
 * Updated: Thu Jan 8 16:45:45 MST 2015
 * Status: works
 *
 * This module is not used directly by end-users. Rather, it is used by other
 * drivers to provide support for an 8254 Programmable Interval Timer. These
 * counters are typically used to generate the pacer clock used for data
 * acquisition. Some drivers also expose the counters for general purpose use.
 *
 * This module provides the following basic functions:
 *
 * comedi_8254_io_alloc() / comedi_8254_mm_alloc()
 *	Initializes this module to access the 8254 registers. The _mm version
 *	sets up the module for MMIO register access; the _io version sets it
 *	up for PIO access.  These functions return a pointer to a struct
 *	comedi_8254 on success, or an ERR_PTR value on failure.  The pointer
 *	returned from these functions is normally stored in the comedi_device
 *	dev->pacer and will be freed by the comedi core during the driver
 *	(*detach). If a driver has multiple 8254 devices, they need to be
 *	stored in the drivers private data and freed when the driver is
 *	detached.  If the ERR_PTR value is stored, code should check the
 *	pointer value with !IS_ERR(pointer) before freeing.
 *
 *	NOTE: The counters are reset by setting them to I8254_MODE0 as part of
 *	this initialization.
 *
 * comedi_8254_set_mode()
 *	Sets a counters operation mode:
 *		I8254_MODE0	Interrupt on terminal count
 *		I8254_MODE1	Hardware retriggerable one-shot
 *		I8254_MODE2	Rate generator
 *		I8254_MODE3	Square wave mode
 *		I8254_MODE4	Software triggered strobe
 *		I8254_MODE5	Hardware triggered strobe (retriggerable)
 *
 *	In addition I8254_BCD and I8254_BINARY specify the counting mode:
 *		I8254_BCD	BCD counting
 *		I8254_BINARY	Binary counting
 *
 * comedi_8254_write()
 *	Writes an initial value to a counter.
 *
 *	The largest possible initial count is 0; this is equivalent to 2^16
 *	for binary counting and 10^4 for BCD counting.
 *
 *	NOTE: The counter does not stop when it reaches zero. In Mode 0, 1, 4,
 *	and 5 the counter "wraps around" to the highest count, either 0xffff
 *	for binary counting or 9999 for BCD counting, and continues counting.
 *	Modes 2 and 3 are periodic; the counter reloads itself with the initial
 *	count and continues counting from there.
 *
 * comedi_8254_read()
 *	Reads the current value from a counter.
 *
 * comedi_8254_status()
 *	Reads the status of a counter.
 *
 * comedi_8254_load()
 *	Sets a counters operation mode and writes the initial value.
 *
 * Typically the pacer clock is created by cascading two of the 16-bit counters
 * to create a 32-bit rate generator (I8254_MODE2). These functions are
 * provided to handle the cascaded counters:
 *
 * comedi_8254_ns_to_timer()
 *	Calculates the divisor value needed for a single counter to generate
 *	ns timing.
 *
 * comedi_8254_cascade_ns_to_timer()
 *	Calculates the two divisor values needed to the generate the pacer
 *	clock (in ns).
 *
 * comedi_8254_update_divisors()
 *	Transfers the intermediate divisor values to the current divisors.
 *
 * comedi_8254_pacer_enable()
 *	Programs the mode of the cascaded counters and writes the current
 *	divisor values.
 *
 * To expose the counters as a subdevice for general purpose use the following
 * functions a provided:
 *
 * comedi_8254_subdevice_init()
 *	Initializes a comedi_subdevice to use the 8254 timer.
 *
 * comedi_8254_set_busy()
 *	Internally flags a counter as "busy". This is done to protect the
 *	counters that are used for the cascaded 32-bit pacer.
 *
 * The subdevice provides (*insn_read) and (*insn_write) operations to read
 * the current value and write an initial value to a counter. A (*insn_config)
 * operation is also provided to handle the following comedi instructions:
 *
 *	INSN_CONFIG_SET_COUNTER_MODE	calls comedi_8254_set_mode()
 *	INSN_CONFIG_8254_READ_STATUS	calls comedi_8254_status()
 *
 * The (*insn_config) member of comedi_8254 can be initialized by the external
 * driver to handle any additional instructions.
 *
 * NOTE: Gate control, clock routing, and any interrupt handling for the
 * counters is not handled by this module. These features are driver dependent.
 */

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/comedi/comedidev.h>
#include <linux/comedi/comedi_8254.h>

#ifdef CONFIG_HAS_IOPORT

static unsigned int i8254_io8_cb(struct comedi_8254 *i8254, int dir,
				unsigned int reg, unsigned int val)
{}

static unsigned int i8254_io16_cb(struct comedi_8254 *i8254, int dir,
				  unsigned int reg, unsigned int val)
{}

static unsigned int i8254_io32_cb(struct comedi_8254 *i8254, int dir,
				  unsigned int reg, unsigned int val)
{}

#endif	/* CONFIG_HAS_IOPORT */

static unsigned int i8254_mmio8_cb(struct comedi_8254 *i8254, int dir,
				   unsigned int reg, unsigned int val)
{}

static unsigned int i8254_mmio16_cb(struct comedi_8254 *i8254, int dir,
				    unsigned int reg, unsigned int val)
{}

static unsigned int i8254_mmio32_cb(struct comedi_8254 *i8254, int dir,
				    unsigned int reg, unsigned int val)
{}

static unsigned int __i8254_read(struct comedi_8254 *i8254, unsigned int reg)
{}

static void __i8254_write(struct comedi_8254 *i8254,
			  unsigned int val, unsigned int reg)
{}

/**
 * comedi_8254_status - return the status of a counter
 * @i8254:	comedi_8254 struct for the timer
 * @counter:	the counter number
 */
unsigned int comedi_8254_status(struct comedi_8254 *i8254, unsigned int counter)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_read - read the current counter value
 * @i8254:	comedi_8254 struct for the timer
 * @counter:	the counter number
 */
unsigned int comedi_8254_read(struct comedi_8254 *i8254, unsigned int counter)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_write - load a 16-bit initial counter value
 * @i8254:	comedi_8254 struct for the timer
 * @counter:	the counter number
 * @val:	the initial value
 */
void comedi_8254_write(struct comedi_8254 *i8254,
		       unsigned int counter, unsigned int val)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_set_mode - set the mode of a counter
 * @i8254:	comedi_8254 struct for the timer
 * @counter:	the counter number
 * @mode:	the I8254_MODEx and I8254_BCD|I8254_BINARY
 */
int comedi_8254_set_mode(struct comedi_8254 *i8254, unsigned int counter,
			 unsigned int mode)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_load - program the mode and initial count of a counter
 * @i8254:	comedi_8254 struct for the timer
 * @counter:	the counter number
 * @mode:	the I8254_MODEx and I8254_BCD|I8254_BINARY
 * @val:	the initial value
 */
int comedi_8254_load(struct comedi_8254 *i8254, unsigned int counter,
		     unsigned int val, unsigned int mode)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_pacer_enable - set the mode and load the cascaded counters
 * @i8254:	comedi_8254 struct for the timer
 * @counter1:	the counter number for the first divisor
 * @counter2:	the counter number for the second divisor
 * @enable:	flag to enable (load) the counters
 */
void comedi_8254_pacer_enable(struct comedi_8254 *i8254,
			      unsigned int counter1,
			      unsigned int counter2,
			      bool enable)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_update_divisors - update the divisors for the cascaded counters
 * @i8254:	comedi_8254 struct for the timer
 */
void comedi_8254_update_divisors(struct comedi_8254 *i8254)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_cascade_ns_to_timer - calculate the cascaded divisor values
 * @i8254:	comedi_8254 struct for the timer
 * @nanosec:	the desired ns time
 * @flags:	comedi_cmd flags
 */
void comedi_8254_cascade_ns_to_timer(struct comedi_8254 *i8254,
				     unsigned int *nanosec,
				     unsigned int flags)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_ns_to_timer - calculate the divisor value for nanosec timing
 * @i8254:	comedi_8254 struct for the timer
 * @nanosec:	the desired ns time
 * @flags:	comedi_cmd flags
 */
void comedi_8254_ns_to_timer(struct comedi_8254 *i8254,
			     unsigned int *nanosec, unsigned int flags)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_8254_set_busy - set/clear the "busy" flag for a given counter
 * @i8254:	comedi_8254 struct for the timer
 * @counter:	the counter number
 * @busy:	set/clear flag
 */
void comedi_8254_set_busy(struct comedi_8254 *i8254,
			  unsigned int counter, bool busy)
{}
EXPORT_SYMBOL_GPL();

static int comedi_8254_insn_read(struct comedi_device *dev,
				 struct comedi_subdevice *s,
				 struct comedi_insn *insn,
				 unsigned int *data)
{}

static int comedi_8254_insn_write(struct comedi_device *dev,
				  struct comedi_subdevice *s,
				  struct comedi_insn *insn,
				  unsigned int *data)
{}

static int comedi_8254_insn_config(struct comedi_device *dev,
				   struct comedi_subdevice *s,
				   struct comedi_insn *insn,
				   unsigned int *data)
{}

/**
 * comedi_8254_subdevice_init - initialize a comedi_subdevice for the 8254 timer
 * @s:		comedi_subdevice struct
 * @i8254:	comedi_8254 struct
 */
void comedi_8254_subdevice_init(struct comedi_subdevice *s,
				struct comedi_8254 *i8254)
{}
EXPORT_SYMBOL_GPL();

static struct comedi_8254 *__i8254_init(comedi_8254_iocb_fn *iocb,
					unsigned long context,
					unsigned int osc_base,
					unsigned int iosize,
					unsigned int regshift)
{}

#ifdef CONFIG_HAS_IOPORT

/**
 * comedi_8254_io_alloc - allocate and initialize the 8254 device for pio access
 * @iobase:	port I/O base address
 * @osc_base:	base time of the counter in ns
 *		OPTIONAL - only used by comedi_8254_cascade_ns_to_timer()
 * @iosize:	I/O register size
 * @regshift:	register gap shift
 *
 * Return: A pointer to a struct comedi_8254 or an ERR_PTR value.
 */
struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase,
					 unsigned int osc_base,
					 unsigned int iosize,
					 unsigned int regshift)
{}
EXPORT_SYMBOL_GPL();

#endif	/* CONFIG_HAS_IOPORT */

/**
 * comedi_8254_mm_alloc - allocate and initialize the 8254 device for mmio access
 * @mmio:	memory mapped I/O base address
 * @osc_base:	base time of the counter in ns
 *		OPTIONAL - only used by comedi_8254_cascade_ns_to_timer()
 * @iosize:	I/O register size
 * @regshift:	register gap shift
 *
 * Return: A pointer to a struct comedi_8254 or an ERR_PTR value.
 */
struct comedi_8254 *comedi_8254_mm_alloc(void __iomem *mmio,
					 unsigned int osc_base,
					 unsigned int iosize,
					 unsigned int regshift)
{}
EXPORT_SYMBOL_GPL();

static int __init comedi_8254_module_init(void)
{}
module_init();

static void __exit comedi_8254_module_exit(void)
{}
module_exit(comedi_8254_module_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();