cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mf6x4.c (7762B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *  comedi/drivers/mf6x4.c
      4 *  Driver for Humusoft MF634 and MF624 Data acquisition cards
      5 *
      6 *  COMEDI - Linux Control and Measurement Device Interface
      7 *  Copyright (C) 2000 David A. Schleef <ds@schleef.org>
      8 */
      9/*
     10 * Driver: mf6x4
     11 * Description: Humusoft MF634 and MF624 Data acquisition card driver
     12 * Devices: [Humusoft] MF634 (mf634), MF624 (mf624)
     13 * Author: Rostislav Lisovy <lisovy@gmail.com>
     14 * Status: works
     15 * Updated:
     16 * Configuration Options: none
     17 */
     18
     19#include <linux/module.h>
     20#include <linux/delay.h>
     21#include <linux/comedi/comedi_pci.h>
     22
     23/* Registers present in BAR0 memory region */
     24#define MF624_GPIOC_REG		0x54
     25
     26#define MF6X4_GPIOC_EOLC	BIT(17)	/* End Of Last Conversion */
     27#define MF6X4_GPIOC_LDAC	BIT(23)	/* Load DACs */
     28#define MF6X4_GPIOC_DACEN	BIT(26)
     29
     30/* BAR1 registers */
     31#define MF6X4_ADDATA_REG	0x00
     32#define MF6X4_ADCTRL_REG	0x00
     33#define MF6X4_ADCTRL_CHAN(x)	BIT(chan)
     34#define MF6X4_DIN_REG		0x10
     35#define MF6X4_DIN_MASK		0xff
     36#define MF6X4_DOUT_REG		0x10
     37#define MF6X4_ADSTART_REG	0x20
     38#define MF6X4_DAC_REG(x)	(0x20 + ((x) * 2))
     39
     40/* BAR2 registers */
     41#define MF634_GPIOC_REG		0x68
     42
     43enum mf6x4_boardid {
     44	BOARD_MF634,
     45	BOARD_MF624,
     46};
     47
     48struct mf6x4_board {
     49	const char *name;
     50	/* We need to keep track of the order of BARs used by the cards */
     51	unsigned int bar_nums[3];
     52};
     53
     54static const struct mf6x4_board mf6x4_boards[] = {
     55	[BOARD_MF634] = {
     56		.name           = "mf634",
     57		.bar_nums	= {0, 2, 3},
     58	},
     59	[BOARD_MF624] = {
     60		.name           = "mf624",
     61		.bar_nums	= {0, 2, 4},
     62	},
     63};
     64
     65struct mf6x4_private {
     66	/*
     67	 * Documentation for both MF634 and MF624 describes registers
     68	 * present in BAR0, 1 and 2 regions.
     69	 * The real (i.e. in HW) BAR numbers are different for MF624
     70	 * and MF634 yet we will call them 0, 1, 2
     71	 */
     72	void __iomem *bar0_mem;
     73	void __iomem *bar2_mem;
     74
     75	/*
     76	 * This configuration register has the same function and fields
     77	 * for both cards however it lies in different BARs on different
     78	 * offsets -- this variable makes the access easier
     79	 */
     80	void __iomem *gpioc_reg;
     81};
     82
     83static int mf6x4_di_insn_bits(struct comedi_device *dev,
     84			      struct comedi_subdevice *s,
     85			      struct comedi_insn *insn,
     86			      unsigned int *data)
     87{
     88	data[1] = ioread16(dev->mmio + MF6X4_DIN_REG) & MF6X4_DIN_MASK;
     89
     90	return insn->n;
     91}
     92
     93static int mf6x4_do_insn_bits(struct comedi_device *dev,
     94			      struct comedi_subdevice *s,
     95			      struct comedi_insn *insn,
     96			      unsigned int *data)
     97{
     98	if (comedi_dio_update_state(s, data))
     99		iowrite16(s->state, dev->mmio + MF6X4_DOUT_REG);
    100
    101	data[1] = s->state;
    102
    103	return insn->n;
    104}
    105
    106static int mf6x4_ai_eoc(struct comedi_device *dev,
    107			struct comedi_subdevice *s,
    108			struct comedi_insn *insn,
    109			unsigned long context)
    110{
    111	struct mf6x4_private *devpriv = dev->private;
    112	unsigned int status;
    113
    114	/* EOLC goes low at end of conversion. */
    115	status = ioread32(devpriv->gpioc_reg);
    116	if ((status & MF6X4_GPIOC_EOLC) == 0)
    117		return 0;
    118	return -EBUSY;
    119}
    120
    121static int mf6x4_ai_insn_read(struct comedi_device *dev,
    122			      struct comedi_subdevice *s,
    123			      struct comedi_insn *insn,
    124			      unsigned int *data)
    125{
    126	unsigned int chan = CR_CHAN(insn->chanspec);
    127	unsigned int d;
    128	int ret;
    129	int i;
    130
    131	/* Set the ADC channel number in the scan list */
    132	iowrite16(MF6X4_ADCTRL_CHAN(chan), dev->mmio + MF6X4_ADCTRL_REG);
    133
    134	for (i = 0; i < insn->n; i++) {
    135		/* Trigger ADC conversion by reading ADSTART */
    136		ioread16(dev->mmio + MF6X4_ADSTART_REG);
    137
    138		ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0);
    139		if (ret)
    140			return ret;
    141
    142		/* Read the actual value */
    143		d = ioread16(dev->mmio + MF6X4_ADDATA_REG);
    144		d &= s->maxdata;
    145		/* munge the 2's complement data to offset binary */
    146		data[i] = comedi_offset_munge(s, d);
    147	}
    148
    149	iowrite16(0x0, dev->mmio + MF6X4_ADCTRL_REG);
    150
    151	return insn->n;
    152}
    153
    154static int mf6x4_ao_insn_write(struct comedi_device *dev,
    155			       struct comedi_subdevice *s,
    156			       struct comedi_insn *insn,
    157			       unsigned int *data)
    158{
    159	struct mf6x4_private *devpriv = dev->private;
    160	unsigned int chan = CR_CHAN(insn->chanspec);
    161	unsigned int val = s->readback[chan];
    162	unsigned int gpioc;
    163	int i;
    164
    165	/* Enable instantaneous update of converters outputs + Enable DACs */
    166	gpioc = ioread32(devpriv->gpioc_reg);
    167	iowrite32((gpioc & ~MF6X4_GPIOC_LDAC) | MF6X4_GPIOC_DACEN,
    168		  devpriv->gpioc_reg);
    169
    170	for (i = 0; i < insn->n; i++) {
    171		val = data[i];
    172		iowrite16(val, dev->mmio + MF6X4_DAC_REG(chan));
    173	}
    174	s->readback[chan] = val;
    175
    176	return insn->n;
    177}
    178
    179static int mf6x4_auto_attach(struct comedi_device *dev, unsigned long context)
    180{
    181	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
    182	const struct mf6x4_board *board = NULL;
    183	struct mf6x4_private *devpriv;
    184	struct comedi_subdevice *s;
    185	int ret;
    186
    187	if (context < ARRAY_SIZE(mf6x4_boards))
    188		board = &mf6x4_boards[context];
    189	else
    190		return -ENODEV;
    191
    192	dev->board_ptr = board;
    193	dev->board_name = board->name;
    194
    195	ret = comedi_pci_enable(dev);
    196	if (ret)
    197		return ret;
    198
    199	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
    200	if (!devpriv)
    201		return -ENOMEM;
    202
    203	devpriv->bar0_mem = pci_ioremap_bar(pcidev, board->bar_nums[0]);
    204	if (!devpriv->bar0_mem)
    205		return -ENODEV;
    206
    207	dev->mmio = pci_ioremap_bar(pcidev, board->bar_nums[1]);
    208	if (!dev->mmio)
    209		return -ENODEV;
    210
    211	devpriv->bar2_mem = pci_ioremap_bar(pcidev, board->bar_nums[2]);
    212	if (!devpriv->bar2_mem)
    213		return -ENODEV;
    214
    215	if (board == &mf6x4_boards[BOARD_MF634])
    216		devpriv->gpioc_reg = devpriv->bar2_mem + MF634_GPIOC_REG;
    217	else
    218		devpriv->gpioc_reg = devpriv->bar0_mem + MF624_GPIOC_REG;
    219
    220	ret = comedi_alloc_subdevices(dev, 4);
    221	if (ret)
    222		return ret;
    223
    224	/* Analog Input subdevice */
    225	s = &dev->subdevices[0];
    226	s->type		= COMEDI_SUBD_AI;
    227	s->subdev_flags	= SDF_READABLE | SDF_GROUND;
    228	s->n_chan	= 8;
    229	s->maxdata	= 0x3fff;
    230	s->range_table	= &range_bipolar10;
    231	s->insn_read	= mf6x4_ai_insn_read;
    232
    233	/* Analog Output subdevice */
    234	s = &dev->subdevices[1];
    235	s->type		= COMEDI_SUBD_AO;
    236	s->subdev_flags	= SDF_WRITABLE;
    237	s->n_chan	= 8;
    238	s->maxdata	= 0x3fff;
    239	s->range_table	= &range_bipolar10;
    240	s->insn_write	= mf6x4_ao_insn_write;
    241
    242	ret = comedi_alloc_subdev_readback(s);
    243	if (ret)
    244		return ret;
    245
    246	/* Digital Input subdevice */
    247	s = &dev->subdevices[2];
    248	s->type		= COMEDI_SUBD_DI;
    249	s->subdev_flags	= SDF_READABLE;
    250	s->n_chan	= 8;
    251	s->maxdata	= 1;
    252	s->range_table	= &range_digital;
    253	s->insn_bits	= mf6x4_di_insn_bits;
    254
    255	/* Digital Output subdevice */
    256	s = &dev->subdevices[3];
    257	s->type		= COMEDI_SUBD_DO;
    258	s->subdev_flags	= SDF_WRITABLE;
    259	s->n_chan	= 8;
    260	s->maxdata	= 1;
    261	s->range_table	= &range_digital;
    262	s->insn_bits	= mf6x4_do_insn_bits;
    263
    264	return 0;
    265}
    266
    267static void mf6x4_detach(struct comedi_device *dev)
    268{
    269	struct mf6x4_private *devpriv = dev->private;
    270
    271	if (devpriv) {
    272		if (devpriv->bar0_mem)
    273			iounmap(devpriv->bar0_mem);
    274		if (devpriv->bar2_mem)
    275			iounmap(devpriv->bar2_mem);
    276	}
    277	comedi_pci_detach(dev);
    278}
    279
    280static struct comedi_driver mf6x4_driver = {
    281	.driver_name    = "mf6x4",
    282	.module         = THIS_MODULE,
    283	.auto_attach    = mf6x4_auto_attach,
    284	.detach         = mf6x4_detach,
    285};
    286
    287static int mf6x4_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
    288{
    289	return comedi_pci_auto_config(dev, &mf6x4_driver, id->driver_data);
    290}
    291
    292static const struct pci_device_id mf6x4_pci_table[] = {
    293	{ PCI_VDEVICE(HUMUSOFT, 0x0634), BOARD_MF634 },
    294	{ PCI_VDEVICE(HUMUSOFT, 0x0624), BOARD_MF624 },
    295	{ 0 }
    296};
    297MODULE_DEVICE_TABLE(pci, mf6x4_pci_table);
    298
    299static struct pci_driver mf6x4_pci_driver = {
    300	.name           = "mf6x4",
    301	.id_table       = mf6x4_pci_table,
    302	.probe          = mf6x4_pci_probe,
    303	.remove         = comedi_pci_auto_unconfig,
    304};
    305
    306module_comedi_pci_driver(mf6x4_driver, mf6x4_pci_driver);
    307
    308MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
    309MODULE_DESCRIPTION("Comedi MF634 and MF624 DAQ cards driver");
    310MODULE_LICENSE("GPL");