xref: /openbmc/linux/drivers/pcmcia/i82365.c (revision 664b0bae0b87f69bc9deb098f5e0158b9cf18e04)
11da177e4SLinus Torvalds /*======================================================================
21da177e4SLinus Torvalds 
31da177e4SLinus Torvalds     Device driver for Intel 82365 and compatible PC Card controllers.
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds     i82365.c 1.265 1999/11/10 18:36:21
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds     The contents of this file are subject to the Mozilla Public
81da177e4SLinus Torvalds     License Version 1.1 (the "License"); you may not use this file
91da177e4SLinus Torvalds     except in compliance with the License. You may obtain a copy of
101da177e4SLinus Torvalds     the License at http://www.mozilla.org/MPL/
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds     Software distributed under the License is distributed on an "AS
131da177e4SLinus Torvalds     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
141da177e4SLinus Torvalds     implied. See the License for the specific language governing
151da177e4SLinus Torvalds     rights and limitations under the License.
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds     The initial developer of the original code is David A. Hinds
181da177e4SLinus Torvalds     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
191da177e4SLinus Torvalds     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds     Alternatively, the contents of this file may be used under the
221da177e4SLinus Torvalds     terms of the GNU General Public License version 2 (the "GPL"), in which
231da177e4SLinus Torvalds     case the provisions of the GPL are applicable instead of the
241da177e4SLinus Torvalds     above.  If you wish to allow the use of your version of this file
251da177e4SLinus Torvalds     only under the terms of the GPL and not to allow others to use
261da177e4SLinus Torvalds     your version of this file under the MPL, indicate your decision
271da177e4SLinus Torvalds     by deleting the provisions above and replace them with the notice
281da177e4SLinus Torvalds     and other provisions required by the GPL.  If you do not delete
291da177e4SLinus Torvalds     the provisions above, a recipient may use your version of this
301da177e4SLinus Torvalds     file under either the MPL or the GPL.
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds ======================================================================*/
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <linux/module.h>
351da177e4SLinus Torvalds #include <linux/moduleparam.h>
361da177e4SLinus Torvalds #include <linux/init.h>
371da177e4SLinus Torvalds #include <linux/types.h>
381da177e4SLinus Torvalds #include <linux/fcntl.h>
391da177e4SLinus Torvalds #include <linux/string.h>
401da177e4SLinus Torvalds #include <linux/kernel.h>
411da177e4SLinus Torvalds #include <linux/errno.h>
421da177e4SLinus Torvalds #include <linux/timer.h>
431da177e4SLinus Torvalds #include <linux/ioport.h>
441da177e4SLinus Torvalds #include <linux/delay.h>
451da177e4SLinus Torvalds #include <linux/workqueue.h>
461da177e4SLinus Torvalds #include <linux/interrupt.h>
47d052d1beSRussell King #include <linux/platform_device.h>
481da177e4SLinus Torvalds #include <linux/bitops.h>
491da177e4SLinus Torvalds #include <asm/irq.h>
501da177e4SLinus Torvalds #include <asm/io.h>
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds #include <pcmcia/ss.h>
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds #include <linux/isapnp.h>
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds /* ISA-bus controllers */
571da177e4SLinus Torvalds #include "i82365.h"
581da177e4SLinus Torvalds #include "cirrus.h"
591da177e4SLinus Torvalds #include "vg468.h"
601da177e4SLinus Torvalds #include "ricoh.h"
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 
637d12e780SDavid Howells static irqreturn_t i365_count_irq(int, void *);
_check_irq(int irq,int flags)641da177e4SLinus Torvalds static inline int _check_irq(int irq, int flags)
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds     if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0)
671da177e4SLinus Torvalds 	return -1;
681da177e4SLinus Torvalds     free_irq(irq, i365_count_irq);
691da177e4SLinus Torvalds     return 0;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds /*====================================================================*/
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds /* Parameters that can be set with 'insmod' */
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds /* Default base address for i82365sl and other ISA chips */
771da177e4SLinus Torvalds static unsigned long i365_base = 0x3e0;
781da177e4SLinus Torvalds /* Should we probe at 0x3e2 for an extra ISA controller? */
791da177e4SLinus Torvalds static int extra_sockets = 0;
801da177e4SLinus Torvalds /* Specify a socket number to ignore */
811da177e4SLinus Torvalds static int ignore = -1;
821da177e4SLinus Torvalds /* Bit map or list of interrupts to choose from */
831da177e4SLinus Torvalds static u_int irq_mask = 0xffff;
841da177e4SLinus Torvalds static int irq_list[16];
8564a6f950SAl Viro static unsigned int irq_list_count;
861da177e4SLinus Torvalds /* The card status change interrupt -- 0 means autoselect */
871da177e4SLinus Torvalds static int cs_irq = 0;
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds /* Probe for safe interrupts? */
901da177e4SLinus Torvalds static int do_scan = 1;
911da177e4SLinus Torvalds /* Poll status interval -- 0 means default to interrupt */
921da177e4SLinus Torvalds static int poll_interval = 0;
931da177e4SLinus Torvalds /* External clock time, in nanoseconds.  120 ns = 8.33 MHz */
941da177e4SLinus Torvalds static int cycle_time = 120;
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds /* Cirrus options */
971da177e4SLinus Torvalds static int has_dma = -1;
981da177e4SLinus Torvalds static int has_led = -1;
991da177e4SLinus Torvalds static int has_ring = -1;
1001da177e4SLinus Torvalds static int dynamic_mode = 0;
1011da177e4SLinus Torvalds static int freq_bypass = -1;
1021da177e4SLinus Torvalds static int setup_time = -1;
1031da177e4SLinus Torvalds static int cmd_time = -1;
1041da177e4SLinus Torvalds static int recov_time = -1;
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds /* Vadem options */
1071da177e4SLinus Torvalds static int async_clock = -1;
1081da177e4SLinus Torvalds static int cable_mode = -1;
1091da177e4SLinus Torvalds static int wakeup = 0;
1101da177e4SLinus Torvalds 
1119149ba1fSDavid Howells module_param_hw(i365_base, ulong, ioport, 0444);
1121da177e4SLinus Torvalds module_param(ignore, int, 0444);
1131da177e4SLinus Torvalds module_param(extra_sockets, int, 0444);
1149149ba1fSDavid Howells module_param_hw(irq_mask, int, other, 0444);
1159149ba1fSDavid Howells module_param_hw_array(irq_list, int, irq, &irq_list_count, 0444);
1169149ba1fSDavid Howells module_param_hw(cs_irq, int, irq, 0444);
1171da177e4SLinus Torvalds module_param(async_clock, int, 0444);
1181da177e4SLinus Torvalds module_param(cable_mode, int, 0444);
1191da177e4SLinus Torvalds module_param(wakeup, int, 0444);
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds module_param(do_scan, int, 0444);
1221da177e4SLinus Torvalds module_param(poll_interval, int, 0444);
1231da177e4SLinus Torvalds module_param(cycle_time, int, 0444);
1241da177e4SLinus Torvalds module_param(has_dma, int, 0444);
1251da177e4SLinus Torvalds module_param(has_led, int, 0444);
1261da177e4SLinus Torvalds module_param(has_ring, int, 0444);
1271da177e4SLinus Torvalds module_param(dynamic_mode, int, 0444);
1281da177e4SLinus Torvalds module_param(freq_bypass, int, 0444);
1291da177e4SLinus Torvalds module_param(setup_time, int, 0444);
1301da177e4SLinus Torvalds module_param(cmd_time, int, 0444);
1311da177e4SLinus Torvalds module_param(recov_time, int, 0444);
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds /*====================================================================*/
1341da177e4SLinus Torvalds 
1358b0eb837SHimangi Saraogi struct cirrus_state {
1361da177e4SLinus Torvalds     u_char		misc1, misc2;
1371da177e4SLinus Torvalds     u_char		timer[6];
1388b0eb837SHimangi Saraogi };
1391da177e4SLinus Torvalds 
1408b0eb837SHimangi Saraogi struct vg46x_state {
1411da177e4SLinus Torvalds     u_char		ctl, ema;
1428b0eb837SHimangi Saraogi };
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds struct i82365_socket {
1451da177e4SLinus Torvalds     u_short		type, flags;
1461da177e4SLinus Torvalds     struct pcmcia_socket	socket;
1471da177e4SLinus Torvalds     unsigned int	number;
148906da809SOlof Johansson     unsigned int	ioaddr;
1491da177e4SLinus Torvalds     u_short		psock;
1501da177e4SLinus Torvalds     u_char		cs_irq, intr;
1511da177e4SLinus Torvalds     union {
1528b0eb837SHimangi Saraogi 	struct cirrus_state		cirrus;
1538b0eb837SHimangi Saraogi 	struct vg46x_state		vg46x;
1541da177e4SLinus Torvalds     } state;
1551da177e4SLinus Torvalds };
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds /* Where we keep track of our sockets... */
1581da177e4SLinus Torvalds static int sockets = 0;
1591da177e4SLinus Torvalds static struct i82365_socket socket[8] = {
1601da177e4SLinus Torvalds     { 0, }, /* ... */
1611da177e4SLinus Torvalds };
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds /* Default ISA interrupt mask */
1641da177e4SLinus Torvalds #define I365_MASK	0xdeb8	/* irq 15,14,12,11,10,9,7,5,4,3 */
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds static int grab_irq;
1671da177e4SLinus Torvalds static DEFINE_SPINLOCK(isa_lock);
1681da177e4SLinus Torvalds #define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f)
1691da177e4SLinus Torvalds #define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f)
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds static struct timer_list poll_timer;
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds /*====================================================================*/
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds /* These definitions must match the pcic table! */
1768b0eb837SHimangi Saraogi enum pcic_id {
1771da177e4SLinus Torvalds     IS_I82365A, IS_I82365B, IS_I82365DF,
1781da177e4SLinus Torvalds     IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
1791da177e4SLinus Torvalds     IS_PD6710, IS_PD672X, IS_VT83C469,
1808b0eb837SHimangi Saraogi };
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds /* Flags for classifying groups of controllers */
1831da177e4SLinus Torvalds #define IS_VADEM	0x0001
1841da177e4SLinus Torvalds #define IS_CIRRUS	0x0002
1851da177e4SLinus Torvalds #define IS_VIA		0x0010
1861da177e4SLinus Torvalds #define IS_UNKNOWN	0x0400
1871da177e4SLinus Torvalds #define IS_VG_PWR	0x0800
1881da177e4SLinus Torvalds #define IS_DF_PWR	0x1000
1891da177e4SLinus Torvalds #define IS_REGISTERED	0x2000
1901da177e4SLinus Torvalds #define IS_ALIVE	0x8000
1911da177e4SLinus Torvalds 
1928b0eb837SHimangi Saraogi struct pcic {
1931da177e4SLinus Torvalds     char		*name;
1941da177e4SLinus Torvalds     u_short		flags;
1958b0eb837SHimangi Saraogi };
1961da177e4SLinus Torvalds 
1978b0eb837SHimangi Saraogi static struct pcic pcic[] = {
1981da177e4SLinus Torvalds     { "Intel i82365sl A step", 0 },
1991da177e4SLinus Torvalds     { "Intel i82365sl B step", 0 },
2001da177e4SLinus Torvalds     { "Intel i82365sl DF", IS_DF_PWR },
2011da177e4SLinus Torvalds     { "IBM Clone", 0 },
2021da177e4SLinus Torvalds     { "Ricoh RF5C296/396", 0 },
2031da177e4SLinus Torvalds     { "VLSI 82C146", 0 },
2041da177e4SLinus Torvalds     { "Vadem VG-468", IS_VADEM },
2051da177e4SLinus Torvalds     { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
2061da177e4SLinus Torvalds     { "Cirrus PD6710", IS_CIRRUS },
2071da177e4SLinus Torvalds     { "Cirrus PD672x", IS_CIRRUS },
2081da177e4SLinus Torvalds     { "VIA VT83C469", IS_CIRRUS|IS_VIA },
2091da177e4SLinus Torvalds };
2101da177e4SLinus Torvalds 
211e632cd94SJim Cromie #define PCIC_COUNT	ARRAY_SIZE(pcic)
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds /*====================================================================*/
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds static DEFINE_SPINLOCK(bus_lock);
2161da177e4SLinus Torvalds 
i365_get(u_short sock,u_short reg)2171da177e4SLinus Torvalds static u_char i365_get(u_short sock, u_short reg)
2181da177e4SLinus Torvalds {
2191da177e4SLinus Torvalds     unsigned long flags;
2201da177e4SLinus Torvalds     spin_lock_irqsave(&bus_lock,flags);
2211da177e4SLinus Torvalds     {
222906da809SOlof Johansson 	unsigned int port = socket[sock].ioaddr;
2231da177e4SLinus Torvalds 	u_char val;
2241da177e4SLinus Torvalds 	reg = I365_REG(socket[sock].psock, reg);
2251da177e4SLinus Torvalds 	outb(reg, port); val = inb(port+1);
2261da177e4SLinus Torvalds 	spin_unlock_irqrestore(&bus_lock,flags);
2271da177e4SLinus Torvalds 	return val;
2281da177e4SLinus Torvalds     }
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
i365_set(u_short sock,u_short reg,u_char data)2311da177e4SLinus Torvalds static void i365_set(u_short sock, u_short reg, u_char data)
2321da177e4SLinus Torvalds {
2331da177e4SLinus Torvalds     unsigned long flags;
2341da177e4SLinus Torvalds     spin_lock_irqsave(&bus_lock,flags);
2351da177e4SLinus Torvalds     {
236906da809SOlof Johansson 	unsigned int port = socket[sock].ioaddr;
2371da177e4SLinus Torvalds 	u_char val = I365_REG(socket[sock].psock, reg);
2381da177e4SLinus Torvalds 	outb(val, port); outb(data, port+1);
2391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&bus_lock,flags);
2401da177e4SLinus Torvalds     }
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
i365_bset(u_short sock,u_short reg,u_char mask)2431da177e4SLinus Torvalds static void i365_bset(u_short sock, u_short reg, u_char mask)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds     u_char d = i365_get(sock, reg);
2461da177e4SLinus Torvalds     d |= mask;
2471da177e4SLinus Torvalds     i365_set(sock, reg, d);
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds 
i365_bclr(u_short sock,u_short reg,u_char mask)2501da177e4SLinus Torvalds static void i365_bclr(u_short sock, u_short reg, u_char mask)
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds     u_char d = i365_get(sock, reg);
2531da177e4SLinus Torvalds     d &= ~mask;
2541da177e4SLinus Torvalds     i365_set(sock, reg, d);
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds 
i365_bflip(u_short sock,u_short reg,u_char mask,int b)2571da177e4SLinus Torvalds static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
2581da177e4SLinus Torvalds {
2591da177e4SLinus Torvalds     u_char d = i365_get(sock, reg);
2601da177e4SLinus Torvalds     if (b)
2611da177e4SLinus Torvalds 	d |= mask;
2621da177e4SLinus Torvalds     else
2631da177e4SLinus Torvalds 	d &= ~mask;
2641da177e4SLinus Torvalds     i365_set(sock, reg, d);
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds 
i365_get_pair(u_short sock,u_short reg)2671da177e4SLinus Torvalds static u_short i365_get_pair(u_short sock, u_short reg)
2681da177e4SLinus Torvalds {
2691da177e4SLinus Torvalds     u_short a, b;
2701da177e4SLinus Torvalds     a = i365_get(sock, reg);
2711da177e4SLinus Torvalds     b = i365_get(sock, reg+1);
2721da177e4SLinus Torvalds     return (a + (b<<8));
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds 
i365_set_pair(u_short sock,u_short reg,u_short data)2751da177e4SLinus Torvalds static void i365_set_pair(u_short sock, u_short reg, u_short data)
2761da177e4SLinus Torvalds {
2771da177e4SLinus Torvalds     i365_set(sock, reg, data & 0xff);
2781da177e4SLinus Torvalds     i365_set(sock, reg+1, data >> 8);
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds /*======================================================================
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds     Code to save and restore global state information for Cirrus
2841da177e4SLinus Torvalds     PD67xx controllers, and to set and report global configuration
2851da177e4SLinus Torvalds     options.
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds     The VIA controllers also use these routines, as they are mostly
2881da177e4SLinus Torvalds     Cirrus lookalikes, without the timing registers.
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds ======================================================================*/
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds #define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
2931da177e4SLinus Torvalds 
cirrus_get_state(u_short s)2941da177e4SLinus Torvalds static void cirrus_get_state(u_short s)
2951da177e4SLinus Torvalds {
2961da177e4SLinus Torvalds     int i;
2978b0eb837SHimangi Saraogi     struct cirrus_state *p = &socket[s].state.cirrus;
2981da177e4SLinus Torvalds     p->misc1 = i365_get(s, PD67_MISC_CTL_1);
2991da177e4SLinus Torvalds     p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
3001da177e4SLinus Torvalds     p->misc2 = i365_get(s, PD67_MISC_CTL_2);
3011da177e4SLinus Torvalds     for (i = 0; i < 6; i++)
3021da177e4SLinus Torvalds 	p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
3031da177e4SLinus Torvalds }
3041da177e4SLinus Torvalds 
cirrus_set_state(u_short s)3051da177e4SLinus Torvalds static void cirrus_set_state(u_short s)
3061da177e4SLinus Torvalds {
3071da177e4SLinus Torvalds     int i;
3081da177e4SLinus Torvalds     u_char misc;
3098b0eb837SHimangi Saraogi     struct cirrus_state *p = &socket[s].state.cirrus;
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds     misc = i365_get(s, PD67_MISC_CTL_2);
3121da177e4SLinus Torvalds     i365_set(s, PD67_MISC_CTL_2, p->misc2);
3131da177e4SLinus Torvalds     if (misc & PD67_MC2_SUSPEND) mdelay(50);
3141da177e4SLinus Torvalds     misc = i365_get(s, PD67_MISC_CTL_1);
3151da177e4SLinus Torvalds     misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
3161da177e4SLinus Torvalds     i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
3171da177e4SLinus Torvalds     for (i = 0; i < 6; i++)
3181da177e4SLinus Torvalds 	i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds 
cirrus_set_opts(u_short s,char * buf)3211da177e4SLinus Torvalds static u_int __init cirrus_set_opts(u_short s, char *buf)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds     struct i82365_socket *t = &socket[s];
3248b0eb837SHimangi Saraogi     struct cirrus_state *p = &socket[s].state.cirrus;
3251da177e4SLinus Torvalds     u_int mask = 0xffff;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds     if (has_ring == -1) has_ring = 1;
3281da177e4SLinus Torvalds     flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
3291da177e4SLinus Torvalds     flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
3301da177e4SLinus Torvalds     flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
3311da177e4SLinus Torvalds     if (p->misc2 & PD67_MC2_IRQ15_RI)
3321da177e4SLinus Torvalds 	strcat(buf, " [ring]");
3331da177e4SLinus Torvalds     if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
3341da177e4SLinus Torvalds 	strcat(buf, " [dyn mode]");
3351da177e4SLinus Torvalds     if (p->misc2 & PD67_MC2_FREQ_BYPASS)
3361da177e4SLinus Torvalds 	strcat(buf, " [freq bypass]");
3371da177e4SLinus Torvalds     if (p->misc1 & PD67_MC1_INPACK_ENA)
3381da177e4SLinus Torvalds 	strcat(buf, " [inpack]");
3391da177e4SLinus Torvalds     if (p->misc2 & PD67_MC2_IRQ15_RI)
3401da177e4SLinus Torvalds 	mask &= ~0x8000;
3411da177e4SLinus Torvalds     if (has_led > 0) {
3421da177e4SLinus Torvalds 	strcat(buf, " [led]");
3431da177e4SLinus Torvalds 	mask &= ~0x1000;
3441da177e4SLinus Torvalds     }
3451da177e4SLinus Torvalds     if (has_dma > 0) {
3461da177e4SLinus Torvalds 	strcat(buf, " [dma]");
3471da177e4SLinus Torvalds 	mask &= ~0x0600;
3481da177e4SLinus Torvalds     }
3491da177e4SLinus Torvalds     if (!(t->flags & IS_VIA)) {
3501da177e4SLinus Torvalds 	if (setup_time >= 0)
3511da177e4SLinus Torvalds 	    p->timer[0] = p->timer[3] = setup_time;
3521da177e4SLinus Torvalds 	if (cmd_time > 0) {
3531da177e4SLinus Torvalds 	    p->timer[1] = cmd_time;
3541da177e4SLinus Torvalds 	    p->timer[4] = cmd_time*2+4;
3551da177e4SLinus Torvalds 	}
3561da177e4SLinus Torvalds 	if (p->timer[1] == 0) {
3571da177e4SLinus Torvalds 	    p->timer[1] = 6; p->timer[4] = 16;
3581da177e4SLinus Torvalds 	    if (p->timer[0] == 0)
3591da177e4SLinus Torvalds 		p->timer[0] = p->timer[3] = 1;
3601da177e4SLinus Torvalds 	}
3611da177e4SLinus Torvalds 	if (recov_time >= 0)
3621da177e4SLinus Torvalds 	    p->timer[2] = p->timer[5] = recov_time;
3631da177e4SLinus Torvalds 	buf += strlen(buf);
3641da177e4SLinus Torvalds 	sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
3651da177e4SLinus Torvalds 		p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
3661da177e4SLinus Torvalds     }
3671da177e4SLinus Torvalds     return mask;
3681da177e4SLinus Torvalds }
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds /*======================================================================
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds     Code to save and restore global state information for Vadem VG468
3731da177e4SLinus Torvalds     and VG469 controllers, and to set and report global configuration
3741da177e4SLinus Torvalds     options.
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds ======================================================================*/
3771da177e4SLinus Torvalds 
vg46x_get_state(u_short s)3781da177e4SLinus Torvalds static void vg46x_get_state(u_short s)
3791da177e4SLinus Torvalds {
3808b0eb837SHimangi Saraogi     struct vg46x_state *p = &socket[s].state.vg46x;
3811da177e4SLinus Torvalds     p->ctl = i365_get(s, VG468_CTL);
3821da177e4SLinus Torvalds     if (socket[s].type == IS_VG469)
3831da177e4SLinus Torvalds 	p->ema = i365_get(s, VG469_EXT_MODE);
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds 
vg46x_set_state(u_short s)3861da177e4SLinus Torvalds static void vg46x_set_state(u_short s)
3871da177e4SLinus Torvalds {
3888b0eb837SHimangi Saraogi     struct vg46x_state *p = &socket[s].state.vg46x;
3891da177e4SLinus Torvalds     i365_set(s, VG468_CTL, p->ctl);
3901da177e4SLinus Torvalds     if (socket[s].type == IS_VG469)
3911da177e4SLinus Torvalds 	i365_set(s, VG469_EXT_MODE, p->ema);
3921da177e4SLinus Torvalds }
3931da177e4SLinus Torvalds 
vg46x_set_opts(u_short s,char * buf)3941da177e4SLinus Torvalds static u_int __init vg46x_set_opts(u_short s, char *buf)
3951da177e4SLinus Torvalds {
3968b0eb837SHimangi Saraogi     struct vg46x_state *p = &socket[s].state.vg46x;
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds     flip(p->ctl, VG468_CTL_ASYNC, async_clock);
3991da177e4SLinus Torvalds     flip(p->ema, VG469_MODE_CABLE, cable_mode);
4001da177e4SLinus Torvalds     if (p->ctl & VG468_CTL_ASYNC)
4011da177e4SLinus Torvalds 	strcat(buf, " [async]");
4021da177e4SLinus Torvalds     if (p->ctl & VG468_CTL_INPACK)
4031da177e4SLinus Torvalds 	strcat(buf, " [inpack]");
4041da177e4SLinus Torvalds     if (socket[s].type == IS_VG469) {
4051da177e4SLinus Torvalds 	u_char vsel = i365_get(s, VG469_VSELECT);
4061da177e4SLinus Torvalds 	if (vsel & VG469_VSEL_EXT_STAT) {
4071da177e4SLinus Torvalds 	    strcat(buf, " [ext mode]");
4081da177e4SLinus Torvalds 	    if (vsel & VG469_VSEL_EXT_BUS)
4091da177e4SLinus Torvalds 		strcat(buf, " [isa buf]");
4101da177e4SLinus Torvalds 	}
4111da177e4SLinus Torvalds 	if (p->ema & VG469_MODE_CABLE)
4121da177e4SLinus Torvalds 	    strcat(buf, " [cable]");
4131da177e4SLinus Torvalds 	if (p->ema & VG469_MODE_COMPAT)
4141da177e4SLinus Torvalds 	    strcat(buf, " [c step]");
4151da177e4SLinus Torvalds     }
4161da177e4SLinus Torvalds     return 0xffff;
4171da177e4SLinus Torvalds }
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds /*======================================================================
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds     Generic routines to get and set controller options
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds ======================================================================*/
4241da177e4SLinus Torvalds 
get_bridge_state(u_short s)4251da177e4SLinus Torvalds static void get_bridge_state(u_short s)
4261da177e4SLinus Torvalds {
4271da177e4SLinus Torvalds     struct i82365_socket *t = &socket[s];
4281da177e4SLinus Torvalds     if (t->flags & IS_CIRRUS)
4291da177e4SLinus Torvalds 	cirrus_get_state(s);
4301da177e4SLinus Torvalds     else if (t->flags & IS_VADEM)
4311da177e4SLinus Torvalds 	vg46x_get_state(s);
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds 
set_bridge_state(u_short s)4341da177e4SLinus Torvalds static void set_bridge_state(u_short s)
4351da177e4SLinus Torvalds {
4361da177e4SLinus Torvalds     struct i82365_socket *t = &socket[s];
4371da177e4SLinus Torvalds     if (t->flags & IS_CIRRUS)
4381da177e4SLinus Torvalds 	cirrus_set_state(s);
4391da177e4SLinus Torvalds     else {
4401da177e4SLinus Torvalds 	i365_set(s, I365_GBLCTL, 0x00);
4411da177e4SLinus Torvalds 	i365_set(s, I365_GENCTL, 0x00);
4421da177e4SLinus Torvalds     }
4431da177e4SLinus Torvalds     i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
4441da177e4SLinus Torvalds     if (t->flags & IS_VADEM)
4451da177e4SLinus Torvalds 	vg46x_set_state(s);
4461da177e4SLinus Torvalds }
4471da177e4SLinus Torvalds 
set_bridge_opts(u_short s,u_short ns)4481da177e4SLinus Torvalds static u_int __init set_bridge_opts(u_short s, u_short ns)
4491da177e4SLinus Torvalds {
4501da177e4SLinus Torvalds     u_short i;
4511da177e4SLinus Torvalds     u_int m = 0xffff;
4521da177e4SLinus Torvalds     char buf[128];
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds     for (i = s; i < s+ns; i++) {
4551da177e4SLinus Torvalds 	if (socket[i].flags & IS_ALIVE) {
4561da177e4SLinus Torvalds 	    printk(KERN_INFO "    host opts [%d]: already alive!\n", i);
4571da177e4SLinus Torvalds 	    continue;
4581da177e4SLinus Torvalds 	}
4591da177e4SLinus Torvalds 	buf[0] = '\0';
4601da177e4SLinus Torvalds 	get_bridge_state(i);
4611da177e4SLinus Torvalds 	if (socket[i].flags & IS_CIRRUS)
4621da177e4SLinus Torvalds 	    m = cirrus_set_opts(i, buf);
4631da177e4SLinus Torvalds 	else if (socket[i].flags & IS_VADEM)
4641da177e4SLinus Torvalds 	    m = vg46x_set_opts(i, buf);
4651da177e4SLinus Torvalds 	set_bridge_state(i);
4661da177e4SLinus Torvalds 	printk(KERN_INFO "    host opts [%d]:%s\n", i,
4671da177e4SLinus Torvalds 	       (*buf) ? buf : " none");
4681da177e4SLinus Torvalds     }
4691da177e4SLinus Torvalds     return m;
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds /*======================================================================
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds     Interrupt testing code, for ISA and PCI interrupts
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds ======================================================================*/
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds static volatile u_int irq_hits;
4791da177e4SLinus Torvalds static u_short irq_sock;
4801da177e4SLinus Torvalds 
i365_count_irq(int irq,void * dev)4817d12e780SDavid Howells static irqreturn_t i365_count_irq(int irq, void *dev)
4821da177e4SLinus Torvalds {
4831da177e4SLinus Torvalds     i365_get(irq_sock, I365_CSC);
4841da177e4SLinus Torvalds     irq_hits++;
485c9f50dddSDominik Brodowski     pr_debug("i82365: -> hit on irq %d\n", irq);
4861da177e4SLinus Torvalds     return IRQ_HANDLED;
4871da177e4SLinus Torvalds }
4881da177e4SLinus Torvalds 
test_irq(u_short sock,int irq)4891da177e4SLinus Torvalds static u_int __init test_irq(u_short sock, int irq)
4901da177e4SLinus Torvalds {
491c9f50dddSDominik Brodowski     pr_debug("i82365:  testing ISA irq %d\n", irq);
492dace1453SThomas Gleixner     if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan",
49313e87ec6SAndrew Morton 			i365_count_irq) != 0)
4941da177e4SLinus Torvalds 	return 1;
4951da177e4SLinus Torvalds     irq_hits = 0; irq_sock = sock;
4961da177e4SLinus Torvalds     msleep(10);
4971da177e4SLinus Torvalds     if (irq_hits) {
4981da177e4SLinus Torvalds 	free_irq(irq, i365_count_irq);
499c9f50dddSDominik Brodowski 	pr_debug("i82365:    spurious hit!\n");
5001da177e4SLinus Torvalds 	return 1;
5011da177e4SLinus Torvalds     }
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds     /* Generate one interrupt */
5041da177e4SLinus Torvalds     i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4));
5051da177e4SLinus Torvalds     i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
5061da177e4SLinus Torvalds     udelay(1000);
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds     free_irq(irq, i365_count_irq);
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds     /* mask all interrupts */
5111da177e4SLinus Torvalds     i365_set(sock, I365_CSCINT, 0);
512c9f50dddSDominik Brodowski     pr_debug("i82365:    hits = %d\n", irq_hits);
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds     return (irq_hits != 1);
5151da177e4SLinus Torvalds }
5161da177e4SLinus Torvalds 
isa_scan(u_short sock,u_int mask0)5171da177e4SLinus Torvalds static u_int __init isa_scan(u_short sock, u_int mask0)
5181da177e4SLinus Torvalds {
5191da177e4SLinus Torvalds     u_int mask1 = 0;
5201da177e4SLinus Torvalds     int i;
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds #ifdef __alpha__
5231da177e4SLinus Torvalds #define PIC 0x4d0
5241da177e4SLinus Torvalds     /* Don't probe level-triggered interrupts -- reserved for PCI */
5251da177e4SLinus Torvalds     mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
5261da177e4SLinus Torvalds #endif
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds     if (do_scan) {
5291da177e4SLinus Torvalds 	set_bridge_state(sock);
5301da177e4SLinus Torvalds 	i365_set(sock, I365_CSCINT, 0);
5311da177e4SLinus Torvalds 	for (i = 0; i < 16; i++)
5321da177e4SLinus Torvalds 	    if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0))
5331da177e4SLinus Torvalds 		mask1 |= (1 << i);
5341da177e4SLinus Torvalds 	for (i = 0; i < 16; i++)
5351da177e4SLinus Torvalds 	    if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0))
5361da177e4SLinus Torvalds 		mask1 ^= (1 << i);
5371da177e4SLinus Torvalds     }
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds     printk(KERN_INFO "    ISA irqs (");
5401da177e4SLinus Torvalds     if (mask1) {
5411da177e4SLinus Torvalds 	printk("scanned");
5421da177e4SLinus Torvalds     } else {
5431da177e4SLinus Torvalds 	/* Fallback: just find interrupts that aren't in use */
5441da177e4SLinus Torvalds 	for (i = 0; i < 16; i++)
545dace1453SThomas Gleixner 	    if ((mask0 & (1 << i)) && (_check_irq(i, IRQF_PROBE_SHARED) == 0))
5461da177e4SLinus Torvalds 		mask1 |= (1 << i);
5471da177e4SLinus Torvalds 	printk("default");
5481da177e4SLinus Torvalds 	/* If scan failed, default to polled status */
5491da177e4SLinus Torvalds 	if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
5501da177e4SLinus Torvalds     }
5511da177e4SLinus Torvalds     printk(") = ");
5521da177e4SLinus Torvalds 
5531da177e4SLinus Torvalds     for (i = 0; i < 16; i++)
5541da177e4SLinus Torvalds 	if (mask1 & (1<<i))
5551da177e4SLinus Torvalds 	    printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
5561da177e4SLinus Torvalds     if (mask1 == 0) printk("none!");
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds     return mask1;
5591da177e4SLinus Torvalds }
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds /*====================================================================*/
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds /* Time conversion functions */
5641da177e4SLinus Torvalds 
to_cycles(int ns)5651da177e4SLinus Torvalds static int to_cycles(int ns)
5661da177e4SLinus Torvalds {
5671da177e4SLinus Torvalds     return ns/cycle_time;
5681da177e4SLinus Torvalds }
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds /*====================================================================*/
5711da177e4SLinus Torvalds 
identify(unsigned int port,u_short sock)572906da809SOlof Johansson static int __init identify(unsigned int port, u_short sock)
5731da177e4SLinus Torvalds {
5741da177e4SLinus Torvalds     u_char val;
5751da177e4SLinus Torvalds     int type = -1;
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds     /* Use the next free entry in the socket table */
5781da177e4SLinus Torvalds     socket[sockets].ioaddr = port;
5791da177e4SLinus Torvalds     socket[sockets].psock = sock;
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds     /* Wake up a sleepy Cirrus controller */
5821da177e4SLinus Torvalds     if (wakeup) {
5831da177e4SLinus Torvalds 	i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
5841da177e4SLinus Torvalds 	/* Pause at least 50 ms */
5851da177e4SLinus Torvalds 	mdelay(50);
5861da177e4SLinus Torvalds     }
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds     if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
5891da177e4SLinus Torvalds 	return -1;
5901da177e4SLinus Torvalds     switch (val) {
5911da177e4SLinus Torvalds     case 0x82:
5921da177e4SLinus Torvalds 	type = IS_I82365A; break;
5931da177e4SLinus Torvalds     case 0x83:
5941da177e4SLinus Torvalds 	type = IS_I82365B; break;
5951da177e4SLinus Torvalds     case 0x84:
5961da177e4SLinus Torvalds 	type = IS_I82365DF; break;
5971da177e4SLinus Torvalds     case 0x88: case 0x89: case 0x8a:
5981da177e4SLinus Torvalds 	type = IS_IBM; break;
5991da177e4SLinus Torvalds     }
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds     /* Check for Vadem VG-468 chips */
6021da177e4SLinus Torvalds     outb(0x0e, port);
6031da177e4SLinus Torvalds     outb(0x37, port);
6041da177e4SLinus Torvalds     i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
6051da177e4SLinus Torvalds     val = i365_get(sockets, I365_IDENT);
6061da177e4SLinus Torvalds     if (val & I365_IDENT_VADEM) {
6071da177e4SLinus Torvalds 	i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
6081da177e4SLinus Torvalds 	type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
6091da177e4SLinus Torvalds     }
6101da177e4SLinus Torvalds 
6111da177e4SLinus Torvalds     /* Check for Ricoh chips */
6121da177e4SLinus Torvalds     val = i365_get(sockets, RF5C_CHIP_ID);
6131da177e4SLinus Torvalds     if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
6141da177e4SLinus Torvalds 	type = IS_RF5Cx96;
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds     /* Check for Cirrus CL-PD67xx chips */
6171da177e4SLinus Torvalds     i365_set(sockets, PD67_CHIP_INFO, 0);
6181da177e4SLinus Torvalds     val = i365_get(sockets, PD67_CHIP_INFO);
6191da177e4SLinus Torvalds     if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
6201da177e4SLinus Torvalds 	val = i365_get(sockets, PD67_CHIP_INFO);
6211da177e4SLinus Torvalds 	if ((val & PD67_INFO_CHIP_ID) == 0) {
6221da177e4SLinus Torvalds 	    type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
6231da177e4SLinus Torvalds 	    i365_set(sockets, PD67_EXT_INDEX, 0xe5);
6241da177e4SLinus Torvalds 	    if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
6251da177e4SLinus Torvalds 		type = IS_VT83C469;
6261da177e4SLinus Torvalds 	}
6271da177e4SLinus Torvalds     }
6281da177e4SLinus Torvalds     return type;
6291da177e4SLinus Torvalds } /* identify */
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds /*======================================================================
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds     See if a card is present, powered up, in IO mode, and already
6341da177e4SLinus Torvalds     bound to a (non PC Card) Linux driver.  We leave these alone.
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds     We make an exception for cards that seem to be serial devices.
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds ======================================================================*/
6391da177e4SLinus Torvalds 
is_alive(u_short sock)6401da177e4SLinus Torvalds static int __init is_alive(u_short sock)
6411da177e4SLinus Torvalds {
6421da177e4SLinus Torvalds     u_char stat;
643906da809SOlof Johansson     unsigned int start, stop;
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds     stat = i365_get(sock, I365_STATUS);
6461da177e4SLinus Torvalds     start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
6471da177e4SLinus Torvalds     stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
6481da177e4SLinus Torvalds     if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
6491da177e4SLinus Torvalds 	(i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
6501da177e4SLinus Torvalds 	(i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
651f354942cSDominik Brodowski 	((start & 0xfeef) != 0x02e8)) {
652f354942cSDominik Brodowski 	if (!request_region(start, stop-start+1, "i82365"))
6531da177e4SLinus Torvalds 	    return 1;
654f354942cSDominik Brodowski 	release_region(start, stop-start+1);
655f354942cSDominik Brodowski     }
656f354942cSDominik Brodowski 
6571da177e4SLinus Torvalds     return 0;
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds /*====================================================================*/
6611da177e4SLinus Torvalds 
add_socket(unsigned int port,int psock,int type)662906da809SOlof Johansson static void __init add_socket(unsigned int port, int psock, int type)
6631da177e4SLinus Torvalds {
6641da177e4SLinus Torvalds     socket[sockets].ioaddr = port;
6651da177e4SLinus Torvalds     socket[sockets].psock = psock;
6661da177e4SLinus Torvalds     socket[sockets].type = type;
6671da177e4SLinus Torvalds     socket[sockets].flags = pcic[type].flags;
6681da177e4SLinus Torvalds     if (is_alive(sockets))
6691da177e4SLinus Torvalds 	socket[sockets].flags |= IS_ALIVE;
6701da177e4SLinus Torvalds     sockets++;
6711da177e4SLinus Torvalds }
6721da177e4SLinus Torvalds 
add_pcic(int ns,int type)6731da177e4SLinus Torvalds static void __init add_pcic(int ns, int type)
6741da177e4SLinus Torvalds {
6751da177e4SLinus Torvalds     u_int mask = 0, i, base;
6761da177e4SLinus Torvalds     int isa_irq = 0;
6771da177e4SLinus Torvalds     struct i82365_socket *t = &socket[sockets-ns];
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds     base = sockets-ns;
6801da177e4SLinus Torvalds     if (base == 0) printk("\n");
6811da177e4SLinus Torvalds     printk(KERN_INFO "  %s", pcic[type].name);
682906da809SOlof Johansson     printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
6831da177e4SLinus Torvalds 	       t->ioaddr, t->psock*0x40);
6841da177e4SLinus Torvalds     printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds     /* Set host options, build basic interrupt mask */
6871da177e4SLinus Torvalds     if (irq_list_count == 0)
6881da177e4SLinus Torvalds 	mask = irq_mask;
6891da177e4SLinus Torvalds     else
6901da177e4SLinus Torvalds 	for (i = mask = 0; i < irq_list_count; i++)
6911da177e4SLinus Torvalds 	    mask |= (1<<irq_list[i]);
6921da177e4SLinus Torvalds     mask &= I365_MASK & set_bridge_opts(base, ns);
6931da177e4SLinus Torvalds     /* Scan for ISA interrupts */
6941da177e4SLinus Torvalds     mask = isa_scan(base, mask);
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds     /* Poll if only two interrupts available */
6971da177e4SLinus Torvalds     if (!poll_interval) {
6981da177e4SLinus Torvalds 	u_int tmp = (mask & 0xff20);
6991da177e4SLinus Torvalds 	tmp = tmp & (tmp-1);
7001da177e4SLinus Torvalds 	if ((tmp & (tmp-1)) == 0)
7011da177e4SLinus Torvalds 	    poll_interval = HZ;
7021da177e4SLinus Torvalds     }
7031da177e4SLinus Torvalds     /* Only try an ISA cs_irq if this is the first controller */
7041da177e4SLinus Torvalds     if (!grab_irq && (cs_irq || !poll_interval)) {
7051da177e4SLinus Torvalds 	/* Avoid irq 12 unless it is explicitly requested */
7061da177e4SLinus Torvalds 	u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
7071da177e4SLinus Torvalds 	for (cs_irq = 15; cs_irq > 0; cs_irq--)
7081da177e4SLinus Torvalds 	    if ((cs_mask & (1 << cs_irq)) &&
709dace1453SThomas Gleixner 		(_check_irq(cs_irq, IRQF_PROBE_SHARED) == 0))
7101da177e4SLinus Torvalds 		break;
7111da177e4SLinus Torvalds 	if (cs_irq) {
7121da177e4SLinus Torvalds 	    grab_irq = 1;
7131da177e4SLinus Torvalds 	    isa_irq = cs_irq;
7141da177e4SLinus Torvalds 	    printk(" status change on irq %d\n", cs_irq);
7151da177e4SLinus Torvalds 	}
7161da177e4SLinus Torvalds     }
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds     if (!isa_irq) {
7191da177e4SLinus Torvalds 	if (poll_interval == 0)
7201da177e4SLinus Torvalds 	    poll_interval = HZ;
7211da177e4SLinus Torvalds 	printk(" polling interval = %d ms\n",
7221da177e4SLinus Torvalds 	       poll_interval * 1000 / HZ);
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds     }
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds     /* Update socket interrupt information, capabilities */
7271da177e4SLinus Torvalds     for (i = 0; i < ns; i++) {
7281da177e4SLinus Torvalds 	t[i].socket.features |= SS_CAP_PCCARD;
7291da177e4SLinus Torvalds 	t[i].socket.map_size = 0x1000;
7301da177e4SLinus Torvalds 	t[i].socket.irq_mask = mask;
7311da177e4SLinus Torvalds 	t[i].cs_irq = isa_irq;
7321da177e4SLinus Torvalds     }
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds } /* add_pcic */
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds /*====================================================================*/
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds #ifdef CONFIG_PNP
7391da177e4SLinus Torvalds static struct isapnp_device_id id_table[] __initdata = {
7401da177e4SLinus Torvalds 	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
7411da177e4SLinus Torvalds 		ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
7421da177e4SLinus Torvalds 	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
7431da177e4SLinus Torvalds 		ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
7441da177e4SLinus Torvalds 	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
7451da177e4SLinus Torvalds 		ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
7461da177e4SLinus Torvalds 	{	0 }
7471da177e4SLinus Torvalds };
7481da177e4SLinus Torvalds MODULE_DEVICE_TABLE(isapnp, id_table);
7491da177e4SLinus Torvalds 
7501da177e4SLinus Torvalds static struct pnp_dev *i82365_pnpdev;
7511da177e4SLinus Torvalds #endif
7521da177e4SLinus Torvalds 
isa_probe(void)7531da177e4SLinus Torvalds static void __init isa_probe(void)
7541da177e4SLinus Torvalds {
7551da177e4SLinus Torvalds     int i, j, sock, k, ns, id;
756906da809SOlof Johansson     unsigned int port;
7571da177e4SLinus Torvalds #ifdef CONFIG_PNP
7581da177e4SLinus Torvalds     struct isapnp_device_id *devid;
7591da177e4SLinus Torvalds     struct pnp_dev *dev;
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds     for (devid = id_table; devid->vendor; devid++) {
7621da177e4SLinus Torvalds 	if ((dev = pnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	    if (pnp_device_attach(dev) < 0)
7651da177e4SLinus Torvalds 	    	continue;
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 	    if (pnp_activate_dev(dev) < 0) {
7681da177e4SLinus Torvalds 		printk("activate failed\n");
7691da177e4SLinus Torvalds 		pnp_device_detach(dev);
7701da177e4SLinus Torvalds 		break;
7711da177e4SLinus Torvalds 	    }
7721da177e4SLinus Torvalds 
7731da177e4SLinus Torvalds 	    if (!pnp_port_valid(dev, 0)) {
7741da177e4SLinus Torvalds 		printk("invalid resources ?\n");
7751da177e4SLinus Torvalds 		pnp_device_detach(dev);
7761da177e4SLinus Torvalds 		break;
7771da177e4SLinus Torvalds 	    }
7781da177e4SLinus Torvalds 	    i365_base = pnp_port_start(dev, 0);
7791da177e4SLinus Torvalds 	    i82365_pnpdev = dev;
7801da177e4SLinus Torvalds 	    break;
7811da177e4SLinus Torvalds 	}
7821da177e4SLinus Torvalds     }
7831da177e4SLinus Torvalds #endif
7841da177e4SLinus Torvalds 
785f354942cSDominik Brodowski     if (!request_region(i365_base, 2, "i82365")) {
7861da177e4SLinus Torvalds 	if (sockets == 0)
7871da177e4SLinus Torvalds 	    printk("port conflict at %#lx\n", i365_base);
7881da177e4SLinus Torvalds 	return;
7891da177e4SLinus Torvalds     }
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds     id = identify(i365_base, 0);
7921da177e4SLinus Torvalds     if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
7931da177e4SLinus Torvalds 	for (i = 0; i < 4; i++) {
7941da177e4SLinus Torvalds 	    if (i == ignore) continue;
7951da177e4SLinus Torvalds 	    port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
7961da177e4SLinus Torvalds 	    sock = (i & 1) << 1;
7971da177e4SLinus Torvalds 	    if (identify(port, sock) == IS_I82365DF) {
7981da177e4SLinus Torvalds 		add_socket(port, sock, IS_VLSI);
7991da177e4SLinus Torvalds 		add_pcic(1, IS_VLSI);
8001da177e4SLinus Torvalds 	    }
8011da177e4SLinus Torvalds 	}
8021da177e4SLinus Torvalds     } else {
8031da177e4SLinus Torvalds 	for (i = 0; i < 8; i += 2) {
8041da177e4SLinus Torvalds 	    if (sockets && !extra_sockets && (i == 4))
8051da177e4SLinus Torvalds 		break;
8061da177e4SLinus Torvalds 	    port = i365_base + 2*(i>>2);
8071da177e4SLinus Torvalds 	    sock = (i & 3);
8081da177e4SLinus Torvalds 	    id = identify(port, sock);
8091da177e4SLinus Torvalds 	    if (id < 0) continue;
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds 	    for (j = ns = 0; j < 2; j++) {
8121da177e4SLinus Torvalds 		/* Does the socket exist? */
8131da177e4SLinus Torvalds 		if ((ignore == i+j) || (identify(port, sock+j) < 0))
8141da177e4SLinus Torvalds 		    continue;
8151da177e4SLinus Torvalds 		/* Check for bad socket decode */
8161da177e4SLinus Torvalds 		for (k = 0; k <= sockets; k++)
8171da177e4SLinus Torvalds 		    i365_set(k, I365_MEM(0)+I365_W_OFF, k);
8181da177e4SLinus Torvalds 		for (k = 0; k <= sockets; k++)
8191da177e4SLinus Torvalds 		    if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
8201da177e4SLinus Torvalds 			break;
8211da177e4SLinus Torvalds 		if (k <= sockets) break;
8221da177e4SLinus Torvalds 		add_socket(port, sock+j, id); ns++;
8231da177e4SLinus Torvalds 	    }
8241da177e4SLinus Torvalds 	    if (ns != 0) add_pcic(ns, id);
8251da177e4SLinus Torvalds 	}
8261da177e4SLinus Torvalds     }
8271da177e4SLinus Torvalds }
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds /*====================================================================*/
8301da177e4SLinus Torvalds 
pcic_interrupt(int irq,void * dev)8317d12e780SDavid Howells static irqreturn_t pcic_interrupt(int irq, void *dev)
8321da177e4SLinus Torvalds {
8331da177e4SLinus Torvalds     int i, j, csc;
8341da177e4SLinus Torvalds     u_int events, active;
8351da177e4SLinus Torvalds     u_long flags = 0;
8361da177e4SLinus Torvalds     int handled = 0;
8371da177e4SLinus Torvalds 
838c9f50dddSDominik Brodowski     pr_debug("pcic_interrupt(%d)\n", irq);
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds     for (j = 0; j < 20; j++) {
8411da177e4SLinus Torvalds 	active = 0;
8421da177e4SLinus Torvalds 	for (i = 0; i < sockets; i++) {
8431da177e4SLinus Torvalds 	    if (socket[i].cs_irq != irq)
8441da177e4SLinus Torvalds 		continue;
8451da177e4SLinus Torvalds 	    handled = 1;
8461da177e4SLinus Torvalds 	    ISA_LOCK(i, flags);
8471da177e4SLinus Torvalds 	    csc = i365_get(i, I365_CSC);
8481da177e4SLinus Torvalds 	    if ((csc == 0) || (i365_get(i, I365_IDENT) & 0x70)) {
8491da177e4SLinus Torvalds 		ISA_UNLOCK(i, flags);
8501da177e4SLinus Torvalds 		continue;
8511da177e4SLinus Torvalds 	    }
8521da177e4SLinus Torvalds 	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
8531da177e4SLinus Torvalds 
8541da177e4SLinus Torvalds 	    if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
8551da177e4SLinus Torvalds 		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
8561da177e4SLinus Torvalds 	    else {
8571da177e4SLinus Torvalds 		events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
8581da177e4SLinus Torvalds 		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
8591da177e4SLinus Torvalds 		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
8601da177e4SLinus Torvalds 	    }
8611da177e4SLinus Torvalds 	    ISA_UNLOCK(i, flags);
862c9f50dddSDominik Brodowski 	    pr_debug("socket %d event 0x%02x\n", i, events);
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds 	    if (events)
8651da177e4SLinus Torvalds 		pcmcia_parse_events(&socket[i].socket, events);
8661da177e4SLinus Torvalds 
8671da177e4SLinus Torvalds 	    active |= events;
8681da177e4SLinus Torvalds 	}
8691da177e4SLinus Torvalds 	if (!active) break;
8701da177e4SLinus Torvalds     }
8711da177e4SLinus Torvalds     if (j == 20)
8721da177e4SLinus Torvalds 	printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
8731da177e4SLinus Torvalds 
874c9f50dddSDominik Brodowski     pr_debug("pcic_interrupt done\n");
8751da177e4SLinus Torvalds     return IRQ_RETVAL(handled);
8761da177e4SLinus Torvalds } /* pcic_interrupt */
8771da177e4SLinus Torvalds 
pcic_interrupt_wrapper(struct timer_list * unused)878*41760d0eSKees Cook static void pcic_interrupt_wrapper(struct timer_list *unused)
8791da177e4SLinus Torvalds {
8807d12e780SDavid Howells     pcic_interrupt(0, NULL);
8811da177e4SLinus Torvalds     poll_timer.expires = jiffies + poll_interval;
8821da177e4SLinus Torvalds     add_timer(&poll_timer);
8831da177e4SLinus Torvalds }
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds /*====================================================================*/
8861da177e4SLinus Torvalds 
i365_get_status(u_short sock,u_int * value)8871da177e4SLinus Torvalds static int i365_get_status(u_short sock, u_int *value)
8881da177e4SLinus Torvalds {
8891da177e4SLinus Torvalds     u_int status;
8901da177e4SLinus Torvalds 
8911da177e4SLinus Torvalds     status = i365_get(sock, I365_STATUS);
8921da177e4SLinus Torvalds     *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
8931da177e4SLinus Torvalds 	? SS_DETECT : 0;
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds     if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
8961da177e4SLinus Torvalds 	*value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
8971da177e4SLinus Torvalds     else {
8981da177e4SLinus Torvalds 	*value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
8991da177e4SLinus Torvalds 	*value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
9001da177e4SLinus Torvalds     }
9011da177e4SLinus Torvalds     *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
9021da177e4SLinus Torvalds     *value |= (status & I365_CS_READY) ? SS_READY : 0;
9031da177e4SLinus Torvalds     *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds     if (socket[sock].type == IS_VG469) {
9061da177e4SLinus Torvalds 	status = i365_get(sock, VG469_VSENSE);
9071da177e4SLinus Torvalds 	if (socket[sock].psock & 1) {
9081da177e4SLinus Torvalds 	    *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
9091da177e4SLinus Torvalds 	    *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
9101da177e4SLinus Torvalds 	} else {
9111da177e4SLinus Torvalds 	    *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
9121da177e4SLinus Torvalds 	    *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
9131da177e4SLinus Torvalds 	}
9141da177e4SLinus Torvalds     }
9151da177e4SLinus Torvalds 
916c9f50dddSDominik Brodowski     pr_debug("GetStatus(%d) = %#4.4x\n", sock, *value);
9171da177e4SLinus Torvalds     return 0;
9181da177e4SLinus Torvalds } /* i365_get_status */
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds /*====================================================================*/
9211da177e4SLinus Torvalds 
i365_set_socket(u_short sock,socket_state_t * state)9221da177e4SLinus Torvalds static int i365_set_socket(u_short sock, socket_state_t *state)
9231da177e4SLinus Torvalds {
9241da177e4SLinus Torvalds     struct i82365_socket *t = &socket[sock];
9251da177e4SLinus Torvalds     u_char reg;
9261da177e4SLinus Torvalds 
927c9f50dddSDominik Brodowski     pr_debug("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
9281da177e4SLinus Torvalds 	  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
9291da177e4SLinus Torvalds 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
9301da177e4SLinus Torvalds 
9311da177e4SLinus Torvalds     /* First set global controller options */
9321da177e4SLinus Torvalds     set_bridge_state(sock);
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds     /* IO card, RESET flag, IO interrupt */
9351da177e4SLinus Torvalds     reg = t->intr;
9361da177e4SLinus Torvalds     reg |= state->io_irq;
9371da177e4SLinus Torvalds     reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
9381da177e4SLinus Torvalds     reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
9391da177e4SLinus Torvalds     i365_set(sock, I365_INTCTL, reg);
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds     reg = I365_PWR_NORESET;
9421da177e4SLinus Torvalds     if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
9431da177e4SLinus Torvalds     if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds     if (t->flags & IS_CIRRUS) {
9461da177e4SLinus Torvalds 	if (state->Vpp != 0) {
9471da177e4SLinus Torvalds 	    if (state->Vpp == 120)
9481da177e4SLinus Torvalds 		reg |= I365_VPP1_12V;
9491da177e4SLinus Torvalds 	    else if (state->Vpp == state->Vcc)
9501da177e4SLinus Torvalds 		reg |= I365_VPP1_5V;
9511da177e4SLinus Torvalds 	    else return -EINVAL;
9521da177e4SLinus Torvalds 	}
9531da177e4SLinus Torvalds 	if (state->Vcc != 0) {
9541da177e4SLinus Torvalds 	    reg |= I365_VCC_5V;
9551da177e4SLinus Torvalds 	    if (state->Vcc == 33)
9561da177e4SLinus Torvalds 		i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
9571da177e4SLinus Torvalds 	    else if (state->Vcc == 50)
9581da177e4SLinus Torvalds 		i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
9591da177e4SLinus Torvalds 	    else return -EINVAL;
9601da177e4SLinus Torvalds 	}
9611da177e4SLinus Torvalds     } else if (t->flags & IS_VG_PWR) {
9621da177e4SLinus Torvalds 	if (state->Vpp != 0) {
9631da177e4SLinus Torvalds 	    if (state->Vpp == 120)
9641da177e4SLinus Torvalds 		reg |= I365_VPP1_12V;
9651da177e4SLinus Torvalds 	    else if (state->Vpp == state->Vcc)
9661da177e4SLinus Torvalds 		reg |= I365_VPP1_5V;
9671da177e4SLinus Torvalds 	    else return -EINVAL;
9681da177e4SLinus Torvalds 	}
9691da177e4SLinus Torvalds 	if (state->Vcc != 0) {
9701da177e4SLinus Torvalds 	    reg |= I365_VCC_5V;
9711da177e4SLinus Torvalds 	    if (state->Vcc == 33)
9721da177e4SLinus Torvalds 		i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
9731da177e4SLinus Torvalds 	    else if (state->Vcc == 50)
9741da177e4SLinus Torvalds 		i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
9751da177e4SLinus Torvalds 	    else return -EINVAL;
9761da177e4SLinus Torvalds 	}
9771da177e4SLinus Torvalds     } else if (t->flags & IS_DF_PWR) {
9781da177e4SLinus Torvalds 	switch (state->Vcc) {
9791da177e4SLinus Torvalds 	case 0:		break;
9801da177e4SLinus Torvalds 	case 33:   	reg |= I365_VCC_3V; break;
9811da177e4SLinus Torvalds 	case 50:	reg |= I365_VCC_5V; break;
9821da177e4SLinus Torvalds 	default:	return -EINVAL;
9831da177e4SLinus Torvalds 	}
9841da177e4SLinus Torvalds 	switch (state->Vpp) {
9851da177e4SLinus Torvalds 	case 0:		break;
9861da177e4SLinus Torvalds 	case 50:   	reg |= I365_VPP1_5V; break;
9871da177e4SLinus Torvalds 	case 120:	reg |= I365_VPP1_12V; break;
9881da177e4SLinus Torvalds 	default:	return -EINVAL;
9891da177e4SLinus Torvalds 	}
9901da177e4SLinus Torvalds     } else {
9911da177e4SLinus Torvalds 	switch (state->Vcc) {
9921da177e4SLinus Torvalds 	case 0:		break;
9931da177e4SLinus Torvalds 	case 50:	reg |= I365_VCC_5V; break;
9941da177e4SLinus Torvalds 	default:	return -EINVAL;
9951da177e4SLinus Torvalds 	}
9961da177e4SLinus Torvalds 	switch (state->Vpp) {
9971da177e4SLinus Torvalds 	case 0:		break;
9981da177e4SLinus Torvalds 	case 50:	reg |= I365_VPP1_5V | I365_VPP2_5V; break;
9991da177e4SLinus Torvalds 	case 120:	reg |= I365_VPP1_12V | I365_VPP2_12V; break;
10001da177e4SLinus Torvalds 	default:	return -EINVAL;
10011da177e4SLinus Torvalds 	}
10021da177e4SLinus Torvalds     }
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds     if (reg != i365_get(sock, I365_POWER))
10051da177e4SLinus Torvalds 	i365_set(sock, I365_POWER, reg);
10061da177e4SLinus Torvalds 
10071da177e4SLinus Torvalds     /* Chipset-specific functions */
10081da177e4SLinus Torvalds     if (t->flags & IS_CIRRUS) {
10091da177e4SLinus Torvalds 	/* Speaker control */
10101da177e4SLinus Torvalds 	i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
10111da177e4SLinus Torvalds 		   state->flags & SS_SPKR_ENA);
10121da177e4SLinus Torvalds     }
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds     /* Card status change interrupt mask */
10151da177e4SLinus Torvalds     reg = t->cs_irq << 4;
10161da177e4SLinus Torvalds     if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
10171da177e4SLinus Torvalds     if (state->flags & SS_IOCARD) {
10181da177e4SLinus Torvalds 	if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
10191da177e4SLinus Torvalds     } else {
10201da177e4SLinus Torvalds 	if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
10211da177e4SLinus Torvalds 	if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
10221da177e4SLinus Torvalds 	if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
10231da177e4SLinus Torvalds     }
10241da177e4SLinus Torvalds     i365_set(sock, I365_CSCINT, reg);
10251da177e4SLinus Torvalds     i365_get(sock, I365_CSC);
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds     return 0;
10281da177e4SLinus Torvalds } /* i365_set_socket */
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds /*====================================================================*/
10311da177e4SLinus Torvalds 
i365_set_io_map(u_short sock,struct pccard_io_map * io)10321da177e4SLinus Torvalds static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
10331da177e4SLinus Torvalds {
10341da177e4SLinus Torvalds     u_char map, ioctl;
10351da177e4SLinus Torvalds 
1036c9f50dddSDominik Brodowski     pr_debug("SetIOMap(%d, %d, %#2.2x, %d ns, "
103701373046SRandy Dunlap 	  "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed,
103801373046SRandy Dunlap 	  (unsigned long long)io->start, (unsigned long long)io->stop);
10391da177e4SLinus Torvalds     map = io->map;
10401da177e4SLinus Torvalds     if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
10411da177e4SLinus Torvalds 	(io->stop < io->start)) return -EINVAL;
10421da177e4SLinus Torvalds     /* Turn off the window before changing anything */
10431da177e4SLinus Torvalds     if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
10441da177e4SLinus Torvalds 	i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
10451da177e4SLinus Torvalds     i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
10461da177e4SLinus Torvalds     i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
10471da177e4SLinus Torvalds     ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
10481da177e4SLinus Torvalds     if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
10491da177e4SLinus Torvalds     if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
10501da177e4SLinus Torvalds     if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
10511da177e4SLinus Torvalds     if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
10521da177e4SLinus Torvalds     i365_set(sock, I365_IOCTL, ioctl);
10531da177e4SLinus Torvalds     /* Turn on the window if necessary */
10541da177e4SLinus Torvalds     if (io->flags & MAP_ACTIVE)
10551da177e4SLinus Torvalds 	i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
10561da177e4SLinus Torvalds     return 0;
10571da177e4SLinus Torvalds } /* i365_set_io_map */
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds /*====================================================================*/
10601da177e4SLinus Torvalds 
i365_set_mem_map(u_short sock,struct pccard_mem_map * mem)10611da177e4SLinus Torvalds static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
10621da177e4SLinus Torvalds {
10631da177e4SLinus Torvalds     u_short base, i;
10641da177e4SLinus Torvalds     u_char map;
10651da177e4SLinus Torvalds 
1066c9f50dddSDominik Brodowski     pr_debug("SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
10671da177e4SLinus Torvalds 	  "%#x)\n", sock, mem->map, mem->flags, mem->speed,
1068490ab72aSGreg Kroah-Hartman 	  (unsigned long long)mem->res->start,
1069490ab72aSGreg Kroah-Hartman 	  (unsigned long long)mem->res->end, mem->card_start);
10701da177e4SLinus Torvalds 
10711da177e4SLinus Torvalds     map = mem->map;
10721da177e4SLinus Torvalds     if ((map > 4) || (mem->card_start > 0x3ffffff) ||
10731da177e4SLinus Torvalds 	(mem->res->start > mem->res->end) || (mem->speed > 1000))
10741da177e4SLinus Torvalds 	return -EINVAL;
10751da177e4SLinus Torvalds     if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff))
10761da177e4SLinus Torvalds 	return -EINVAL;
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds     /* Turn off the window before changing anything */
10791da177e4SLinus Torvalds     if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
10801da177e4SLinus Torvalds 	i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
10811da177e4SLinus Torvalds 
10821da177e4SLinus Torvalds     base = I365_MEM(map);
10831da177e4SLinus Torvalds     i = (mem->res->start >> 12) & 0x0fff;
10841da177e4SLinus Torvalds     if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
10851da177e4SLinus Torvalds     if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
10861da177e4SLinus Torvalds     i365_set_pair(sock, base+I365_W_START, i);
10871da177e4SLinus Torvalds 
10881da177e4SLinus Torvalds     i = (mem->res->end >> 12) & 0x0fff;
10891da177e4SLinus Torvalds     switch (to_cycles(mem->speed)) {
10901da177e4SLinus Torvalds     case 0:	break;
10911da177e4SLinus Torvalds     case 1:	i |= I365_MEM_WS0; break;
10921da177e4SLinus Torvalds     case 2:	i |= I365_MEM_WS1; break;
10931da177e4SLinus Torvalds     default:	i |= I365_MEM_WS1 | I365_MEM_WS0; break;
10941da177e4SLinus Torvalds     }
10951da177e4SLinus Torvalds     i365_set_pair(sock, base+I365_W_STOP, i);
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds     i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
10981da177e4SLinus Torvalds     if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
10991da177e4SLinus Torvalds     if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
11001da177e4SLinus Torvalds     i365_set_pair(sock, base+I365_W_OFF, i);
11011da177e4SLinus Torvalds 
11021da177e4SLinus Torvalds     /* Turn on the window if necessary */
11031da177e4SLinus Torvalds     if (mem->flags & MAP_ACTIVE)
11041da177e4SLinus Torvalds 	i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
11051da177e4SLinus Torvalds     return 0;
11061da177e4SLinus Torvalds } /* i365_set_mem_map */
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds #if 0 /* driver model ordering issue */
11091da177e4SLinus Torvalds /*======================================================================
11101da177e4SLinus Torvalds 
11111da177e4SLinus Torvalds     Routines for accessing socket information and register dumps via
11121da177e4SLinus Torvalds     /sys/class/pcmcia_socket/...
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds ======================================================================*/
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds static ssize_t show_info(struct class_device *class_dev, char *buf)
11171da177e4SLinus Torvalds {
11181da177e4SLinus Torvalds 	struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
11191da177e4SLinus Torvalds 	return sprintf(buf, "type:     %s\npsock:    %d\n",
11201da177e4SLinus Torvalds 		       pcic[s->type].name, s->psock);
11211da177e4SLinus Torvalds }
11221da177e4SLinus Torvalds 
11231da177e4SLinus Torvalds static ssize_t show_exca(struct class_device *class_dev, char *buf)
11241da177e4SLinus Torvalds {
11251da177e4SLinus Torvalds 	struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
11261da177e4SLinus Torvalds 	unsigned short sock;
11271da177e4SLinus Torvalds 	int i;
11281da177e4SLinus Torvalds 	ssize_t ret = 0;
11291da177e4SLinus Torvalds 	unsigned long flags = 0;
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 	sock = s->number;
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 	ISA_LOCK(sock, flags);
11341da177e4SLinus Torvalds 	for (i = 0; i < 0x40; i += 4) {
11351da177e4SLinus Torvalds 		ret += sprintf(buf, "%02x %02x %02x %02x%s",
11361da177e4SLinus Torvalds 			       i365_get(sock,i), i365_get(sock,i+1),
11371da177e4SLinus Torvalds 			       i365_get(sock,i+2), i365_get(sock,i+3),
11381da177e4SLinus Torvalds 			       ((i % 16) == 12) ? "\n" : " ");
11391da177e4SLinus Torvalds 		buf += ret;
11401da177e4SLinus Torvalds 	}
11411da177e4SLinus Torvalds 	ISA_UNLOCK(sock, flags);
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds 	return ret;
11441da177e4SLinus Torvalds }
11451da177e4SLinus Torvalds 
11461da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
11471da177e4SLinus Torvalds static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
11481da177e4SLinus Torvalds #endif
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds /*====================================================================*/
11511da177e4SLinus Torvalds 
11521da177e4SLinus Torvalds /* this is horribly ugly... proper locking needs to be done here at
11531da177e4SLinus Torvalds  * some time... */
11541da177e4SLinus Torvalds #define LOCKED(x) do { \
11551da177e4SLinus Torvalds 	int retval; \
11561da177e4SLinus Torvalds 	unsigned long flags; \
11571da177e4SLinus Torvalds 	spin_lock_irqsave(&isa_lock, flags); \
11581da177e4SLinus Torvalds 	retval = x; \
11591da177e4SLinus Torvalds 	spin_unlock_irqrestore(&isa_lock, flags); \
11601da177e4SLinus Torvalds 	return retval; \
11611da177e4SLinus Torvalds } while (0)
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 
pcic_get_status(struct pcmcia_socket * s,u_int * value)11641da177e4SLinus Torvalds static int pcic_get_status(struct pcmcia_socket *s, u_int *value)
11651da177e4SLinus Torvalds {
11661da177e4SLinus Torvalds 	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 	if (socket[sock].flags & IS_ALIVE) {
11691da177e4SLinus Torvalds 		*value = 0;
11701da177e4SLinus Torvalds 		return -EINVAL;
11711da177e4SLinus Torvalds 	}
11721da177e4SLinus Torvalds 
11731da177e4SLinus Torvalds 	LOCKED(i365_get_status(sock, value));
11741da177e4SLinus Torvalds }
11751da177e4SLinus Torvalds 
pcic_set_socket(struct pcmcia_socket * s,socket_state_t * state)11761da177e4SLinus Torvalds static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state)
11771da177e4SLinus Torvalds {
11781da177e4SLinus Torvalds 	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 	if (socket[sock].flags & IS_ALIVE)
11811da177e4SLinus Torvalds 		return -EINVAL;
11821da177e4SLinus Torvalds 
11831da177e4SLinus Torvalds 	LOCKED(i365_set_socket(sock, state));
11841da177e4SLinus Torvalds }
11851da177e4SLinus Torvalds 
pcic_set_io_map(struct pcmcia_socket * s,struct pccard_io_map * io)11861da177e4SLinus Torvalds static int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
11871da177e4SLinus Torvalds {
11881da177e4SLinus Torvalds 	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
11891da177e4SLinus Torvalds 	if (socket[sock].flags & IS_ALIVE)
11901da177e4SLinus Torvalds 		return -EINVAL;
11911da177e4SLinus Torvalds 
11921da177e4SLinus Torvalds 	LOCKED(i365_set_io_map(sock, io));
11931da177e4SLinus Torvalds }
11941da177e4SLinus Torvalds 
pcic_set_mem_map(struct pcmcia_socket * s,struct pccard_mem_map * mem)11951da177e4SLinus Torvalds static int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
11961da177e4SLinus Torvalds {
11971da177e4SLinus Torvalds 	unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
11981da177e4SLinus Torvalds 	if (socket[sock].flags & IS_ALIVE)
11991da177e4SLinus Torvalds 		return -EINVAL;
12001da177e4SLinus Torvalds 
12011da177e4SLinus Torvalds 	LOCKED(i365_set_mem_map(sock, mem));
12021da177e4SLinus Torvalds }
12031da177e4SLinus Torvalds 
pcic_init(struct pcmcia_socket * s)12041da177e4SLinus Torvalds static int pcic_init(struct pcmcia_socket *s)
12051da177e4SLinus Torvalds {
12061da177e4SLinus Torvalds 	int i;
12071da177e4SLinus Torvalds 	struct resource res = { .start = 0, .end = 0x1000 };
12081da177e4SLinus Torvalds 	pccard_io_map io = { 0, 0, 0, 0, 1 };
12091da177e4SLinus Torvalds 	pccard_mem_map mem = { .res = &res, };
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
12121da177e4SLinus Torvalds 		io.map = i;
12131da177e4SLinus Torvalds 		pcic_set_io_map(s, &io);
12141da177e4SLinus Torvalds 	}
12151da177e4SLinus Torvalds 	for (i = 0; i < 5; i++) {
12161da177e4SLinus Torvalds 		mem.map = i;
12171da177e4SLinus Torvalds 		pcic_set_mem_map(s, &mem);
12181da177e4SLinus Torvalds 	}
12191da177e4SLinus Torvalds 	return 0;
12201da177e4SLinus Torvalds }
12211da177e4SLinus Torvalds 
12227a192ec3SMing Lei 
12231da177e4SLinus Torvalds static struct pccard_operations pcic_operations = {
12241da177e4SLinus Torvalds 	.init			= pcic_init,
12251da177e4SLinus Torvalds 	.get_status		= pcic_get_status,
12261da177e4SLinus Torvalds 	.set_socket		= pcic_set_socket,
12271da177e4SLinus Torvalds 	.set_io_map		= pcic_set_io_map,
12281da177e4SLinus Torvalds 	.set_mem_map		= pcic_set_mem_map,
12291da177e4SLinus Torvalds };
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds /*====================================================================*/
12321da177e4SLinus Torvalds 
12337a192ec3SMing Lei static struct platform_driver i82365_driver = {
12347a192ec3SMing Lei 	.driver = {
12351da177e4SLinus Torvalds 		.name = "i82365",
12367a192ec3SMing Lei 	},
12371da177e4SLinus Torvalds };
12381da177e4SLinus Torvalds 
1239dfb279c9SDominik Brodowski static struct platform_device *i82365_device;
12401da177e4SLinus Torvalds 
init_i82365(void)12411da177e4SLinus Torvalds static int __init init_i82365(void)
12421da177e4SLinus Torvalds {
12431da177e4SLinus Torvalds     int i, ret;
12441da177e4SLinus Torvalds 
12457a192ec3SMing Lei     ret = platform_driver_register(&i82365_driver);
12461da177e4SLinus Torvalds     if (ret)
12472df69703SLeonardo Potenza 	goto err_out;
12481da177e4SLinus Torvalds 
1249dfb279c9SDominik Brodowski     i82365_device = platform_device_alloc("i82365", 0);
1250dfb279c9SDominik Brodowski     if (i82365_device) {
1251dfb279c9SDominik Brodowski 	    ret = platform_device_add(i82365_device);
1252dfb279c9SDominik Brodowski 	    if (ret)
1253dfb279c9SDominik Brodowski 		    platform_device_put(i82365_device);
1254dfb279c9SDominik Brodowski     } else
1255dfb279c9SDominik Brodowski 	    ret = -ENOMEM;
1256dfb279c9SDominik Brodowski 
12572df69703SLeonardo Potenza     if (ret)
12582df69703SLeonardo Potenza 	goto err_driver_unregister;
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds     printk(KERN_INFO "Intel ISA PCIC probe: ");
12611da177e4SLinus Torvalds     sockets = 0;
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds     isa_probe();
12641da177e4SLinus Torvalds 
12651da177e4SLinus Torvalds     if (sockets == 0) {
12661da177e4SLinus Torvalds 	printk("not found.\n");
12672df69703SLeonardo Potenza 	ret = -ENODEV;
12682df69703SLeonardo Potenza 	goto err_dev_unregister;
12691da177e4SLinus Torvalds     }
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds     /* Set up interrupt handler(s) */
12721da177e4SLinus Torvalds     if (grab_irq != 0)
12732df69703SLeonardo Potenza 	ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
12742df69703SLeonardo Potenza 
12752df69703SLeonardo Potenza     if (ret)
12762df69703SLeonardo Potenza 	goto err_socket_release;
12771da177e4SLinus Torvalds 
12781da177e4SLinus Torvalds     /* register sockets with the pcmcia core */
12791da177e4SLinus Torvalds     for (i = 0; i < sockets; i++) {
128087373318SGreg Kroah-Hartman 	    socket[i].socket.dev.parent = &i82365_device->dev;
12811da177e4SLinus Torvalds 	    socket[i].socket.ops = &pcic_operations;
12821da177e4SLinus Torvalds 	    socket[i].socket.resource_ops = &pccard_nonstatic_ops;
12831da177e4SLinus Torvalds 	    socket[i].socket.owner = THIS_MODULE;
12841da177e4SLinus Torvalds 	    socket[i].number = i;
12851da177e4SLinus Torvalds 	    ret = pcmcia_register_socket(&socket[i].socket);
12861da177e4SLinus Torvalds 	    if (!ret)
12871da177e4SLinus Torvalds 		    socket[i].flags |= IS_REGISTERED;
12881da177e4SLinus Torvalds     }
12891da177e4SLinus Torvalds 
12901da177e4SLinus Torvalds     /* Finally, schedule a polling interrupt */
12911da177e4SLinus Torvalds     if (poll_interval != 0) {
1292*41760d0eSKees Cook 	timer_setup(&poll_timer, pcic_interrupt_wrapper, 0);
12931da177e4SLinus Torvalds     	poll_timer.expires = jiffies + poll_interval;
12941da177e4SLinus Torvalds 	add_timer(&poll_timer);
12951da177e4SLinus Torvalds     }
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds     return 0;
12982df69703SLeonardo Potenza err_socket_release:
12992df69703SLeonardo Potenza     for (i = 0; i < sockets; i++) {
13002df69703SLeonardo Potenza 	/* Turn off all interrupt sources! */
13012df69703SLeonardo Potenza 	i365_set(i, I365_CSCINT, 0);
13022df69703SLeonardo Potenza 	release_region(socket[i].ioaddr, 2);
13032df69703SLeonardo Potenza     }
13042df69703SLeonardo Potenza err_dev_unregister:
13052df69703SLeonardo Potenza     platform_device_unregister(i82365_device);
13062df69703SLeonardo Potenza     release_region(i365_base, 2);
13072df69703SLeonardo Potenza #ifdef CONFIG_PNP
13082df69703SLeonardo Potenza     if (i82365_pnpdev)
13092df69703SLeonardo Potenza 	pnp_disable_dev(i82365_pnpdev);
13102df69703SLeonardo Potenza #endif
13112df69703SLeonardo Potenza err_driver_unregister:
13127a192ec3SMing Lei     platform_driver_unregister(&i82365_driver);
13132df69703SLeonardo Potenza err_out:
13142df69703SLeonardo Potenza     return ret;
13151da177e4SLinus Torvalds } /* init_i82365 */
13161da177e4SLinus Torvalds 
exit_i82365(void)13171da177e4SLinus Torvalds static void __exit exit_i82365(void)
13181da177e4SLinus Torvalds {
13191da177e4SLinus Torvalds     int i;
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds     for (i = 0; i < sockets; i++) {
13221da177e4SLinus Torvalds 	    if (socket[i].flags & IS_REGISTERED)
13231da177e4SLinus Torvalds 		    pcmcia_unregister_socket(&socket[i].socket);
13241da177e4SLinus Torvalds     }
1325dfb279c9SDominik Brodowski     platform_device_unregister(i82365_device);
13261da177e4SLinus Torvalds     if (poll_interval != 0)
13271da177e4SLinus Torvalds 	del_timer_sync(&poll_timer);
13281da177e4SLinus Torvalds     if (grab_irq != 0)
13291da177e4SLinus Torvalds 	free_irq(cs_irq, pcic_interrupt);
13301da177e4SLinus Torvalds     for (i = 0; i < sockets; i++) {
13311da177e4SLinus Torvalds 	/* Turn off all interrupt sources! */
13321da177e4SLinus Torvalds 	i365_set(i, I365_CSCINT, 0);
13331da177e4SLinus Torvalds 	release_region(socket[i].ioaddr, 2);
13341da177e4SLinus Torvalds     }
1335f354942cSDominik Brodowski     release_region(i365_base, 2);
13361da177e4SLinus Torvalds #ifdef CONFIG_PNP
13371da177e4SLinus Torvalds     if (i82365_pnpdev)
13381da177e4SLinus Torvalds     		pnp_disable_dev(i82365_pnpdev);
13391da177e4SLinus Torvalds #endif
13407a192ec3SMing Lei     platform_driver_unregister(&i82365_driver);
13411da177e4SLinus Torvalds } /* exit_i82365 */
13421da177e4SLinus Torvalds 
13431da177e4SLinus Torvalds module_init(init_i82365);
13441da177e4SLinus Torvalds module_exit(exit_i82365);
13451da177e4SLinus Torvalds MODULE_LICENSE("Dual MPL/GPL");
13461da177e4SLinus Torvalds /*====================================================================*/
1347