162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * pcl724.c
462306a36Sopenharmony_ci * Comedi driver for 8255 based ISA and PC/104 DIO boards
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Michal Dobes <dobes@tesnet.cz>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * Driver: pcl724
1162306a36Sopenharmony_ci * Description: Comedi driver for 8255 based ISA DIO boards
1262306a36Sopenharmony_ci * Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731),
1362306a36Sopenharmony_ci *  [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio),
1462306a36Sopenharmony_ci *  [WinSystems] PCM-IO48 (pcmio48),
1562306a36Sopenharmony_ci *  [Diamond Systems] ONYX-MM-DIO (onyx-mm-dio)
1662306a36Sopenharmony_ci * Author: Michal Dobes <dobes@tesnet.cz>
1762306a36Sopenharmony_ci * Status: untested
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Configuration options:
2062306a36Sopenharmony_ci *   [0] - IO Base
2162306a36Sopenharmony_ci *   [1] - IRQ (not supported)
2262306a36Sopenharmony_ci *   [2] - number of DIO (pcl722 and acl7122 boards)
2362306a36Sopenharmony_ci *	   0, 144: 144 DIO configuration
2462306a36Sopenharmony_ci *	   1,  96:  96 DIO configuration
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <linux/module.h>
2862306a36Sopenharmony_ci#include <linux/comedi/comedidev.h>
2962306a36Sopenharmony_ci#include <linux/comedi/comedi_8255.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct pcl724_board {
3262306a36Sopenharmony_ci	const char *name;
3362306a36Sopenharmony_ci	unsigned int io_range;
3462306a36Sopenharmony_ci	unsigned int can_have96:1;
3562306a36Sopenharmony_ci	unsigned int is_pet48:1;
3662306a36Sopenharmony_ci	int numofports;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const struct pcl724_board boardtypes[] = {
4062306a36Sopenharmony_ci	{
4162306a36Sopenharmony_ci		.name		= "pcl724",
4262306a36Sopenharmony_ci		.io_range	= 0x04,
4362306a36Sopenharmony_ci		.numofports	= 1,	/* 24 DIO channels */
4462306a36Sopenharmony_ci	}, {
4562306a36Sopenharmony_ci		.name		= "pcl722",
4662306a36Sopenharmony_ci		.io_range	= 0x20,
4762306a36Sopenharmony_ci		.can_have96	= 1,
4862306a36Sopenharmony_ci		.numofports	= 6,	/* 144 (or 96) DIO channels */
4962306a36Sopenharmony_ci	}, {
5062306a36Sopenharmony_ci		.name		= "pcl731",
5162306a36Sopenharmony_ci		.io_range	= 0x08,
5262306a36Sopenharmony_ci		.numofports	= 2,	/* 48 DIO channels */
5362306a36Sopenharmony_ci	}, {
5462306a36Sopenharmony_ci		.name		= "acl7122",
5562306a36Sopenharmony_ci		.io_range	= 0x20,
5662306a36Sopenharmony_ci		.can_have96	= 1,
5762306a36Sopenharmony_ci		.numofports	= 6,	/* 144 (or 96) DIO channels */
5862306a36Sopenharmony_ci	}, {
5962306a36Sopenharmony_ci		.name		= "acl7124",
6062306a36Sopenharmony_ci		.io_range	= 0x04,
6162306a36Sopenharmony_ci		.numofports	= 1,	/* 24 DIO channels */
6262306a36Sopenharmony_ci	}, {
6362306a36Sopenharmony_ci		.name		= "pet48dio",
6462306a36Sopenharmony_ci		.io_range	= 0x02,
6562306a36Sopenharmony_ci		.is_pet48	= 1,
6662306a36Sopenharmony_ci		.numofports	= 2,	/* 48 DIO channels */
6762306a36Sopenharmony_ci	}, {
6862306a36Sopenharmony_ci		.name		= "pcmio48",
6962306a36Sopenharmony_ci		.io_range	= 0x08,
7062306a36Sopenharmony_ci		.numofports	= 2,	/* 48 DIO channels */
7162306a36Sopenharmony_ci	}, {
7262306a36Sopenharmony_ci		.name		= "onyx-mm-dio",
7362306a36Sopenharmony_ci		.io_range	= 0x10,
7462306a36Sopenharmony_ci		.numofports	= 2,	/* 48 DIO channels */
7562306a36Sopenharmony_ci	},
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic int pcl724_8255mapped_io(struct comedi_device *dev,
7962306a36Sopenharmony_ci				int dir, int port, int data,
8062306a36Sopenharmony_ci				unsigned long iobase)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	int movport = I8255_SIZE * (iobase >> 12);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	iobase &= 0x0fff;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	outb(port + movport, iobase);
8762306a36Sopenharmony_ci	if (dir) {
8862306a36Sopenharmony_ci		outb(data, iobase + 1);
8962306a36Sopenharmony_ci		return 0;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci	return inb(iobase + 1);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int pcl724_attach(struct comedi_device *dev,
9562306a36Sopenharmony_ci			 struct comedi_devconfig *it)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	const struct pcl724_board *board = dev->board_ptr;
9862306a36Sopenharmony_ci	struct comedi_subdevice *s;
9962306a36Sopenharmony_ci	unsigned long iobase;
10062306a36Sopenharmony_ci	unsigned int iorange;
10162306a36Sopenharmony_ci	int n_subdevices;
10262306a36Sopenharmony_ci	int ret;
10362306a36Sopenharmony_ci	int i;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	iorange = board->io_range;
10662306a36Sopenharmony_ci	n_subdevices = board->numofports;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Handle PCL-724 in 96 DIO configuration */
10962306a36Sopenharmony_ci	if (board->can_have96 &&
11062306a36Sopenharmony_ci	    (it->options[2] == 1 || it->options[2] == 96)) {
11162306a36Sopenharmony_ci		iorange = 0x10;
11262306a36Sopenharmony_ci		n_subdevices = 4;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	ret = comedi_request_region(dev, it->options[0], iorange);
11662306a36Sopenharmony_ci	if (ret)
11762306a36Sopenharmony_ci		return ret;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	ret = comedi_alloc_subdevices(dev, n_subdevices);
12062306a36Sopenharmony_ci	if (ret)
12162306a36Sopenharmony_ci		return ret;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	for (i = 0; i < dev->n_subdevices; i++) {
12462306a36Sopenharmony_ci		s = &dev->subdevices[i];
12562306a36Sopenharmony_ci		if (board->is_pet48) {
12662306a36Sopenharmony_ci			iobase = dev->iobase + (i * 0x1000);
12762306a36Sopenharmony_ci			ret = subdev_8255_init(dev, s, pcl724_8255mapped_io,
12862306a36Sopenharmony_ci					       iobase);
12962306a36Sopenharmony_ci		} else {
13062306a36Sopenharmony_ci			ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
13162306a36Sopenharmony_ci		}
13262306a36Sopenharmony_ci		if (ret)
13362306a36Sopenharmony_ci			return ret;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic struct comedi_driver pcl724_driver = {
14062306a36Sopenharmony_ci	.driver_name	= "pcl724",
14162306a36Sopenharmony_ci	.module		= THIS_MODULE,
14262306a36Sopenharmony_ci	.attach		= pcl724_attach,
14362306a36Sopenharmony_ci	.detach		= comedi_legacy_detach,
14462306a36Sopenharmony_ci	.board_name	= &boardtypes[0].name,
14562306a36Sopenharmony_ci	.num_names	= ARRAY_SIZE(boardtypes),
14662306a36Sopenharmony_ci	.offset		= sizeof(struct pcl724_board),
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_cimodule_comedi_driver(pcl724_driver);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciMODULE_AUTHOR("Comedi https://www.comedi.org");
15162306a36Sopenharmony_ciMODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards");
15262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
153