19dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch/*
29dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * GE PIO2 6U VME I/O Driver
39dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch *
49dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * Author: Martyn Welch <martyn.welch@ge.com>
59dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * Copyright 2009 GE Intelligent Platforms Embedded Systems, Inc.
69dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch *
79dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * This program is free software; you can redistribute  it and/or modify it
89dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * under  the terms of  the GNU General  Public License as published by the
99dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * Free Software Foundation;  either version 2 of the  License, or (at your
109dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * option) any later version.
119dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch */
129dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
139dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/version.h>
149dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/module.h>
159dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/moduleparam.h>
169dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/types.h>
179dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/kernel.h>
189dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/errno.h>
199dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/device.h>
209dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/ctype.h>
219dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/gpio.h>
229dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include <linux/slab.h>
239dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
249dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include "../vme.h"
259dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch#include "vme_pio2.h"
269dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
279dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
289dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic const char driver_name[] = "pio2";
299dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
309dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int bus[PIO2_CARDS_MAX];
319dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int bus_num;
329dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic long base[PIO2_CARDS_MAX];
339dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int base_num;
349dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int vector[PIO2_CARDS_MAX];
359dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int vector_num;
369dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int level[PIO2_CARDS_MAX];
379dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int level_num;
38eaa004a4ba3264d17d7e6882948a7980e14e9d20Gerard Snitselaarstatic char *variant[PIO2_CARDS_MAX];
399dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int variant_num;
409dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
41eaa004a4ba3264d17d7e6882948a7980e14e9d20Gerard Snitselaarstatic bool loopback;
429dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
439dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int pio2_match(struct vme_dev *);
449dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int __devinit pio2_probe(struct vme_dev *);
459dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int __devexit pio2_remove(struct vme_dev *);
469dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
479dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int pio2_get_led(struct pio2_card *card)
489dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
499dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Can't read hardware, state saved in structure */
509dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return card->led;
519dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
529dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
539dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int pio2_set_led(struct pio2_card *card, int state)
549dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
559dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	u8 reg;
569dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int retval;
579dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
589dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	reg = card->irq_level;
599dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
609dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Register state inverse of led state */
619dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (!state)
629dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		reg |= PIO2_LED;
639dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
649dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (loopback)
659dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		reg |= PIO2_LOOP;
669dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
679dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_master_write(card->window, &reg, 1, PIO2_REGS_CTRL);
689dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0)
699dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return retval;
709dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
719dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card->led = state ? 1 : 0;
729dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
739dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return 0;
749dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
759dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
769dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic void pio2_int(int level, int vector, void *ptr)
779dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
789dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int vec, i, channel, retval;
799dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	u8 reg;
809dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	struct pio2_card *card  = ptr;
819dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
829dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vec = vector & ~PIO2_VME_VECTOR_MASK;
839dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
849dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	switch (vec) {
859dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 0:
869dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_warn(&card->vdev->dev, "Spurious Interrupt\n");
879dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		break;
889dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 1:
899dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 2:
909dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 3:
919dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 4:
929dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		/* Channels 0 to 7 */
939dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		retval = vme_master_read(card->window, &reg, 1,
949dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			PIO2_REGS_INT_STAT[vec - 1]);
959dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		if (retval < 0) {
969dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			dev_err(&card->vdev->dev,
979dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch				"Unable to read IRQ status register\n");
989dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			return;
999dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		}
1009dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		for (i = 0; i < 8; i++) {
1019dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			channel = ((vec - 1) * 8) + i;
1029dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			if (reg & PIO2_CHANNEL_BIT[channel])
1039dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch				dev_info(&card->vdev->dev,
1049dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch					"Interrupt on I/O channel %d\n",
1059dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch					channel);
1069dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		}
1079dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		break;
1089dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 5:
1099dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 6:
1109dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 7:
1119dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 8:
1129dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 9:
1139dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	case 10:
1149dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		/* Counters are dealt with by their own handler */
1159dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev,
1169dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"Counter interrupt\n");
1179dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		break;
1189dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
1199dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
1209dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1219dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1229dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch/*
1239dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * We return whether this has been successful - this is used in the probe to
1249dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch * ensure we have a valid card.
1259dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch */
1269dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int pio2_reset_card(struct pio2_card *card)
1279dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
1289dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int retval = 0;
1299dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	u8 data = 0;
1309dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1319dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Clear main register*/
1329dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_master_write(card->window, &data, 1, PIO2_REGS_CTRL);
1339dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0)
1349dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return retval;
1359dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1369dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Clear VME vector */
1379dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_master_write(card->window, &data, 1, PIO2_REGS_VME_VECTOR);
1389dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0)
1399dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return retval;
1409dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1419dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Reset GPIO */
1429dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = pio2_gpio_reset(card);
1439dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0)
1449dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return retval;
1459dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1469dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Reset counters */
1479dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = pio2_cntr_reset(card);
1489dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0)
1499dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return retval;
1509dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1519dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return 0;
1529dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
1539dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1549dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic struct vme_driver pio2_driver = {
1559dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	.name = driver_name,
1569dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	.match = pio2_match,
1579dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	.probe = pio2_probe,
1589dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	.remove = __devexit_p(pio2_remove),
1599dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch};
1609dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1619dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1629dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int __init pio2_init(void)
1639dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
1649dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int retval = 0;
1659dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1669dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (bus_num == 0) {
1679dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		printk(KERN_ERR "%s: No cards, skipping registration\n",
1689dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			driver_name);
1699dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_nocard;
1709dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
1719dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1729dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (bus_num > PIO2_CARDS_MAX) {
1739dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		printk(KERN_ERR
1749dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"%s: Driver only able to handle %d PIO2 Cards\n",
1759dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			driver_name, PIO2_CARDS_MAX);
1769dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		bus_num = PIO2_CARDS_MAX;
1779dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
1789dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1799dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Register the PIO2 driver */
1809dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_register_driver(&pio2_driver, bus_num);
1819dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval != 0)
1829dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_reg;
1839dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1849dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return retval;
1859dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1869dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_reg:
1879dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_nocard:
1889dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return retval;
1899dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
1909dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1919dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int pio2_match(struct vme_dev *vdev)
1929dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
1939dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
1949dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (vdev->num >= bus_num) {
1959dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&vdev->dev,
1969dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"The enumeration of the VMEbus to which the board is connected must be specified");
1979dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return 0;
1989dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
1999dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2009dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (vdev->num >= base_num) {
2019dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&vdev->dev,
2029dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"The VME address for the cards registers must be specified");
2039dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return 0;
2049dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
2059dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2069dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (vdev->num >= vector_num) {
2079dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&vdev->dev,
2089dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"The IRQ vector used by the card must be specified");
2099dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return 0;
2109dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
2119dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2129dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (vdev->num >= level_num) {
2139dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&vdev->dev,
2149dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"The IRQ level used by the card must be specified");
2159dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return 0;
2169dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
2179dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2189dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (vdev->num >= variant_num) {
2199dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&vdev->dev, "The variant of the card must be specified");
2209dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return 0;
2219dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
2229dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2239dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return 1;
2249dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
2259dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2269dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int __devinit pio2_probe(struct vme_dev *vdev)
2279dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
2289dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	struct pio2_card *card;
2299dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int retval;
2309dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int i;
2319dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	u8 reg;
2329dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int vec;
2339dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2349dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card = kzalloc(sizeof(struct pio2_card), GFP_KERNEL);
2359dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (card == NULL) {
2369dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&vdev->dev, "Unable to allocate card structure\n");
2379dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		retval = -ENOMEM;
2389dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_struct;
2399dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
2409dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2419dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card->id = vdev->num;
2429dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card->bus = bus[card->id];
2439dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card->base = base[card->id];
2449dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card->irq_vector = vector[card->id];
2459dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card->irq_level = level[card->id] & PIO2_VME_INT_MASK;
2469dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	strncpy(card->variant, variant[card->id], PIO2_VARIANT_LENGTH);
2479dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card->vdev = vdev;
2489dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2499dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	for (i = 0; i < PIO2_VARIANT_LENGTH; i++) {
2509dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2519dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		if (isdigit(card->variant[i]) == 0) {
2529dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			dev_err(&card->vdev->dev, "Variant invalid\n");
2539dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			retval = -EINVAL;
2549dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			goto err_variant;
2559dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		}
2569dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
2579dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2589dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/*
2599dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * Bottom 4 bits of VME interrupt vector used to determine source,
2609dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * provided vector should only use upper 4 bits.
2619dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 */
2629dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (card->irq_vector & ~PIO2_VME_VECTOR_MASK) {
2639dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev,
2649dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"Invalid VME IRQ Vector, vector must not use lower 4 bits\n");
2659dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		retval = -EINVAL;
2669dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_vector;
2679dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
2689dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
2699dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/*
2709dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * There is no way to determine the build variant or whether each bank
2719dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * is input, output or both at run time. The inputs are also inverted
2729dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * if configured as both.
2739dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 *
2749dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * We pass in the board variant and use that to determine the
2759dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * configuration of the banks.
2769dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 */
2779dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	for (i = 1; i < PIO2_VARIANT_LENGTH; i++) {
2789dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		switch (card->variant[i]) {
2799dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '0':
2809dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			card->bank[i-1].config = NOFIT;
2819dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			break;
2829dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '1':
2839dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '2':
2849dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '3':
2859dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '4':
2869dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			card->bank[i-1].config = INPUT;
2879dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			break;
2889dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '5':
2899dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			card->bank[i-1].config = OUTPUT;
2909dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			break;
2919dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '6':
2929dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '7':
2939dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '8':
2949dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		case '9':
2959dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			card->bank[i-1].config = BOTH;
2969dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			break;
2979dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		}
2989dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
2999dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3009dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Get a master window and position over regs */
3019dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	card->window = vme_master_request(vdev, VME_A24, VME_SCT, VME_D16);
3029dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (card->window == NULL) {
3039dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev,
3049dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"Unable to assign VME master resource\n");
3059dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		retval = -EIO;
3069dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_window;
3079dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
3089dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3099dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_master_set(card->window, 1, card->base, 0x10000, VME_A24,
3109dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		(VME_SCT | VME_USER | VME_DATA), VME_D16);
3119dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval) {
3129dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev,
3139dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"Unable to configure VME master resource\n");
3149dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_set;
3159dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
3169dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3179dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/*
3189dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * There is also no obvious register which we can probe to determine
3199dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * whether the provided base is valid. If we can read the "ID Register"
3209dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * offset and the reset function doesn't error, assume we have a valid
3219dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * location.
3229dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 */
3239dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_master_read(card->window, &reg, 1, PIO2_REGS_ID);
3249dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0) {
3259dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev, "Unable to read from device\n");
3269dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_read;
3279dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
3289dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3299dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	dev_dbg(&card->vdev->dev, "ID Register:%x\n", reg);
3309dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3319dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/*
3329dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * Ensure all the I/O is cleared. We can't read back the states, so
3339dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * this is the only method we have to ensure that the I/O is in a known
3349dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 * state.
3359dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 */
3369dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = pio2_reset_card(card);
3379dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval) {
3389dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev,
3399dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"Failed to reset card, is location valid?");
3409dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		retval = -ENODEV;
3419dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_reset;
3429dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
3439dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3449dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Configure VME Interrupts */
3459dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	reg = card->irq_level;
3469dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (pio2_get_led(card))
3479dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		reg |= PIO2_LED;
3489dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (loopback)
3499dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		reg |= PIO2_LOOP;
3509dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_master_write(card->window, &reg, 1, PIO2_REGS_CTRL);
3519dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0)
3529dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return retval;
3539dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3549dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Set VME vector */
3559dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_master_write(card->window, &card->irq_vector, 1,
3569dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		PIO2_REGS_VME_VECTOR);
3579dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0)
3589dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		return retval;
3599dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3609dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Attach spurious interrupt handler. */
3619dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vec = card->irq_vector | PIO2_VME_VECTOR_SPUR;
3629dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3639dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = vme_irq_request(vdev, card->irq_level, vec,
3649dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		&pio2_int, (void *)card);
3659dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0) {
3669dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev,
3679dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"Unable to attach VME interrupt vector0x%x, level 0x%x\n",
3689dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			 vec, card->irq_level);
3699dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_irq;
3709dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
3719dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3729dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Attach GPIO interrupt handlers. */
3739dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	for (i = 0; i < 4; i++) {
3749dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vec = card->irq_vector | PIO2_VECTOR_BANK[i];
3759dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3769dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		retval = vme_irq_request(vdev, card->irq_level, vec,
3779dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			&pio2_int, (void *)card);
3789dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		if (retval < 0) {
3799dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			dev_err(&card->vdev->dev,
3809dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch				"Unable to attach VME interrupt vector0x%x, level 0x%x\n",
3819dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch				 vec, card->irq_level);
3829dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			goto err_gpio_irq;
3839dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		}
3849dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
3859dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3869dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Attach counter interrupt handlers. */
3879dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	for (i = 0; i < 6; i++) {
3889dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vec = card->irq_vector | PIO2_VECTOR_CNTR[i];
3899dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
3909dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		retval = vme_irq_request(vdev, card->irq_level, vec,
3919dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			&pio2_int, (void *)card);
3929dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		if (retval < 0) {
3939dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			dev_err(&card->vdev->dev,
3949dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch				"Unable to attach VME interrupt vector0x%x, level 0x%x\n",
3959dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch				vec, card->irq_level);
3969dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			goto err_cntr_irq;
3979dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		}
3989dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
3999dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4009dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Register IO */
4019dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = pio2_gpio_init(card);
4029dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0) {
4039dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev,
4049dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch			"Unable to register with GPIO framework\n");
4059dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_gpio;
4069dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
4079dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4089dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	/* Set LED - This also sets interrupt level */
4099dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	retval = pio2_set_led(card, 0);
4109dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	if (retval < 0) {
4119dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		dev_err(&card->vdev->dev, "Unable to set LED\n");
4129dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		goto err_led;
4139dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
4149dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4159dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	dev_set_drvdata(&card->vdev->dev, card);
4169dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4179dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	dev_info(&card->vdev->dev,
4189dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		"PIO2 (variant %s) configured at 0x%lx\n", card->variant,
4199dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		card->base);
4209dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4219dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return 0;
4229dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4239dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_led:
4249dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	pio2_gpio_exit(card);
4259dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_gpio:
4269dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	i = 6;
4279dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_cntr_irq:
4289dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	while (i > 0) {
4299dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		i--;
4309dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vec = card->irq_vector | PIO2_VECTOR_CNTR[i];
4319dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vme_irq_free(vdev, card->irq_level, vec);
4329dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
4339dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4349dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	i = 4;
4359dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_gpio_irq:
4369dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	while (i > 0) {
4379dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		i--;
4389dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vec = card->irq_vector | PIO2_VECTOR_BANK[i];
4399dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vme_irq_free(vdev, card->irq_level, vec);
4409dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
4419dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4429dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vec = (card->irq_vector & PIO2_VME_VECTOR_MASK) | PIO2_VME_VECTOR_SPUR;
4439dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vme_irq_free(vdev, card->irq_level, vec);
4449dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_irq:
4459dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	 pio2_reset_card(card);
4469dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_reset:
4479dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_read:
4489dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vme_master_set(card->window, 0, 0, 0, VME_A16, 0, VME_D16);
4499dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_set:
4509dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vme_master_free(card->window);
4519dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_window:
4529dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_vector:
4539dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_variant:
4549dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	kfree(card);
4559dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welcherr_struct:
4569dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return retval;
4579dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
4589dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4599dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic int __devexit pio2_remove(struct vme_dev *vdev)
4609dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
4619dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int vec;
4629dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	int i;
4639dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4649dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	struct pio2_card *card = dev_get_drvdata(&vdev->dev);
4659dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4669dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	pio2_gpio_exit(card);
4679dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4689dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	for (i = 0; i < 6; i++) {
4699dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vec = card->irq_vector | PIO2_VECTOR_CNTR[i];
4709dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vme_irq_free(vdev, card->irq_level, vec);
4719dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
4729dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4739dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	for (i = 0; i < 4; i++) {
4749dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vec = card->irq_vector | PIO2_VECTOR_BANK[i];
4759dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch		vme_irq_free(vdev, card->irq_level, vec);
4769dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	}
4779dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4789dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vec = (card->irq_vector & PIO2_VME_VECTOR_MASK) | PIO2_VME_VECTOR_SPUR;
4799dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vme_irq_free(vdev, card->irq_level, vec);
4809dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4819dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	pio2_reset_card(card);
4829dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4839dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vme_master_set(card->window, 0, 0, 0, VME_A16, 0, VME_D16);
4849dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4859dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vme_master_free(card->window);
4869dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4879dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	kfree(card);
4889dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4899dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	return 0;
4909dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
4919dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4929dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchstatic void __exit pio2_exit(void)
4939dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch{
4949dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch	vme_unregister_driver(&pio2_driver);
4959dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch}
4969dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4979dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
4989dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch/* These are required for each board */
4999dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the board is connected");
5009dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchmodule_param_array(bus, int, &bus_num, S_IRUGO);
5019dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
5029dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_PARM_DESC(base, "Base VME address for PIO2 Registers");
5039dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchmodule_param_array(base, long, &base_num, S_IRUGO);
5049dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
5059dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_PARM_DESC(vector, "VME IRQ Vector (Lower 4 bits masked)");
5069dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchmodule_param_array(vector, int, &vector_num, S_IRUGO);
5079dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
5089dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_PARM_DESC(level, "VME IRQ Level");
5099dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchmodule_param_array(level, int, &level_num, S_IRUGO);
5109dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
5119dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_PARM_DESC(variant, "Last 4 characters of PIO2 board variant");
5129dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchmodule_param_array(variant, charp, &variant_num, S_IRUGO);
5139dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
5149dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch/* This is for debugging */
5159dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_PARM_DESC(loopback, "Enable loopback mode on all cards");
5169dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchmodule_param(loopback, bool, S_IRUGO);
5179dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
5189dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_DESCRIPTION("GE PIO2 6U VME I/O Driver");
5199dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
5209dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn WelchMODULE_LICENSE("GPL");
5219dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
5229dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchmodule_init(pio2_init);
5239dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welchmodule_exit(pio2_exit);
5249dc367bc4c76cc4c6595e9fab6a5a02523b537c6Martyn Welch
525