18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Regular cardbus driver ("yenta_socket")
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * (C) Copyright 1999, 2000 Linus Torvalds
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Changelog:
88c2ecf20Sopenharmony_ci * Aug 2002: Manfred Spraul <manfred@colorfullife.com>
98c2ecf20Sopenharmony_ci * 	Dynamically adjust the size of the bridge resource
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * May 2003: Dominik Brodowski <linux@brodo.de>
128c2ecf20Sopenharmony_ci * 	Merge pci_socket.c and yenta.c into one file
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/pci.h>
168c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
178c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
188c2ecf20Sopenharmony_ci#include <linux/delay.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/io.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <pcmcia/ss.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "yenta_socket.h"
268c2ecf20Sopenharmony_ci#include "i82365.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic bool disable_clkrun;
298c2ecf20Sopenharmony_cimodule_param(disable_clkrun, bool, 0444);
308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_clkrun,
318c2ecf20Sopenharmony_ci		 "If PC card doesn't function properly, please try this option (TI and Ricoh bridges only)");
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic bool isa_probe = 1;
348c2ecf20Sopenharmony_cimodule_param(isa_probe, bool, 0444);
358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(isa_probe, "If set ISA interrupts are probed (default). Set to N to disable probing");
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic bool pwr_irqs_off;
388c2ecf20Sopenharmony_cimodule_param(pwr_irqs_off, bool, 0644);
398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!");
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic char o2_speedup[] = "default";
428c2ecf20Sopenharmony_cimodule_param_string(o2_speedup, o2_speedup, sizeof(o2_speedup), 0444);
438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(o2_speedup, "Use prefetch/burst for O2-bridges: 'on', 'off' "
448c2ecf20Sopenharmony_ci	"or 'default' (uses recommended behaviour for the detected bridge)");
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/*
478c2ecf20Sopenharmony_ci * Only probe "regular" interrupts, don't
488c2ecf20Sopenharmony_ci * touch dangerous spots like the mouse irq,
498c2ecf20Sopenharmony_ci * because there are mice that apparently
508c2ecf20Sopenharmony_ci * get really confused if they get fondled
518c2ecf20Sopenharmony_ci * too intimately.
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * Default to 11, 10, 9, 7, 6, 5, 4, 3.
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_cistatic u32 isa_interrupts = 0x0ef8;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define debug(x, s, args...) dev_dbg(&s->dev->dev, x, ##args)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/* Don't ask.. */
618c2ecf20Sopenharmony_ci#define to_cycles(ns)	((ns)/120)
628c2ecf20Sopenharmony_ci#define to_ns(cycles)	((cycles)*120)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * yenta PCI irq probing.
668c2ecf20Sopenharmony_ci * currently only used in the TI/EnE initialization code
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_TI
698c2ecf20Sopenharmony_cistatic int yenta_probe_cb_irq(struct yenta_socket *socket);
708c2ecf20Sopenharmony_cistatic unsigned int yenta_probe_irq(struct yenta_socket *socket,
718c2ecf20Sopenharmony_ci				u32 isa_irq_mask);
728c2ecf20Sopenharmony_ci#endif
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic unsigned int override_bios;
768c2ecf20Sopenharmony_cimodule_param(override_bios, uint, 0000);
778c2ecf20Sopenharmony_ciMODULE_PARM_DESC(override_bios, "yenta ignore bios resource allocation");
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * Generate easy-to-use ways of reading a cardbus sockets
818c2ecf20Sopenharmony_ci * regular memory space ("cb_xxx"), configuration space
828c2ecf20Sopenharmony_ci * ("config_xxx") and compatibility space ("exca_xxxx")
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_cistatic inline u32 cb_readl(struct yenta_socket *socket, unsigned reg)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	u32 val = readl(socket->base + reg);
878c2ecf20Sopenharmony_ci	debug("%04x %08x\n", socket, reg, val);
888c2ecf20Sopenharmony_ci	return val;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	debug("%04x %08x\n", socket, reg, val);
948c2ecf20Sopenharmony_ci	writel(val, socket->base + reg);
958c2ecf20Sopenharmony_ci	readl(socket->base + reg); /* avoid problems with PCI write posting */
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic inline u8 config_readb(struct yenta_socket *socket, unsigned offset)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	u8 val;
1018c2ecf20Sopenharmony_ci	pci_read_config_byte(socket->dev, offset, &val);
1028c2ecf20Sopenharmony_ci	debug("%04x %02x\n", socket, offset, val);
1038c2ecf20Sopenharmony_ci	return val;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic inline u16 config_readw(struct yenta_socket *socket, unsigned offset)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	u16 val;
1098c2ecf20Sopenharmony_ci	pci_read_config_word(socket->dev, offset, &val);
1108c2ecf20Sopenharmony_ci	debug("%04x %04x\n", socket, offset, val);
1118c2ecf20Sopenharmony_ci	return val;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic inline u32 config_readl(struct yenta_socket *socket, unsigned offset)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	u32 val;
1178c2ecf20Sopenharmony_ci	pci_read_config_dword(socket->dev, offset, &val);
1188c2ecf20Sopenharmony_ci	debug("%04x %08x\n", socket, offset, val);
1198c2ecf20Sopenharmony_ci	return val;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	debug("%04x %02x\n", socket, offset, val);
1258c2ecf20Sopenharmony_ci	pci_write_config_byte(socket->dev, offset, val);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	debug("%04x %04x\n", socket, offset, val);
1318c2ecf20Sopenharmony_ci	pci_write_config_word(socket->dev, offset, val);
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	debug("%04x %08x\n", socket, offset, val);
1378c2ecf20Sopenharmony_ci	pci_write_config_dword(socket->dev, offset, val);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic inline u8 exca_readb(struct yenta_socket *socket, unsigned reg)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	u8 val = readb(socket->base + 0x800 + reg);
1438c2ecf20Sopenharmony_ci	debug("%04x %02x\n", socket, reg, val);
1448c2ecf20Sopenharmony_ci	return val;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic inline u8 exca_readw(struct yenta_socket *socket, unsigned reg)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	u16 val;
1508c2ecf20Sopenharmony_ci	val = readb(socket->base + 0x800 + reg);
1518c2ecf20Sopenharmony_ci	val |= readb(socket->base + 0x800 + reg + 1) << 8;
1528c2ecf20Sopenharmony_ci	debug("%04x %04x\n", socket, reg, val);
1538c2ecf20Sopenharmony_ci	return val;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	debug("%04x %02x\n", socket, reg, val);
1598c2ecf20Sopenharmony_ci	writeb(val, socket->base + 0x800 + reg);
1608c2ecf20Sopenharmony_ci	readb(socket->base + 0x800 + reg); /* PCI write posting... */
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	debug("%04x %04x\n", socket, reg, val);
1668c2ecf20Sopenharmony_ci	writeb(val, socket->base + 0x800 + reg);
1678c2ecf20Sopenharmony_ci	writeb(val >> 8, socket->base + 0x800 + reg + 1);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* PCI write posting... */
1708c2ecf20Sopenharmony_ci	readb(socket->base + 0x800 + reg);
1718c2ecf20Sopenharmony_ci	readb(socket->base + 0x800 + reg + 1);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic ssize_t show_yenta_registers(struct device *yentadev, struct device_attribute *attr, char *buf)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct yenta_socket *socket = dev_get_drvdata(yentadev);
1778c2ecf20Sopenharmony_ci	int offset = 0, i;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	offset = snprintf(buf, PAGE_SIZE, "CB registers:");
1808c2ecf20Sopenharmony_ci	for (i = 0; i < 0x24; i += 4) {
1818c2ecf20Sopenharmony_ci		unsigned val;
1828c2ecf20Sopenharmony_ci		if (!(i & 15))
1838c2ecf20Sopenharmony_ci			offset += scnprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i);
1848c2ecf20Sopenharmony_ci		val = cb_readl(socket, i);
1858c2ecf20Sopenharmony_ci		offset += scnprintf(buf + offset, PAGE_SIZE - offset, " %08x", val);
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	offset += scnprintf(buf + offset, PAGE_SIZE - offset, "\n\nExCA registers:");
1898c2ecf20Sopenharmony_ci	for (i = 0; i < 0x45; i++) {
1908c2ecf20Sopenharmony_ci		unsigned char val;
1918c2ecf20Sopenharmony_ci		if (!(i & 7)) {
1928c2ecf20Sopenharmony_ci			if (i & 8) {
1938c2ecf20Sopenharmony_ci				memcpy(buf + offset, " -", 2);
1948c2ecf20Sopenharmony_ci				offset += 2;
1958c2ecf20Sopenharmony_ci			} else
1968c2ecf20Sopenharmony_ci				offset += scnprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i);
1978c2ecf20Sopenharmony_ci		}
1988c2ecf20Sopenharmony_ci		val = exca_readb(socket, i);
1998c2ecf20Sopenharmony_ci		offset += scnprintf(buf + offset, PAGE_SIZE - offset, " %02x", val);
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci	buf[offset++] = '\n';
2028c2ecf20Sopenharmony_ci	return offset;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic DEVICE_ATTR(yenta_registers, S_IRUSR, show_yenta_registers, NULL);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/*
2088c2ecf20Sopenharmony_ci * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend
2098c2ecf20Sopenharmony_ci * on what kind of card is inserted..
2108c2ecf20Sopenharmony_ci */
2118c2ecf20Sopenharmony_cistatic int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
2148c2ecf20Sopenharmony_ci	unsigned int val;
2158c2ecf20Sopenharmony_ci	u32 state = cb_readl(socket, CB_SOCKET_STATE);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	val  = (state & CB_3VCARD) ? SS_3VCARD : 0;
2188c2ecf20Sopenharmony_ci	val |= (state & CB_XVCARD) ? SS_XVCARD : 0;
2198c2ecf20Sopenharmony_ci	val |= (state & (CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING;
2208c2ecf20Sopenharmony_ci	val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? SS_PENDING : 0;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (state & CB_CBCARD) {
2248c2ecf20Sopenharmony_ci		val |= SS_CARDBUS;
2258c2ecf20Sopenharmony_ci		val |= (state & CB_CARDSTS) ? SS_STSCHG : 0;
2268c2ecf20Sopenharmony_ci		val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT;
2278c2ecf20Sopenharmony_ci		val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0;
2288c2ecf20Sopenharmony_ci	} else if (state & CB_16BITCARD) {
2298c2ecf20Sopenharmony_ci		u8 status = exca_readb(socket, I365_STATUS);
2308c2ecf20Sopenharmony_ci		val |= ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0;
2318c2ecf20Sopenharmony_ci		if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) {
2328c2ecf20Sopenharmony_ci			val |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
2338c2ecf20Sopenharmony_ci		} else {
2348c2ecf20Sopenharmony_ci			val |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
2358c2ecf20Sopenharmony_ci			val |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
2368c2ecf20Sopenharmony_ci		}
2378c2ecf20Sopenharmony_ci		val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
2388c2ecf20Sopenharmony_ci		val |= (status & I365_CS_READY) ? SS_READY : 0;
2398c2ecf20Sopenharmony_ci		val |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	*value = val;
2438c2ecf20Sopenharmony_ci	return 0;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic void yenta_set_power(struct yenta_socket *socket, socket_state_t *state)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	/* some birdges require to use the ExCA registers to power 16bit cards */
2498c2ecf20Sopenharmony_ci	if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
2508c2ecf20Sopenharmony_ci	    (socket->flags & YENTA_16BIT_POWER_EXCA)) {
2518c2ecf20Sopenharmony_ci		u8 reg, old;
2528c2ecf20Sopenharmony_ci		reg = old = exca_readb(socket, I365_POWER);
2538c2ecf20Sopenharmony_ci		reg &= ~(I365_VCC_MASK | I365_VPP1_MASK | I365_VPP2_MASK);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		/* i82365SL-DF style */
2568c2ecf20Sopenharmony_ci		if (socket->flags & YENTA_16BIT_POWER_DF) {
2578c2ecf20Sopenharmony_ci			switch (state->Vcc) {
2588c2ecf20Sopenharmony_ci			case 33:
2598c2ecf20Sopenharmony_ci				reg |= I365_VCC_3V;
2608c2ecf20Sopenharmony_ci				break;
2618c2ecf20Sopenharmony_ci			case 50:
2628c2ecf20Sopenharmony_ci				reg |= I365_VCC_5V;
2638c2ecf20Sopenharmony_ci				break;
2648c2ecf20Sopenharmony_ci			default:
2658c2ecf20Sopenharmony_ci				reg = 0;
2668c2ecf20Sopenharmony_ci				break;
2678c2ecf20Sopenharmony_ci			}
2688c2ecf20Sopenharmony_ci			switch (state->Vpp) {
2698c2ecf20Sopenharmony_ci			case 33:
2708c2ecf20Sopenharmony_ci			case 50:
2718c2ecf20Sopenharmony_ci				reg |= I365_VPP1_5V;
2728c2ecf20Sopenharmony_ci				break;
2738c2ecf20Sopenharmony_ci			case 120:
2748c2ecf20Sopenharmony_ci				reg |= I365_VPP1_12V;
2758c2ecf20Sopenharmony_ci				break;
2768c2ecf20Sopenharmony_ci			}
2778c2ecf20Sopenharmony_ci		} else {
2788c2ecf20Sopenharmony_ci			/* i82365SL-B style */
2798c2ecf20Sopenharmony_ci			switch (state->Vcc) {
2808c2ecf20Sopenharmony_ci			case 50:
2818c2ecf20Sopenharmony_ci				reg |= I365_VCC_5V;
2828c2ecf20Sopenharmony_ci				break;
2838c2ecf20Sopenharmony_ci			default:
2848c2ecf20Sopenharmony_ci				reg = 0;
2858c2ecf20Sopenharmony_ci				break;
2868c2ecf20Sopenharmony_ci			}
2878c2ecf20Sopenharmony_ci			switch (state->Vpp) {
2888c2ecf20Sopenharmony_ci			case 50:
2898c2ecf20Sopenharmony_ci				reg |= I365_VPP1_5V | I365_VPP2_5V;
2908c2ecf20Sopenharmony_ci				break;
2918c2ecf20Sopenharmony_ci			case 120:
2928c2ecf20Sopenharmony_ci				reg |= I365_VPP1_12V | I365_VPP2_12V;
2938c2ecf20Sopenharmony_ci				break;
2948c2ecf20Sopenharmony_ci			}
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		if (reg != old)
2988c2ecf20Sopenharmony_ci			exca_writeb(socket, I365_POWER, reg);
2998c2ecf20Sopenharmony_ci	} else {
3008c2ecf20Sopenharmony_ci		u32 reg = 0;	/* CB_SC_STPCLK? */
3018c2ecf20Sopenharmony_ci		switch (state->Vcc) {
3028c2ecf20Sopenharmony_ci		case 33:
3038c2ecf20Sopenharmony_ci			reg = CB_SC_VCC_3V;
3048c2ecf20Sopenharmony_ci			break;
3058c2ecf20Sopenharmony_ci		case 50:
3068c2ecf20Sopenharmony_ci			reg = CB_SC_VCC_5V;
3078c2ecf20Sopenharmony_ci			break;
3088c2ecf20Sopenharmony_ci		default:
3098c2ecf20Sopenharmony_ci			reg = 0;
3108c2ecf20Sopenharmony_ci			break;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci		switch (state->Vpp) {
3138c2ecf20Sopenharmony_ci		case 33:
3148c2ecf20Sopenharmony_ci			reg |= CB_SC_VPP_3V;
3158c2ecf20Sopenharmony_ci			break;
3168c2ecf20Sopenharmony_ci		case 50:
3178c2ecf20Sopenharmony_ci			reg |= CB_SC_VPP_5V;
3188c2ecf20Sopenharmony_ci			break;
3198c2ecf20Sopenharmony_ci		case 120:
3208c2ecf20Sopenharmony_ci			reg |= CB_SC_VPP_12V;
3218c2ecf20Sopenharmony_ci			break;
3228c2ecf20Sopenharmony_ci		}
3238c2ecf20Sopenharmony_ci		if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
3248c2ecf20Sopenharmony_ci			cb_writel(socket, CB_SOCKET_CONTROL, reg);
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
3318c2ecf20Sopenharmony_ci	u16 bridge;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* if powering down: do it immediately */
3348c2ecf20Sopenharmony_ci	if (state->Vcc == 0)
3358c2ecf20Sopenharmony_ci		yenta_set_power(socket, state);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	socket->io_irq = state->io_irq;
3388c2ecf20Sopenharmony_ci	bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR);
3398c2ecf20Sopenharmony_ci	if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
3408c2ecf20Sopenharmony_ci		u8 intr;
3418c2ecf20Sopenharmony_ci		bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		/* ISA interrupt control? */
3448c2ecf20Sopenharmony_ci		intr = exca_readb(socket, I365_INTCTL);
3458c2ecf20Sopenharmony_ci		intr = (intr & ~0xf);
3468c2ecf20Sopenharmony_ci		if (!socket->dev->irq) {
3478c2ecf20Sopenharmony_ci			intr |= socket->cb_irq ? socket->cb_irq : state->io_irq;
3488c2ecf20Sopenharmony_ci			bridge |= CB_BRIDGE_INTR;
3498c2ecf20Sopenharmony_ci		}
3508c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_INTCTL, intr);
3518c2ecf20Sopenharmony_ci	}  else {
3528c2ecf20Sopenharmony_ci		u8 reg;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA);
3558c2ecf20Sopenharmony_ci		reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
3568c2ecf20Sopenharmony_ci		reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
3578c2ecf20Sopenharmony_ci		if (state->io_irq != socket->dev->irq) {
3588c2ecf20Sopenharmony_ci			reg |= state->io_irq;
3598c2ecf20Sopenharmony_ci			bridge |= CB_BRIDGE_INTR;
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_INTCTL, reg);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		reg = exca_readb(socket, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK);
3648c2ecf20Sopenharmony_ci		reg |= I365_PWR_NORESET;
3658c2ecf20Sopenharmony_ci		if (state->flags & SS_PWR_AUTO)
3668c2ecf20Sopenharmony_ci			reg |= I365_PWR_AUTO;
3678c2ecf20Sopenharmony_ci		if (state->flags & SS_OUTPUT_ENA)
3688c2ecf20Sopenharmony_ci			reg |= I365_PWR_OUT;
3698c2ecf20Sopenharmony_ci		if (exca_readb(socket, I365_POWER) != reg)
3708c2ecf20Sopenharmony_ci			exca_writeb(socket, I365_POWER, reg);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		/* CSC interrupt: no ISA irq for CSC */
3738c2ecf20Sopenharmony_ci		reg = exca_readb(socket, I365_CSCINT);
3748c2ecf20Sopenharmony_ci		reg &= I365_CSC_IRQ_MASK;
3758c2ecf20Sopenharmony_ci		reg |= I365_CSC_DETECT;
3768c2ecf20Sopenharmony_ci		if (state->flags & SS_IOCARD) {
3778c2ecf20Sopenharmony_ci			if (state->csc_mask & SS_STSCHG)
3788c2ecf20Sopenharmony_ci				reg |= I365_CSC_STSCHG;
3798c2ecf20Sopenharmony_ci		} else {
3808c2ecf20Sopenharmony_ci			if (state->csc_mask & SS_BATDEAD)
3818c2ecf20Sopenharmony_ci				reg |= I365_CSC_BVD1;
3828c2ecf20Sopenharmony_ci			if (state->csc_mask & SS_BATWARN)
3838c2ecf20Sopenharmony_ci				reg |= I365_CSC_BVD2;
3848c2ecf20Sopenharmony_ci			if (state->csc_mask & SS_READY)
3858c2ecf20Sopenharmony_ci				reg |= I365_CSC_READY;
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_CSCINT, reg);
3888c2ecf20Sopenharmony_ci		exca_readb(socket, I365_CSC);
3898c2ecf20Sopenharmony_ci		if (sock->zoom_video)
3908c2ecf20Sopenharmony_ci			sock->zoom_video(sock, state->flags & SS_ZVCARD);
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci	config_writew(socket, CB_BRIDGE_CONTROL, bridge);
3938c2ecf20Sopenharmony_ci	/* Socket event mask: get card insert/remove events.. */
3948c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_EVENT, -1);
3958c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* if powering up: do it as the last step when the socket is configured */
3988c2ecf20Sopenharmony_ci	if (state->Vcc != 0)
3998c2ecf20Sopenharmony_ci		yenta_set_power(socket, state);
4008c2ecf20Sopenharmony_ci	return 0;
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic int yenta_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
4068c2ecf20Sopenharmony_ci	int map;
4078c2ecf20Sopenharmony_ci	unsigned char ioctl, addr, enable;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	map = io->map;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (map > 1)
4128c2ecf20Sopenharmony_ci		return -EINVAL;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	enable = I365_ENA_IO(map);
4158c2ecf20Sopenharmony_ci	addr = exca_readb(socket, I365_ADDRWIN);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/* Disable the window before changing it.. */
4188c2ecf20Sopenharmony_ci	if (addr & enable) {
4198c2ecf20Sopenharmony_ci		addr &= ~enable;
4208c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_ADDRWIN, addr);
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	exca_writew(socket, I365_IO(map)+I365_W_START, io->start);
4248c2ecf20Sopenharmony_ci	exca_writew(socket, I365_IO(map)+I365_W_STOP, io->stop);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	ioctl = exca_readb(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);
4278c2ecf20Sopenharmony_ci	if (io->flags & MAP_0WS)
4288c2ecf20Sopenharmony_ci		ioctl |= I365_IOCTL_0WS(map);
4298c2ecf20Sopenharmony_ci	if (io->flags & MAP_16BIT)
4308c2ecf20Sopenharmony_ci		ioctl |= I365_IOCTL_16BIT(map);
4318c2ecf20Sopenharmony_ci	if (io->flags & MAP_AUTOSZ)
4328c2ecf20Sopenharmony_ci		ioctl |= I365_IOCTL_IOCS16(map);
4338c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_IOCTL, ioctl);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (io->flags & MAP_ACTIVE)
4368c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_ADDRWIN, addr | enable);
4378c2ecf20Sopenharmony_ci	return 0;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
4438c2ecf20Sopenharmony_ci	struct pci_bus_region region;
4448c2ecf20Sopenharmony_ci	int map;
4458c2ecf20Sopenharmony_ci	unsigned char addr, enable;
4468c2ecf20Sopenharmony_ci	unsigned int start, stop, card_start;
4478c2ecf20Sopenharmony_ci	unsigned short word;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(socket->dev->bus, &region, mem->res);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	map = mem->map;
4528c2ecf20Sopenharmony_ci	start = region.start;
4538c2ecf20Sopenharmony_ci	stop = region.end;
4548c2ecf20Sopenharmony_ci	card_start = mem->card_start;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	if (map > 4 || start > stop || ((start ^ stop) >> 24) ||
4578c2ecf20Sopenharmony_ci	    (card_start >> 26) || mem->speed > 1000)
4588c2ecf20Sopenharmony_ci		return -EINVAL;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	enable = I365_ENA_MEM(map);
4618c2ecf20Sopenharmony_ci	addr = exca_readb(socket, I365_ADDRWIN);
4628c2ecf20Sopenharmony_ci	if (addr & enable) {
4638c2ecf20Sopenharmony_ci		addr &= ~enable;
4648c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_ADDRWIN, addr);
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	exca_writeb(socket, CB_MEM_PAGE(map), start >> 24);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	word = (start >> 12) & 0x0fff;
4708c2ecf20Sopenharmony_ci	if (mem->flags & MAP_16BIT)
4718c2ecf20Sopenharmony_ci		word |= I365_MEM_16BIT;
4728c2ecf20Sopenharmony_ci	if (mem->flags & MAP_0WS)
4738c2ecf20Sopenharmony_ci		word |= I365_MEM_0WS;
4748c2ecf20Sopenharmony_ci	exca_writew(socket, I365_MEM(map) + I365_W_START, word);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	word = (stop >> 12) & 0x0fff;
4778c2ecf20Sopenharmony_ci	switch (to_cycles(mem->speed)) {
4788c2ecf20Sopenharmony_ci	case 0:
4798c2ecf20Sopenharmony_ci		break;
4808c2ecf20Sopenharmony_ci	case 1:
4818c2ecf20Sopenharmony_ci		word |= I365_MEM_WS0;
4828c2ecf20Sopenharmony_ci		break;
4838c2ecf20Sopenharmony_ci	case 2:
4848c2ecf20Sopenharmony_ci		word |= I365_MEM_WS1;
4858c2ecf20Sopenharmony_ci		break;
4868c2ecf20Sopenharmony_ci	default:
4878c2ecf20Sopenharmony_ci		word |= I365_MEM_WS1 | I365_MEM_WS0;
4888c2ecf20Sopenharmony_ci		break;
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci	exca_writew(socket, I365_MEM(map) + I365_W_STOP, word);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	word = ((card_start - start) >> 12) & 0x3fff;
4938c2ecf20Sopenharmony_ci	if (mem->flags & MAP_WRPROT)
4948c2ecf20Sopenharmony_ci		word |= I365_MEM_WRPROT;
4958c2ecf20Sopenharmony_ci	if (mem->flags & MAP_ATTRIB)
4968c2ecf20Sopenharmony_ci		word |= I365_MEM_REG;
4978c2ecf20Sopenharmony_ci	exca_writew(socket, I365_MEM(map) + I365_W_OFF, word);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (mem->flags & MAP_ACTIVE)
5008c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_ADDRWIN, addr | enable);
5018c2ecf20Sopenharmony_ci	return 0;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic irqreturn_t yenta_interrupt(int irq, void *dev_id)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	unsigned int events;
5098c2ecf20Sopenharmony_ci	struct yenta_socket *socket = (struct yenta_socket *) dev_id;
5108c2ecf20Sopenharmony_ci	u8 csc;
5118c2ecf20Sopenharmony_ci	u32 cb_event;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	/* Clear interrupt status for the event */
5148c2ecf20Sopenharmony_ci	cb_event = cb_readl(socket, CB_SOCKET_EVENT);
5158c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_EVENT, cb_event);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	csc = exca_readb(socket, I365_CSC);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (!(cb_event || csc))
5208c2ecf20Sopenharmony_ci		return IRQ_NONE;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	events = (cb_event & (CB_CD1EVENT | CB_CD2EVENT)) ? SS_DETECT : 0 ;
5238c2ecf20Sopenharmony_ci	events |= (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
5248c2ecf20Sopenharmony_ci	if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) {
5258c2ecf20Sopenharmony_ci		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
5268c2ecf20Sopenharmony_ci	} else {
5278c2ecf20Sopenharmony_ci		events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
5288c2ecf20Sopenharmony_ci		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
5298c2ecf20Sopenharmony_ci		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (events)
5338c2ecf20Sopenharmony_ci		pcmcia_parse_events(&socket->socket, events);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic void yenta_interrupt_wrapper(struct timer_list *t)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	struct yenta_socket *socket = from_timer(socket, t, poll_timer);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	yenta_interrupt(0, (void *)socket);
5438c2ecf20Sopenharmony_ci	socket->poll_timer.expires = jiffies + HZ;
5448c2ecf20Sopenharmony_ci	add_timer(&socket->poll_timer);
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_cistatic void yenta_clear_maps(struct yenta_socket *socket)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	int i;
5508c2ecf20Sopenharmony_ci	struct resource res = { .start = 0, .end = 0x0fff };
5518c2ecf20Sopenharmony_ci	pccard_io_map io = { 0, 0, 0, 0, 1 };
5528c2ecf20Sopenharmony_ci	pccard_mem_map mem = { .res = &res, };
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	yenta_set_socket(&socket->socket, &dead_socket);
5558c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
5568c2ecf20Sopenharmony_ci		io.map = i;
5578c2ecf20Sopenharmony_ci		yenta_set_io_map(&socket->socket, &io);
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++) {
5608c2ecf20Sopenharmony_ci		mem.map = i;
5618c2ecf20Sopenharmony_ci		yenta_set_mem_map(&socket->socket, &mem);
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci/* redoes voltage interrogation if required */
5668c2ecf20Sopenharmony_cistatic void yenta_interrogate(struct yenta_socket *socket)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	u32 state;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	state = cb_readl(socket, CB_SOCKET_STATE);
5718c2ecf20Sopenharmony_ci	if (!(state & (CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD)) ||
5728c2ecf20Sopenharmony_ci	    (state & (CB_CDETECT1 | CB_CDETECT2 | CB_NOTACARD | CB_BADVCCREQ)) ||
5738c2ecf20Sopenharmony_ci	    ((state & (CB_16BITCARD | CB_CBCARD)) == (CB_16BITCARD | CB_CBCARD)))
5748c2ecf20Sopenharmony_ci		cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST);
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci/* Called at resume and initialization events */
5788c2ecf20Sopenharmony_cistatic int yenta_sock_init(struct pcmcia_socket *sock)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_GBLCTL, 0x00);
5838c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_GENCTL, 0x00);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* Redo card voltage interrogation */
5868c2ecf20Sopenharmony_ci	yenta_interrogate(socket);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	yenta_clear_maps(socket);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	if (socket->type && socket->type->sock_init)
5918c2ecf20Sopenharmony_ci		socket->type->sock_init(socket);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* Re-enable CSC interrupts */
5948c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	return 0;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cistatic int yenta_sock_suspend(struct pcmcia_socket *sock)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	/* Disable CSC interrupts */
6048c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_MASK, 0x0);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	return 0;
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci/*
6108c2ecf20Sopenharmony_ci * Use an adaptive allocation for the memory resource,
6118c2ecf20Sopenharmony_ci * sometimes the memory behind pci bridges is limited:
6128c2ecf20Sopenharmony_ci * 1/8 of the size of the io window of the parent.
6138c2ecf20Sopenharmony_ci * max 4 MB, min 16 kB. We try very hard to not get below
6148c2ecf20Sopenharmony_ci * the "ACC" values, though.
6158c2ecf20Sopenharmony_ci */
6168c2ecf20Sopenharmony_ci#define BRIDGE_MEM_MAX (4*1024*1024)
6178c2ecf20Sopenharmony_ci#define BRIDGE_MEM_ACC (128*1024)
6188c2ecf20Sopenharmony_ci#define BRIDGE_MEM_MIN (16*1024)
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci#define BRIDGE_IO_MAX 512
6218c2ecf20Sopenharmony_ci#define BRIDGE_IO_ACC 256
6228c2ecf20Sopenharmony_ci#define BRIDGE_IO_MIN 32
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci#ifndef PCIBIOS_MIN_CARDBUS_IO
6258c2ecf20Sopenharmony_ci#define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO
6268c2ecf20Sopenharmony_ci#endif
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic int yenta_search_one_res(struct resource *root, struct resource *res,
6298c2ecf20Sopenharmony_ci				u32 min)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	u32 align, size, start, end;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO) {
6348c2ecf20Sopenharmony_ci		align = 1024;
6358c2ecf20Sopenharmony_ci		size = BRIDGE_IO_MAX;
6368c2ecf20Sopenharmony_ci		start = PCIBIOS_MIN_CARDBUS_IO;
6378c2ecf20Sopenharmony_ci		end = ~0U;
6388c2ecf20Sopenharmony_ci	} else {
6398c2ecf20Sopenharmony_ci		unsigned long avail = root->end - root->start;
6408c2ecf20Sopenharmony_ci		int i;
6418c2ecf20Sopenharmony_ci		size = BRIDGE_MEM_MAX;
6428c2ecf20Sopenharmony_ci		if (size > avail/8) {
6438c2ecf20Sopenharmony_ci			size = (avail+1)/8;
6448c2ecf20Sopenharmony_ci			/* round size down to next power of 2 */
6458c2ecf20Sopenharmony_ci			i = 0;
6468c2ecf20Sopenharmony_ci			while ((size /= 2) != 0)
6478c2ecf20Sopenharmony_ci				i++;
6488c2ecf20Sopenharmony_ci			size = 1 << i;
6498c2ecf20Sopenharmony_ci		}
6508c2ecf20Sopenharmony_ci		if (size < min)
6518c2ecf20Sopenharmony_ci			size = min;
6528c2ecf20Sopenharmony_ci		align = size;
6538c2ecf20Sopenharmony_ci		start = PCIBIOS_MIN_MEM;
6548c2ecf20Sopenharmony_ci		end = ~0U;
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	do {
6588c2ecf20Sopenharmony_ci		if (allocate_resource(root, res, size, start, end, align,
6598c2ecf20Sopenharmony_ci				      NULL, NULL) == 0) {
6608c2ecf20Sopenharmony_ci			return 1;
6618c2ecf20Sopenharmony_ci		}
6628c2ecf20Sopenharmony_ci		size = size/2;
6638c2ecf20Sopenharmony_ci		align = size;
6648c2ecf20Sopenharmony_ci	} while (size >= min);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	return 0;
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cistatic int yenta_search_res(struct yenta_socket *socket, struct resource *res,
6718c2ecf20Sopenharmony_ci			    u32 min)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	struct resource *root;
6748c2ecf20Sopenharmony_ci	int i;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	pci_bus_for_each_resource(socket->dev->bus, root, i) {
6778c2ecf20Sopenharmony_ci		if (!root)
6788c2ecf20Sopenharmony_ci			continue;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		if ((res->flags ^ root->flags) &
6818c2ecf20Sopenharmony_ci		    (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH))
6828c2ecf20Sopenharmony_ci			continue; /* Wrong type */
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		if (yenta_search_one_res(root, res, min))
6858c2ecf20Sopenharmony_ci			return 1;
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci	return 0;
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_cistatic int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	struct pci_dev *dev = socket->dev;
6938c2ecf20Sopenharmony_ci	struct resource *res;
6948c2ecf20Sopenharmony_ci	struct pci_bus_region region;
6958c2ecf20Sopenharmony_ci	unsigned mask;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	res = &dev->resource[nr];
6988c2ecf20Sopenharmony_ci	/* Already allocated? */
6998c2ecf20Sopenharmony_ci	if (res->parent)
7008c2ecf20Sopenharmony_ci		return 0;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	/* The granularity of the memory limit is 4kB, on IO it's 4 bytes */
7038c2ecf20Sopenharmony_ci	mask = ~0xfff;
7048c2ecf20Sopenharmony_ci	if (type & IORESOURCE_IO)
7058c2ecf20Sopenharmony_ci		mask = ~3;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	res->name = dev->subordinate->name;
7088c2ecf20Sopenharmony_ci	res->flags = type;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	region.start = config_readl(socket, addr_start) & mask;
7118c2ecf20Sopenharmony_ci	region.end = config_readl(socket, addr_end) | ~mask;
7128c2ecf20Sopenharmony_ci	if (region.start && region.end > region.start && !override_bios) {
7138c2ecf20Sopenharmony_ci		pcibios_bus_to_resource(dev->bus, res, &region);
7148c2ecf20Sopenharmony_ci		if (pci_claim_resource(dev, nr) == 0)
7158c2ecf20Sopenharmony_ci			return 0;
7168c2ecf20Sopenharmony_ci		dev_info(&dev->dev,
7178c2ecf20Sopenharmony_ci			 "Preassigned resource %d busy or not available, reconfiguring...\n",
7188c2ecf20Sopenharmony_ci			 nr);
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	if (type & IORESOURCE_IO) {
7228c2ecf20Sopenharmony_ci		if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) ||
7238c2ecf20Sopenharmony_ci		    (yenta_search_res(socket, res, BRIDGE_IO_ACC)) ||
7248c2ecf20Sopenharmony_ci		    (yenta_search_res(socket, res, BRIDGE_IO_MIN)))
7258c2ecf20Sopenharmony_ci			return 1;
7268c2ecf20Sopenharmony_ci	} else {
7278c2ecf20Sopenharmony_ci		if (type & IORESOURCE_PREFETCH) {
7288c2ecf20Sopenharmony_ci			if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) ||
7298c2ecf20Sopenharmony_ci			    (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) ||
7308c2ecf20Sopenharmony_ci			    (yenta_search_res(socket, res, BRIDGE_MEM_MIN)))
7318c2ecf20Sopenharmony_ci				return 1;
7328c2ecf20Sopenharmony_ci			/* Approximating prefetchable by non-prefetchable */
7338c2ecf20Sopenharmony_ci			res->flags = IORESOURCE_MEM;
7348c2ecf20Sopenharmony_ci		}
7358c2ecf20Sopenharmony_ci		if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) ||
7368c2ecf20Sopenharmony_ci		    (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) ||
7378c2ecf20Sopenharmony_ci		    (yenta_search_res(socket, res, BRIDGE_MEM_MIN)))
7388c2ecf20Sopenharmony_ci			return 1;
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	dev_info(&dev->dev,
7428c2ecf20Sopenharmony_ci		 "no resource of type %x available, trying to continue...\n",
7438c2ecf20Sopenharmony_ci		 type);
7448c2ecf20Sopenharmony_ci	res->start = res->end = res->flags = 0;
7458c2ecf20Sopenharmony_ci	return 0;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic void yenta_free_res(struct yenta_socket *socket, int nr)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	struct pci_dev *dev = socket->dev;
7518c2ecf20Sopenharmony_ci	struct resource *res;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	res = &dev->resource[nr];
7548c2ecf20Sopenharmony_ci	if (res->start != 0 && res->end != 0)
7558c2ecf20Sopenharmony_ci		release_resource(res);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	res->start = res->end = res->flags = 0;
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci/*
7618c2ecf20Sopenharmony_ci * Allocate the bridge mappings for the device..
7628c2ecf20Sopenharmony_ci */
7638c2ecf20Sopenharmony_cistatic void yenta_allocate_resources(struct yenta_socket *socket)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	int program = 0;
7668c2ecf20Sopenharmony_ci	program += yenta_allocate_res(socket, PCI_CB_BRIDGE_IO_0_WINDOW,
7678c2ecf20Sopenharmony_ci			   IORESOURCE_IO,
7688c2ecf20Sopenharmony_ci			   PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0);
7698c2ecf20Sopenharmony_ci	program += yenta_allocate_res(socket, PCI_CB_BRIDGE_IO_1_WINDOW,
7708c2ecf20Sopenharmony_ci			   IORESOURCE_IO,
7718c2ecf20Sopenharmony_ci			   PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1);
7728c2ecf20Sopenharmony_ci	program += yenta_allocate_res(socket, PCI_CB_BRIDGE_MEM_0_WINDOW,
7738c2ecf20Sopenharmony_ci			   IORESOURCE_MEM | IORESOURCE_PREFETCH,
7748c2ecf20Sopenharmony_ci			   PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0);
7758c2ecf20Sopenharmony_ci	program += yenta_allocate_res(socket, PCI_CB_BRIDGE_MEM_1_WINDOW,
7768c2ecf20Sopenharmony_ci			   IORESOURCE_MEM,
7778c2ecf20Sopenharmony_ci			   PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1);
7788c2ecf20Sopenharmony_ci	if (program)
7798c2ecf20Sopenharmony_ci		pci_setup_cardbus(socket->dev->subordinate);
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci/*
7848c2ecf20Sopenharmony_ci * Free the bridge mappings for the device..
7858c2ecf20Sopenharmony_ci */
7868c2ecf20Sopenharmony_cistatic void yenta_free_resources(struct yenta_socket *socket)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	yenta_free_res(socket, PCI_CB_BRIDGE_IO_0_WINDOW);
7898c2ecf20Sopenharmony_ci	yenta_free_res(socket, PCI_CB_BRIDGE_IO_1_WINDOW);
7908c2ecf20Sopenharmony_ci	yenta_free_res(socket, PCI_CB_BRIDGE_MEM_0_WINDOW);
7918c2ecf20Sopenharmony_ci	yenta_free_res(socket, PCI_CB_BRIDGE_MEM_1_WINDOW);
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci/*
7968c2ecf20Sopenharmony_ci * Close it down - release our resources and go home..
7978c2ecf20Sopenharmony_ci */
7988c2ecf20Sopenharmony_cistatic void yenta_close(struct pci_dev *dev)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	struct yenta_socket *sock = pci_get_drvdata(dev);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	/* Remove the register attributes */
8038c2ecf20Sopenharmony_ci	device_remove_file(&dev->dev, &dev_attr_yenta_registers);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	/* we don't want a dying socket registered */
8068c2ecf20Sopenharmony_ci	pcmcia_unregister_socket(&sock->socket);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	/* Disable all events so we don't die in an IRQ storm */
8098c2ecf20Sopenharmony_ci	cb_writel(sock, CB_SOCKET_MASK, 0x0);
8108c2ecf20Sopenharmony_ci	exca_writeb(sock, I365_CSCINT, 0);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (sock->cb_irq)
8138c2ecf20Sopenharmony_ci		free_irq(sock->cb_irq, sock);
8148c2ecf20Sopenharmony_ci	else
8158c2ecf20Sopenharmony_ci		del_timer_sync(&sock->poll_timer);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	iounmap(sock->base);
8188c2ecf20Sopenharmony_ci	yenta_free_resources(sock);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	pci_release_regions(dev);
8218c2ecf20Sopenharmony_ci	pci_disable_device(dev);
8228c2ecf20Sopenharmony_ci	pci_set_drvdata(dev, NULL);
8238c2ecf20Sopenharmony_ci	kfree(sock);
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic struct pccard_operations yenta_socket_operations = {
8288c2ecf20Sopenharmony_ci	.init			= yenta_sock_init,
8298c2ecf20Sopenharmony_ci	.suspend		= yenta_sock_suspend,
8308c2ecf20Sopenharmony_ci	.get_status		= yenta_get_status,
8318c2ecf20Sopenharmony_ci	.set_socket		= yenta_set_socket,
8328c2ecf20Sopenharmony_ci	.set_io_map		= yenta_set_io_map,
8338c2ecf20Sopenharmony_ci	.set_mem_map		= yenta_set_mem_map,
8348c2ecf20Sopenharmony_ci};
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_TI
8388c2ecf20Sopenharmony_ci#include "ti113x.h"
8398c2ecf20Sopenharmony_ci#endif
8408c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_RICOH
8418c2ecf20Sopenharmony_ci#include "ricoh.h"
8428c2ecf20Sopenharmony_ci#endif
8438c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_TOSHIBA
8448c2ecf20Sopenharmony_ci#include "topic.h"
8458c2ecf20Sopenharmony_ci#endif
8468c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_O2
8478c2ecf20Sopenharmony_ci#include "o2micro.h"
8488c2ecf20Sopenharmony_ci#endif
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cienum {
8518c2ecf20Sopenharmony_ci	CARDBUS_TYPE_DEFAULT = -1,
8528c2ecf20Sopenharmony_ci	CARDBUS_TYPE_TI,
8538c2ecf20Sopenharmony_ci	CARDBUS_TYPE_TI113X,
8548c2ecf20Sopenharmony_ci	CARDBUS_TYPE_TI12XX,
8558c2ecf20Sopenharmony_ci	CARDBUS_TYPE_TI1250,
8568c2ecf20Sopenharmony_ci	CARDBUS_TYPE_RICOH,
8578c2ecf20Sopenharmony_ci	CARDBUS_TYPE_TOPIC95,
8588c2ecf20Sopenharmony_ci	CARDBUS_TYPE_TOPIC97,
8598c2ecf20Sopenharmony_ci	CARDBUS_TYPE_O2MICRO,
8608c2ecf20Sopenharmony_ci	CARDBUS_TYPE_ENE,
8618c2ecf20Sopenharmony_ci};
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci/*
8648c2ecf20Sopenharmony_ci * Different cardbus controllers have slightly different
8658c2ecf20Sopenharmony_ci * initialization sequences etc details. List them here..
8668c2ecf20Sopenharmony_ci */
8678c2ecf20Sopenharmony_cistatic struct cardbus_type cardbus_type[] = {
8688c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_TI
8698c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_TI]	= {
8708c2ecf20Sopenharmony_ci		.override	= ti_override,
8718c2ecf20Sopenharmony_ci		.save_state	= ti_save_state,
8728c2ecf20Sopenharmony_ci		.restore_state	= ti_restore_state,
8738c2ecf20Sopenharmony_ci		.sock_init	= ti_init,
8748c2ecf20Sopenharmony_ci	},
8758c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_TI113X]	= {
8768c2ecf20Sopenharmony_ci		.override	= ti113x_override,
8778c2ecf20Sopenharmony_ci		.save_state	= ti_save_state,
8788c2ecf20Sopenharmony_ci		.restore_state	= ti_restore_state,
8798c2ecf20Sopenharmony_ci		.sock_init	= ti_init,
8808c2ecf20Sopenharmony_ci	},
8818c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_TI12XX]	= {
8828c2ecf20Sopenharmony_ci		.override	= ti12xx_override,
8838c2ecf20Sopenharmony_ci		.save_state	= ti_save_state,
8848c2ecf20Sopenharmony_ci		.restore_state	= ti_restore_state,
8858c2ecf20Sopenharmony_ci		.sock_init	= ti_init,
8868c2ecf20Sopenharmony_ci	},
8878c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_TI1250]	= {
8888c2ecf20Sopenharmony_ci		.override	= ti1250_override,
8898c2ecf20Sopenharmony_ci		.save_state	= ti_save_state,
8908c2ecf20Sopenharmony_ci		.restore_state	= ti_restore_state,
8918c2ecf20Sopenharmony_ci		.sock_init	= ti_init,
8928c2ecf20Sopenharmony_ci	},
8938c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_ENE]	= {
8948c2ecf20Sopenharmony_ci		.override	= ene_override,
8958c2ecf20Sopenharmony_ci		.save_state	= ti_save_state,
8968c2ecf20Sopenharmony_ci		.restore_state	= ti_restore_state,
8978c2ecf20Sopenharmony_ci		.sock_init	= ti_init,
8988c2ecf20Sopenharmony_ci	},
8998c2ecf20Sopenharmony_ci#endif
9008c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_RICOH
9018c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_RICOH]	= {
9028c2ecf20Sopenharmony_ci		.override	= ricoh_override,
9038c2ecf20Sopenharmony_ci		.save_state	= ricoh_save_state,
9048c2ecf20Sopenharmony_ci		.restore_state	= ricoh_restore_state,
9058c2ecf20Sopenharmony_ci	},
9068c2ecf20Sopenharmony_ci#endif
9078c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_TOSHIBA
9088c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_TOPIC95]	= {
9098c2ecf20Sopenharmony_ci		.override	= topic95_override,
9108c2ecf20Sopenharmony_ci	},
9118c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_TOPIC97]	= {
9128c2ecf20Sopenharmony_ci		.override	= topic97_override,
9138c2ecf20Sopenharmony_ci	},
9148c2ecf20Sopenharmony_ci#endif
9158c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_O2
9168c2ecf20Sopenharmony_ci	[CARDBUS_TYPE_O2MICRO]	= {
9178c2ecf20Sopenharmony_ci		.override	= o2micro_override,
9188c2ecf20Sopenharmony_ci		.restore_state	= o2micro_restore_state,
9198c2ecf20Sopenharmony_ci	},
9208c2ecf20Sopenharmony_ci#endif
9218c2ecf20Sopenharmony_ci};
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_cistatic unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mask)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	int i;
9278c2ecf20Sopenharmony_ci	unsigned long val;
9288c2ecf20Sopenharmony_ci	u32 mask;
9298c2ecf20Sopenharmony_ci	u8 reg;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	/*
9328c2ecf20Sopenharmony_ci	 * Probe for usable interrupts using the force
9338c2ecf20Sopenharmony_ci	 * register to generate bogus card status events.
9348c2ecf20Sopenharmony_ci	 */
9358c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_EVENT, -1);
9368c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
9378c2ecf20Sopenharmony_ci	reg = exca_readb(socket, I365_CSCINT);
9388c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_CSCINT, 0);
9398c2ecf20Sopenharmony_ci	val = probe_irq_on() & isa_irq_mask;
9408c2ecf20Sopenharmony_ci	for (i = 1; i < 16; i++) {
9418c2ecf20Sopenharmony_ci		if (!((val >> i) & 1))
9428c2ecf20Sopenharmony_ci			continue;
9438c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4));
9448c2ecf20Sopenharmony_ci		cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
9458c2ecf20Sopenharmony_ci		udelay(100);
9468c2ecf20Sopenharmony_ci		cb_writel(socket, CB_SOCKET_EVENT, -1);
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_MASK, 0);
9498c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_CSCINT, reg);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	mask = probe_irq_mask(val) & 0xffff;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	return mask;
9548c2ecf20Sopenharmony_ci}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci/*
9588c2ecf20Sopenharmony_ci * yenta PCI irq probing.
9598c2ecf20Sopenharmony_ci * currently only used in the TI/EnE initialization code
9608c2ecf20Sopenharmony_ci */
9618c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_TI
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci/* interrupt handler, only used during probing */
9648c2ecf20Sopenharmony_cistatic irqreturn_t yenta_probe_handler(int irq, void *dev_id)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	struct yenta_socket *socket = (struct yenta_socket *) dev_id;
9678c2ecf20Sopenharmony_ci	u8 csc;
9688c2ecf20Sopenharmony_ci	u32 cb_event;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	/* Clear interrupt status for the event */
9718c2ecf20Sopenharmony_ci	cb_event = cb_readl(socket, CB_SOCKET_EVENT);
9728c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_EVENT, -1);
9738c2ecf20Sopenharmony_ci	csc = exca_readb(socket, I365_CSC);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	if (cb_event || csc) {
9768c2ecf20Sopenharmony_ci		socket->probe_status = 1;
9778c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
9788c2ecf20Sopenharmony_ci	}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	return IRQ_NONE;
9818c2ecf20Sopenharmony_ci}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci/* probes the PCI interrupt, use only on override functions */
9848c2ecf20Sopenharmony_cistatic int yenta_probe_cb_irq(struct yenta_socket *socket)
9858c2ecf20Sopenharmony_ci{
9868c2ecf20Sopenharmony_ci	u8 reg = 0;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	if (!socket->cb_irq)
9898c2ecf20Sopenharmony_ci		return -1;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	socket->probe_status = 0;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (request_irq(socket->cb_irq, yenta_probe_handler, IRQF_SHARED, "yenta", socket)) {
9948c2ecf20Sopenharmony_ci		dev_warn(&socket->dev->dev,
9958c2ecf20Sopenharmony_ci			 "request_irq() in yenta_probe_cb_irq() failed!\n");
9968c2ecf20Sopenharmony_ci		return -1;
9978c2ecf20Sopenharmony_ci	}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	/* generate interrupt, wait */
10008c2ecf20Sopenharmony_ci	if (!socket->dev->irq)
10018c2ecf20Sopenharmony_ci		reg = exca_readb(socket, I365_CSCINT);
10028c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_CSCINT, reg | I365_CSC_STSCHG);
10038c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_EVENT, -1);
10048c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
10058c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	msleep(100);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	/* disable interrupts */
10108c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_MASK, 0);
10118c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_CSCINT, reg);
10128c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_EVENT, -1);
10138c2ecf20Sopenharmony_ci	exca_readb(socket, I365_CSC);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	free_irq(socket->cb_irq, socket);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	return (int) socket->probe_status;
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci#endif /* CONFIG_YENTA_TI */
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci/*
10248c2ecf20Sopenharmony_ci * Set static data that doesn't need re-initializing..
10258c2ecf20Sopenharmony_ci */
10268c2ecf20Sopenharmony_cistatic void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	socket->socket.pci_irq = socket->cb_irq;
10298c2ecf20Sopenharmony_ci	if (isa_probe)
10308c2ecf20Sopenharmony_ci		socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask);
10318c2ecf20Sopenharmony_ci	else
10328c2ecf20Sopenharmony_ci		socket->socket.irq_mask = 0;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev, "ISA IRQ mask 0x%04x, PCI irq %d\n",
10358c2ecf20Sopenharmony_ci		 socket->socket.irq_mask, socket->cb_irq);
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci/*
10398c2ecf20Sopenharmony_ci * Initialize the standard cardbus registers
10408c2ecf20Sopenharmony_ci */
10418c2ecf20Sopenharmony_cistatic void yenta_config_init(struct yenta_socket *socket)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	u16 bridge;
10448c2ecf20Sopenharmony_ci	struct pci_dev *dev = socket->dev;
10458c2ecf20Sopenharmony_ci	struct pci_bus_region region;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(socket->dev->bus, &region, &dev->resource[0]);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	config_writel(socket, CB_LEGACY_MODE_BASE, 0);
10508c2ecf20Sopenharmony_ci	config_writel(socket, PCI_BASE_ADDRESS_0, region.start);
10518c2ecf20Sopenharmony_ci	config_writew(socket, PCI_COMMAND,
10528c2ecf20Sopenharmony_ci			PCI_COMMAND_IO |
10538c2ecf20Sopenharmony_ci			PCI_COMMAND_MEMORY |
10548c2ecf20Sopenharmony_ci			PCI_COMMAND_MASTER |
10558c2ecf20Sopenharmony_ci			PCI_COMMAND_WAIT);
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	/* MAGIC NUMBERS! Fixme */
10588c2ecf20Sopenharmony_ci	config_writeb(socket, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
10598c2ecf20Sopenharmony_ci	config_writeb(socket, PCI_LATENCY_TIMER, 168);
10608c2ecf20Sopenharmony_ci	config_writel(socket, PCI_PRIMARY_BUS,
10618c2ecf20Sopenharmony_ci		(176 << 24) |			   /* sec. latency timer */
10628c2ecf20Sopenharmony_ci		((unsigned int)dev->subordinate->busn_res.end << 16) | /* subordinate bus */
10638c2ecf20Sopenharmony_ci		((unsigned int)dev->subordinate->busn_res.start << 8) |  /* secondary bus */
10648c2ecf20Sopenharmony_ci		dev->subordinate->primary);		   /* primary bus */
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	/*
10678c2ecf20Sopenharmony_ci	 * Set up the bridging state:
10688c2ecf20Sopenharmony_ci	 *  - enable write posting.
10698c2ecf20Sopenharmony_ci	 *  - memory window 0 prefetchable, window 1 non-prefetchable
10708c2ecf20Sopenharmony_ci	 *  - PCI interrupts enabled if a PCI interrupt exists..
10718c2ecf20Sopenharmony_ci	 */
10728c2ecf20Sopenharmony_ci	bridge = config_readw(socket, CB_BRIDGE_CONTROL);
10738c2ecf20Sopenharmony_ci	bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN);
10748c2ecf20Sopenharmony_ci	bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN;
10758c2ecf20Sopenharmony_ci	config_writew(socket, CB_BRIDGE_CONTROL, bridge);
10768c2ecf20Sopenharmony_ci}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci/**
10798c2ecf20Sopenharmony_ci * yenta_fixup_parent_bridge - Fix subordinate bus# of the parent bridge
10808c2ecf20Sopenharmony_ci * @cardbus_bridge: The PCI bus which the CardBus bridge bridges to
10818c2ecf20Sopenharmony_ci *
10828c2ecf20Sopenharmony_ci * Checks if devices on the bus which the CardBus bridge bridges to would be
10838c2ecf20Sopenharmony_ci * invisible during PCI scans because of a misconfigured subordinate number
10848c2ecf20Sopenharmony_ci * of the parent brige - some BIOSes seem to be too lazy to set it right.
10858c2ecf20Sopenharmony_ci * Does the fixup carefully by checking how far it can go without conflicts.
10868c2ecf20Sopenharmony_ci * See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information.
10878c2ecf20Sopenharmony_ci */
10888c2ecf20Sopenharmony_cistatic void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci	struct pci_bus *sibling;
10918c2ecf20Sopenharmony_ci	unsigned char upper_limit;
10928c2ecf20Sopenharmony_ci	/*
10938c2ecf20Sopenharmony_ci	 * We only check and fix the parent bridge: All systems which need
10948c2ecf20Sopenharmony_ci	 * this fixup that have been reviewed are laptops and the only bridge
10958c2ecf20Sopenharmony_ci	 * which needed fixing was the parent bridge of the CardBus bridge:
10968c2ecf20Sopenharmony_ci	 */
10978c2ecf20Sopenharmony_ci	struct pci_bus *bridge_to_fix = cardbus_bridge->parent;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	/* Check bus numbers are already set up correctly: */
11008c2ecf20Sopenharmony_ci	if (bridge_to_fix->busn_res.end >= cardbus_bridge->busn_res.end)
11018c2ecf20Sopenharmony_ci		return; /* The subordinate number is ok, nothing to do */
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	if (!bridge_to_fix->parent)
11048c2ecf20Sopenharmony_ci		return; /* Root bridges are ok */
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	/* stay within the limits of the bus range of the parent: */
11078c2ecf20Sopenharmony_ci	upper_limit = bridge_to_fix->parent->busn_res.end;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	/* check the bus ranges of all sibling bridges to prevent overlap */
11108c2ecf20Sopenharmony_ci	list_for_each_entry(sibling, &bridge_to_fix->parent->children,
11118c2ecf20Sopenharmony_ci			node) {
11128c2ecf20Sopenharmony_ci		/*
11138c2ecf20Sopenharmony_ci		 * If the sibling has a higher secondary bus number
11148c2ecf20Sopenharmony_ci		 * and it's secondary is equal or smaller than our
11158c2ecf20Sopenharmony_ci		 * current upper limit, set the new upper limit to
11168c2ecf20Sopenharmony_ci		 * the bus number below the sibling's range:
11178c2ecf20Sopenharmony_ci		 */
11188c2ecf20Sopenharmony_ci		if (sibling->busn_res.start > bridge_to_fix->busn_res.end
11198c2ecf20Sopenharmony_ci		    && sibling->busn_res.start <= upper_limit)
11208c2ecf20Sopenharmony_ci			upper_limit = sibling->busn_res.start - 1;
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	/* Show that the wanted subordinate number is not possible: */
11248c2ecf20Sopenharmony_ci	if (cardbus_bridge->busn_res.end > upper_limit)
11258c2ecf20Sopenharmony_ci		dev_warn(&cardbus_bridge->dev,
11268c2ecf20Sopenharmony_ci			 "Upper limit for fixing this bridge's parent bridge: #%02x\n",
11278c2ecf20Sopenharmony_ci			 upper_limit);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	/* If we have room to increase the bridge's subordinate number, */
11308c2ecf20Sopenharmony_ci	if (bridge_to_fix->busn_res.end < upper_limit) {
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		/* use the highest number of the hidden bus, within limits */
11338c2ecf20Sopenharmony_ci		unsigned char subordinate_to_assign =
11348c2ecf20Sopenharmony_ci			min_t(int, cardbus_bridge->busn_res.end, upper_limit);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci		dev_info(&bridge_to_fix->dev,
11378c2ecf20Sopenharmony_ci			 "Raising subordinate bus# of parent bus (#%02x) from #%02x to #%02x\n",
11388c2ecf20Sopenharmony_ci			 bridge_to_fix->number,
11398c2ecf20Sopenharmony_ci			 (int)bridge_to_fix->busn_res.end,
11408c2ecf20Sopenharmony_ci			 subordinate_to_assign);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci		/* Save the new subordinate in the bus struct of the bridge */
11438c2ecf20Sopenharmony_ci		bridge_to_fix->busn_res.end = subordinate_to_assign;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci		/* and update the PCI config space with the new subordinate */
11468c2ecf20Sopenharmony_ci		pci_write_config_byte(bridge_to_fix->self,
11478c2ecf20Sopenharmony_ci			PCI_SUBORDINATE_BUS, bridge_to_fix->busn_res.end);
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci/*
11528c2ecf20Sopenharmony_ci * Initialize a cardbus controller. Make sure we have a usable
11538c2ecf20Sopenharmony_ci * interrupt, and that we can map the cardbus area. Fill in the
11548c2ecf20Sopenharmony_ci * socket information structure..
11558c2ecf20Sopenharmony_ci */
11568c2ecf20Sopenharmony_cistatic int yenta_probe(struct pci_dev *dev, const struct pci_device_id *id)
11578c2ecf20Sopenharmony_ci{
11588c2ecf20Sopenharmony_ci	struct yenta_socket *socket;
11598c2ecf20Sopenharmony_ci	int ret;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	/*
11628c2ecf20Sopenharmony_ci	 * If we failed to assign proper bus numbers for this cardbus
11638c2ecf20Sopenharmony_ci	 * controller during PCI probe, its subordinate pci_bus is NULL.
11648c2ecf20Sopenharmony_ci	 * Bail out if so.
11658c2ecf20Sopenharmony_ci	 */
11668c2ecf20Sopenharmony_ci	if (!dev->subordinate) {
11678c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "no bus associated! (try 'pci=assign-busses')\n");
11688c2ecf20Sopenharmony_ci		return -ENODEV;
11698c2ecf20Sopenharmony_ci	}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	socket = kzalloc(sizeof(struct yenta_socket), GFP_KERNEL);
11728c2ecf20Sopenharmony_ci	if (!socket)
11738c2ecf20Sopenharmony_ci		return -ENOMEM;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	/* prepare pcmcia_socket */
11768c2ecf20Sopenharmony_ci	socket->socket.ops = &yenta_socket_operations;
11778c2ecf20Sopenharmony_ci	socket->socket.resource_ops = &pccard_nonstatic_ops;
11788c2ecf20Sopenharmony_ci	socket->socket.dev.parent = &dev->dev;
11798c2ecf20Sopenharmony_ci	socket->socket.driver_data = socket;
11808c2ecf20Sopenharmony_ci	socket->socket.owner = THIS_MODULE;
11818c2ecf20Sopenharmony_ci	socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
11828c2ecf20Sopenharmony_ci	socket->socket.map_size = 0x1000;
11838c2ecf20Sopenharmony_ci	socket->socket.cb_dev = dev;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	/* prepare struct yenta_socket */
11868c2ecf20Sopenharmony_ci	socket->dev = dev;
11878c2ecf20Sopenharmony_ci	pci_set_drvdata(dev, socket);
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	/*
11908c2ecf20Sopenharmony_ci	 * Do some basic sanity checking..
11918c2ecf20Sopenharmony_ci	 */
11928c2ecf20Sopenharmony_ci	if (pci_enable_device(dev)) {
11938c2ecf20Sopenharmony_ci		ret = -EBUSY;
11948c2ecf20Sopenharmony_ci		goto free;
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	ret = pci_request_regions(dev, "yenta_socket");
11988c2ecf20Sopenharmony_ci	if (ret)
11998c2ecf20Sopenharmony_ci		goto disable;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	if (!pci_resource_start(dev, 0)) {
12028c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "No cardbus resource!\n");
12038c2ecf20Sopenharmony_ci		ret = -ENODEV;
12048c2ecf20Sopenharmony_ci		goto release;
12058c2ecf20Sopenharmony_ci	}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	/*
12088c2ecf20Sopenharmony_ci	 * Ok, start setup.. Map the cardbus registers,
12098c2ecf20Sopenharmony_ci	 * and request the IRQ.
12108c2ecf20Sopenharmony_ci	 */
12118c2ecf20Sopenharmony_ci	socket->base = ioremap(pci_resource_start(dev, 0), 0x1000);
12128c2ecf20Sopenharmony_ci	if (!socket->base) {
12138c2ecf20Sopenharmony_ci		ret = -ENOMEM;
12148c2ecf20Sopenharmony_ci		goto release;
12158c2ecf20Sopenharmony_ci	}
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	/*
12188c2ecf20Sopenharmony_ci	 * report the subsystem vendor and device for help debugging
12198c2ecf20Sopenharmony_ci	 * the irq stuff...
12208c2ecf20Sopenharmony_ci	 */
12218c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "CardBus bridge found [%04x:%04x]\n",
12228c2ecf20Sopenharmony_ci		 dev->subsystem_vendor, dev->subsystem_device);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	yenta_config_init(socket);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	/* Disable all events */
12278c2ecf20Sopenharmony_ci	cb_writel(socket, CB_SOCKET_MASK, 0x0);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	/* Set up the bridge regions.. */
12308c2ecf20Sopenharmony_ci	yenta_allocate_resources(socket);
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	socket->cb_irq = dev->irq;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	/* Do we have special options for the device? */
12358c2ecf20Sopenharmony_ci	if (id->driver_data != CARDBUS_TYPE_DEFAULT &&
12368c2ecf20Sopenharmony_ci	    id->driver_data < ARRAY_SIZE(cardbus_type)) {
12378c2ecf20Sopenharmony_ci		socket->type = &cardbus_type[id->driver_data];
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci		ret = socket->type->override(socket);
12408c2ecf20Sopenharmony_ci		if (ret < 0)
12418c2ecf20Sopenharmony_ci			goto unmap;
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	/* We must finish initialization here */
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, IRQF_SHARED, "yenta", socket)) {
12478c2ecf20Sopenharmony_ci		/* No IRQ or request_irq failed. Poll */
12488c2ecf20Sopenharmony_ci		socket->cb_irq = 0; /* But zero is a valid IRQ number. */
12498c2ecf20Sopenharmony_ci		timer_setup(&socket->poll_timer, yenta_interrupt_wrapper, 0);
12508c2ecf20Sopenharmony_ci		mod_timer(&socket->poll_timer, jiffies + HZ);
12518c2ecf20Sopenharmony_ci		dev_info(&dev->dev,
12528c2ecf20Sopenharmony_ci			 "no PCI IRQ, CardBus support disabled for this socket.\n");
12538c2ecf20Sopenharmony_ci		dev_info(&dev->dev,
12548c2ecf20Sopenharmony_ci			 "check your BIOS CardBus, BIOS IRQ or ACPI settings.\n");
12558c2ecf20Sopenharmony_ci	} else {
12568c2ecf20Sopenharmony_ci		socket->socket.features |= SS_CAP_CARDBUS;
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	/* Figure out what the dang thing can do for the PCMCIA layer... */
12608c2ecf20Sopenharmony_ci	yenta_interrogate(socket);
12618c2ecf20Sopenharmony_ci	yenta_get_socket_capabilities(socket, isa_interrupts);
12628c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "Socket status: %08x\n",
12638c2ecf20Sopenharmony_ci		 cb_readl(socket, CB_SOCKET_STATE));
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	yenta_fixup_parent_bridge(dev->subordinate);
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	/* Register it with the pcmcia layer.. */
12688c2ecf20Sopenharmony_ci	ret = pcmcia_register_socket(&socket->socket);
12698c2ecf20Sopenharmony_ci	if (ret)
12708c2ecf20Sopenharmony_ci		goto free_irq;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	/* Add the yenta register attributes */
12738c2ecf20Sopenharmony_ci	ret = device_create_file(&dev->dev, &dev_attr_yenta_registers);
12748c2ecf20Sopenharmony_ci	if (ret)
12758c2ecf20Sopenharmony_ci		goto unregister_socket;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	return ret;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	/* error path... */
12808c2ecf20Sopenharmony_ci unregister_socket:
12818c2ecf20Sopenharmony_ci	pcmcia_unregister_socket(&socket->socket);
12828c2ecf20Sopenharmony_ci free_irq:
12838c2ecf20Sopenharmony_ci	if (socket->cb_irq)
12848c2ecf20Sopenharmony_ci		free_irq(socket->cb_irq, socket);
12858c2ecf20Sopenharmony_ci	else
12868c2ecf20Sopenharmony_ci		del_timer_sync(&socket->poll_timer);
12878c2ecf20Sopenharmony_ci unmap:
12888c2ecf20Sopenharmony_ci	iounmap(socket->base);
12898c2ecf20Sopenharmony_ci	yenta_free_resources(socket);
12908c2ecf20Sopenharmony_ci release:
12918c2ecf20Sopenharmony_ci	pci_release_regions(dev);
12928c2ecf20Sopenharmony_ci disable:
12938c2ecf20Sopenharmony_ci	pci_disable_device(dev);
12948c2ecf20Sopenharmony_ci free:
12958c2ecf20Sopenharmony_ci	pci_set_drvdata(dev, NULL);
12968c2ecf20Sopenharmony_ci	kfree(socket);
12978c2ecf20Sopenharmony_ci	return ret;
12988c2ecf20Sopenharmony_ci}
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
13018c2ecf20Sopenharmony_cistatic int yenta_dev_suspend_noirq(struct device *dev)
13028c2ecf20Sopenharmony_ci{
13038c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
13048c2ecf20Sopenharmony_ci	struct yenta_socket *socket = pci_get_drvdata(pdev);
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	if (!socket)
13078c2ecf20Sopenharmony_ci		return 0;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	if (socket->type && socket->type->save_state)
13108c2ecf20Sopenharmony_ci		socket->type->save_state(socket);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	pci_save_state(pdev);
13138c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, 16*4, &socket->saved_state[0]);
13148c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, 17*4, &socket->saved_state[1]);
13158c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	return 0;
13188c2ecf20Sopenharmony_ci}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_cistatic int yenta_dev_resume_noirq(struct device *dev)
13218c2ecf20Sopenharmony_ci{
13228c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
13238c2ecf20Sopenharmony_ci	struct yenta_socket *socket = pci_get_drvdata(pdev);
13248c2ecf20Sopenharmony_ci	int ret;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	if (!socket)
13278c2ecf20Sopenharmony_ci		return 0;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, 16*4, socket->saved_state[0]);
13308c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, 17*4, socket->saved_state[1]);
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	ret = pci_enable_device(pdev);
13338c2ecf20Sopenharmony_ci	if (ret)
13348c2ecf20Sopenharmony_ci		return ret;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	pci_set_master(pdev);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if (socket->type && socket->type->restore_state)
13398c2ecf20Sopenharmony_ci		socket->type->restore_state(socket);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	return 0;
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_cistatic const struct dev_pm_ops yenta_pm_ops = {
13458c2ecf20Sopenharmony_ci	.suspend_noirq = yenta_dev_suspend_noirq,
13468c2ecf20Sopenharmony_ci	.resume_noirq = yenta_dev_resume_noirq,
13478c2ecf20Sopenharmony_ci	.freeze_noirq = yenta_dev_suspend_noirq,
13488c2ecf20Sopenharmony_ci	.thaw_noirq = yenta_dev_resume_noirq,
13498c2ecf20Sopenharmony_ci	.poweroff_noirq = yenta_dev_suspend_noirq,
13508c2ecf20Sopenharmony_ci	.restore_noirq = yenta_dev_resume_noirq,
13518c2ecf20Sopenharmony_ci};
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci#define YENTA_PM_OPS	(&yenta_pm_ops)
13548c2ecf20Sopenharmony_ci#else
13558c2ecf20Sopenharmony_ci#define YENTA_PM_OPS	NULL
13568c2ecf20Sopenharmony_ci#endif
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci#define CB_ID(vend, dev, type)				\
13598c2ecf20Sopenharmony_ci	{						\
13608c2ecf20Sopenharmony_ci		.vendor		= vend,			\
13618c2ecf20Sopenharmony_ci		.device		= dev,			\
13628c2ecf20Sopenharmony_ci		.subvendor	= PCI_ANY_ID,		\
13638c2ecf20Sopenharmony_ci		.subdevice	= PCI_ANY_ID,		\
13648c2ecf20Sopenharmony_ci		.class		= PCI_CLASS_BRIDGE_CARDBUS << 8, \
13658c2ecf20Sopenharmony_ci		.class_mask	= ~0,			\
13668c2ecf20Sopenharmony_ci		.driver_data	= CARDBUS_TYPE_##type,	\
13678c2ecf20Sopenharmony_ci	}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_cistatic const struct pci_device_id yenta_table[] = {
13708c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1031, TI),
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	/*
13738c2ecf20Sopenharmony_ci	 * TBD: Check if these TI variants can use more
13748c2ecf20Sopenharmony_ci	 * advanced overrides instead.  (I can't get the
13758c2ecf20Sopenharmony_ci	 * data sheets for these devices. --rmk)
13768c2ecf20Sopenharmony_ci	 */
13778c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_TI
13788c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210, TI),
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130, TI113X),
13818c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131, TI113X),
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211, TI12XX),
13848c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220, TI12XX),
13858c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221, TI12XX),
13868c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225, TI12XX),
13878c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A, TI12XX),
13888c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B, TI12XX),
13898c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, TI12XX),
13908c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450, TI12XX),
13918c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1451A, TI12XX),
13928c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1510, TI12XX),
13938c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, TI12XX),
13948c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1620, TI12XX),
13958c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX),
13968c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX),
13978c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX),
13988c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4510, TI12XX),
13998c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4520, TI12XX),
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250),
14028c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250),
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11, TI12XX),
14058c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X515, TI12XX),
14068c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12, TI12XX),
14078c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X420, TI12XX),
14088c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X620, TI12XX),
14098c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7410, TI12XX),
14108c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7510, TI12XX),
14118c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7610, TI12XX),
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_710, ENE),
14148c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_712, ENE),
14158c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_720, ENE),
14168c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_722, ENE),
14178c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, ENE),
14188c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, ENE),
14198c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, ENE),
14208c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, ENE),
14218c2ecf20Sopenharmony_ci#endif /* CONFIG_YENTA_TI */
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_RICOH
14248c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH),
14258c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH),
14268c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475, RICOH),
14278c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH),
14288c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH),
14298c2ecf20Sopenharmony_ci#endif
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_TOSHIBA
14328c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95),
14338c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97),
14348c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97),
14358c2ecf20Sopenharmony_ci#endif
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_O2
14388c2ecf20Sopenharmony_ci	CB_ID(PCI_VENDOR_ID_O2, PCI_ANY_ID, O2MICRO),
14398c2ecf20Sopenharmony_ci#endif
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	/* match any cardbus bridge */
14428c2ecf20Sopenharmony_ci	CB_ID(PCI_ANY_ID, PCI_ANY_ID, DEFAULT),
14438c2ecf20Sopenharmony_ci	{ /* all zeroes */ }
14448c2ecf20Sopenharmony_ci};
14458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, yenta_table);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_cistatic struct pci_driver yenta_cardbus_driver = {
14498c2ecf20Sopenharmony_ci	.name		= "yenta_cardbus",
14508c2ecf20Sopenharmony_ci	.id_table	= yenta_table,
14518c2ecf20Sopenharmony_ci	.probe		= yenta_probe,
14528c2ecf20Sopenharmony_ci	.remove		= yenta_close,
14538c2ecf20Sopenharmony_ci	.driver.pm	= YENTA_PM_OPS,
14548c2ecf20Sopenharmony_ci};
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_cimodule_pci_driver(yenta_cardbus_driver);
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1459