xref: /openbmc/linux/drivers/macintosh/via-macii.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Device driver for the via ADB on (many) Mac II-class machines
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Based on the original ADB keyboard handler Copyright (c) 1997 Alan Cox
61da177e4SLinus Torvalds  * Also derived from code Copyright (C) 1996 Paul Mackerras.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * With various updates provided over the years by Michael Schmitz,
91da177e4SLinus Torvalds  * Guideo Koerber and others.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Rewrite for Unified ADB by Joshua M. Thompson (funaho@jurai.org)
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
141da177e4SLinus Torvalds  * 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org>
151da177e4SLinus Torvalds  *            - Big overhaul, should actually work now.
16d0c2c269SFinn Thain  * 2006-12-31 Finn Thain - Another overhaul.
17d95fd5fcSFinn Thain  *
18d95fd5fcSFinn Thain  * Suggested reading:
19d95fd5fcSFinn Thain  *   Inside Macintosh, ch. 5 ADB Manager
20d95fd5fcSFinn Thain  *   Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus
21d95fd5fcSFinn Thain  *   Rockwell R6522 VIA datasheet
22d95fd5fcSFinn Thain  *
23d95fd5fcSFinn Thain  * Apple's "ADB Analyzer" bus sniffer is invaluable:
24d95fd5fcSFinn Thain  *   ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/
251da177e4SLinus Torvalds  */
261da177e4SLinus Torvalds #include <linux/types.h>
271da177e4SLinus Torvalds #include <linux/errno.h>
281da177e4SLinus Torvalds #include <linux/kernel.h>
291da177e4SLinus Torvalds #include <linux/delay.h>
301da177e4SLinus Torvalds #include <linux/adb.h>
311da177e4SLinus Torvalds #include <linux/interrupt.h>
321da177e4SLinus Torvalds #include <linux/init.h>
331da177e4SLinus Torvalds #include <asm/macintosh.h>
341da177e4SLinus Torvalds #include <asm/macints.h>
351da177e4SLinus Torvalds #include <asm/mac_via.h>
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds static volatile unsigned char *via;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds /* VIA registers - spaced 0x200 bytes apart */
401da177e4SLinus Torvalds #define RS		0x200		/* skip between registers */
411da177e4SLinus Torvalds #define B		0		/* B-side data */
421da177e4SLinus Torvalds #define A		RS		/* A-side data */
431da177e4SLinus Torvalds #define DIRB		(2*RS)		/* B-side direction (1=output) */
441da177e4SLinus Torvalds #define DIRA		(3*RS)		/* A-side direction (1=output) */
451da177e4SLinus Torvalds #define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
461da177e4SLinus Torvalds #define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
471da177e4SLinus Torvalds #define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
481da177e4SLinus Torvalds #define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
491da177e4SLinus Torvalds #define T2CL		(8*RS)		/* Timer 2 ctr/latch (low 8 bits) */
501da177e4SLinus Torvalds #define T2CH		(9*RS)		/* Timer 2 counter (high 8 bits) */
511da177e4SLinus Torvalds #define SR		(10*RS)		/* Shift register */
521da177e4SLinus Torvalds #define ACR		(11*RS)		/* Auxiliary control register */
531da177e4SLinus Torvalds #define PCR		(12*RS)		/* Peripheral control register */
541da177e4SLinus Torvalds #define IFR		(13*RS)		/* Interrupt flag register */
551da177e4SLinus Torvalds #define IER		(14*RS)		/* Interrupt enable register */
561da177e4SLinus Torvalds #define ANH		(15*RS)		/* A-side data, no handshake */
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds /* Bits in B data register: all active low */
59d95fd5fcSFinn Thain #define CTLR_IRQ	0x08		/* Controller rcv status (input) */
601da177e4SLinus Torvalds #define ST_MASK		0x30		/* mask for selecting ADB state bits */
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds /* Bits in ACR */
631da177e4SLinus Torvalds #define SR_CTRL		0x1c		/* Shift register control bits */
641da177e4SLinus Torvalds #define SR_EXT		0x0c		/* Shift on external clock */
651da177e4SLinus Torvalds #define SR_OUT		0x10		/* Shift out if 1 */
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds /* Bits in IFR and IER */
681da177e4SLinus Torvalds #define IER_SET		0x80		/* set bits in IER */
691da177e4SLinus Torvalds #define IER_CLR		0		/* clear bits in IER */
701da177e4SLinus Torvalds #define SR_INT		0x04		/* Shift register full/empty */
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds /* ADB transaction states according to GMHW */
731da177e4SLinus Torvalds #define ST_CMD		0x00		/* ADB state: command byte */
741da177e4SLinus Torvalds #define ST_EVEN		0x10		/* ADB state: even data byte */
751da177e4SLinus Torvalds #define ST_ODD		0x20		/* ADB state: odd data byte */
761da177e4SLinus Torvalds #define ST_IDLE		0x30		/* ADB state: idle, nothing to send */
771da177e4SLinus Torvalds 
78f93bfeb5SFinn Thain /* ADB command byte structure */
79f93bfeb5SFinn Thain #define ADDR_MASK	0xF0
80f93bfeb5SFinn Thain #define CMD_MASK	0x0F
81b4d76c28SFinn Thain #define OP_MASK		0x0C
82b4d76c28SFinn Thain #define TALK		0x0C
83f93bfeb5SFinn Thain 
841da177e4SLinus Torvalds static int macii_init_via(void);
851da177e4SLinus Torvalds static void macii_start(void);
867d12e780SDavid Howells static irqreturn_t macii_interrupt(int irq, void *arg);
871da177e4SLinus Torvalds static void macii_queue_poll(void);
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds static int macii_probe(void);
901da177e4SLinus Torvalds static int macii_init(void);
911da177e4SLinus Torvalds static int macii_send_request(struct adb_request *req, int sync);
921da177e4SLinus Torvalds static int macii_write(struct adb_request *req);
931da177e4SLinus Torvalds static int macii_autopoll(int devs);
941da177e4SLinus Torvalds static void macii_poll(void);
951da177e4SLinus Torvalds static int macii_reset_bus(void);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds struct adb_driver via_macii_driver = {
983a52f6f9SFinn Thain 	.name         = "Mac II",
993a52f6f9SFinn Thain 	.probe        = macii_probe,
1003a52f6f9SFinn Thain 	.init         = macii_init,
1013a52f6f9SFinn Thain 	.send_request = macii_send_request,
1023a52f6f9SFinn Thain 	.autopoll     = macii_autopoll,
1033a52f6f9SFinn Thain 	.poll         = macii_poll,
1043a52f6f9SFinn Thain 	.reset_bus    = macii_reset_bus,
1051da177e4SLinus Torvalds };
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds static enum macii_state {
1081da177e4SLinus Torvalds 	idle,
1091da177e4SLinus Torvalds 	sending,
1101da177e4SLinus Torvalds 	reading,
1111da177e4SLinus Torvalds } macii_state;
1121da177e4SLinus Torvalds 
113d95fd5fcSFinn Thain static struct adb_request *current_req; /* first request struct in the queue */
114d95fd5fcSFinn Thain static struct adb_request *last_req;     /* last request struct in the queue */
115d95fd5fcSFinn Thain static unsigned char reply_buf[16];        /* storage for autopolled replies */
116eb4da4ceSFinn Thain static unsigned char *reply_ptr;     /* next byte in reply_buf or req->reply */
117f87a1625SFinn Thain static bool reading_reply;       /* store reply in reply_buf else req->reply */
118d95fd5fcSFinn Thain static int data_index;      /* index of the next byte to send from req->data */
119d95fd5fcSFinn Thain static int reply_len; /* number of bytes received in reply_buf or req->reply */
120d95fd5fcSFinn Thain static int status;          /* VIA's ADB status bits captured upon interrupt */
121b4d76c28SFinn Thain static bool bus_timeout;                   /* no data was sent by the device */
122b4d76c28SFinn Thain static bool srq_asserted;    /* have to poll for the device that asserted it */
123f93bfeb5SFinn Thain static u8 last_cmd;              /* the most recent command byte transmitted */
124b4d76c28SFinn Thain static u8 last_talk_cmd;    /* the most recent Talk command byte transmitted */
125f93bfeb5SFinn Thain static u8 last_poll_cmd; /* the most recent Talk R0 command byte transmitted */
1265c0c15a1SFinn Thain static unsigned int autopoll_devs;  /* bits set are device addresses to poll */
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds /* Check for MacII style ADB */
macii_probe(void)1291da177e4SLinus Torvalds static int macii_probe(void)
1301da177e4SLinus Torvalds {
13147fd2060SFinn Thain 	if (macintosh_config->adb_type != MAC_ADB_II)
13247fd2060SFinn Thain 		return -ENODEV;
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	via = via1;
1351da177e4SLinus Torvalds 
136351e5ad3SFinn Thain 	pr_info("adb: Mac II ADB Driver v1.0 for Unified ADB\n");
1371da177e4SLinus Torvalds 	return 0;
1381da177e4SLinus Torvalds }
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds /* Initialize the driver */
macii_init(void)1413327e58aSFinn Thain static int macii_init(void)
1421da177e4SLinus Torvalds {
1431da177e4SLinus Torvalds 	int err;
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 	err = macii_init_via();
14647fd2060SFinn Thain 	if (err)
147*d43a8c7eSFinn Thain 		return err;
1481da177e4SLinus Torvalds 
1495a239453SGeert Uytterhoeven 	err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB",
1501da177e4SLinus Torvalds 			  macii_interrupt);
15147fd2060SFinn Thain 	if (err)
152*d43a8c7eSFinn Thain 		return err;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	macii_state = idle;
155*d43a8c7eSFinn Thain 	return 0;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds /* initialize the hardware */
macii_init_via(void)1591da177e4SLinus Torvalds static int macii_init_via(void)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds 	unsigned char x;
1621da177e4SLinus Torvalds 
163d95fd5fcSFinn Thain 	/* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */
164d95fd5fcSFinn Thain 	via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	/* Set up state: idle */
1671da177e4SLinus Torvalds 	via[B] |= ST_IDLE;
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds 	/* Shift register on input */
1701da177e4SLinus Torvalds 	via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	/* Wipe any pending data and int */
1731da177e4SLinus Torvalds 	x = via[SR];
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	return 0;
1761da177e4SLinus Torvalds }
1771da177e4SLinus Torvalds 
178d95fd5fcSFinn Thain /* Send an ADB poll (Talk Register 0 command prepended to the request queue) */
macii_queue_poll(void)1791da177e4SLinus Torvalds static void macii_queue_poll(void)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds 	static struct adb_request req;
182f93bfeb5SFinn Thain 	unsigned char poll_command;
183f93bfeb5SFinn Thain 	unsigned int poll_addr;
1841da177e4SLinus Torvalds 
185f93bfeb5SFinn Thain 	/* This only polls devices in the autopoll list, which assumes that
186f93bfeb5SFinn Thain 	 * unprobed devices never assert SRQ. That could happen if a device was
187f93bfeb5SFinn Thain 	 * plugged in after the adb bus scan. Unplugging it again will resolve
188f93bfeb5SFinn Thain 	 * the problem. This behaviour is similar to MacOS.
189f93bfeb5SFinn Thain 	 */
19047fd2060SFinn Thain 	if (!autopoll_devs)
19147fd2060SFinn Thain 		return;
1921da177e4SLinus Torvalds 
193f93bfeb5SFinn Thain 	/* The device most recently polled may not be the best device to poll
194f93bfeb5SFinn Thain 	 * right now. Some other device(s) may have signalled SRQ (the active
195f93bfeb5SFinn Thain 	 * device won't do that). Or the autopoll list may have been changed.
196f93bfeb5SFinn Thain 	 * Try polling the next higher address.
197f93bfeb5SFinn Thain 	 */
198f93bfeb5SFinn Thain 	poll_addr = (last_poll_cmd & ADDR_MASK) >> 4;
199f93bfeb5SFinn Thain 	if ((srq_asserted && last_cmd == last_poll_cmd) ||
200f93bfeb5SFinn Thain 	    !(autopoll_devs & (1 << poll_addr))) {
201f93bfeb5SFinn Thain 		unsigned int higher_devs;
2021da177e4SLinus Torvalds 
203f93bfeb5SFinn Thain 		higher_devs = autopoll_devs & -(1 << (poll_addr + 1));
204f93bfeb5SFinn Thain 		poll_addr = ffs(higher_devs ? higher_devs : autopoll_devs) - 1;
205f93bfeb5SFinn Thain 	}
206f93bfeb5SFinn Thain 
207f93bfeb5SFinn Thain 	/* Send a Talk Register 0 command */
208f93bfeb5SFinn Thain 	poll_command = ADB_READREG(poll_addr, 0);
209f93bfeb5SFinn Thain 
210f93bfeb5SFinn Thain 	/* No need to repeat this Talk command. The transceiver will do that
211f93bfeb5SFinn Thain 	 * as long as it is idle.
212f93bfeb5SFinn Thain 	 */
213f93bfeb5SFinn Thain 	if (poll_command == last_cmd)
214f93bfeb5SFinn Thain 		return;
215f93bfeb5SFinn Thain 
216f93bfeb5SFinn Thain 	adb_request(&req, NULL, ADBREQ_NOSEND, 1, poll_command);
2171da177e4SLinus Torvalds 
218d95fd5fcSFinn Thain 	req.sent = 0;
219d95fd5fcSFinn Thain 	req.complete = 0;
220d95fd5fcSFinn Thain 	req.reply_len = 0;
2211da177e4SLinus Torvalds 	req.next = current_req;
2221da177e4SLinus Torvalds 
223f93bfeb5SFinn Thain 	if (WARN_ON(current_req)) {
224d95fd5fcSFinn Thain 		current_req = &req;
2251da177e4SLinus Torvalds 	} else {
226d95fd5fcSFinn Thain 		current_req = &req;
227d95fd5fcSFinn Thain 		last_req = &req;
2281da177e4SLinus Torvalds 	}
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds /* Send an ADB request; if sync, poll out the reply 'till it's done */
macii_send_request(struct adb_request * req,int sync)2321da177e4SLinus Torvalds static int macii_send_request(struct adb_request *req, int sync)
2331da177e4SLinus Torvalds {
234d95fd5fcSFinn Thain 	int err;
2351da177e4SLinus Torvalds 
236d95fd5fcSFinn Thain 	err = macii_write(req);
2375ce6185cSFinn Thain 	if (err)
2385ce6185cSFinn Thain 		return err;
239d95fd5fcSFinn Thain 
2405ce6185cSFinn Thain 	if (sync)
2415f93d708SFinn Thain 		while (!req->complete)
242d95fd5fcSFinn Thain 			macii_poll();
243d95fd5fcSFinn Thain 
2445ce6185cSFinn Thain 	return 0;
245d95fd5fcSFinn Thain }
246d95fd5fcSFinn Thain 
247d95fd5fcSFinn Thain /* Send an ADB request (append to request queue) */
macii_write(struct adb_request * req)248d95fd5fcSFinn Thain static int macii_write(struct adb_request *req)
249d95fd5fcSFinn Thain {
2505ce6185cSFinn Thain 	unsigned long flags;
2515ce6185cSFinn Thain 
2521da177e4SLinus Torvalds 	if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) {
2531da177e4SLinus Torvalds 		req->complete = 1;
2541da177e4SLinus Torvalds 		return -EINVAL;
2551da177e4SLinus Torvalds 	}
2561da177e4SLinus Torvalds 
257a5d361fcSAl Viro 	req->next = NULL;
2581da177e4SLinus Torvalds 	req->sent = 0;
2591da177e4SLinus Torvalds 	req->complete = 0;
2601da177e4SLinus Torvalds 	req->reply_len = 0;
2611da177e4SLinus Torvalds 
2625ce6185cSFinn Thain 	local_irq_save(flags);
2635ce6185cSFinn Thain 
2641da177e4SLinus Torvalds 	if (current_req != NULL) {
2651da177e4SLinus Torvalds 		last_req->next = req;
2661da177e4SLinus Torvalds 		last_req = req;
2671da177e4SLinus Torvalds 	} else {
2681da177e4SLinus Torvalds 		current_req = req;
2691da177e4SLinus Torvalds 		last_req = req;
27047fd2060SFinn Thain 		if (macii_state == idle)
27147fd2060SFinn Thain 			macii_start();
2721da177e4SLinus Torvalds 	}
2735ce6185cSFinn Thain 
2745ce6185cSFinn Thain 	local_irq_restore(flags);
2755ce6185cSFinn Thain 
2761da177e4SLinus Torvalds 	return 0;
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds /* Start auto-polling */
macii_autopoll(int devs)2801da177e4SLinus Torvalds static int macii_autopoll(int devs)
2811da177e4SLinus Torvalds {
282d95fd5fcSFinn Thain 	unsigned long flags;
283d95fd5fcSFinn Thain 
28459ea38f6SFinn Thain 	local_irq_save(flags);
28559ea38f6SFinn Thain 
286d95fd5fcSFinn Thain 	/* bit 1 == device 1, and so on. */
2875c0c15a1SFinn Thain 	autopoll_devs = (unsigned int)devs & 0xFFFE;
288d95fd5fcSFinn Thain 
289f93bfeb5SFinn Thain 	if (!current_req) {
290f93bfeb5SFinn Thain 		macii_queue_poll();
291f93bfeb5SFinn Thain 		if (current_req && macii_state == idle)
292f93bfeb5SFinn Thain 			macii_start();
293d95fd5fcSFinn Thain 	}
294d95fd5fcSFinn Thain 
295d95fd5fcSFinn Thain 	local_irq_restore(flags);
296d95fd5fcSFinn Thain 
2971da177e4SLinus Torvalds 	return 0;
2981da177e4SLinus Torvalds }
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds /* Prod the chip without interrupts */
macii_poll(void)3011da177e4SLinus Torvalds static void macii_poll(void)
3021da177e4SLinus Torvalds {
303d95fd5fcSFinn Thain 	macii_interrupt(0, NULL);
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds /* Reset the bus */
macii_reset_bus(void)3071da177e4SLinus Torvalds static int macii_reset_bus(void)
3081da177e4SLinus Torvalds {
309046ace82SFinn Thain 	struct adb_request req;
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	/* Command = 0, Address = ignored */
312b52dce87SFinn Thain 	adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET);
313b52dce87SFinn Thain 	macii_send_request(&req, 1);
3141da177e4SLinus Torvalds 
315d95fd5fcSFinn Thain 	/* Don't want any more requests during the Global Reset low time. */
316d95fd5fcSFinn Thain 	udelay(3000);
317d95fd5fcSFinn Thain 
3181da177e4SLinus Torvalds 	return 0;
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds /* Start sending ADB packet */
macii_start(void)3221da177e4SLinus Torvalds static void macii_start(void)
3231da177e4SLinus Torvalds {
3241da177e4SLinus Torvalds 	struct adb_request *req;
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 	req = current_req;
3271da177e4SLinus Torvalds 
328d95fd5fcSFinn Thain 	/* Now send it. Be careful though, that first byte of the request
329d95fd5fcSFinn Thain 	 * is actually ADB_PACKET; the real data begins at index 1!
330d95fd5fcSFinn Thain 	 * And req->nbytes is the number of bytes of real data plus one.
3311da177e4SLinus Torvalds 	 */
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	/* Output mode */
3341da177e4SLinus Torvalds 	via[ACR] |= SR_OUT;
3351da177e4SLinus Torvalds 	/* Load data */
3361da177e4SLinus Torvalds 	via[SR] = req->data[1];
3371da177e4SLinus Torvalds 	/* set ADB state to 'command' */
3381da177e4SLinus Torvalds 	via[B] = (via[B] & ~ST_MASK) | ST_CMD;
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	macii_state = sending;
3411da177e4SLinus Torvalds 	data_index = 2;
342b4d76c28SFinn Thain 
343b4d76c28SFinn Thain 	bus_timeout = false;
344b4d76c28SFinn Thain 	srq_asserted = false;
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds /*
348d95fd5fcSFinn Thain  * The notorious ADB interrupt handler - does all of the protocol handling.
349d95fd5fcSFinn Thain  * Relies on the ADB controller sending and receiving data, thereby
350d95fd5fcSFinn Thain  * generating shift register interrupts (SR_INT) for us. This means there has
351d95fd5fcSFinn Thain  * to be activity on the ADB bus. The chip will poll to achieve this.
3521da177e4SLinus Torvalds  *
353b4d76c28SFinn Thain  * The VIA Port B output signalling works as follows. After the ADB transceiver
354b4d76c28SFinn Thain  * sees a transition on the PB4 and PB5 lines it will crank over the VIA shift
355b4d76c28SFinn Thain  * register which eventually raises the SR_INT interrupt. The PB4/PB5 outputs
356b4d76c28SFinn Thain  * are toggled with each byte as the ADB transaction progresses.
357b4d76c28SFinn Thain  *
358b4d76c28SFinn Thain  * Request with no reply expected (and empty transceiver buffer):
359b4d76c28SFinn Thain  *     CMD -> IDLE
360b4d76c28SFinn Thain  * Request with expected reply packet (or with buffered autopoll packet):
361b4d76c28SFinn Thain  *     CMD -> EVEN -> ODD -> EVEN -> ... -> IDLE
362b4d76c28SFinn Thain  * Unsolicited packet:
363b4d76c28SFinn Thain  *     IDLE -> EVEN -> ODD -> EVEN -> ... -> IDLE
3641da177e4SLinus Torvalds  */
macii_interrupt(int irq,void * arg)3657d12e780SDavid Howells static irqreturn_t macii_interrupt(int irq, void *arg)
3661da177e4SLinus Torvalds {
367d95fd5fcSFinn Thain 	int x;
3681da177e4SLinus Torvalds 	struct adb_request *req;
3695ce6185cSFinn Thain 	unsigned long flags;
3705ce6185cSFinn Thain 
3715ce6185cSFinn Thain 	local_irq_save(flags);
3721da177e4SLinus Torvalds 
373d95fd5fcSFinn Thain 	if (!arg) {
374d95fd5fcSFinn Thain 		/* Clear the SR IRQ flag when polling. */
375d95fd5fcSFinn Thain 		if (via[IFR] & SR_INT)
376d95fd5fcSFinn Thain 			via[IFR] = SR_INT;
3775ce6185cSFinn Thain 		else {
3785ce6185cSFinn Thain 			local_irq_restore(flags);
3791da177e4SLinus Torvalds 			return IRQ_NONE;
3801da177e4SLinus Torvalds 		}
3815ce6185cSFinn Thain 	}
3821da177e4SLinus Torvalds 
383d95fd5fcSFinn Thain 	status = via[B] & (ST_MASK | CTLR_IRQ);
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	switch (macii_state) {
3861da177e4SLinus Torvalds 	case idle:
387b4d76c28SFinn Thain 		WARN_ON((status & ST_MASK) != ST_IDLE);
388b4d76c28SFinn Thain 
389d95fd5fcSFinn Thain 		reply_ptr = reply_buf;
390f87a1625SFinn Thain 		reading_reply = false;
391b4d76c28SFinn Thain 
392b4d76c28SFinn Thain 		bus_timeout = false;
393b4d76c28SFinn Thain 		srq_asserted = false;
394d95fd5fcSFinn Thain 
3951da177e4SLinus Torvalds 		x = via[SR];
396d95fd5fcSFinn Thain 
397b4d76c28SFinn Thain 		if (!(status & CTLR_IRQ)) {
398b4d76c28SFinn Thain 			/* /CTLR_IRQ asserted in idle state means we must
399b4d76c28SFinn Thain 			 * read an autopoll reply from the transceiver buffer.
400d95fd5fcSFinn Thain 			 */
401d95fd5fcSFinn Thain 			macii_state = reading;
402d95fd5fcSFinn Thain 			*reply_ptr = x;
403d95fd5fcSFinn Thain 			reply_len = 1;
404b4d76c28SFinn Thain 		} else {
405b4d76c28SFinn Thain 			/* bus timeout */
406b4d76c28SFinn Thain 			reply_len = 0;
407b16b6768SFinn Thain 			break;
408d95fd5fcSFinn Thain 		}
409d95fd5fcSFinn Thain 
4101da177e4SLinus Torvalds 		/* set ADB state = even for first data byte */
4111da177e4SLinus Torvalds 		via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
4121da177e4SLinus Torvalds 		break;
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds 	case sending:
4151da177e4SLinus Torvalds 		req = current_req;
416b4d76c28SFinn Thain 
417b4d76c28SFinn Thain 		if (status == (ST_CMD | CTLR_IRQ)) {
418b4d76c28SFinn Thain 			/* /CTLR_IRQ de-asserted after the command byte means
419b4d76c28SFinn Thain 			 * the host can continue with the transaction.
420b4d76c28SFinn Thain 			 */
421b4d76c28SFinn Thain 
422b4d76c28SFinn Thain 			/* Store command byte */
423b4d76c28SFinn Thain 			last_cmd = req->data[1];
424b4d76c28SFinn Thain 			if ((last_cmd & OP_MASK) == TALK) {
425b4d76c28SFinn Thain 				last_talk_cmd = last_cmd;
426b4d76c28SFinn Thain 				if ((last_cmd & CMD_MASK) == ADB_READREG(0, 0))
427b4d76c28SFinn Thain 					last_poll_cmd = last_cmd;
428b4d76c28SFinn Thain 			}
429b4d76c28SFinn Thain 		}
430b4d76c28SFinn Thain 
431b4d76c28SFinn Thain 		if (status == ST_CMD) {
432b4d76c28SFinn Thain 			/* /CTLR_IRQ asserted after the command byte means we
433b4d76c28SFinn Thain 			 * must read an autopoll reply. The first byte was
434b4d76c28SFinn Thain 			 * lost because the shift register was an output.
435b4d76c28SFinn Thain 			 */
436b4d76c28SFinn Thain 			macii_state = reading;
437b4d76c28SFinn Thain 
438f87a1625SFinn Thain 			reading_reply = false;
439b4d76c28SFinn Thain 			reply_ptr = reply_buf;
440b4d76c28SFinn Thain 			*reply_ptr = last_talk_cmd;
441b4d76c28SFinn Thain 			reply_len = 1;
442b4d76c28SFinn Thain 
443b4d76c28SFinn Thain 			/* reset to shift in */
444b4d76c28SFinn Thain 			via[ACR] &= ~SR_OUT;
445b4d76c28SFinn Thain 			x = via[SR];
446b4d76c28SFinn Thain 		} else if (data_index >= req->nbytes) {
447d95fd5fcSFinn Thain 			req->sent = 1;
448d95fd5fcSFinn Thain 
449d95fd5fcSFinn Thain 			if (req->reply_expected) {
450b4d76c28SFinn Thain 				macii_state = reading;
451b4d76c28SFinn Thain 
452f87a1625SFinn Thain 				reading_reply = true;
453b4d76c28SFinn Thain 				reply_ptr = req->reply;
454b4d76c28SFinn Thain 				*reply_ptr = req->data[1];
455b4d76c28SFinn Thain 				reply_len = 1;
456b4d76c28SFinn Thain 
457b4d76c28SFinn Thain 				via[ACR] &= ~SR_OUT;
458b4d76c28SFinn Thain 				x = via[SR];
459624cf5b5SFinn Thain 			} else if ((req->data[1] & OP_MASK) == TALK) {
460624cf5b5SFinn Thain 				macii_state = reading;
461624cf5b5SFinn Thain 
462f87a1625SFinn Thain 				reading_reply = false;
463624cf5b5SFinn Thain 				reply_ptr = reply_buf;
464624cf5b5SFinn Thain 				*reply_ptr = req->data[1];
465624cf5b5SFinn Thain 				reply_len = 1;
466624cf5b5SFinn Thain 
467624cf5b5SFinn Thain 				via[ACR] &= ~SR_OUT;
468624cf5b5SFinn Thain 				x = via[SR];
469624cf5b5SFinn Thain 
470624cf5b5SFinn Thain 				req->complete = 1;
471624cf5b5SFinn Thain 				current_req = req->next;
472624cf5b5SFinn Thain 				if (req->done)
473624cf5b5SFinn Thain 					(*req->done)(req);
474d95fd5fcSFinn Thain 			} else {
475b4d76c28SFinn Thain 				macii_state = idle;
476b4d76c28SFinn Thain 
477d95fd5fcSFinn Thain 				req->complete = 1;
478d95fd5fcSFinn Thain 				current_req = req->next;
47947fd2060SFinn Thain 				if (req->done)
48047fd2060SFinn Thain 					(*req->done)(req);
481b4d76c28SFinn Thain 				break;
482b4d76c28SFinn Thain 			}
4831da177e4SLinus Torvalds 		} else {
4841da177e4SLinus Torvalds 			via[SR] = req->data[data_index++];
485b4d76c28SFinn Thain 		}
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 		if ((via[B] & ST_MASK) == ST_CMD) {
4881da177e4SLinus Torvalds 			/* just sent the command byte, set to EVEN */
4891da177e4SLinus Torvalds 			via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
4901da177e4SLinus Torvalds 		} else {
4911da177e4SLinus Torvalds 			/* invert state bits, toggle ODD/EVEN */
4921da177e4SLinus Torvalds 			via[B] ^= ST_MASK;
4931da177e4SLinus Torvalds 		}
4941da177e4SLinus Torvalds 		break;
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 	case reading:
497d95fd5fcSFinn Thain 		x = via[SR];
4985f93d708SFinn Thain 		WARN_ON((status & ST_MASK) == ST_CMD ||
499d95fd5fcSFinn Thain 			(status & ST_MASK) == ST_IDLE);
5001da177e4SLinus Torvalds 
501d95fd5fcSFinn Thain 		if (!(status & CTLR_IRQ)) {
502b4d76c28SFinn Thain 			if (status == ST_EVEN && reply_len == 1) {
503b4d76c28SFinn Thain 				bus_timeout = true;
504b4d76c28SFinn Thain 			} else if (status == ST_ODD && reply_len == 2) {
505b4d76c28SFinn Thain 				srq_asserted = true;
506b4d76c28SFinn Thain 			} else {
507b16b6768SFinn Thain 				macii_state = idle;
508b16b6768SFinn Thain 
509b16b6768SFinn Thain 				if (bus_timeout)
510b16b6768SFinn Thain 					reply_len = 0;
511b16b6768SFinn Thain 
512b16b6768SFinn Thain 				if (reading_reply) {
513b16b6768SFinn Thain 					struct adb_request *req = current_req;
514b16b6768SFinn Thain 
515b16b6768SFinn Thain 					req->reply_len = reply_len;
516b16b6768SFinn Thain 
517b16b6768SFinn Thain 					req->complete = 1;
518b16b6768SFinn Thain 					current_req = req->next;
519b16b6768SFinn Thain 					if (req->done)
520b16b6768SFinn Thain 						(*req->done)(req);
521624cf5b5SFinn Thain 				} else if (reply_len && autopoll_devs &&
522624cf5b5SFinn Thain 					   reply_buf[0] == last_poll_cmd) {
523624cf5b5SFinn Thain 					adb_input(reply_buf, reply_len, 1);
524b16b6768SFinn Thain 				}
525b16b6768SFinn Thain 				break;
526d95fd5fcSFinn Thain 			}
527d95fd5fcSFinn Thain 		}
5281da177e4SLinus Torvalds 
529b16b6768SFinn Thain 		if (reply_len < ARRAY_SIZE(reply_buf)) {
5301da177e4SLinus Torvalds 			reply_ptr++;
531d95fd5fcSFinn Thain 			*reply_ptr = x;
5321da177e4SLinus Torvalds 			reply_len++;
5331da177e4SLinus Torvalds 		}
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 		/* invert state bits, toggle ODD/EVEN */
5361da177e4SLinus Torvalds 		via[B] ^= ST_MASK;
5371da177e4SLinus Torvalds 		break;
5381da177e4SLinus Torvalds 
539b16b6768SFinn Thain 	default:
540b16b6768SFinn Thain 		break;
541b16b6768SFinn Thain 	}
542d95fd5fcSFinn Thain 
543b16b6768SFinn Thain 	if (macii_state == idle) {
544f93bfeb5SFinn Thain 		if (!current_req)
5451da177e4SLinus Torvalds 			macii_queue_poll();
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds 		if (current_req)
5481da177e4SLinus Torvalds 			macii_start();
549d95fd5fcSFinn Thain 
550b16b6768SFinn Thain 		if (macii_state == idle) {
551b16b6768SFinn Thain 			via[ACR] &= ~SR_OUT;
552b16b6768SFinn Thain 			x = via[SR];
553d95fd5fcSFinn Thain 			via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
554b16b6768SFinn Thain 		}
5551da177e4SLinus Torvalds 	}
556d95fd5fcSFinn Thain 
5575ce6185cSFinn Thain 	local_irq_restore(flags);
5581da177e4SLinus Torvalds 	return IRQ_HANDLED;
5591da177e4SLinus Torvalds }
560