18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * ti113x.h 1.16 1999/10/25 20:03:34
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * The contents of this file are subject to the Mozilla Public License
58c2ecf20Sopenharmony_ci * Version 1.1 (the "License"); you may not use this file except in
68c2ecf20Sopenharmony_ci * compliance with the License. You may obtain a copy of the License
78c2ecf20Sopenharmony_ci * at http://www.mozilla.org/MPL/
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Software distributed under the License is distributed on an "AS IS"
108c2ecf20Sopenharmony_ci * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
118c2ecf20Sopenharmony_ci * the License for the specific language governing rights and
128c2ecf20Sopenharmony_ci * limitations under the License.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * The initial developer of the original code is David A. Hinds
158c2ecf20Sopenharmony_ci * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
168c2ecf20Sopenharmony_ci * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Alternatively, the contents of this file may be used under the
198c2ecf20Sopenharmony_ci * terms of the GNU General Public License version 2 (the "GPL"), in which
208c2ecf20Sopenharmony_ci * case the provisions of the GPL are applicable instead of the
218c2ecf20Sopenharmony_ci * above.  If you wish to allow the use of your version of this file
228c2ecf20Sopenharmony_ci * only under the terms of the GPL and not to allow others to use
238c2ecf20Sopenharmony_ci * your version of this file under the MPL, indicate your decision by
248c2ecf20Sopenharmony_ci * deleting the provisions above and replace them with the notice and
258c2ecf20Sopenharmony_ci * other provisions required by the GPL.  If you do not delete the
268c2ecf20Sopenharmony_ci * provisions above, a recipient may use your version of this file
278c2ecf20Sopenharmony_ci * under either the MPL or the GPL.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#ifndef _LINUX_TI113X_H
318c2ecf20Sopenharmony_ci#define _LINUX_TI113X_H
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Register definitions for TI 113X PCI-to-CardBus bridges */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* System Control Register */
378c2ecf20Sopenharmony_ci#define TI113X_SYSTEM_CONTROL		0x0080	/* 32 bit */
388c2ecf20Sopenharmony_ci#define  TI113X_SCR_SMIROUTE		0x04000000
398c2ecf20Sopenharmony_ci#define  TI113X_SCR_SMISTATUS		0x02000000
408c2ecf20Sopenharmony_ci#define  TI113X_SCR_SMIENB		0x01000000
418c2ecf20Sopenharmony_ci#define  TI113X_SCR_VCCPROT		0x00200000
428c2ecf20Sopenharmony_ci#define  TI113X_SCR_REDUCEZV		0x00100000
438c2ecf20Sopenharmony_ci#define  TI113X_SCR_CDREQEN		0x00080000
448c2ecf20Sopenharmony_ci#define  TI113X_SCR_CDMACHAN		0x00070000
458c2ecf20Sopenharmony_ci#define  TI113X_SCR_SOCACTIVE		0x00002000
468c2ecf20Sopenharmony_ci#define  TI113X_SCR_PWRSTREAM		0x00000800
478c2ecf20Sopenharmony_ci#define  TI113X_SCR_DELAYUP		0x00000400
488c2ecf20Sopenharmony_ci#define  TI113X_SCR_DELAYDOWN		0x00000200
498c2ecf20Sopenharmony_ci#define  TI113X_SCR_INTERROGATE		0x00000100
508c2ecf20Sopenharmony_ci#define  TI113X_SCR_CLKRUN_SEL		0x00000080
518c2ecf20Sopenharmony_ci#define  TI113X_SCR_PWRSAVINGS		0x00000040
528c2ecf20Sopenharmony_ci#define  TI113X_SCR_SUBSYSRW		0x00000020
538c2ecf20Sopenharmony_ci#define  TI113X_SCR_CB_DPAR		0x00000010
548c2ecf20Sopenharmony_ci#define  TI113X_SCR_CDMA_EN		0x00000008
558c2ecf20Sopenharmony_ci#define  TI113X_SCR_ASYNC_IRQ		0x00000004
568c2ecf20Sopenharmony_ci#define  TI113X_SCR_KEEPCLK		0x00000002
578c2ecf20Sopenharmony_ci#define  TI113X_SCR_CLKRUN_ENA		0x00000001
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define  TI122X_SCR_SER_STEP		0xc0000000
608c2ecf20Sopenharmony_ci#define  TI122X_SCR_INTRTIE		0x20000000
618c2ecf20Sopenharmony_ci#define  TIXX21_SCR_TIEALL		0x10000000
628c2ecf20Sopenharmony_ci#define  TI122X_SCR_CBRSVD		0x00400000
638c2ecf20Sopenharmony_ci#define  TI122X_SCR_MRBURSTDN		0x00008000
648c2ecf20Sopenharmony_ci#define  TI122X_SCR_MRBURSTUP		0x00004000
658c2ecf20Sopenharmony_ci#define  TI122X_SCR_RIMUX		0x00000001
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/* Multimedia Control Register */
688c2ecf20Sopenharmony_ci#define TI1250_MULTIMEDIA_CTL		0x0084	/* 8 bit */
698c2ecf20Sopenharmony_ci#define  TI1250_MMC_ZVOUTEN		0x80
708c2ecf20Sopenharmony_ci#define  TI1250_MMC_PORTSEL		0x40
718c2ecf20Sopenharmony_ci#define  TI1250_MMC_ZVEN1		0x02
728c2ecf20Sopenharmony_ci#define  TI1250_MMC_ZVEN0		0x01
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define TI1250_GENERAL_STATUS		0x0085	/* 8 bit */
758c2ecf20Sopenharmony_ci#define TI1250_GPIO0_CONTROL		0x0088	/* 8 bit */
768c2ecf20Sopenharmony_ci#define TI1250_GPIO1_CONTROL		0x0089	/* 8 bit */
778c2ecf20Sopenharmony_ci#define TI1250_GPIO2_CONTROL		0x008a	/* 8 bit */
788c2ecf20Sopenharmony_ci#define TI1250_GPIO3_CONTROL		0x008b	/* 8 bit */
798c2ecf20Sopenharmony_ci#define TI1250_GPIO_MODE_MASK		0xc0
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/* IRQMUX/MFUNC Register */
828c2ecf20Sopenharmony_ci#define TI122X_MFUNC			0x008c	/* 32 bit */
838c2ecf20Sopenharmony_ci#define TI122X_MFUNC0_MASK		0x0000000f
848c2ecf20Sopenharmony_ci#define TI122X_MFUNC1_MASK		0x000000f0
858c2ecf20Sopenharmony_ci#define TI122X_MFUNC2_MASK		0x00000f00
868c2ecf20Sopenharmony_ci#define TI122X_MFUNC3_MASK		0x0000f000
878c2ecf20Sopenharmony_ci#define TI122X_MFUNC4_MASK		0x000f0000
888c2ecf20Sopenharmony_ci#define TI122X_MFUNC5_MASK		0x00f00000
898c2ecf20Sopenharmony_ci#define TI122X_MFUNC6_MASK		0x0f000000
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#define TI122X_MFUNC0_INTA		0x00000002
928c2ecf20Sopenharmony_ci#define TI125X_MFUNC0_INTB		0x00000001
938c2ecf20Sopenharmony_ci#define TI122X_MFUNC1_INTB		0x00000020
948c2ecf20Sopenharmony_ci#define TI122X_MFUNC3_IRQSER		0x00001000
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* Retry Status Register */
988c2ecf20Sopenharmony_ci#define TI113X_RETRY_STATUS		0x0090	/* 8 bit */
998c2ecf20Sopenharmony_ci#define  TI113X_RSR_PCIRETRY		0x80
1008c2ecf20Sopenharmony_ci#define  TI113X_RSR_CBRETRY		0x40
1018c2ecf20Sopenharmony_ci#define  TI113X_RSR_TEXP_CBB		0x20
1028c2ecf20Sopenharmony_ci#define  TI113X_RSR_MEXP_CBB		0x10
1038c2ecf20Sopenharmony_ci#define  TI113X_RSR_TEXP_CBA		0x08
1048c2ecf20Sopenharmony_ci#define  TI113X_RSR_MEXP_CBA		0x04
1058c2ecf20Sopenharmony_ci#define  TI113X_RSR_TEXP_PCI		0x02
1068c2ecf20Sopenharmony_ci#define  TI113X_RSR_MEXP_PCI		0x01
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/* Card Control Register */
1098c2ecf20Sopenharmony_ci#define TI113X_CARD_CONTROL		0x0091	/* 8 bit */
1108c2ecf20Sopenharmony_ci#define  TI113X_CCR_RIENB		0x80
1118c2ecf20Sopenharmony_ci#define  TI113X_CCR_ZVENABLE		0x40
1128c2ecf20Sopenharmony_ci#define  TI113X_CCR_PCI_IRQ_ENA		0x20
1138c2ecf20Sopenharmony_ci#define  TI113X_CCR_PCI_IREQ		0x10
1148c2ecf20Sopenharmony_ci#define  TI113X_CCR_PCI_CSC		0x08
1158c2ecf20Sopenharmony_ci#define  TI113X_CCR_SPKROUTEN		0x02
1168c2ecf20Sopenharmony_ci#define  TI113X_CCR_IFG			0x01
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define  TI1220_CCR_PORT_SEL		0x20
1198c2ecf20Sopenharmony_ci#define  TI122X_CCR_AUD2MUX		0x04
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/* Device Control Register */
1228c2ecf20Sopenharmony_ci#define TI113X_DEVICE_CONTROL		0x0092	/* 8 bit */
1238c2ecf20Sopenharmony_ci#define  TI113X_DCR_5V_FORCE		0x40
1248c2ecf20Sopenharmony_ci#define  TI113X_DCR_3V_FORCE		0x20
1258c2ecf20Sopenharmony_ci#define  TI113X_DCR_IMODE_MASK		0x06
1268c2ecf20Sopenharmony_ci#define  TI113X_DCR_IMODE_ISA		0x02
1278c2ecf20Sopenharmony_ci#define  TI113X_DCR_IMODE_SERIAL	0x04
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#define  TI12XX_DCR_IMODE_PCI_ONLY	0x00
1308c2ecf20Sopenharmony_ci#define  TI12XX_DCR_IMODE_ALL_SERIAL	0x06
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* Buffer Control Register */
1338c2ecf20Sopenharmony_ci#define TI113X_BUFFER_CONTROL		0x0093	/* 8 bit */
1348c2ecf20Sopenharmony_ci#define  TI113X_BCR_CB_READ_DEPTH	0x08
1358c2ecf20Sopenharmony_ci#define  TI113X_BCR_CB_WRITE_DEPTH	0x04
1368c2ecf20Sopenharmony_ci#define  TI113X_BCR_PCI_READ_DEPTH	0x02
1378c2ecf20Sopenharmony_ci#define  TI113X_BCR_PCI_WRITE_DEPTH	0x01
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/* Diagnostic Register */
1408c2ecf20Sopenharmony_ci#define TI1250_DIAGNOSTIC		0x0093	/* 8 bit */
1418c2ecf20Sopenharmony_ci#define  TI1250_DIAG_TRUE_VALUE		0x80
1428c2ecf20Sopenharmony_ci#define  TI1250_DIAG_PCI_IREQ		0x40
1438c2ecf20Sopenharmony_ci#define  TI1250_DIAG_PCI_CSC		0x20
1448c2ecf20Sopenharmony_ci#define  TI1250_DIAG_ASYNC_CSC		0x01
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci/* DMA Registers */
1478c2ecf20Sopenharmony_ci#define TI113X_DMA_0			0x0094	/* 32 bit */
1488c2ecf20Sopenharmony_ci#define TI113X_DMA_1			0x0098	/* 32 bit */
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* ExCA IO offset registers */
1518c2ecf20Sopenharmony_ci#define TI113X_IO_OFFSET(map)		(0x36+((map)<<1))
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/* EnE test register */
1548c2ecf20Sopenharmony_ci#define ENE_TEST_C9			0xc9	/* 8bit */
1558c2ecf20Sopenharmony_ci#define ENE_TEST_C9_TLTENABLE		0x02
1568c2ecf20Sopenharmony_ci#define ENE_TEST_C9_PFENABLE_F0		0x04
1578c2ecf20Sopenharmony_ci#define ENE_TEST_C9_PFENABLE_F1		0x08
1588c2ecf20Sopenharmony_ci#define ENE_TEST_C9_PFENABLE		(ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F1)
1598c2ecf20Sopenharmony_ci#define ENE_TEST_C9_WPDISALBLE_F0	0x40
1608c2ecf20Sopenharmony_ci#define ENE_TEST_C9_WPDISALBLE_F1	0x80
1618c2ecf20Sopenharmony_ci#define ENE_TEST_C9_WPDISALBLE		(ENE_TEST_C9_WPDISALBLE_F0 | ENE_TEST_C9_WPDISALBLE_F1)
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/*
1648c2ecf20Sopenharmony_ci * Texas Instruments CardBus controller overrides.
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_ci#define ti_sysctl(socket)	((socket)->private[0])
1678c2ecf20Sopenharmony_ci#define ti_cardctl(socket)	((socket)->private[1])
1688c2ecf20Sopenharmony_ci#define ti_devctl(socket)	((socket)->private[2])
1698c2ecf20Sopenharmony_ci#define ti_diag(socket)		((socket)->private[3])
1708c2ecf20Sopenharmony_ci#define ti_mfunc(socket)	((socket)->private[4])
1718c2ecf20Sopenharmony_ci#define ene_test_c9(socket)	((socket)->private[5])
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/*
1748c2ecf20Sopenharmony_ci * These are the TI specific power management handlers.
1758c2ecf20Sopenharmony_ci */
1768c2ecf20Sopenharmony_cistatic void ti_save_state(struct yenta_socket *socket)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL);
1798c2ecf20Sopenharmony_ci	ti_mfunc(socket) = config_readl(socket, TI122X_MFUNC);
1808c2ecf20Sopenharmony_ci	ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL);
1818c2ecf20Sopenharmony_ci	ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL);
1828c2ecf20Sopenharmony_ci	ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (socket->dev->vendor == PCI_VENDOR_ID_ENE)
1858c2ecf20Sopenharmony_ci		ene_test_c9(socket) = config_readb(socket, ENE_TEST_C9);
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic void ti_restore_state(struct yenta_socket *socket)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket));
1918c2ecf20Sopenharmony_ci	config_writel(socket, TI122X_MFUNC, ti_mfunc(socket));
1928c2ecf20Sopenharmony_ci	config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket));
1938c2ecf20Sopenharmony_ci	config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket));
1948c2ecf20Sopenharmony_ci	config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket));
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (socket->dev->vendor == PCI_VENDOR_ID_ENE)
1978c2ecf20Sopenharmony_ci		config_writeb(socket, ENE_TEST_C9, ene_test_c9(socket));
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/*
2018c2ecf20Sopenharmony_ci *	Zoom video control for TI122x/113x chips
2028c2ecf20Sopenharmony_ci */
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic void ti_zoom_video(struct pcmcia_socket *sock, int onoff)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	u8 reg;
2078c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* If we don't have a Zoom Video switch this is harmless,
2108c2ecf20Sopenharmony_ci	   we just tristate the unused (ZV) lines */
2118c2ecf20Sopenharmony_ci	reg = config_readb(socket, TI113X_CARD_CONTROL);
2128c2ecf20Sopenharmony_ci	if (onoff)
2138c2ecf20Sopenharmony_ci		/* Zoom zoom, we will all go together, zoom zoom, zoom zoom */
2148c2ecf20Sopenharmony_ci		reg |= TI113X_CCR_ZVENABLE;
2158c2ecf20Sopenharmony_ci	else
2168c2ecf20Sopenharmony_ci		reg &= ~TI113X_CCR_ZVENABLE;
2178c2ecf20Sopenharmony_ci	config_writeb(socket, TI113X_CARD_CONTROL, reg);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/*
2218c2ecf20Sopenharmony_ci *	The 145x series can also use this. They have an additional
2228c2ecf20Sopenharmony_ci *	ZV autodetect mode we don't use but don't actually need.
2238c2ecf20Sopenharmony_ci *	FIXME: manual says its in func0 and func1 but disagrees with
2248c2ecf20Sopenharmony_ci *	itself about this - do we need to force func0, if so we need
2258c2ecf20Sopenharmony_ci *	to know a lot more about socket pairings in pcmcia_socket than
2268c2ecf20Sopenharmony_ci *	we do now.. uggh.
2278c2ecf20Sopenharmony_ci */
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic void ti1250_zoom_video(struct pcmcia_socket *sock, int onoff)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
2328c2ecf20Sopenharmony_ci	int shift = 0;
2338c2ecf20Sopenharmony_ci	u8 reg;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	ti_zoom_video(sock, onoff);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	reg = config_readb(socket, TI1250_MULTIMEDIA_CTL);
2388c2ecf20Sopenharmony_ci	reg |= TI1250_MMC_ZVOUTEN;	/* ZV bus enable */
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if(PCI_FUNC(socket->dev->devfn)==1)
2418c2ecf20Sopenharmony_ci		shift = 1;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if(onoff)
2448c2ecf20Sopenharmony_ci	{
2458c2ecf20Sopenharmony_ci		reg &= ~(1<<6); 	/* Clear select bit */
2468c2ecf20Sopenharmony_ci		reg |= shift<<6;	/* Favour our socket */
2478c2ecf20Sopenharmony_ci		reg |= 1<<shift;	/* Socket zoom video on */
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci	else
2508c2ecf20Sopenharmony_ci	{
2518c2ecf20Sopenharmony_ci		reg &= ~(1<<6); 	/* Clear select bit */
2528c2ecf20Sopenharmony_ci		reg |= (1^shift)<<6;	/* Favour other socket */
2538c2ecf20Sopenharmony_ci		reg &= ~(1<<shift);	/* Socket zoon video off */
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	config_writeb(socket, TI1250_MULTIMEDIA_CTL, reg);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic void ti_set_zv(struct yenta_socket *socket)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	if(socket->dev->vendor == PCI_VENDOR_ID_TI)
2628c2ecf20Sopenharmony_ci	{
2638c2ecf20Sopenharmony_ci		switch(socket->dev->device)
2648c2ecf20Sopenharmony_ci		{
2658c2ecf20Sopenharmony_ci			/* There may be more .. */
2668c2ecf20Sopenharmony_ci			case PCI_DEVICE_ID_TI_1220:
2678c2ecf20Sopenharmony_ci			case PCI_DEVICE_ID_TI_1221:
2688c2ecf20Sopenharmony_ci			case PCI_DEVICE_ID_TI_1225:
2698c2ecf20Sopenharmony_ci			case PCI_DEVICE_ID_TI_4510:
2708c2ecf20Sopenharmony_ci				socket->socket.zoom_video = ti_zoom_video;
2718c2ecf20Sopenharmony_ci				break;
2728c2ecf20Sopenharmony_ci			case PCI_DEVICE_ID_TI_1250:
2738c2ecf20Sopenharmony_ci			case PCI_DEVICE_ID_TI_1251A:
2748c2ecf20Sopenharmony_ci			case PCI_DEVICE_ID_TI_1251B:
2758c2ecf20Sopenharmony_ci			case PCI_DEVICE_ID_TI_1450:
2768c2ecf20Sopenharmony_ci				socket->socket.zoom_video = ti1250_zoom_video;
2778c2ecf20Sopenharmony_ci		}
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci/*
2838c2ecf20Sopenharmony_ci * Generic TI init - TI has an extension for the
2848c2ecf20Sopenharmony_ci * INTCTL register that sets the PCI CSC interrupt.
2858c2ecf20Sopenharmony_ci * Make sure we set it correctly at open and init
2868c2ecf20Sopenharmony_ci * time
2878c2ecf20Sopenharmony_ci * - override: disable the PCI CSC interrupt. This makes
2888c2ecf20Sopenharmony_ci *   it possible to use the CSC interrupt to probe the
2898c2ecf20Sopenharmony_ci *   ISA interrupts.
2908c2ecf20Sopenharmony_ci * - init: set the interrupt to match our PCI state.
2918c2ecf20Sopenharmony_ci *   This makes us correctly get PCI CSC interrupt
2928c2ecf20Sopenharmony_ci *   events.
2938c2ecf20Sopenharmony_ci */
2948c2ecf20Sopenharmony_cistatic int ti_init(struct yenta_socket *socket)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	u8 new, reg = exca_readb(socket, I365_INTCTL);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	new = reg & ~I365_INTR_ENA;
2998c2ecf20Sopenharmony_ci	if (socket->dev->irq)
3008c2ecf20Sopenharmony_ci		new |= I365_INTR_ENA;
3018c2ecf20Sopenharmony_ci	if (new != reg)
3028c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_INTCTL, new);
3038c2ecf20Sopenharmony_ci	return 0;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int ti_override(struct yenta_socket *socket)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	u8 new, reg = exca_readb(socket, I365_INTCTL);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	new = reg & ~I365_INTR_ENA;
3118c2ecf20Sopenharmony_ci	if (new != reg)
3128c2ecf20Sopenharmony_ci		exca_writeb(socket, I365_INTCTL, new);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	ti_set_zv(socket);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic void ti113x_use_isa_irq(struct yenta_socket *socket)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	int isa_irq = -1;
3228c2ecf20Sopenharmony_ci	u8 intctl;
3238c2ecf20Sopenharmony_ci	u32 isa_irq_mask = 0;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (!isa_probe)
3268c2ecf20Sopenharmony_ci		return;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* get a free isa int */
3298c2ecf20Sopenharmony_ci	isa_irq_mask = yenta_probe_irq(socket, isa_interrupts);
3308c2ecf20Sopenharmony_ci	if (!isa_irq_mask)
3318c2ecf20Sopenharmony_ci		return; /* no useable isa irq found */
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* choose highest available */
3348c2ecf20Sopenharmony_ci	for (; isa_irq_mask; isa_irq++)
3358c2ecf20Sopenharmony_ci		isa_irq_mask >>= 1;
3368c2ecf20Sopenharmony_ci	socket->cb_irq = isa_irq;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_CSCINT, (isa_irq << 4));
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	intctl = exca_readb(socket, I365_INTCTL);
3418c2ecf20Sopenharmony_ci	intctl &= ~(I365_INTR_ENA | I365_IRQ_MASK);     /* CSC Enable */
3428c2ecf20Sopenharmony_ci	exca_writeb(socket, I365_INTCTL, intctl);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev,
3458c2ecf20Sopenharmony_ci		"Yenta TI113x: using isa irq %d for CardBus\n", isa_irq);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int ti113x_override(struct yenta_socket *socket)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	u8 cardctl;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	cardctl = config_readb(socket, TI113X_CARD_CONTROL);
3548c2ecf20Sopenharmony_ci	cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC);
3558c2ecf20Sopenharmony_ci	if (socket->dev->irq)
3568c2ecf20Sopenharmony_ci		cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC | TI113X_CCR_PCI_IREQ;
3578c2ecf20Sopenharmony_ci	else
3588c2ecf20Sopenharmony_ci		ti113x_use_isa_irq(socket);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	config_writeb(socket, TI113X_CARD_CONTROL, cardctl);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return ti_override(socket);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci/* irqrouting for func0, probes PCI interrupt and ISA interrupts */
3678c2ecf20Sopenharmony_cistatic void ti12xx_irqroute_func0(struct yenta_socket *socket)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	u32 mfunc, mfunc_old, devctl;
3708c2ecf20Sopenharmony_ci	u8 gpio3, gpio3_old;
3718c2ecf20Sopenharmony_ci	int pci_irq_status;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
3748c2ecf20Sopenharmony_ci	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
3758c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev, "TI: mfunc 0x%08x, devctl 0x%02x\n",
3768c2ecf20Sopenharmony_ci		 mfunc, devctl);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* make sure PCI interrupts are enabled before probing */
3798c2ecf20Sopenharmony_ci	ti_init(socket);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/* test PCI interrupts first. only try fixing if return value is 0! */
3828c2ecf20Sopenharmony_ci	pci_irq_status = yenta_probe_cb_irq(socket);
3838c2ecf20Sopenharmony_ci	if (pci_irq_status)
3848c2ecf20Sopenharmony_ci		goto out;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/*
3878c2ecf20Sopenharmony_ci	 * We're here which means PCI interrupts are _not_ delivered. try to
3888c2ecf20Sopenharmony_ci	 * find the right setting (all serial or parallel)
3898c2ecf20Sopenharmony_ci	 */
3908c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev,
3918c2ecf20Sopenharmony_ci		 "TI: probing PCI interrupt failed, trying to fix\n");
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/* for serial PCI make sure MFUNC3 is set to IRQSER */
3948c2ecf20Sopenharmony_ci	if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
3958c2ecf20Sopenharmony_ci		switch (socket->dev->device) {
3968c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1250:
3978c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251A:
3988c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251B:
3998c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1450:
4008c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1451A:
4018c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_4450:
4028c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_4451:
4038c2ecf20Sopenharmony_ci			/* these chips have no IRQSER setting in MFUNC3  */
4048c2ecf20Sopenharmony_ci			break;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci		default:
4078c2ecf20Sopenharmony_ci			mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci			/* write down if changed, probe */
4108c2ecf20Sopenharmony_ci			if (mfunc != mfunc_old) {
4118c2ecf20Sopenharmony_ci				config_writel(socket, TI122X_MFUNC, mfunc);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci				pci_irq_status = yenta_probe_cb_irq(socket);
4148c2ecf20Sopenharmony_ci				if (pci_irq_status == 1) {
4158c2ecf20Sopenharmony_ci					dev_info(&socket->dev->dev,
4168c2ecf20Sopenharmony_ci						 "TI: all-serial interrupts ok\n");
4178c2ecf20Sopenharmony_ci					mfunc_old = mfunc;
4188c2ecf20Sopenharmony_ci					goto out;
4198c2ecf20Sopenharmony_ci				}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci				/* not working, back to old value */
4228c2ecf20Sopenharmony_ci				mfunc = mfunc_old;
4238c2ecf20Sopenharmony_ci				config_writel(socket, TI122X_MFUNC, mfunc);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci				if (pci_irq_status == -1)
4268c2ecf20Sopenharmony_ci					goto out;
4278c2ecf20Sopenharmony_ci			}
4288c2ecf20Sopenharmony_ci		}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci		/* serial PCI interrupts not working fall back to parallel */
4318c2ecf20Sopenharmony_ci		dev_info(&socket->dev->dev,
4328c2ecf20Sopenharmony_ci			 "TI: falling back to parallel PCI interrupts\n");
4338c2ecf20Sopenharmony_ci		devctl &= ~TI113X_DCR_IMODE_MASK;
4348c2ecf20Sopenharmony_ci		devctl |= TI113X_DCR_IMODE_SERIAL; /* serial ISA could be right */
4358c2ecf20Sopenharmony_ci		config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	/* parallel PCI interrupts: route INTA */
4398c2ecf20Sopenharmony_ci	switch (socket->dev->device) {
4408c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1250:
4418c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1251A:
4428c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1251B:
4438c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1450:
4448c2ecf20Sopenharmony_ci		/* make sure GPIO3 is set to INTA */
4458c2ecf20Sopenharmony_ci		gpio3 = gpio3_old = config_readb(socket, TI1250_GPIO3_CONTROL);
4468c2ecf20Sopenharmony_ci		gpio3 &= ~TI1250_GPIO_MODE_MASK;
4478c2ecf20Sopenharmony_ci		if (gpio3 != gpio3_old)
4488c2ecf20Sopenharmony_ci			config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3);
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	default:
4528c2ecf20Sopenharmony_ci		gpio3 = gpio3_old = 0;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		mfunc = (mfunc & ~TI122X_MFUNC0_MASK) | TI122X_MFUNC0_INTA;
4558c2ecf20Sopenharmony_ci		if (mfunc != mfunc_old)
4568c2ecf20Sopenharmony_ci			config_writel(socket, TI122X_MFUNC, mfunc);
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/* time to probe again */
4608c2ecf20Sopenharmony_ci	pci_irq_status = yenta_probe_cb_irq(socket);
4618c2ecf20Sopenharmony_ci	if (pci_irq_status == 1) {
4628c2ecf20Sopenharmony_ci		mfunc_old = mfunc;
4638c2ecf20Sopenharmony_ci		dev_info(&socket->dev->dev, "TI: parallel PCI interrupts ok\n");
4648c2ecf20Sopenharmony_ci	} else {
4658c2ecf20Sopenharmony_ci		/* not working, back to old value */
4668c2ecf20Sopenharmony_ci		mfunc = mfunc_old;
4678c2ecf20Sopenharmony_ci		config_writel(socket, TI122X_MFUNC, mfunc);
4688c2ecf20Sopenharmony_ci		if (gpio3 != gpio3_old)
4698c2ecf20Sopenharmony_ci			config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3_old);
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ciout:
4738c2ecf20Sopenharmony_ci	if (pci_irq_status < 1) {
4748c2ecf20Sopenharmony_ci		socket->cb_irq = 0;
4758c2ecf20Sopenharmony_ci		dev_info(&socket->dev->dev,
4768c2ecf20Sopenharmony_ci			 "Yenta TI: no PCI interrupts. Fish. Please report.\n");
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/* changes the irq of func1 to match that of func0 */
4828c2ecf20Sopenharmony_cistatic int ti12xx_align_irqs(struct yenta_socket *socket, int *old_irq)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct pci_dev *func0;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* find func0 device */
4878c2ecf20Sopenharmony_ci	func0 = pci_get_slot(socket->dev->bus, socket->dev->devfn & ~0x07);
4888c2ecf20Sopenharmony_ci	if (!func0)
4898c2ecf20Sopenharmony_ci		return 0;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	if (old_irq)
4928c2ecf20Sopenharmony_ci		*old_irq = socket->cb_irq;
4938c2ecf20Sopenharmony_ci	socket->cb_irq = socket->dev->irq = func0->irq;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	pci_dev_put(func0);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return 1;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci/*
5018c2ecf20Sopenharmony_ci * ties INTA and INTB together. also changes the devices irq to that of
5028c2ecf20Sopenharmony_ci * the function 0 device. call from func1 only.
5038c2ecf20Sopenharmony_ci * returns 1 if INTRTIE changed, 0 otherwise.
5048c2ecf20Sopenharmony_ci */
5058c2ecf20Sopenharmony_cistatic int ti12xx_tie_interrupts(struct yenta_socket *socket, int *old_irq)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	u32 sysctl;
5088c2ecf20Sopenharmony_ci	int ret;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
5118c2ecf20Sopenharmony_ci	if (sysctl & TI122X_SCR_INTRTIE)
5128c2ecf20Sopenharmony_ci		return 0;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/* align */
5158c2ecf20Sopenharmony_ci	ret = ti12xx_align_irqs(socket, old_irq);
5168c2ecf20Sopenharmony_ci	if (!ret)
5178c2ecf20Sopenharmony_ci		return 0;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	/* tie */
5208c2ecf20Sopenharmony_ci	sysctl |= TI122X_SCR_INTRTIE;
5218c2ecf20Sopenharmony_ci	config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	return 1;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci/* undo what ti12xx_tie_interrupts() did */
5278c2ecf20Sopenharmony_cistatic void ti12xx_untie_interrupts(struct yenta_socket *socket, int old_irq)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	u32 sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
5308c2ecf20Sopenharmony_ci	sysctl &= ~TI122X_SCR_INTRTIE;
5318c2ecf20Sopenharmony_ci	config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	socket->cb_irq = socket->dev->irq = old_irq;
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci/*
5378c2ecf20Sopenharmony_ci * irqrouting for func1, plays with INTB routing
5388c2ecf20Sopenharmony_ci * only touches MFUNC for INTB routing. all other bits are taken
5398c2ecf20Sopenharmony_ci * care of in func0 already.
5408c2ecf20Sopenharmony_ci */
5418c2ecf20Sopenharmony_cistatic void ti12xx_irqroute_func1(struct yenta_socket *socket)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	u32 mfunc, mfunc_old, devctl, sysctl;
5448c2ecf20Sopenharmony_ci	int pci_irq_status;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC);
5478c2ecf20Sopenharmony_ci	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
5488c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev, "TI: mfunc 0x%08x, devctl 0x%02x\n",
5498c2ecf20Sopenharmony_ci		 mfunc, devctl);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/* if IRQs are configured as tied, align irq of func1 with func0 */
5528c2ecf20Sopenharmony_ci	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
5538c2ecf20Sopenharmony_ci	if (sysctl & TI122X_SCR_INTRTIE)
5548c2ecf20Sopenharmony_ci		ti12xx_align_irqs(socket, NULL);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	/* make sure PCI interrupts are enabled before probing */
5578c2ecf20Sopenharmony_ci	ti_init(socket);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* test PCI interrupts first. only try fixing if return value is 0! */
5608c2ecf20Sopenharmony_ci	pci_irq_status = yenta_probe_cb_irq(socket);
5618c2ecf20Sopenharmony_ci	if (pci_irq_status)
5628c2ecf20Sopenharmony_ci		goto out;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	/*
5658c2ecf20Sopenharmony_ci	 * We're here which means PCI interrupts are _not_ delivered. try to
5668c2ecf20Sopenharmony_ci	 * find the right setting
5678c2ecf20Sopenharmony_ci	 */
5688c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev,
5698c2ecf20Sopenharmony_ci		 "TI: probing PCI interrupt failed, trying to fix\n");
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	/* if all serial: set INTRTIE, probe again */
5728c2ecf20Sopenharmony_ci	if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
5738c2ecf20Sopenharmony_ci		int old_irq;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci		if (ti12xx_tie_interrupts(socket, &old_irq)) {
5768c2ecf20Sopenharmony_ci			pci_irq_status = yenta_probe_cb_irq(socket);
5778c2ecf20Sopenharmony_ci			if (pci_irq_status == 1) {
5788c2ecf20Sopenharmony_ci				dev_info(&socket->dev->dev,
5798c2ecf20Sopenharmony_ci					 "TI: all-serial interrupts, tied ok\n");
5808c2ecf20Sopenharmony_ci				goto out;
5818c2ecf20Sopenharmony_ci			}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci			ti12xx_untie_interrupts(socket, old_irq);
5848c2ecf20Sopenharmony_ci		}
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci	/* parallel PCI: route INTB, probe again */
5878c2ecf20Sopenharmony_ci	else {
5888c2ecf20Sopenharmony_ci		int old_irq;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		switch (socket->dev->device) {
5918c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1250:
5928c2ecf20Sopenharmony_ci			/* the 1250 has one pin for IRQSER/INTB depending on devctl */
5938c2ecf20Sopenharmony_ci			break;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251A:
5968c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251B:
5978c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1450:
5988c2ecf20Sopenharmony_ci			/*
5998c2ecf20Sopenharmony_ci			 *  those have a pin for IRQSER/INTB plus INTB in MFUNC0
6008c2ecf20Sopenharmony_ci			 *  we alread probed the shared pin, now go for MFUNC0
6018c2ecf20Sopenharmony_ci			 */
6028c2ecf20Sopenharmony_ci			mfunc = (mfunc & ~TI122X_MFUNC0_MASK) | TI125X_MFUNC0_INTB;
6038c2ecf20Sopenharmony_ci			break;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		default:
6068c2ecf20Sopenharmony_ci			mfunc = (mfunc & ~TI122X_MFUNC1_MASK) | TI122X_MFUNC1_INTB;
6078c2ecf20Sopenharmony_ci			break;
6088c2ecf20Sopenharmony_ci		}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci		/* write, probe */
6118c2ecf20Sopenharmony_ci		if (mfunc != mfunc_old) {
6128c2ecf20Sopenharmony_ci			config_writel(socket, TI122X_MFUNC, mfunc);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci			pci_irq_status = yenta_probe_cb_irq(socket);
6158c2ecf20Sopenharmony_ci			if (pci_irq_status == 1) {
6168c2ecf20Sopenharmony_ci				dev_info(&socket->dev->dev,
6178c2ecf20Sopenharmony_ci					 "TI: parallel PCI interrupts ok\n");
6188c2ecf20Sopenharmony_ci				goto out;
6198c2ecf20Sopenharmony_ci			}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci			mfunc = mfunc_old;
6228c2ecf20Sopenharmony_ci			config_writel(socket, TI122X_MFUNC, mfunc);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci			if (pci_irq_status == -1)
6258c2ecf20Sopenharmony_ci				goto out;
6268c2ecf20Sopenharmony_ci		}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci		/* still nothing: set INTRTIE */
6298c2ecf20Sopenharmony_ci		if (ti12xx_tie_interrupts(socket, &old_irq)) {
6308c2ecf20Sopenharmony_ci			pci_irq_status = yenta_probe_cb_irq(socket);
6318c2ecf20Sopenharmony_ci			if (pci_irq_status == 1) {
6328c2ecf20Sopenharmony_ci				dev_info(&socket->dev->dev,
6338c2ecf20Sopenharmony_ci					 "TI: parallel PCI interrupts, tied ok\n");
6348c2ecf20Sopenharmony_ci				goto out;
6358c2ecf20Sopenharmony_ci			}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci			ti12xx_untie_interrupts(socket, old_irq);
6388c2ecf20Sopenharmony_ci		}
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ciout:
6428c2ecf20Sopenharmony_ci	if (pci_irq_status < 1) {
6438c2ecf20Sopenharmony_ci		socket->cb_irq = 0;
6448c2ecf20Sopenharmony_ci		dev_info(&socket->dev->dev,
6458c2ecf20Sopenharmony_ci			 "TI: no PCI interrupts. Fish. Please report.\n");
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci/* Returns true value if the second slot of a two-slot controller is empty */
6518c2ecf20Sopenharmony_cistatic int ti12xx_2nd_slot_empty(struct yenta_socket *socket)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	struct pci_dev *func;
6548c2ecf20Sopenharmony_ci	struct yenta_socket *slot2;
6558c2ecf20Sopenharmony_ci	int devfn;
6568c2ecf20Sopenharmony_ci	unsigned int state;
6578c2ecf20Sopenharmony_ci	int ret = 1;
6588c2ecf20Sopenharmony_ci	u32 sysctl;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	/* catch the two-slot controllers */
6618c2ecf20Sopenharmony_ci	switch (socket->dev->device) {
6628c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1220:
6638c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1221:
6648c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1225:
6658c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1251A:
6668c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1251B:
6678c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1420:
6688c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1450:
6698c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1451A:
6708c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1520:
6718c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_1620:
6728c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_4520:
6738c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_4450:
6748c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_4451:
6758c2ecf20Sopenharmony_ci		/*
6768c2ecf20Sopenharmony_ci		 * there are way more, but they need to be added in yenta_socket.c
6778c2ecf20Sopenharmony_ci		 * and pci_ids.h first anyway.
6788c2ecf20Sopenharmony_ci		 */
6798c2ecf20Sopenharmony_ci		break;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_XX12:
6828c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_X515:
6838c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_X420:
6848c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_X620:
6858c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_XX21_XX11:
6868c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_7410:
6878c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_TI_7610:
6888c2ecf20Sopenharmony_ci		/*
6898c2ecf20Sopenharmony_ci		 * those are either single or dual slot CB with additional functions
6908c2ecf20Sopenharmony_ci		 * like 1394, smartcard reader, etc. check the TIEALL flag for them
6918c2ecf20Sopenharmony_ci		 * the TIEALL flag binds the IRQ of all functions together.
6928c2ecf20Sopenharmony_ci		 * we catch the single slot variants later.
6938c2ecf20Sopenharmony_ci		 */
6948c2ecf20Sopenharmony_ci		sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
6958c2ecf20Sopenharmony_ci		if (sysctl & TIXX21_SCR_TIEALL)
6968c2ecf20Sopenharmony_ci			return 0;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		break;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	/* single-slot controllers have the 2nd slot empty always :) */
7018c2ecf20Sopenharmony_ci	default:
7028c2ecf20Sopenharmony_ci		return 1;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	/* get other slot */
7068c2ecf20Sopenharmony_ci	devfn = socket->dev->devfn & ~0x07;
7078c2ecf20Sopenharmony_ci	func = pci_get_slot(socket->dev->bus,
7088c2ecf20Sopenharmony_ci	                    (socket->dev->devfn & 0x07) ? devfn : devfn | 0x01);
7098c2ecf20Sopenharmony_ci	if (!func)
7108c2ecf20Sopenharmony_ci		return 1;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	/*
7138c2ecf20Sopenharmony_ci	 * check that the device id of both slots match. this is needed for the
7148c2ecf20Sopenharmony_ci	 * XX21 and the XX11 controller that share the same device id for single
7158c2ecf20Sopenharmony_ci	 * and dual slot controllers. return '2nd slot empty'. we already checked
7168c2ecf20Sopenharmony_ci	 * if the interrupt is tied to another function.
7178c2ecf20Sopenharmony_ci	 */
7188c2ecf20Sopenharmony_ci	if (socket->dev->device != func->device)
7198c2ecf20Sopenharmony_ci		goto out;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	slot2 = pci_get_drvdata(func);
7228c2ecf20Sopenharmony_ci	if (!slot2)
7238c2ecf20Sopenharmony_ci		goto out;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	/* check state */
7268c2ecf20Sopenharmony_ci	yenta_get_status(&slot2->socket, &state);
7278c2ecf20Sopenharmony_ci	if (state & SS_DETECT) {
7288c2ecf20Sopenharmony_ci		ret = 0;
7298c2ecf20Sopenharmony_ci		goto out;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ciout:
7338c2ecf20Sopenharmony_ci	pci_dev_put(func);
7348c2ecf20Sopenharmony_ci	return ret;
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci/*
7388c2ecf20Sopenharmony_ci * TI specifiy parts for the power hook.
7398c2ecf20Sopenharmony_ci *
7408c2ecf20Sopenharmony_ci * some TI's with some CB's produces interrupt storm on power on. it has been
7418c2ecf20Sopenharmony_ci * seen with atheros wlan cards on TI1225 and TI1410. solution is simply to
7428c2ecf20Sopenharmony_ci * disable any CB interrupts during this time.
7438c2ecf20Sopenharmony_ci */
7448c2ecf20Sopenharmony_cistatic int ti12xx_power_hook(struct pcmcia_socket *sock, int operation)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
7478c2ecf20Sopenharmony_ci	u32 mfunc, devctl, sysctl;
7488c2ecf20Sopenharmony_ci	u8 gpio3;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/* only POWER_PRE and POWER_POST are interesting */
7518c2ecf20Sopenharmony_ci	if ((operation != HOOK_POWER_PRE) && (operation != HOOK_POWER_POST))
7528c2ecf20Sopenharmony_ci		return 0;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
7558c2ecf20Sopenharmony_ci	sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
7568c2ecf20Sopenharmony_ci	mfunc = config_readl(socket, TI122X_MFUNC);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	/*
7598c2ecf20Sopenharmony_ci	 * all serial/tied: only disable when modparm set. always doing it
7608c2ecf20Sopenharmony_ci	 * would mean a regression for working setups 'cos it disables the
7618c2ecf20Sopenharmony_ci	 * interrupts for both both slots on 2-slot controllers
7628c2ecf20Sopenharmony_ci	 * (and users of single slot controllers where it's save have to
7638c2ecf20Sopenharmony_ci	 * live with setting the modparm, most don't have to anyway)
7648c2ecf20Sopenharmony_ci	 */
7658c2ecf20Sopenharmony_ci	if (((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) &&
7668c2ecf20Sopenharmony_ci	    (pwr_irqs_off || ti12xx_2nd_slot_empty(socket))) {
7678c2ecf20Sopenharmony_ci		switch (socket->dev->device) {
7688c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1250:
7698c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251A:
7708c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251B:
7718c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1450:
7728c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1451A:
7738c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_4450:
7748c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_4451:
7758c2ecf20Sopenharmony_ci			/* these chips have no IRQSER setting in MFUNC3  */
7768c2ecf20Sopenharmony_ci			break;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci		default:
7798c2ecf20Sopenharmony_ci			if (operation == HOOK_POWER_PRE)
7808c2ecf20Sopenharmony_ci				mfunc = (mfunc & ~TI122X_MFUNC3_MASK);
7818c2ecf20Sopenharmony_ci			else
7828c2ecf20Sopenharmony_ci				mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER;
7838c2ecf20Sopenharmony_ci		}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci		return 0;
7868c2ecf20Sopenharmony_ci	}
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	/* do the job differently for func0/1 */
7898c2ecf20Sopenharmony_ci	if ((PCI_FUNC(socket->dev->devfn) == 0) ||
7908c2ecf20Sopenharmony_ci	    ((sysctl & TI122X_SCR_INTRTIE) &&
7918c2ecf20Sopenharmony_ci	     (pwr_irqs_off || ti12xx_2nd_slot_empty(socket)))) {
7928c2ecf20Sopenharmony_ci		/* some bridges are different */
7938c2ecf20Sopenharmony_ci		switch (socket->dev->device) {
7948c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1250:
7958c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251A:
7968c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251B:
7978c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1450:
7988c2ecf20Sopenharmony_ci			/* those oldies use gpio3 for INTA */
7998c2ecf20Sopenharmony_ci			gpio3 = config_readb(socket, TI1250_GPIO3_CONTROL);
8008c2ecf20Sopenharmony_ci			if (operation == HOOK_POWER_PRE)
8018c2ecf20Sopenharmony_ci				gpio3 = (gpio3 & ~TI1250_GPIO_MODE_MASK) | 0x40;
8028c2ecf20Sopenharmony_ci			else
8038c2ecf20Sopenharmony_ci				gpio3 &= ~TI1250_GPIO_MODE_MASK;
8048c2ecf20Sopenharmony_ci			config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3);
8058c2ecf20Sopenharmony_ci			break;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci		default:
8088c2ecf20Sopenharmony_ci			/* all new bridges are the same */
8098c2ecf20Sopenharmony_ci			if (operation == HOOK_POWER_PRE)
8108c2ecf20Sopenharmony_ci				mfunc &= ~TI122X_MFUNC0_MASK;
8118c2ecf20Sopenharmony_ci			else
8128c2ecf20Sopenharmony_ci				mfunc |= TI122X_MFUNC0_INTA;
8138c2ecf20Sopenharmony_ci			config_writel(socket, TI122X_MFUNC, mfunc);
8148c2ecf20Sopenharmony_ci		}
8158c2ecf20Sopenharmony_ci	} else {
8168c2ecf20Sopenharmony_ci		switch (socket->dev->device) {
8178c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251A:
8188c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1251B:
8198c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_TI_1450:
8208c2ecf20Sopenharmony_ci			/* those have INTA elsewhere and INTB in MFUNC0 */
8218c2ecf20Sopenharmony_ci			if (operation == HOOK_POWER_PRE)
8228c2ecf20Sopenharmony_ci				mfunc &= ~TI122X_MFUNC0_MASK;
8238c2ecf20Sopenharmony_ci			else
8248c2ecf20Sopenharmony_ci				mfunc |= TI125X_MFUNC0_INTB;
8258c2ecf20Sopenharmony_ci			config_writel(socket, TI122X_MFUNC, mfunc);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci			break;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci		default:
8308c2ecf20Sopenharmony_ci			/* all new bridges are the same */
8318c2ecf20Sopenharmony_ci			if (operation == HOOK_POWER_PRE)
8328c2ecf20Sopenharmony_ci				mfunc &= ~TI122X_MFUNC1_MASK;
8338c2ecf20Sopenharmony_ci			else
8348c2ecf20Sopenharmony_ci				mfunc |= TI122X_MFUNC1_INTB;
8358c2ecf20Sopenharmony_ci			config_writel(socket, TI122X_MFUNC, mfunc);
8368c2ecf20Sopenharmony_ci		}
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	return 0;
8408c2ecf20Sopenharmony_ci}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_cistatic int ti12xx_override(struct yenta_socket *socket)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	u32 val, val_orig;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	/* make sure that memory burst is active */
8478c2ecf20Sopenharmony_ci	val_orig = val = config_readl(socket, TI113X_SYSTEM_CONTROL);
8488c2ecf20Sopenharmony_ci	if (disable_clkrun && PCI_FUNC(socket->dev->devfn) == 0) {
8498c2ecf20Sopenharmony_ci		dev_info(&socket->dev->dev, "Disabling CLKRUN feature\n");
8508c2ecf20Sopenharmony_ci		val |= TI113X_SCR_KEEPCLK;
8518c2ecf20Sopenharmony_ci	}
8528c2ecf20Sopenharmony_ci	if (!(val & TI122X_SCR_MRBURSTUP)) {
8538c2ecf20Sopenharmony_ci		dev_info(&socket->dev->dev,
8548c2ecf20Sopenharmony_ci			 "Enabling burst memory read transactions\n");
8558c2ecf20Sopenharmony_ci		val |= TI122X_SCR_MRBURSTUP;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci	if (val_orig != val)
8588c2ecf20Sopenharmony_ci		config_writel(socket, TI113X_SYSTEM_CONTROL, val);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	/*
8618c2ecf20Sopenharmony_ci	 * Yenta expects controllers to use CSCINT to route
8628c2ecf20Sopenharmony_ci	 * CSC interrupts to PCI rather than INTVAL.
8638c2ecf20Sopenharmony_ci	 */
8648c2ecf20Sopenharmony_ci	val = config_readb(socket, TI1250_DIAGNOSTIC);
8658c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev, "Using %s to route CSC interrupts to PCI\n",
8668c2ecf20Sopenharmony_ci		 (val & TI1250_DIAG_PCI_CSC) ? "CSCINT" : "INTVAL");
8678c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev, "Routing CardBus interrupts to %s\n",
8688c2ecf20Sopenharmony_ci		 (val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA");
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	/* do irqrouting, depending on function */
8718c2ecf20Sopenharmony_ci	if (PCI_FUNC(socket->dev->devfn) == 0)
8728c2ecf20Sopenharmony_ci		ti12xx_irqroute_func0(socket);
8738c2ecf20Sopenharmony_ci	else
8748c2ecf20Sopenharmony_ci		ti12xx_irqroute_func1(socket);
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/* install power hook */
8778c2ecf20Sopenharmony_ci	socket->socket.power_hook = ti12xx_power_hook;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	return ti_override(socket);
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic int ti1250_override(struct yenta_socket *socket)
8848c2ecf20Sopenharmony_ci{
8858c2ecf20Sopenharmony_ci	u8 old, diag;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	old = config_readb(socket, TI1250_DIAGNOSTIC);
8888c2ecf20Sopenharmony_ci	diag = old & ~(TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ);
8898c2ecf20Sopenharmony_ci	if (socket->cb_irq)
8908c2ecf20Sopenharmony_ci		diag |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	if (diag != old) {
8938c2ecf20Sopenharmony_ci		dev_info(&socket->dev->dev,
8948c2ecf20Sopenharmony_ci			 "adjusting diagnostic: %02x -> %02x\n",
8958c2ecf20Sopenharmony_ci			 old, diag);
8968c2ecf20Sopenharmony_ci		config_writeb(socket, TI1250_DIAGNOSTIC, diag);
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	return ti12xx_override(socket);
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci/**
9048c2ecf20Sopenharmony_ci * EnE specific part. EnE bridges are register compatible with TI bridges but
9058c2ecf20Sopenharmony_ci * have their own test registers and more important their own little problems.
9068c2ecf20Sopenharmony_ci * Some fixup code to make everybody happy (TM).
9078c2ecf20Sopenharmony_ci */
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci#ifdef CONFIG_YENTA_ENE_TUNE
9108c2ecf20Sopenharmony_ci/*
9118c2ecf20Sopenharmony_ci * set/clear various test bits:
9128c2ecf20Sopenharmony_ci * Defaults to clear the bit.
9138c2ecf20Sopenharmony_ci * - mask (u8) defines what bits to change
9148c2ecf20Sopenharmony_ci * - bits (u8) is the values to change them to
9158c2ecf20Sopenharmony_ci * -> it's
9168c2ecf20Sopenharmony_ci * 	current = (current & ~mask) | bits
9178c2ecf20Sopenharmony_ci */
9188c2ecf20Sopenharmony_ci/* pci ids of devices that wants to have the bit set */
9198c2ecf20Sopenharmony_ci#define DEVID(_vend,_dev,_subvend,_subdev,mask,bits) {		\
9208c2ecf20Sopenharmony_ci		.vendor		= _vend,			\
9218c2ecf20Sopenharmony_ci		.device		= _dev,				\
9228c2ecf20Sopenharmony_ci		.subvendor	= _subvend,			\
9238c2ecf20Sopenharmony_ci		.subdevice	= _subdev,			\
9248c2ecf20Sopenharmony_ci		.driver_data	= ((mask) << 8 | (bits)),	\
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_cistatic struct pci_device_id ene_tune_tbl[] = {
9278c2ecf20Sopenharmony_ci	/* Echo Audio products based on motorola DSP56301 and DSP56361 */
9288c2ecf20Sopenharmony_ci	DEVID(PCI_VENDOR_ID_MOTOROLA, 0x1801, 0xECC0, PCI_ANY_ID,
9298c2ecf20Sopenharmony_ci		ENE_TEST_C9_TLTENABLE | ENE_TEST_C9_PFENABLE, ENE_TEST_C9_TLTENABLE),
9308c2ecf20Sopenharmony_ci	DEVID(PCI_VENDOR_ID_MOTOROLA, 0x3410, 0xECC0, PCI_ANY_ID,
9318c2ecf20Sopenharmony_ci		ENE_TEST_C9_TLTENABLE | ENE_TEST_C9_PFENABLE, ENE_TEST_C9_TLTENABLE),
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	{}
9348c2ecf20Sopenharmony_ci};
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_cistatic void ene_tune_bridge(struct pcmcia_socket *sock, struct pci_bus *bus)
9378c2ecf20Sopenharmony_ci{
9388c2ecf20Sopenharmony_ci	struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
9398c2ecf20Sopenharmony_ci	struct pci_dev *dev;
9408c2ecf20Sopenharmony_ci	struct pci_device_id *id = NULL;
9418c2ecf20Sopenharmony_ci	u8 test_c9, old_c9, mask, bits;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
9448c2ecf20Sopenharmony_ci		id = (struct pci_device_id *) pci_match_id(ene_tune_tbl, dev);
9458c2ecf20Sopenharmony_ci		if (id)
9468c2ecf20Sopenharmony_ci			break;
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	test_c9 = old_c9 = config_readb(socket, ENE_TEST_C9);
9508c2ecf20Sopenharmony_ci	if (id) {
9518c2ecf20Sopenharmony_ci		mask = (id->driver_data >> 8) & 0xFF;
9528c2ecf20Sopenharmony_ci		bits = id->driver_data & 0xFF;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci		test_c9 = (test_c9 & ~mask) | bits;
9558c2ecf20Sopenharmony_ci	}
9568c2ecf20Sopenharmony_ci	else
9578c2ecf20Sopenharmony_ci		/* default to clear TLTEnable bit, old behaviour */
9588c2ecf20Sopenharmony_ci		test_c9 &= ~ENE_TEST_C9_TLTENABLE;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	dev_info(&socket->dev->dev,
9618c2ecf20Sopenharmony_ci		 "EnE: changing testregister 0xC9, %02x -> %02x\n",
9628c2ecf20Sopenharmony_ci		 old_c9, test_c9);
9638c2ecf20Sopenharmony_ci	config_writeb(socket, ENE_TEST_C9, test_c9);
9648c2ecf20Sopenharmony_ci}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_cistatic int ene_override(struct yenta_socket *socket)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	/* install tune_bridge() function */
9698c2ecf20Sopenharmony_ci	socket->socket.tune_bridge = ene_tune_bridge;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	return ti1250_override(socket);
9728c2ecf20Sopenharmony_ci}
9738c2ecf20Sopenharmony_ci#else
9748c2ecf20Sopenharmony_ci#  define ene_override ti1250_override
9758c2ecf20Sopenharmony_ci#endif /* !CONFIG_YENTA_ENE_TUNE */
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci#endif /* _LINUX_TI113X_H */
9788c2ecf20Sopenharmony_ci
979