Contributors: 4
Author Tokens Token Proportion Commits Commit Proportion
Dave Penkler 476 97.14% 2 33.33%
Arnd Bergmann 8 1.63% 2 33.33%
Michael Rubin 4 0.82% 1 16.67%
Paul Retourné 2 0.41% 1 16.67%
Total 490 6


/* SPDX-License-Identifier: GPL-2.0 */

/***************************************************************************
 *   Author: Frank Mori Hess <fmh6jj@gmail.com>
 *   copyright: (C) 2006, 2010, 2015 Fluke Corporation
 ***************************************************************************/

#include <linux/compiler.h>
#include <linux/dmaengine.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include "nec7210.h"

struct fluke_priv {
	struct nec7210_priv nec7210_priv;
	struct resource *gpib_iomem_res;
	struct resource *write_transfer_counter_res;
	struct resource *dma_port_res;
	int irq;
	struct dma_chan *dma_channel;
	u8 *dma_buffer;
	int dma_buffer_size;
	void __iomem *write_transfer_counter;
};

// cb7210 specific registers and bits
enum cb7210_regs {
	STATE1_REG = 0x4,
	ISR0_IMR0 = 0x6,
	BUS_STATUS = 0x7
};

enum cb7210_page_in {
	ISR0_IMR0_PAGE = 1,
	BUS_STATUS_PAGE = 1,
	STATE1_PAGE = 1
};

/* IMR0 -- Interrupt Mode Register 0 */
enum imr0_bits {
	FLUKE_IFCIE_BIT = 0x8,	/* interface clear interrupt */
};

/* ISR0 -- Interrupt Status Register 0 */
enum isr0_bits {
	FLUKE_IFCI_BIT = 0x8,	/* interface clear interrupt */
};

enum state1_bits {
	SOURCE_HANDSHAKE_SIDS_BITS = 0x0, /* source idle state */
	SOURCE_HANDSHAKE_SGNS_BITS = 0x1, /* source generate state */
	SOURCE_HANDSHAKE_SDYS_BITS = 0x2, /* source delay state */
	SOURCE_HANDSHAKE_STRS_BITS = 0x5, /* source transfer state */
	SOURCE_HANDSHAKE_MASK = 0x7
};

/*
 * we customized the cb7210 vhdl to give the "data in" status
 * on the unused bit 7 of the address0 register.
 */
enum cb7210_address0 {
	DATA_IN_STATUS = 0x80
};

static inline int cb7210_page_in_bits(unsigned int page)
{
	return 0x50 | (page & 0xf);
}

// don't use without locking nec_priv->register_page_lock
static inline u8 fluke_read_byte_nolock(struct nec7210_priv *nec_priv,
					int register_num)
{
	u8 retval;

	retval = readl(nec_priv->mmiobase + register_num * nec_priv->offset);
	return retval;
}

// don't use without locking nec_priv->register_page_lock
static inline void fluke_write_byte_nolock(struct nec7210_priv *nec_priv, u8 data,
					   int register_num)
{
	writel(data, nec_priv->mmiobase + register_num * nec_priv->offset);
}

static inline u8 fluke_paged_read_byte(struct fluke_priv *e_priv,
				       unsigned int register_num, unsigned int page)
{
	struct nec7210_priv *nec_priv = &e_priv->nec7210_priv;
	u8 retval;
	unsigned long flags;

	spin_lock_irqsave(&nec_priv->register_page_lock, flags);
	fluke_write_byte_nolock(nec_priv, cb7210_page_in_bits(page), AUXMR);
	udelay(1);
	/* chip auto clears the page after a read */
	retval = fluke_read_byte_nolock(nec_priv, register_num);
	spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
	return retval;
}

static inline void fluke_paged_write_byte(struct fluke_priv *e_priv, u8 data,
					  unsigned int register_num, unsigned int page)
{
	struct nec7210_priv *nec_priv = &e_priv->nec7210_priv;
	unsigned long flags;

	spin_lock_irqsave(&nec_priv->register_page_lock, flags);
	fluke_write_byte_nolock(nec_priv, cb7210_page_in_bits(page), AUXMR);
	udelay(1);
	fluke_write_byte_nolock(nec_priv, data, register_num);
	spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
}

enum bus_status_bits {
	BSR_ATN_BIT = 0x1,
	BSR_EOI_BIT = 0x2,
	BSR_SRQ_BIT = 0x4,
	BSR_IFC_BIT = 0x8,
	BSR_REN_BIT = 0x10,
	BSR_DAV_BIT = 0x20,
	BSR_NRFD_BIT = 0x40,
	BSR_NDAC_BIT = 0x80,
};

enum cb7210_aux_cmds {
/*
 * AUX_RTL2 is an undocumented aux command which causes cb7210 to assert
 * (and keep asserted) local rtl message.  This is used in conjunction
 * with the (stupid) cb7210 implementation
 * of the normal nec7210 AUX_RTL aux command, which
 * causes the rtl message to toggle between on and off.
 */
	AUX_RTL2 = 0xd,
	AUX_NBAF = 0xe,	// new byte available false (also clears seoi)
	AUX_LO_SPEED = 0x40,
	AUX_HI_SPEED = 0x41,
};

enum {
	fluke_reg_offset = 4,
	fluke_num_regs = 8,
	write_transfer_counter_mask = 0x7ff,
};