root/drivers/gpib/eastwood/fluke_gpib.h
/* 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,
};