xref: /openbmc/linux/drivers/i2c/busses/i2c-i801.c (revision 9144f784f852f9a125cabe9927b986d909bfa439)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
41da177e4SLinus Torvalds     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
51da177e4SLinus Torvalds     <mdsxyz123@yahoo.com>
6b3b8df97SJean Delvare     Copyright (C) 2007 - 2014  Jean Delvare <jdelvare@suse.de>
70cd96eb0SDavid Woodhouse     Copyright (C) 2010         Intel Corporation,
80cd96eb0SDavid Woodhouse                                David Woodhouse <dwmw2@infradead.org>
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds /*
13ce316110SJean Delvare  * Supports the following Intel I/O Controller Hubs (ICH):
14ce316110SJean Delvare  *
15ce316110SJean Delvare  *					I/O			Block	I2C
16ce316110SJean Delvare  *					region	SMBus	Block	proc.	block
17ce316110SJean Delvare  * Chip name			PCI ID	size	PEC	buffer	call	read
18ce316110SJean Delvare  * ---------------------------------------------------------------------------
19ce316110SJean Delvare  * 82801AA (ICH)		0x2413	16	no	no	no	no
20ce316110SJean Delvare  * 82801AB (ICH0)		0x2423	16	no	no	no	no
21ce316110SJean Delvare  * 82801BA (ICH2)		0x2443	16	no	no	no	no
22ce316110SJean Delvare  * 82801CA (ICH3)		0x2483	32	soft	no	no	no
23ce316110SJean Delvare  * 82801DB (ICH4)		0x24c3	32	hard	yes	no	no
24ce316110SJean Delvare  * 82801E (ICH5)		0x24d3	32	hard	yes	yes	yes
25ce316110SJean Delvare  * 6300ESB			0x25a4	32	hard	yes	yes	yes
26ce316110SJean Delvare  * 82801F (ICH6)		0x266a	32	hard	yes	yes	yes
27ce316110SJean Delvare  * 6310ESB/6320ESB		0x269b	32	hard	yes	yes	yes
28ce316110SJean Delvare  * 82801G (ICH7)		0x27da	32	hard	yes	yes	yes
29ce316110SJean Delvare  * 82801H (ICH8)		0x283e	32	hard	yes	yes	yes
30ce316110SJean Delvare  * 82801I (ICH9)		0x2930	32	hard	yes	yes	yes
31ce316110SJean Delvare  * EP80579 (Tolapai)		0x5032	32	hard	yes	yes	yes
32ce316110SJean Delvare  * ICH10			0x3a30	32	hard	yes	yes	yes
33ce316110SJean Delvare  * ICH10			0x3a60	32	hard	yes	yes	yes
34ce316110SJean Delvare  * 5/3400 Series (PCH)		0x3b30	32	hard	yes	yes	yes
35ce316110SJean Delvare  * 6 Series (PCH)		0x1c22	32	hard	yes	yes	yes
36ce316110SJean Delvare  * Patsburg (PCH)		0x1d22	32	hard	yes	yes	yes
37ce316110SJean Delvare  * Patsburg (PCH) IDF		0x1d70	32	hard	yes	yes	yes
38ce316110SJean Delvare  * Patsburg (PCH) IDF		0x1d71	32	hard	yes	yes	yes
39ce316110SJean Delvare  * Patsburg (PCH) IDF		0x1d72	32	hard	yes	yes	yes
40ce316110SJean Delvare  * DH89xxCC (PCH)		0x2330	32	hard	yes	yes	yes
41ce316110SJean Delvare  * Panther Point (PCH)		0x1e22	32	hard	yes	yes	yes
42ce316110SJean Delvare  * Lynx Point (PCH)		0x8c22	32	hard	yes	yes	yes
43ce316110SJean Delvare  * Lynx Point-LP (PCH)		0x9c22	32	hard	yes	yes	yes
44ce316110SJean Delvare  * Avoton (SOC)			0x1f3c	32	hard	yes	yes	yes
45ce316110SJean Delvare  * Wellsburg (PCH)		0x8d22	32	hard	yes	yes	yes
46ce316110SJean Delvare  * Wellsburg (PCH) MS		0x8d7d	32	hard	yes	yes	yes
47ce316110SJean Delvare  * Wellsburg (PCH) MS		0x8d7e	32	hard	yes	yes	yes
48ce316110SJean Delvare  * Wellsburg (PCH) MS		0x8d7f	32	hard	yes	yes	yes
49ce316110SJean Delvare  * Coleto Creek (PCH)		0x23b0	32	hard	yes	yes	yes
50b299de83SJean Delvare  * Wildcat Point (PCH)		0x8ca2	32	hard	yes	yes	yes
51ce316110SJean Delvare  * Wildcat Point-LP (PCH)	0x9ca2	32	hard	yes	yes	yes
52ce316110SJean Delvare  * BayTrail (SOC)		0x0f12	32	hard	yes	yes	yes
5315407798SJarkko Nikula  * Braswell (SOC)		0x2292	32	hard	yes	yes	yes
543e27a844Sjames.d.ralston@intel.com  * Sunrise Point-H (PCH) 	0xa123  32	hard	yes	yes	yes
553eee1799SDevin Ryles  * Sunrise Point-LP (PCH)	0x9d23	32	hard	yes	yes	yes
5684d7f2ebSMika Westerberg  * DNV (SOC)			0x19df	32	hard	yes	yes	yes
5712745b07SMika Westerberg  * Emmitsburg (PCH)		0x1bc9	32	hard	yes	yes	yes
58dd77f423SJarkko Nikula  * Broxton (SOC)		0x5ad4	32	hard	yes	yes	yes
59cdc5a311SAlexandra Yates  * Lewisburg (PCH)		0xa1a3	32	hard	yes	yes	yes
60cdc5a311SAlexandra Yates  * Lewisburg Supersku (PCH)	0xa223	32	hard	yes	yes	yes
6131158763SAndy Shevchenko  * Kaby Lake PCH-H (PCH)	0xa2a3	32	hard	yes	yes	yes
629827f9ebSMika Westerberg  * Gemini Lake (SOC)		0x31d4	32	hard	yes	yes	yes
6309a1de04SSrinivas Pandruvada  * Cannon Lake-H (PCH)		0xa323	32	hard	yes	yes	yes
6409a1de04SSrinivas Pandruvada  * Cannon Lake-LP (PCH)		0x9da3	32	hard	yes	yes	yes
65cb09d943SJarkko Nikula  * Cedar Fork (PCH)		0x18df	32	hard	yes	yes	yes
660bff2a86SMika Westerberg  * Ice Lake-LP (PCH)		0x34a3	32	hard	yes	yes	yes
6776eb4db6SAndy Shevchenko  * Ice Lake-N (PCH)		0x38a3	32	hard	yes	yes	yes
685cd1c56cSJarkko Nikula  * Comet Lake (PCH)		0x02a3	32	hard	yes	yes	yes
6907f047e3SJarkko Nikula  * Comet Lake-H (PCH)		0x06a3	32	hard	yes	yes	yes
709be1485aSJarkko Nikula  * Elkhart Lake (PCH)		0x4b23	32	hard	yes	yes	yes
71051d769fSJarkko Nikula  * Tiger Lake-LP (PCH)		0xa0a3	32	hard	yes	yes	yes
72f46efbcaSJarkko Nikula  * Tiger Lake-H (PCH)		0x43a3	32	hard	yes	yes	yes
73790591f4SAndy Shevchenko  * Jasper Lake (SOC)		0x4da3	32	hard	yes	yes	yes
74f53938d2SJarkko Nikula  * Comet Lake-V (PCH)		0xa3a3	32	hard	yes	yes	yes
75332fdaebSJarkko Nikula  * Alder Lake-S (PCH)		0x7aa3	32	hard	yes	yes	yes
76d1f50bcfSJarkko Nikula  * Alder Lake-P (PCH)		0x51a3	32	hard	yes	yes	yes
778f51c176SJarkko Nikula  * Alder Lake-M (PCH)		0x54a3	32	hard	yes	yes	yes
789c02d401SJarkko Nikula  * Raptor Lake-S (PCH)		0x7a23	32	hard	yes	yes	yes
7924fff66fSJarkko Nikula  * Meteor Lake-P (SOC)		0x7e22	32	hard	yes	yes	yes
80e755ef00SJarkko Nikula  * Meteor Lake SoC-S (SOC)	0xae22	32	hard	yes	yes	yes
81bcfc2ab7SJarkko Nikula  * Meteor Lake PCH-S (PCH)	0x7f23	32	hard	yes	yes	yes
82c0015277SJarkko Nikula  * Birch Stream (SOC)		0x5796	32	hard	yes	yes	yes
83f38ca98bSJarkko Nikula  * Arrow Lake-H (SOC)		0x7722	32	hard	yes	yes	yes
84*6e6a3479SJarkko Nikula  * Panther Lake-H (SOC)		0xe322	32	hard	yes	yes	yes
85*6e6a3479SJarkko Nikula  * Panther Lake-P (SOC)		0xe422	32	hard	yes	yes	yes
86ce316110SJean Delvare  *
87ce316110SJean Delvare  * Features supported by this driver:
88ce316110SJean Delvare  * Software PEC				no
89ce316110SJean Delvare  * Hardware PEC				yes
90ce316110SJean Delvare  * Block buffer				yes
91315cd67cSAlexander Sverdlin  * Block process call transaction	yes
92ce316110SJean Delvare  * I2C block read transaction		yes (doesn't use the block buffer)
93ce316110SJean Delvare  * Slave mode				no
947b0ed334SBenjamin Tissoires  * SMBus Host Notify			yes
95ce316110SJean Delvare  * Interrupt processing			yes
96ce316110SJean Delvare  *
97ccf988b6SMauro Carvalho Chehab  * See the file Documentation/i2c/busses/i2c-i801.rst for details.
981da177e4SLinus Torvalds  */
991da177e4SLinus Torvalds 
100d4a994f6SHeiner Kallweit #define DRV_NAME	"i801_smbus"
101d4a994f6SHeiner Kallweit 
102636752bcSDaniel Kurtz #include <linux/interrupt.h>
1031da177e4SLinus Torvalds #include <linux/module.h>
1041da177e4SLinus Torvalds #include <linux/pci.h>
1051da177e4SLinus Torvalds #include <linux/kernel.h>
1061da177e4SLinus Torvalds #include <linux/stddef.h>
1071da177e4SLinus Torvalds #include <linux/delay.h>
1081da177e4SLinus Torvalds #include <linux/ioport.h>
1091da177e4SLinus Torvalds #include <linux/init.h>
1101da177e4SLinus Torvalds #include <linux/i2c.h>
1117b0ed334SBenjamin Tissoires #include <linux/i2c-smbus.h>
11254fb4a05SJean Delvare #include <linux/acpi.h>
1131561bfe5SJean Delvare #include <linux/io.h>
114fa5bfab7SHans de Goede #include <linux/dmi.h>
115665a96b7SBen Hutchings #include <linux/slab.h>
116af668d65SAndy Shevchenko #include <linux/string.h>
1171de93d5dSHeiner Kallweit #include <linux/completion.h>
1183ad7ea18SJean Delvare #include <linux/err.h>
11994246930SMika Westerberg #include <linux/platform_device.h>
12094246930SMika Westerberg #include <linux/platform_data/itco_wdt.h>
1215c7b9167SAndy Shevchenko #include <linux/platform_data/x86/p2sb.h>
122a7401ca5SJarkko Nikula #include <linux/pm_runtime.h>
1231a987c69SHeiner Kallweit #include <linux/mutex.h>
1243ad7ea18SJean Delvare 
125175c7080SJavier Martinez Canillas #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
126d308dfbfSLinus Walleij #include <linux/gpio/machine.h>
12762ea22c4SWolfram Sang #include <linux/platform_data/i2c-mux-gpio.h>
1283ad7ea18SJean Delvare #endif
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds /* I801 SMBus address offsets */
1310cd96eb0SDavid Woodhouse #define SMBHSTSTS(p)	(0 + (p)->smba)
1320cd96eb0SDavid Woodhouse #define SMBHSTCNT(p)	(2 + (p)->smba)
1330cd96eb0SDavid Woodhouse #define SMBHSTCMD(p)	(3 + (p)->smba)
1340cd96eb0SDavid Woodhouse #define SMBHSTADD(p)	(4 + (p)->smba)
1350cd96eb0SDavid Woodhouse #define SMBHSTDAT0(p)	(5 + (p)->smba)
1360cd96eb0SDavid Woodhouse #define SMBHSTDAT1(p)	(6 + (p)->smba)
1370cd96eb0SDavid Woodhouse #define SMBBLKDAT(p)	(7 + (p)->smba)
1380cd96eb0SDavid Woodhouse #define SMBPEC(p)	(8 + (p)->smba)		/* ICH3 and later */
1390cd96eb0SDavid Woodhouse #define SMBAUXSTS(p)	(12 + (p)->smba)	/* ICH4 and later */
1400cd96eb0SDavid Woodhouse #define SMBAUXCTL(p)	(13 + (p)->smba)	/* ICH4 and later */
1417b0ed334SBenjamin Tissoires #define SMBSLVSTS(p)	(16 + (p)->smba)	/* ICH3 and later */
1427b0ed334SBenjamin Tissoires #define SMBSLVCMD(p)	(17 + (p)->smba)	/* ICH3 and later */
1437b0ed334SBenjamin Tissoires #define SMBNTFDADD(p)	(20 + (p)->smba)	/* ICH3 and later */
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds /* PCI Address Constants */
1466dcc19dfSJean Delvare #define SMBBAR		4
1471da177e4SLinus Torvalds #define SMBHSTCFG	0x040
14894246930SMika Westerberg #define TCOBASE		0x050
14994246930SMika Westerberg #define TCOCTL		0x054
15094246930SMika Westerberg 
15194246930SMika Westerberg #define SBREG_SMBCTRL		0xc6000c
152851a1511SFelipe Balbi #define SBREG_SMBCTRL_DNV	0xcf000c
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds /* Host configuration bits for SMBHSTCFG */
155fe9ba3ecSBenjamin Tissoires #define SMBHSTCFG_HST_EN	BIT(0)
156fe9ba3ecSBenjamin Tissoires #define SMBHSTCFG_SMB_SMI_EN	BIT(1)
157fe9ba3ecSBenjamin Tissoires #define SMBHSTCFG_I2C_EN	BIT(2)
158fe9ba3ecSBenjamin Tissoires #define SMBHSTCFG_SPD_WD	BIT(4)
1591da177e4SLinus Torvalds 
16094246930SMika Westerberg /* TCO configuration bits for TCOCTL */
161fe9ba3ecSBenjamin Tissoires #define TCOCTL_EN		BIT(8)
16294246930SMika Westerberg 
16397d34ec1SEllen Wang /* Auxiliary status register bits, ICH4+ only */
164fe9ba3ecSBenjamin Tissoires #define SMBAUXSTS_CRCE		BIT(0)
165fe9ba3ecSBenjamin Tissoires #define SMBAUXSTS_STCO		BIT(1)
16697d34ec1SEllen Wang 
16725985edcSLucas De Marchi /* Auxiliary control register bits, ICH4+ only */
168fe9ba3ecSBenjamin Tissoires #define SMBAUXCTL_CRC		BIT(0)
169fe9ba3ecSBenjamin Tissoires #define SMBAUXCTL_E32B		BIT(1)
170ca8b9e32SOleg Ryjkov 
1711da177e4SLinus Torvalds /* I801 command constants */
1721da177e4SLinus Torvalds #define I801_QUICK		0x00
1731da177e4SLinus Torvalds #define I801_BYTE		0x04
1741da177e4SLinus Torvalds #define I801_BYTE_DATA		0x08
1751da177e4SLinus Torvalds #define I801_WORD_DATA		0x0C
17655b6f82eSJean Delvare #define I801_PROC_CALL		0x10
1771da177e4SLinus Torvalds #define I801_BLOCK_DATA		0x14
1786342064cSJean Delvare #define I801_I2C_BLOCK_DATA	0x18	/* ICH5 and later */
179315cd67cSAlexander Sverdlin #define I801_BLOCK_PROC_CALL	0x1C
180edbeea63SDaniel Kurtz 
181edbeea63SDaniel Kurtz /* I801 Host Control register bits */
182fe9ba3ecSBenjamin Tissoires #define SMBHSTCNT_INTREN	BIT(0)
183fe9ba3ecSBenjamin Tissoires #define SMBHSTCNT_KILL		BIT(1)
184fe9ba3ecSBenjamin Tissoires #define SMBHSTCNT_LAST_BYTE	BIT(5)
185fe9ba3ecSBenjamin Tissoires #define SMBHSTCNT_START		BIT(6)
186fe9ba3ecSBenjamin Tissoires #define SMBHSTCNT_PEC_EN	BIT(7)	/* ICH3 and later */
1871da177e4SLinus Torvalds 
188ca8b9e32SOleg Ryjkov /* I801 Hosts Status register bits */
189fe9ba3ecSBenjamin Tissoires #define SMBHSTSTS_BYTE_DONE	BIT(7)
190fe9ba3ecSBenjamin Tissoires #define SMBHSTSTS_INUSE_STS	BIT(6)
191fe9ba3ecSBenjamin Tissoires #define SMBHSTSTS_SMBALERT_STS	BIT(5)
192fe9ba3ecSBenjamin Tissoires #define SMBHSTSTS_FAILED	BIT(4)
193fe9ba3ecSBenjamin Tissoires #define SMBHSTSTS_BUS_ERR	BIT(3)
194fe9ba3ecSBenjamin Tissoires #define SMBHSTSTS_DEV_ERR	BIT(2)
195fe9ba3ecSBenjamin Tissoires #define SMBHSTSTS_INTR		BIT(1)
196fe9ba3ecSBenjamin Tissoires #define SMBHSTSTS_HOST_BUSY	BIT(0)
1971da177e4SLinus Torvalds 
1989786b1f1SBenjamin Tissoires /* Host Notify Status register bits */
199fe9ba3ecSBenjamin Tissoires #define SMBSLVSTS_HST_NTFY_STS	BIT(0)
2007b0ed334SBenjamin Tissoires 
2019786b1f1SBenjamin Tissoires /* Host Notify Command register bits */
20203a976c9SJarkko Nikula #define SMBSLVCMD_SMBALERT_DISABLE	BIT(2)
203fe9ba3ecSBenjamin Tissoires #define SMBSLVCMD_HST_NTFY_INTREN	BIT(0)
2047b0ed334SBenjamin Tissoires 
20570a1cc19SDaniel Kurtz #define STATUS_ERROR_FLAGS	(SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
20670a1cc19SDaniel Kurtz 				 SMBHSTSTS_DEV_ERR)
20770a1cc19SDaniel Kurtz 
20870a1cc19SDaniel Kurtz #define STATUS_FLAGS		(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \
20970a1cc19SDaniel Kurtz 				 STATUS_ERROR_FLAGS)
210cf898dc5SJean Delvare 
211a6e5e2beSJean Delvare /* Older devices have their ID defined in <linux/pci_ids.h> */
212856078bfSJarkko Nikula #define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS		0x02a3
21307f047e3SJarkko Nikula #define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS		0x06a3
2141b31e9b7SChew, Kean ho #define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS		0x0f12
215cb09d943SJarkko Nikula #define PCI_DEVICE_ID_INTEL_CDF_SMBUS			0x18df
21634b57f40SAndy Shevchenko #define PCI_DEVICE_ID_INTEL_DNV_SMBUS			0x19df
21712745b07SMika Westerberg #define PCI_DEVICE_ID_INTEL_EBG_SMBUS			0x1bc9
218a6e5e2beSJean Delvare #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS		0x1c22
219a6e5e2beSJean Delvare #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS		0x1d22
22055fee8d7SDavid Woodhouse /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
22155fee8d7SDavid Woodhouse #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0		0x1d70
22255fee8d7SDavid Woodhouse #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1		0x1d71
22355fee8d7SDavid Woodhouse #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2		0x1d72
2246e2a851eSSeth Heasley #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS		0x1e22
225c2db409cSSeth Heasley #define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS		0x1f3c
22634b57f40SAndy Shevchenko #define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS		0x2292
227a6e5e2beSJean Delvare #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS		0x2330
228f39901c1SSeth Heasley #define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS		0x23b0
2299827f9ebSMika Westerberg #define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS		0x31d4
2300bff2a86SMika Westerberg #define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS		0x34a3
23176eb4db6SAndy Shevchenko #define PCI_DEVICE_ID_INTEL_ICELAKE_N_SMBUS		0x38a3
232a6e5e2beSJean Delvare #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS		0x3b30
233f46efbcaSJarkko Nikula #define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS		0x43a3
234856078bfSJarkko Nikula #define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS		0x4b23
235790591f4SAndy Shevchenko #define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS		0x4da3
236d1f50bcfSJarkko Nikula #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS		0x51a3
2378f51c176SJarkko Nikula #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS		0x54a3
238c0015277SJarkko Nikula #define PCI_DEVICE_ID_INTEL_BIRCH_STREAM_SMBUS		0x5796
23934b57f40SAndy Shevchenko #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS		0x5ad4
240f38ca98bSJarkko Nikula #define PCI_DEVICE_ID_INTEL_ARROW_LAKE_H_SMBUS		0x7722
2419c02d401SJarkko Nikula #define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS		0x7a23
242332fdaebSJarkko Nikula #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS		0x7aa3
24324fff66fSJarkko Nikula #define PCI_DEVICE_ID_INTEL_METEOR_LAKE_P_SMBUS		0x7e22
244bcfc2ab7SJarkko Nikula #define PCI_DEVICE_ID_INTEL_METEOR_LAKE_PCH_S_SMBUS	0x7f23
245062737fbSSeth Heasley #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS		0x8c22
246b299de83SJean Delvare #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS		0x8ca2
247a3fc0ff0SJames Ralston #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS		0x8d22
248a3fc0ff0SJames Ralston #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0		0x8d7d
249a3fc0ff0SJames Ralston #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1		0x8d7e
250a3fc0ff0SJames Ralston #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2		0x8d7f
2514a8f1dddSJames Ralston #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS		0x9c22
252afc65924SJames Ralston #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS	0x9ca2
2533eee1799SDevin Ryles #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS	0x9d23
25409a1de04SSrinivas Pandruvada #define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS		0x9da3
255051d769fSJarkko Nikula #define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS		0xa0a3
25634b57f40SAndy Shevchenko #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS	0xa123
257cdc5a311SAlexandra Yates #define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS		0xa1a3
258cdc5a311SAlexandra Yates #define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS	0xa223
25931158763SAndy Shevchenko #define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS	0xa2a3
26009a1de04SSrinivas Pandruvada #define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS		0xa323
261f53938d2SJarkko Nikula #define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS		0xa3a3
262e755ef00SJarkko Nikula #define PCI_DEVICE_ID_INTEL_METEOR_LAKE_SOC_S_SMBUS	0xae22
263*6e6a3479SJarkko Nikula #define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_H_SMBUS	0xe322
264*6e6a3479SJarkko Nikula #define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_P_SMBUS	0xe422
26555fee8d7SDavid Woodhouse 
2663ad7ea18SJean Delvare struct i801_mux_config {
2673ad7ea18SJean Delvare 	char *gpio_chip;
2683ad7ea18SJean Delvare 	unsigned values[3];
2693ad7ea18SJean Delvare 	int n_values;
2703ad7ea18SJean Delvare 	unsigned classes[3];
2713ad7ea18SJean Delvare 	unsigned gpios[2];		/* Relative to gpio_chip->base */
2723ad7ea18SJean Delvare 	int n_gpios;
2733ad7ea18SJean Delvare };
2743ad7ea18SJean Delvare 
2750cd96eb0SDavid Woodhouse struct i801_priv {
2760cd96eb0SDavid Woodhouse 	struct i2c_adapter adapter;
2770cd96eb0SDavid Woodhouse 	unsigned long smba;
2780cd96eb0SDavid Woodhouse 	unsigned char original_hstcfg;
2799b5bf587SJean Delvare 	unsigned char original_hstcnt;
28022e94bd6SBenjamin Tissoires 	unsigned char original_slvcmd;
2810cd96eb0SDavid Woodhouse 	struct pci_dev *pci_dev;
2820cd96eb0SDavid Woodhouse 	unsigned int features;
283636752bcSDaniel Kurtz 
284636752bcSDaniel Kurtz 	/* isr processing */
2851de93d5dSHeiner Kallweit 	struct completion done;
286636752bcSDaniel Kurtz 	u8 status;
287d3ff6ce4SDaniel Kurtz 
288d3ff6ce4SDaniel Kurtz 	/* Command state used by isr for byte-by-byte block transactions */
289d3ff6ce4SDaniel Kurtz 	u8 cmd;
290d3ff6ce4SDaniel Kurtz 	bool is_read;
291d3ff6ce4SDaniel Kurtz 	int count;
292d3ff6ce4SDaniel Kurtz 	int len;
293d3ff6ce4SDaniel Kurtz 	u8 *data;
2943ad7ea18SJean Delvare 
295175c7080SJavier Martinez Canillas #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
2963ad7ea18SJean Delvare 	const struct i801_mux_config *mux_drvdata;
2973ad7ea18SJean Delvare 	struct platform_device *mux_pdev;
298d308dfbfSLinus Walleij 	struct gpiod_lookup_table *lookup;
2993ad7ea18SJean Delvare #endif
30094246930SMika Westerberg 	struct platform_device *tco_pdev;
301a7ae8195SMika Westerberg 
302a7ae8195SMika Westerberg 	/*
303a7ae8195SMika Westerberg 	 * If set to true the host controller registers are reserved for
304a7ae8195SMika Westerberg 	 * ACPI AML use. Protected by acpi_lock.
305a7ae8195SMika Westerberg 	 */
306a7ae8195SMika Westerberg 	bool acpi_reserved;
307a7ae8195SMika Westerberg 	struct mutex acpi_lock;
3080cd96eb0SDavid Woodhouse };
3090cd96eb0SDavid Woodhouse 
310f91fba62SBenjamin Tissoires #define FEATURE_SMBUS_PEC	BIT(0)
311f91fba62SBenjamin Tissoires #define FEATURE_BLOCK_BUFFER	BIT(1)
312f91fba62SBenjamin Tissoires #define FEATURE_BLOCK_PROC	BIT(2)
313f91fba62SBenjamin Tissoires #define FEATURE_I2C_BLOCK_READ	BIT(3)
314f91fba62SBenjamin Tissoires #define FEATURE_IRQ		BIT(4)
315f91fba62SBenjamin Tissoires #define FEATURE_HOST_NOTIFY	BIT(5)
316e7198fbfSJean Delvare /* Not really a feature, but it's convenient to handle it as such */
317f91fba62SBenjamin Tissoires #define FEATURE_IDF		BIT(15)
318b84398d6SMika Westerberg #define FEATURE_TCO_SPT		BIT(16)
319b84398d6SMika Westerberg #define FEATURE_TCO_CNL		BIT(17)
3201da177e4SLinus Torvalds 
321adff687dSJean Delvare static const char *i801_feature_names[] = {
322adff687dSJean Delvare 	"SMBus PEC",
323adff687dSJean Delvare 	"Block buffer",
324adff687dSJean Delvare 	"Block process call",
325adff687dSJean Delvare 	"I2C block read",
326636752bcSDaniel Kurtz 	"Interrupt",
3277b0ed334SBenjamin Tissoires 	"SMBus Host Notify",
328adff687dSJean Delvare };
329adff687dSJean Delvare 
330adff687dSJean Delvare static unsigned int disable_features;
331adff687dSJean Delvare module_param(disable_features, uint, S_IRUGO | S_IWUSR);
33253229345SJean Delvare MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n"
33353229345SJean Delvare 	"\t\t  0x01  disable SMBus PEC\n"
33453229345SJean Delvare 	"\t\t  0x02  disable the block buffer\n"
33553229345SJean Delvare 	"\t\t  0x08  disable the I2C block read functionality\n"
3367b0ed334SBenjamin Tissoires 	"\t\t  0x10  don't use interrupts\n"
3377b0ed334SBenjamin Tissoires 	"\t\t  0x20  disable SMBus Host Notify ");
338adff687dSJean Delvare 
339cf898dc5SJean Delvare /* Make sure the SMBus host is ready to start transmitting.
340cf898dc5SJean Delvare    Return 0 if it is, -EBUSY if it is not. */
i801_check_pre(struct i801_priv * priv)3410cd96eb0SDavid Woodhouse static int i801_check_pre(struct i801_priv *priv)
342cf898dc5SJean Delvare {
343cf898dc5SJean Delvare 	int status;
344cf898dc5SJean Delvare 
3450cd96eb0SDavid Woodhouse 	status = inb_p(SMBHSTSTS(priv));
346cf898dc5SJean Delvare 	if (status & SMBHSTSTS_HOST_BUSY) {
3478c7a8967SHeiner Kallweit 		pci_err(priv->pci_dev, "SMBus is busy, can't use it!\n");
348cf898dc5SJean Delvare 		return -EBUSY;
349cf898dc5SJean Delvare 	}
350cf898dc5SJean Delvare 
351cf898dc5SJean Delvare 	status &= STATUS_FLAGS;
352cf898dc5SJean Delvare 	if (status) {
3538c7a8967SHeiner Kallweit 		pci_dbg(priv->pci_dev, "Clearing status flags (%02x)\n", status);
3540cd96eb0SDavid Woodhouse 		outb_p(status, SMBHSTSTS(priv));
355cf898dc5SJean Delvare 	}
356cf898dc5SJean Delvare 
35797d34ec1SEllen Wang 	/*
35897d34ec1SEllen Wang 	 * Clear CRC status if needed.
35997d34ec1SEllen Wang 	 * During normal operation, i801_check_post() takes care
36097d34ec1SEllen Wang 	 * of it after every operation.  We do it here only in case
36197d34ec1SEllen Wang 	 * the hardware was already in this state when the driver
36297d34ec1SEllen Wang 	 * started.
36397d34ec1SEllen Wang 	 */
36497d34ec1SEllen Wang 	if (priv->features & FEATURE_SMBUS_PEC) {
36597d34ec1SEllen Wang 		status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
36697d34ec1SEllen Wang 		if (status) {
3678c7a8967SHeiner Kallweit 			pci_dbg(priv->pci_dev, "Clearing aux status flags (%02x)\n", status);
36897d34ec1SEllen Wang 			outb_p(status, SMBAUXSTS(priv));
36997d34ec1SEllen Wang 		}
37097d34ec1SEllen Wang 	}
37197d34ec1SEllen Wang 
372cf898dc5SJean Delvare 	return 0;
373cf898dc5SJean Delvare }
374cf898dc5SJean Delvare 
i801_check_post(struct i801_priv * priv,int status)3756cad93c4SJean Delvare static int i801_check_post(struct i801_priv *priv, int status)
376cf898dc5SJean Delvare {
377cf898dc5SJean Delvare 	int result = 0;
378cf898dc5SJean Delvare 
379636752bcSDaniel Kurtz 	/*
380636752bcSDaniel Kurtz 	 * If the SMBus is still busy, we give up
381636752bcSDaniel Kurtz 	 */
3826cad93c4SJean Delvare 	if (unlikely(status < 0)) {
3830cd96eb0SDavid Woodhouse 		dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
384cf898dc5SJean Delvare 		/* try to stop the current command */
3850cd96eb0SDavid Woodhouse 		dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
386e4d8716cSJean Delvare 		outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv));
38784c1af4cSJean Delvare 		usleep_range(1000, 2000);
388e4d8716cSJean Delvare 		outb_p(0, SMBHSTCNT(priv));
389cf898dc5SJean Delvare 
390cf898dc5SJean Delvare 		/* Check if it worked */
3910cd96eb0SDavid Woodhouse 		status = inb_p(SMBHSTSTS(priv));
392cf898dc5SJean Delvare 		if ((status & SMBHSTSTS_HOST_BUSY) ||
393cf898dc5SJean Delvare 		    !(status & SMBHSTSTS_FAILED))
3940cd96eb0SDavid Woodhouse 			dev_err(&priv->pci_dev->dev,
395cf898dc5SJean Delvare 				"Failed terminating the transaction\n");
396cf898dc5SJean Delvare 		return -ETIMEDOUT;
397cf898dc5SJean Delvare 	}
398cf898dc5SJean Delvare 
399cf898dc5SJean Delvare 	if (status & SMBHSTSTS_FAILED) {
400cf898dc5SJean Delvare 		result = -EIO;
4010cd96eb0SDavid Woodhouse 		dev_err(&priv->pci_dev->dev, "Transaction failed\n");
402cf898dc5SJean Delvare 	}
403cf898dc5SJean Delvare 	if (status & SMBHSTSTS_DEV_ERR) {
40497d34ec1SEllen Wang 		/*
40597d34ec1SEllen Wang 		 * This may be a PEC error, check and clear it.
40697d34ec1SEllen Wang 		 *
40797d34ec1SEllen Wang 		 * AUXSTS is handled differently from HSTSTS.
40897d34ec1SEllen Wang 		 * For HSTSTS, i801_isr() or i801_wait_intr()
40997d34ec1SEllen Wang 		 * has already cleared the error bits in hardware,
41097d34ec1SEllen Wang 		 * and we are passed a copy of the original value
41197d34ec1SEllen Wang 		 * in "status".
41297d34ec1SEllen Wang 		 * For AUXSTS, the hardware register is left
41397d34ec1SEllen Wang 		 * for us to handle here.
41497d34ec1SEllen Wang 		 * This is asymmetric, slightly iffy, but safe,
41597d34ec1SEllen Wang 		 * since all this code is serialized and the CRCE
41697d34ec1SEllen Wang 		 * bit is harmless as long as it's cleared before
41797d34ec1SEllen Wang 		 * the next operation.
41897d34ec1SEllen Wang 		 */
41997d34ec1SEllen Wang 		if ((priv->features & FEATURE_SMBUS_PEC) &&
42097d34ec1SEllen Wang 		    (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) {
42197d34ec1SEllen Wang 			outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv));
42297d34ec1SEllen Wang 			result = -EBADMSG;
42397d34ec1SEllen Wang 			dev_dbg(&priv->pci_dev->dev, "PEC error\n");
42497d34ec1SEllen Wang 		} else {
425cf898dc5SJean Delvare 			result = -ENXIO;
4260cd96eb0SDavid Woodhouse 			dev_dbg(&priv->pci_dev->dev, "No response\n");
427cf898dc5SJean Delvare 		}
42897d34ec1SEllen Wang 	}
429cf898dc5SJean Delvare 	if (status & SMBHSTSTS_BUS_ERR) {
430cf898dc5SJean Delvare 		result = -EAGAIN;
4310cd96eb0SDavid Woodhouse 		dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
432cf898dc5SJean Delvare 	}
433cf898dc5SJean Delvare 
434cf898dc5SJean Delvare 	return result;
435cf898dc5SJean Delvare }
436cf898dc5SJean Delvare 
4376cad93c4SJean Delvare /* Wait for BUSY being cleared and either INTR or an error flag being set */
i801_wait_intr(struct i801_priv * priv)4386cad93c4SJean Delvare static int i801_wait_intr(struct i801_priv *priv)
4396cad93c4SJean Delvare {
44044c54c4eSHeiner Kallweit 	unsigned long timeout = jiffies + priv->adapter.timeout;
44144c54c4eSHeiner Kallweit 	int status, busy;
4426cad93c4SJean Delvare 
4436cad93c4SJean Delvare 	do {
4446cad93c4SJean Delvare 		usleep_range(250, 500);
4456cad93c4SJean Delvare 		status = inb_p(SMBHSTSTS(priv));
44644c54c4eSHeiner Kallweit 		busy = status & SMBHSTSTS_HOST_BUSY;
44744c54c4eSHeiner Kallweit 		status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
44844c54c4eSHeiner Kallweit 		if (!busy && status)
449de461a26SHeiner Kallweit 			return status & STATUS_ERROR_FLAGS;
45044c54c4eSHeiner Kallweit 	} while (time_is_after_eq_jiffies(timeout));
4516cad93c4SJean Delvare 
4526cad93c4SJean Delvare 	return -ETIMEDOUT;
4536cad93c4SJean Delvare }
4546cad93c4SJean Delvare 
4556cad93c4SJean Delvare /* Wait for either BYTE_DONE or an error flag being set */
i801_wait_byte_done(struct i801_priv * priv)4566cad93c4SJean Delvare static int i801_wait_byte_done(struct i801_priv *priv)
4576cad93c4SJean Delvare {
45844c54c4eSHeiner Kallweit 	unsigned long timeout = jiffies + priv->adapter.timeout;
4596cad93c4SJean Delvare 	int status;
4606cad93c4SJean Delvare 
4616cad93c4SJean Delvare 	do {
4626cad93c4SJean Delvare 		usleep_range(250, 500);
4636cad93c4SJean Delvare 		status = inb_p(SMBHSTSTS(priv));
46444c54c4eSHeiner Kallweit 		if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE))
4656cad93c4SJean Delvare 			return status & STATUS_ERROR_FLAGS;
46644c54c4eSHeiner Kallweit 	} while (time_is_after_eq_jiffies(timeout));
46744c54c4eSHeiner Kallweit 
46844c54c4eSHeiner Kallweit 	return -ETIMEDOUT;
4696cad93c4SJean Delvare }
4706cad93c4SJean Delvare 
i801_transaction(struct i801_priv * priv,int xact)4710cd96eb0SDavid Woodhouse static int i801_transaction(struct i801_priv *priv, int xact)
4721da177e4SLinus Torvalds {
4731de93d5dSHeiner Kallweit 	unsigned long result;
474b3b8df97SJean Delvare 	const struct i2c_adapter *adap = &priv->adapter;
4751da177e4SLinus Torvalds 
476636752bcSDaniel Kurtz 	if (priv->features & FEATURE_IRQ) {
4771de93d5dSHeiner Kallweit 		reinit_completion(&priv->done);
478636752bcSDaniel Kurtz 		outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
479636752bcSDaniel Kurtz 		       SMBHSTCNT(priv));
4801de93d5dSHeiner Kallweit 		result = wait_for_completion_timeout(&priv->done, adap->timeout);
481de461a26SHeiner Kallweit 		return result ? priv->status : -ETIMEDOUT;
482636752bcSDaniel Kurtz 	}
483636752bcSDaniel Kurtz 
484edbeea63SDaniel Kurtz 	outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
4851da177e4SLinus Torvalds 
486de461a26SHeiner Kallweit 	return i801_wait_intr(priv);
487ca8b9e32SOleg Ryjkov }
488ca8b9e32SOleg Ryjkov 
i801_block_transaction_by_block(struct i801_priv * priv,union i2c_smbus_data * data,char read_write,int command)4890cd96eb0SDavid Woodhouse static int i801_block_transaction_by_block(struct i801_priv *priv,
4900cd96eb0SDavid Woodhouse 					   union i2c_smbus_data *data,
491a6b8bb6aSHeiner Kallweit 					   char read_write, int command)
4927edcb9abSOleg Ryjkov {
493a6b8bb6aSHeiner Kallweit 	int i, len, status, xact;
494315cd67cSAlexander Sverdlin 
495315cd67cSAlexander Sverdlin 	switch (command) {
496315cd67cSAlexander Sverdlin 	case I2C_SMBUS_BLOCK_PROC_CALL:
497a6b8bb6aSHeiner Kallweit 		xact = I801_BLOCK_PROC_CALL;
498315cd67cSAlexander Sverdlin 		break;
499315cd67cSAlexander Sverdlin 	case I2C_SMBUS_BLOCK_DATA:
500a6b8bb6aSHeiner Kallweit 		xact = I801_BLOCK_DATA;
501315cd67cSAlexander Sverdlin 		break;
502315cd67cSAlexander Sverdlin 	default:
503315cd67cSAlexander Sverdlin 		return -EOPNOTSUPP;
504315cd67cSAlexander Sverdlin 	}
5057edcb9abSOleg Ryjkov 
5061e1d6582SHeiner Kallweit 	/* Set block buffer mode */
5071e1d6582SHeiner Kallweit 	outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
5081e1d6582SHeiner Kallweit 
5097edcb9abSOleg Ryjkov 	if (read_write == I2C_SMBUS_WRITE) {
5107edcb9abSOleg Ryjkov 		len = data->block[0];
5110cd96eb0SDavid Woodhouse 		outb_p(len, SMBHSTDAT0(priv));
5126be99c51SJean Delvare 		inb_p(SMBHSTCNT(priv));	/* reset the data buffer index */
5137edcb9abSOleg Ryjkov 		for (i = 0; i < len; i++)
5140cd96eb0SDavid Woodhouse 			outb_p(data->block[i+1], SMBBLKDAT(priv));
5157edcb9abSOleg Ryjkov 	}
5167edcb9abSOleg Ryjkov 
517315cd67cSAlexander Sverdlin 	status = i801_transaction(priv, xact);
51897140342SDavid Brownell 	if (status)
51963fd342fSHeiner Kallweit 		goto out;
5207edcb9abSOleg Ryjkov 
521315cd67cSAlexander Sverdlin 	if (read_write == I2C_SMBUS_READ ||
522315cd67cSAlexander Sverdlin 	    command == I2C_SMBUS_BLOCK_PROC_CALL) {
5230cd96eb0SDavid Woodhouse 		len = inb_p(SMBHSTDAT0(priv));
52463fd342fSHeiner Kallweit 		if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
52563fd342fSHeiner Kallweit 			status = -EPROTO;
52663fd342fSHeiner Kallweit 			goto out;
52763fd342fSHeiner Kallweit 		}
5287edcb9abSOleg Ryjkov 
5297edcb9abSOleg Ryjkov 		data->block[0] = len;
5306be99c51SJean Delvare 		inb_p(SMBHSTCNT(priv));	/* reset the data buffer index */
5317edcb9abSOleg Ryjkov 		for (i = 0; i < len; i++)
5320cd96eb0SDavid Woodhouse 			data->block[i + 1] = inb_p(SMBBLKDAT(priv));
5337edcb9abSOleg Ryjkov 	}
53463fd342fSHeiner Kallweit out:
53563fd342fSHeiner Kallweit 	outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_E32B, SMBAUXCTL(priv));
53663fd342fSHeiner Kallweit 	return status;
5377edcb9abSOleg Ryjkov }
5387edcb9abSOleg Ryjkov 
i801_isr_byte_done(struct i801_priv * priv)539d3ff6ce4SDaniel Kurtz static void i801_isr_byte_done(struct i801_priv *priv)
540d3ff6ce4SDaniel Kurtz {
541d3ff6ce4SDaniel Kurtz 	if (priv->is_read) {
542d3ff6ce4SDaniel Kurtz 		/* For SMBus block reads, length is received with first byte */
543d3ff6ce4SDaniel Kurtz 		if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) &&
544d3ff6ce4SDaniel Kurtz 		    (priv->count == 0)) {
545d3ff6ce4SDaniel Kurtz 			priv->len = inb_p(SMBHSTDAT0(priv));
546d3ff6ce4SDaniel Kurtz 			if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) {
547d3ff6ce4SDaniel Kurtz 				dev_err(&priv->pci_dev->dev,
548d3ff6ce4SDaniel Kurtz 					"Illegal SMBus block read size %d\n",
549d3ff6ce4SDaniel Kurtz 					priv->len);
550d3ff6ce4SDaniel Kurtz 				/* FIXME: Recover */
551d3ff6ce4SDaniel Kurtz 				priv->len = I2C_SMBUS_BLOCK_MAX;
552d3ff6ce4SDaniel Kurtz 			}
553d3ff6ce4SDaniel Kurtz 			priv->data[-1] = priv->len;
554d3ff6ce4SDaniel Kurtz 		}
555d3ff6ce4SDaniel Kurtz 
556d3ff6ce4SDaniel Kurtz 		/* Read next byte */
557d3ff6ce4SDaniel Kurtz 		if (priv->count < priv->len)
558d3ff6ce4SDaniel Kurtz 			priv->data[priv->count++] = inb(SMBBLKDAT(priv));
559d3ff6ce4SDaniel Kurtz 		else
560d3ff6ce4SDaniel Kurtz 			dev_dbg(&priv->pci_dev->dev,
561d3ff6ce4SDaniel Kurtz 				"Discarding extra byte on block read\n");
562d3ff6ce4SDaniel Kurtz 
563d3ff6ce4SDaniel Kurtz 		/* Set LAST_BYTE for last byte of read transaction */
564d3ff6ce4SDaniel Kurtz 		if (priv->count == priv->len - 1)
565d3ff6ce4SDaniel Kurtz 			outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE,
566d3ff6ce4SDaniel Kurtz 			       SMBHSTCNT(priv));
567d3ff6ce4SDaniel Kurtz 	} else if (priv->count < priv->len - 1) {
568d3ff6ce4SDaniel Kurtz 		/* Write next byte, except for IRQ after last byte */
569d3ff6ce4SDaniel Kurtz 		outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
570d3ff6ce4SDaniel Kurtz 	}
571d3ff6ce4SDaniel Kurtz }
572d3ff6ce4SDaniel Kurtz 
i801_host_notify_isr(struct i801_priv * priv)5737b0ed334SBenjamin Tissoires static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
5747b0ed334SBenjamin Tissoires {
5757b0ed334SBenjamin Tissoires 	unsigned short addr;
5767b0ed334SBenjamin Tissoires 
5777b0ed334SBenjamin Tissoires 	addr = inb_p(SMBNTFDADD(priv)) >> 1;
5787b0ed334SBenjamin Tissoires 
579c912a25aSBenjamin Tissoires 	/*
580c912a25aSBenjamin Tissoires 	 * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba)
5814d5538f5SBenjamin Tissoires 	 * always returns 0. Our current implementation doesn't provide
5824d5538f5SBenjamin Tissoires 	 * data, so we just ignore it.
583c912a25aSBenjamin Tissoires 	 */
5844d5538f5SBenjamin Tissoires 	i2c_handle_smbus_host_notify(&priv->adapter, addr);
5857b0ed334SBenjamin Tissoires 
5867b0ed334SBenjamin Tissoires 	/* clear Host Notify bit and return */
5877b0ed334SBenjamin Tissoires 	outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
5887b0ed334SBenjamin Tissoires 	return IRQ_HANDLED;
5897b0ed334SBenjamin Tissoires }
5907b0ed334SBenjamin Tissoires 
591efa3cb15SDaniel Kurtz /*
5927b0ed334SBenjamin Tissoires  * There are three kinds of interrupts:
593d3ff6ce4SDaniel Kurtz  *
594d3ff6ce4SDaniel Kurtz  * 1) i801 signals transaction completion with one of these interrupts:
595636752bcSDaniel Kurtz  *      INTR - Success
596636752bcSDaniel Kurtz  *      DEV_ERR - Invalid command, NAK or communication timeout
597636752bcSDaniel Kurtz  *      BUS_ERR - SMI# transaction collision
598636752bcSDaniel Kurtz  *      FAILED - transaction was canceled due to a KILL request
5991de93d5dSHeiner Kallweit  *    When any of these occur, update ->status and signal completion.
600d3ff6ce4SDaniel Kurtz  *
601d3ff6ce4SDaniel Kurtz  * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
602d3ff6ce4SDaniel Kurtz  *    occurs for each byte of a byte-by-byte to prepare the next byte.
6037b0ed334SBenjamin Tissoires  *
6047b0ed334SBenjamin Tissoires  * 3) Host Notify interrupts
605636752bcSDaniel Kurtz  */
i801_isr(int irq,void * dev_id)606636752bcSDaniel Kurtz static irqreturn_t i801_isr(int irq, void *dev_id)
607636752bcSDaniel Kurtz {
608636752bcSDaniel Kurtz 	struct i801_priv *priv = dev_id;
609636752bcSDaniel Kurtz 	u16 pcists;
610636752bcSDaniel Kurtz 	u8 status;
611636752bcSDaniel Kurtz 
612636752bcSDaniel Kurtz 	/* Confirm this is our interrupt */
6130d3f1e45SHeiner Kallweit 	pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists);
6140d3f1e45SHeiner Kallweit 	if (!(pcists & PCI_STATUS_INTERRUPT))
615636752bcSDaniel Kurtz 		return IRQ_NONE;
616636752bcSDaniel Kurtz 
6177b0ed334SBenjamin Tissoires 	if (priv->features & FEATURE_HOST_NOTIFY) {
6187b0ed334SBenjamin Tissoires 		status = inb_p(SMBSLVSTS(priv));
6197b0ed334SBenjamin Tissoires 		if (status & SMBSLVSTS_HST_NTFY_STS)
6207b0ed334SBenjamin Tissoires 			return i801_host_notify_isr(priv);
6217b0ed334SBenjamin Tissoires 	}
6227b0ed334SBenjamin Tissoires 
623636752bcSDaniel Kurtz 	status = inb_p(SMBHSTSTS(priv));
624c467d919SHeiner Kallweit 	if ((status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS)) == SMBHSTSTS_BYTE_DONE)
625d3ff6ce4SDaniel Kurtz 		i801_isr_byte_done(priv);
626d3ff6ce4SDaniel Kurtz 
627636752bcSDaniel Kurtz 	/*
628c467d919SHeiner Kallweit 	 * Clear IRQ sources: SMB_ALERT status is set after signal assertion
629c467d919SHeiner Kallweit 	 * independently of the interrupt generation being blocked or not
630c467d919SHeiner Kallweit 	 * so clear it always when the status is set.
63103a976c9SJarkko Nikula 	 */
632c467d919SHeiner Kallweit 	status &= STATUS_FLAGS | SMBHSTSTS_SMBALERT_STS;
63303a976c9SJarkko Nikula 	outb_p(status, SMBHSTSTS(priv));
634c467d919SHeiner Kallweit 
635c467d919SHeiner Kallweit 	status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
636636752bcSDaniel Kurtz 	if (status) {
637de461a26SHeiner Kallweit 		priv->status = status & STATUS_ERROR_FLAGS;
6381de93d5dSHeiner Kallweit 		complete(&priv->done);
639636752bcSDaniel Kurtz 	}
640636752bcSDaniel Kurtz 
641636752bcSDaniel Kurtz 	return IRQ_HANDLED;
642636752bcSDaniel Kurtz }
643636752bcSDaniel Kurtz 
644636752bcSDaniel Kurtz /*
645efa3cb15SDaniel Kurtz  * For "byte-by-byte" block transactions:
646efa3cb15SDaniel Kurtz  *   I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1
647efa3cb15SDaniel Kurtz  *   I2C read uses cmd=I801_I2C_BLOCK_DATA
648efa3cb15SDaniel Kurtz  */
i801_block_transaction_byte_by_byte(struct i801_priv * priv,union i2c_smbus_data * data,char read_write,int command)6490cd96eb0SDavid Woodhouse static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
6500cd96eb0SDavid Woodhouse 					       union i2c_smbus_data *data,
651a6b8bb6aSHeiner Kallweit 					       char read_write, int command)
6521da177e4SLinus Torvalds {
6531da177e4SLinus Torvalds 	int i, len;
6541da177e4SLinus Torvalds 	int smbcmd;
6552b73809dSJean Delvare 	int status;
6561de93d5dSHeiner Kallweit 	unsigned long result;
657b3b8df97SJean Delvare 	const struct i2c_adapter *adap = &priv->adapter;
658cf898dc5SJean Delvare 
659315cd67cSAlexander Sverdlin 	if (command == I2C_SMBUS_BLOCK_PROC_CALL)
660315cd67cSAlexander Sverdlin 		return -EOPNOTSUPP;
661315cd67cSAlexander Sverdlin 
6621da177e4SLinus Torvalds 	len = data->block[0];
6637edcb9abSOleg Ryjkov 
6647edcb9abSOleg Ryjkov 	if (read_write == I2C_SMBUS_WRITE) {
6650cd96eb0SDavid Woodhouse 		outb_p(len, SMBHSTDAT0(priv));
6660cd96eb0SDavid Woodhouse 		outb_p(data->block[1], SMBBLKDAT(priv));
6671da177e4SLinus Torvalds 	}
6681da177e4SLinus Torvalds 
669efa3cb15SDaniel Kurtz 	if (command == I2C_SMBUS_I2C_BLOCK_DATA &&
670efa3cb15SDaniel Kurtz 	    read_write == I2C_SMBUS_READ)
6716342064cSJean Delvare 		smbcmd = I801_I2C_BLOCK_DATA;
6721da177e4SLinus Torvalds 	else
6731da177e4SLinus Torvalds 		smbcmd = I801_BLOCK_DATA;
674efa3cb15SDaniel Kurtz 
675d3ff6ce4SDaniel Kurtz 	if (priv->features & FEATURE_IRQ) {
676d3ff6ce4SDaniel Kurtz 		priv->is_read = (read_write == I2C_SMBUS_READ);
677d3ff6ce4SDaniel Kurtz 		if (len == 1 && priv->is_read)
678d3ff6ce4SDaniel Kurtz 			smbcmd |= SMBHSTCNT_LAST_BYTE;
679d3ff6ce4SDaniel Kurtz 		priv->cmd = smbcmd | SMBHSTCNT_INTREN;
680d3ff6ce4SDaniel Kurtz 		priv->len = len;
681d3ff6ce4SDaniel Kurtz 		priv->count = 0;
682d3ff6ce4SDaniel Kurtz 		priv->data = &data->block[1];
683d3ff6ce4SDaniel Kurtz 
6841de93d5dSHeiner Kallweit 		reinit_completion(&priv->done);
685d3ff6ce4SDaniel Kurtz 		outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
6861de93d5dSHeiner Kallweit 		result = wait_for_completion_timeout(&priv->done, adap->timeout);
687de461a26SHeiner Kallweit 		return result ? priv->status : -ETIMEDOUT;
688d3ff6ce4SDaniel Kurtz 	}
689d3ff6ce4SDaniel Kurtz 
69074ee67b1SHeiner Kallweit 	if (len == 1 && read_write == I2C_SMBUS_READ)
691edbeea63SDaniel Kurtz 		smbcmd |= SMBHSTCNT_LAST_BYTE;
69274ee67b1SHeiner Kallweit 	outb_p(smbcmd | SMBHSTCNT_START, SMBHSTCNT(priv));
6931da177e4SLinus Torvalds 
69474ee67b1SHeiner Kallweit 	for (i = 1; i <= len; i++) {
6956cad93c4SJean Delvare 		status = i801_wait_byte_done(priv);
6966cad93c4SJean Delvare 		if (status)
697de461a26SHeiner Kallweit 			return status;
6981da177e4SLinus Torvalds 
6996342064cSJean Delvare 		if (i == 1 && read_write == I2C_SMBUS_READ
7006342064cSJean Delvare 		 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
7010cd96eb0SDavid Woodhouse 			len = inb_p(SMBHSTDAT0(priv));
702cf898dc5SJean Delvare 			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
7030cd96eb0SDavid Woodhouse 				dev_err(&priv->pci_dev->dev,
704cf898dc5SJean Delvare 					"Illegal SMBus block read size %d\n",
705cf898dc5SJean Delvare 					len);
706cf898dc5SJean Delvare 				/* Recover */
7070cd96eb0SDavid Woodhouse 				while (inb_p(SMBHSTSTS(priv)) &
7080cd96eb0SDavid Woodhouse 				       SMBHSTSTS_HOST_BUSY)
7090cd96eb0SDavid Woodhouse 					outb_p(SMBHSTSTS_BYTE_DONE,
7100cd96eb0SDavid Woodhouse 					       SMBHSTSTS(priv));
7110cd96eb0SDavid Woodhouse 				outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
71297140342SDavid Brownell 				return -EPROTO;
713cf898dc5SJean Delvare 			}
7141da177e4SLinus Torvalds 			data->block[0] = len;
7151da177e4SLinus Torvalds 		}
7161da177e4SLinus Torvalds 
71774ee67b1SHeiner Kallweit 		if (read_write == I2C_SMBUS_READ) {
7180cd96eb0SDavid Woodhouse 			data->block[i] = inb_p(SMBBLKDAT(priv));
71974ee67b1SHeiner Kallweit 			if (i == len - 1)
72074ee67b1SHeiner Kallweit 				outb_p(smbcmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv));
72174ee67b1SHeiner Kallweit 		}
72274ee67b1SHeiner Kallweit 
7231da177e4SLinus Torvalds 		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
7240cd96eb0SDavid Woodhouse 			outb_p(data->block[i+1], SMBBLKDAT(priv));
7251da177e4SLinus Torvalds 
726cf898dc5SJean Delvare 		/* signals SMBBLKDAT ready */
7276cad93c4SJean Delvare 		outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
7281da177e4SLinus Torvalds 	}
7291da177e4SLinus Torvalds 
730de461a26SHeiner Kallweit 	return i801_wait_intr(priv);
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds 
i801_set_hstadd(struct i801_priv * priv,u8 addr,char read_write)733eb4d8bacSHeiner Kallweit static void i801_set_hstadd(struct i801_priv *priv, u8 addr, char read_write)
734eb4d8bacSHeiner Kallweit {
735eb4d8bacSHeiner Kallweit 	outb_p((addr << 1) | (read_write & 0x01), SMBHSTADD(priv));
736eb4d8bacSHeiner Kallweit }
737eb4d8bacSHeiner Kallweit 
738dd2d18b5SHeiner Kallweit /* Single value transaction function */
i801_simple_transaction(struct i801_priv * priv,union i2c_smbus_data * data,u8 addr,u8 hstcmd,char read_write,int command)739dd2d18b5SHeiner Kallweit static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
74024592482SHeiner Kallweit 				   u8 addr, u8 hstcmd, char read_write, int command)
741dd2d18b5SHeiner Kallweit {
742dd2d18b5SHeiner Kallweit 	int xact, ret;
743dd2d18b5SHeiner Kallweit 
744dd2d18b5SHeiner Kallweit 	switch (command) {
745dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_QUICK:
74624592482SHeiner Kallweit 		i801_set_hstadd(priv, addr, read_write);
747dd2d18b5SHeiner Kallweit 		xact = I801_QUICK;
748dd2d18b5SHeiner Kallweit 		break;
749dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_BYTE:
75024592482SHeiner Kallweit 		i801_set_hstadd(priv, addr, read_write);
75124592482SHeiner Kallweit 		if (read_write == I2C_SMBUS_WRITE)
75224592482SHeiner Kallweit 			outb_p(hstcmd, SMBHSTCMD(priv));
753dd2d18b5SHeiner Kallweit 		xact = I801_BYTE;
754dd2d18b5SHeiner Kallweit 		break;
755dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_BYTE_DATA:
75624592482SHeiner Kallweit 		i801_set_hstadd(priv, addr, read_write);
757dd2d18b5SHeiner Kallweit 		if (read_write == I2C_SMBUS_WRITE)
758dd2d18b5SHeiner Kallweit 			outb_p(data->byte, SMBHSTDAT0(priv));
75924592482SHeiner Kallweit 		outb_p(hstcmd, SMBHSTCMD(priv));
760dd2d18b5SHeiner Kallweit 		xact = I801_BYTE_DATA;
761dd2d18b5SHeiner Kallweit 		break;
762dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_WORD_DATA:
76324592482SHeiner Kallweit 		i801_set_hstadd(priv, addr, read_write);
764dd2d18b5SHeiner Kallweit 		if (read_write == I2C_SMBUS_WRITE) {
765dd2d18b5SHeiner Kallweit 			outb_p(data->word & 0xff, SMBHSTDAT0(priv));
766dd2d18b5SHeiner Kallweit 			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
767dd2d18b5SHeiner Kallweit 		}
76824592482SHeiner Kallweit 		outb_p(hstcmd, SMBHSTCMD(priv));
769dd2d18b5SHeiner Kallweit 		xact = I801_WORD_DATA;
770dd2d18b5SHeiner Kallweit 		break;
771dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_PROC_CALL:
77224592482SHeiner Kallweit 		i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
773dd2d18b5SHeiner Kallweit 		outb_p(data->word & 0xff, SMBHSTDAT0(priv));
774dd2d18b5SHeiner Kallweit 		outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
77524592482SHeiner Kallweit 		outb_p(hstcmd, SMBHSTCMD(priv));
77624592482SHeiner Kallweit 		read_write = I2C_SMBUS_READ;
777dd2d18b5SHeiner Kallweit 		xact = I801_PROC_CALL;
778dd2d18b5SHeiner Kallweit 		break;
779dd2d18b5SHeiner Kallweit 	default:
78024592482SHeiner Kallweit 		pci_err(priv->pci_dev, "Unsupported transaction %d\n", command);
781dd2d18b5SHeiner Kallweit 		return -EOPNOTSUPP;
782dd2d18b5SHeiner Kallweit 	}
783dd2d18b5SHeiner Kallweit 
784dd2d18b5SHeiner Kallweit 	ret = i801_transaction(priv, xact);
785dd2d18b5SHeiner Kallweit 	if (ret || read_write == I2C_SMBUS_WRITE)
786dd2d18b5SHeiner Kallweit 		return ret;
787dd2d18b5SHeiner Kallweit 
788dd2d18b5SHeiner Kallweit 	switch (command) {
789dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_BYTE:
790dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_BYTE_DATA:
791dd2d18b5SHeiner Kallweit 		data->byte = inb_p(SMBHSTDAT0(priv));
792dd2d18b5SHeiner Kallweit 		break;
793dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_WORD_DATA:
794dd2d18b5SHeiner Kallweit 	case I2C_SMBUS_PROC_CALL:
795dd2d18b5SHeiner Kallweit 		data->word = inb_p(SMBHSTDAT0(priv)) +
796dd2d18b5SHeiner Kallweit 			     (inb_p(SMBHSTDAT1(priv)) << 8);
797dd2d18b5SHeiner Kallweit 		break;
798dd2d18b5SHeiner Kallweit 	}
799dd2d18b5SHeiner Kallweit 
800dd2d18b5SHeiner Kallweit 	return 0;
801dd2d18b5SHeiner Kallweit }
802dd2d18b5SHeiner Kallweit 
8037edcb9abSOleg Ryjkov /* Block transaction function */
i801_block_transaction(struct i801_priv * priv,union i2c_smbus_data * data,u8 addr,u8 hstcmd,char read_write,int command)804a6b8bb6aSHeiner Kallweit static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
805a3989dc0SHeiner Kallweit 				  u8 addr, u8 hstcmd, char read_write, int command)
8067edcb9abSOleg Ryjkov {
8077edcb9abSOleg Ryjkov 	int result = 0;
8087edcb9abSOleg Ryjkov 	unsigned char hostc;
8097edcb9abSOleg Ryjkov 
810effa4531SHeiner Kallweit 	if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA)
811effa4531SHeiner Kallweit 		data->block[0] = I2C_SMBUS_BLOCK_MAX;
812effa4531SHeiner Kallweit 	else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
813effa4531SHeiner Kallweit 		return -EPROTO;
814effa4531SHeiner Kallweit 
815a3989dc0SHeiner Kallweit 	switch (command) {
816a3989dc0SHeiner Kallweit 	case I2C_SMBUS_BLOCK_DATA:
817a3989dc0SHeiner Kallweit 		i801_set_hstadd(priv, addr, read_write);
818a3989dc0SHeiner Kallweit 		outb_p(hstcmd, SMBHSTCMD(priv));
819a3989dc0SHeiner Kallweit 		break;
820a3989dc0SHeiner Kallweit 	case I2C_SMBUS_I2C_BLOCK_DATA:
821a3989dc0SHeiner Kallweit 		/*
822a3989dc0SHeiner Kallweit 		 * NB: page 240 of ICH5 datasheet shows that the R/#W
823a3989dc0SHeiner Kallweit 		 * bit should be cleared here, even when reading.
824a3989dc0SHeiner Kallweit 		 * However if SPD Write Disable is set (Lynx Point and later),
825a3989dc0SHeiner Kallweit 		 * the read will fail if we don't set the R/#W bit.
826a3989dc0SHeiner Kallweit 		 */
827a3989dc0SHeiner Kallweit 		i801_set_hstadd(priv, addr,
828a3989dc0SHeiner Kallweit 				priv->original_hstcfg & SMBHSTCFG_SPD_WD ?
829a3989dc0SHeiner Kallweit 				read_write : I2C_SMBUS_WRITE);
830a3989dc0SHeiner Kallweit 		if (read_write == I2C_SMBUS_READ) {
831a3989dc0SHeiner Kallweit 			/* NB: page 240 of ICH5 datasheet also shows
832a3989dc0SHeiner Kallweit 			 * that DATA1 is the cmd field when reading
833a3989dc0SHeiner Kallweit 			 */
834a3989dc0SHeiner Kallweit 			outb_p(hstcmd, SMBHSTDAT1(priv));
835a3989dc0SHeiner Kallweit 		} else
836a3989dc0SHeiner Kallweit 			outb_p(hstcmd, SMBHSTCMD(priv));
837a3989dc0SHeiner Kallweit 
8387edcb9abSOleg Ryjkov 		if (read_write == I2C_SMBUS_WRITE) {
8397edcb9abSOleg Ryjkov 			/* set I2C_EN bit in configuration register */
8400cd96eb0SDavid Woodhouse 			pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
8410cd96eb0SDavid Woodhouse 			pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
8427edcb9abSOleg Ryjkov 					      hostc | SMBHSTCFG_I2C_EN);
8430cd96eb0SDavid Woodhouse 		} else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
8440cd96eb0SDavid Woodhouse 			dev_err(&priv->pci_dev->dev,
8456342064cSJean Delvare 				"I2C block read is unsupported!\n");
84697140342SDavid Brownell 			return -EOPNOTSUPP;
8477edcb9abSOleg Ryjkov 		}
848a3989dc0SHeiner Kallweit 		break;
849a3989dc0SHeiner Kallweit 	case I2C_SMBUS_BLOCK_PROC_CALL:
850a3989dc0SHeiner Kallweit 		/* Needs to be flagged as write transaction */
851a3989dc0SHeiner Kallweit 		i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
852a3989dc0SHeiner Kallweit 		outb_p(hstcmd, SMBHSTCMD(priv));
853a3989dc0SHeiner Kallweit 		break;
8547edcb9abSOleg Ryjkov 	}
8557edcb9abSOleg Ryjkov 
856c074c39dSJean Delvare 	/* Experience has shown that the block buffer can only be used for
857c074c39dSJean Delvare 	   SMBus (not I2C) block transactions, even though the datasheet
858c074c39dSJean Delvare 	   doesn't mention this limitation. */
8591e1d6582SHeiner Kallweit 	if ((priv->features & FEATURE_BLOCK_BUFFER) &&
8601e1d6582SHeiner Kallweit 	    command != I2C_SMBUS_I2C_BLOCK_DATA)
8610cd96eb0SDavid Woodhouse 		result = i801_block_transaction_by_block(priv, data,
862315cd67cSAlexander Sverdlin 							 read_write,
863a6b8bb6aSHeiner Kallweit 							 command);
8647edcb9abSOleg Ryjkov 	else
8650cd96eb0SDavid Woodhouse 		result = i801_block_transaction_byte_by_byte(priv, data,
8660cd96eb0SDavid Woodhouse 							     read_write,
867a6b8bb6aSHeiner Kallweit 							     command);
8687edcb9abSOleg Ryjkov 
8696342064cSJean Delvare 	if (command == I2C_SMBUS_I2C_BLOCK_DATA
8706342064cSJean Delvare 	 && read_write == I2C_SMBUS_WRITE) {
8711da177e4SLinus Torvalds 		/* restore saved configuration register value */
8720cd96eb0SDavid Woodhouse 		pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
8731da177e4SLinus Torvalds 	}
8741da177e4SLinus Torvalds 	return result;
8751da177e4SLinus Torvalds }
8761da177e4SLinus Torvalds 
87797140342SDavid Brownell /* Return negative errno on error. */
i801_access(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)8781da177e4SLinus Torvalds static s32 i801_access(struct i2c_adapter *adap, u16 addr,
8791da177e4SLinus Torvalds 		       unsigned short flags, char read_write, u8 command,
8801da177e4SLinus Torvalds 		       int size, union i2c_smbus_data *data)
8811da177e4SLinus Torvalds {
882a3989dc0SHeiner Kallweit 	int hwpec, ret;
8830cd96eb0SDavid Woodhouse 	struct i801_priv *priv = i2c_get_adapdata(adap);
8841da177e4SLinus Torvalds 
885a7ae8195SMika Westerberg 	mutex_lock(&priv->acpi_lock);
886a7ae8195SMika Westerberg 	if (priv->acpi_reserved) {
887a7ae8195SMika Westerberg 		mutex_unlock(&priv->acpi_lock);
888a7ae8195SMika Westerberg 		return -EBUSY;
889a7ae8195SMika Westerberg 	}
890a7ae8195SMika Westerberg 
891a7401ca5SJarkko Nikula 	pm_runtime_get_sync(&priv->pci_dev->dev);
892a7401ca5SJarkko Nikula 
8931f760b87SHeiner Kallweit 	ret = i801_check_pre(priv);
8941f760b87SHeiner Kallweit 	if (ret)
8951f760b87SHeiner Kallweit 		goto out;
8961f760b87SHeiner Kallweit 
8970cd96eb0SDavid Woodhouse 	hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
898e8aac4a9SJean Delvare 		&& size != I2C_SMBUS_QUICK
899e8aac4a9SJean Delvare 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
9001da177e4SLinus Torvalds 
901ca8b9e32SOleg Ryjkov 	if (hwpec)	/* enable/disable hardware PEC */
9020cd96eb0SDavid Woodhouse 		outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
903ca8b9e32SOleg Ryjkov 	else
9040cd96eb0SDavid Woodhouse 		outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
9050cd96eb0SDavid Woodhouse 		       SMBAUXCTL(priv));
906e8aac4a9SJean Delvare 
907a3989dc0SHeiner Kallweit 	if (size == I2C_SMBUS_BLOCK_DATA ||
908a3989dc0SHeiner Kallweit 	    size == I2C_SMBUS_I2C_BLOCK_DATA ||
909a3989dc0SHeiner Kallweit 	    size == I2C_SMBUS_BLOCK_PROC_CALL)
910a3989dc0SHeiner Kallweit 		ret = i801_block_transaction(priv, data, addr, command, read_write, size);
9117edcb9abSOleg Ryjkov 	else
91224592482SHeiner Kallweit 		ret = i801_simple_transaction(priv, data, addr, command, read_write, size);
9131da177e4SLinus Torvalds 
914de461a26SHeiner Kallweit 	ret = i801_check_post(priv, ret);
915de461a26SHeiner Kallweit 
916c79cfbacSJean Delvare 	/* Some BIOSes don't like it when PEC is enabled at reboot or resume
91763fd342fSHeiner Kallweit 	 * time, so we forcibly disable it after every transaction.
91863fd342fSHeiner Kallweit 	 */
91963fd342fSHeiner Kallweit 	if (hwpec)
92063fd342fSHeiner Kallweit 		outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
9211f760b87SHeiner Kallweit out:
9224f7275fcSHeiner Kallweit 	/*
9234f7275fcSHeiner Kallweit 	 * Unlock the SMBus device for use by BIOS/ACPI,
9244f7275fcSHeiner Kallweit 	 * and clear status flags if not done already.
9254f7275fcSHeiner Kallweit 	 */
9264f7275fcSHeiner Kallweit 	outb_p(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
927065b6211SHeiner Kallweit 
928a7401ca5SJarkko Nikula 	pm_runtime_mark_last_busy(&priv->pci_dev->dev);
929a7401ca5SJarkko Nikula 	pm_runtime_put_autosuspend(&priv->pci_dev->dev);
930a7ae8195SMika Westerberg 	mutex_unlock(&priv->acpi_lock);
931a7401ca5SJarkko Nikula 	return ret;
9321da177e4SLinus Torvalds }
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds 
i801_func(struct i2c_adapter * adapter)9351da177e4SLinus Torvalds static u32 i801_func(struct i2c_adapter *adapter)
9361da177e4SLinus Torvalds {
9370cd96eb0SDavid Woodhouse 	struct i801_priv *priv = i2c_get_adapdata(adapter);
9380cd96eb0SDavid Woodhouse 
9391da177e4SLinus Torvalds 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
9401da177e4SLinus Torvalds 	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
94155b6f82eSJean Delvare 	       I2C_FUNC_SMBUS_PROC_CALL |
942369f6f4aSJean Delvare 	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
9430cd96eb0SDavid Woodhouse 	       ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
944315cd67cSAlexander Sverdlin 	       ((priv->features & FEATURE_BLOCK_PROC) ?
945315cd67cSAlexander Sverdlin 		I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) |
9460cd96eb0SDavid Woodhouse 	       ((priv->features & FEATURE_I2C_BLOCK_READ) ?
9477b0ed334SBenjamin Tissoires 		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) |
9487b0ed334SBenjamin Tissoires 	       ((priv->features & FEATURE_HOST_NOTIFY) ?
9497b0ed334SBenjamin Tissoires 		I2C_FUNC_SMBUS_HOST_NOTIFY : 0);
9507b0ed334SBenjamin Tissoires }
9517b0ed334SBenjamin Tissoires 
i801_enable_host_notify(struct i2c_adapter * adapter)9524d5538f5SBenjamin Tissoires static void i801_enable_host_notify(struct i2c_adapter *adapter)
9537b0ed334SBenjamin Tissoires {
9547b0ed334SBenjamin Tissoires 	struct i801_priv *priv = i2c_get_adapdata(adapter);
9557b0ed334SBenjamin Tissoires 
9567b0ed334SBenjamin Tissoires 	if (!(priv->features & FEATURE_HOST_NOTIFY))
9574d5538f5SBenjamin Tissoires 		return;
9587b0ed334SBenjamin Tissoires 
95903a976c9SJarkko Nikula 	/*
96003a976c9SJarkko Nikula 	 * Enable host notify interrupt and block the generation of interrupt
96103a976c9SJarkko Nikula 	 * from the SMB_ALERT signal because the driver does not support
96203a976c9SJarkko Nikula 	 * SMBus Alert.
96303a976c9SJarkko Nikula 	 */
96403a976c9SJarkko Nikula 	outb_p(SMBSLVCMD_HST_NTFY_INTREN | SMBSLVCMD_SMBALERT_DISABLE |
96503a976c9SJarkko Nikula 	       priv->original_slvcmd, SMBSLVCMD(priv));
96622e94bd6SBenjamin Tissoires 
9677b0ed334SBenjamin Tissoires 	/* clear Host Notify bit to allow a new notification */
9687b0ed334SBenjamin Tissoires 	outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
9691da177e4SLinus Torvalds }
9701da177e4SLinus Torvalds 
i801_disable_host_notify(struct i801_priv * priv)97122e94bd6SBenjamin Tissoires static void i801_disable_host_notify(struct i801_priv *priv)
97222e94bd6SBenjamin Tissoires {
97322e94bd6SBenjamin Tissoires 	if (!(priv->features & FEATURE_HOST_NOTIFY))
97422e94bd6SBenjamin Tissoires 		return;
97522e94bd6SBenjamin Tissoires 
97622e94bd6SBenjamin Tissoires 	outb_p(priv->original_slvcmd, SMBSLVCMD(priv));
97722e94bd6SBenjamin Tissoires }
97822e94bd6SBenjamin Tissoires 
9798f9082c5SJean Delvare static const struct i2c_algorithm smbus_algorithm = {
9801da177e4SLinus Torvalds 	.smbus_xfer	= i801_access,
9811da177e4SLinus Torvalds 	.functionality	= i801_func,
9821da177e4SLinus Torvalds };
9831da177e4SLinus Torvalds 
98441acd4b0SHeiner Kallweit #define FEATURES_ICH5	(FEATURE_BLOCK_PROC | FEATURE_I2C_BLOCK_READ	| \
98541acd4b0SHeiner Kallweit 			 FEATURE_IRQ | FEATURE_SMBUS_PEC		| \
98641acd4b0SHeiner Kallweit 			 FEATURE_BLOCK_BUFFER | FEATURE_HOST_NOTIFY)
98741acd4b0SHeiner Kallweit #define FEATURES_ICH4	(FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER | \
98841acd4b0SHeiner Kallweit 			 FEATURE_HOST_NOTIFY)
98941acd4b0SHeiner Kallweit 
990392debf1SJingoo Han static const struct pci_device_id i801_ids[] = {
99141acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, 82801AA_3,			0)				 },
99241acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, 82801AB_3,			0)				 },
99341acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, 82801BA_2,			0)				 },
99441acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, 82801CA_3,			FEATURE_HOST_NOTIFY)		 },
99541acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, 82801DB_3,			FEATURES_ICH4)			 },
99641acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, 82801EB_3,			FEATURES_ICH5)			 },
99741acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ESB_4,				FEATURES_ICH5)			 },
99841acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ICH6_16,			FEATURES_ICH5)			 },
99941acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ICH7_17,			FEATURES_ICH5)			 },
100041acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ESB2_17,			FEATURES_ICH5)			 },
100141acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ICH8_5,			FEATURES_ICH5)			 },
100241acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ICH9_6,			FEATURES_ICH5)			 },
100341acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, EP80579_1,			FEATURES_ICH5)			 },
100441acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ICH10_4,			FEATURES_ICH5)			 },
100541acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ICH10_5,			FEATURES_ICH5)			 },
100641acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, 5_3400_SERIES_SMBUS,		FEATURES_ICH5)			 },
100741acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, COUGARPOINT_SMBUS,		FEATURES_ICH5)			 },
100841acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS,		FEATURES_ICH5)			 },
100941acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF0,		FEATURES_ICH5 | FEATURE_IDF)	 },
101041acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF1,		FEATURES_ICH5 | FEATURE_IDF)	 },
101141acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF2,		FEATURES_ICH5 | FEATURE_IDF)	 },
101241acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, DH89XXCC_SMBUS,		FEATURES_ICH5)			 },
101341acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, PANTHERPOINT_SMBUS,		FEATURES_ICH5)			 },
101441acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, LYNXPOINT_SMBUS,		FEATURES_ICH5)			 },
101541acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, LYNXPOINT_LP_SMBUS,		FEATURES_ICH5)			 },
101641acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, AVOTON_SMBUS,			FEATURES_ICH5)			 },
101741acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS,		FEATURES_ICH5)			 },
101841acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS0,		FEATURES_ICH5 | FEATURE_IDF)	 },
101941acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS1,		FEATURES_ICH5 | FEATURE_IDF)	 },
102041acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS2,		FEATURES_ICH5 | FEATURE_IDF)	 },
102141acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, COLETOCREEK_SMBUS,		FEATURES_ICH5)			 },
102241acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, GEMINILAKE_SMBUS,		FEATURES_ICH5)			 },
102341acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, WILDCATPOINT_SMBUS,		FEATURES_ICH5)			 },
102441acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, WILDCATPOINT_LP_SMBUS,		FEATURES_ICH5)			 },
102541acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, BAYTRAIL_SMBUS,		FEATURES_ICH5)			 },
102641acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, BRASWELL_SMBUS,		FEATURES_ICH5)			 },
102741acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, SUNRISEPOINT_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_SPT) },
102841acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, SUNRISEPOINT_LP_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_SPT) },
102941acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, CDF_SMBUS,			FEATURES_ICH5 | FEATURE_TCO_CNL) },
103041acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, DNV_SMBUS,			FEATURES_ICH5 | FEATURE_TCO_SPT) },
103141acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, EBG_SMBUS,			FEATURES_ICH5 | FEATURE_TCO_CNL) },
103241acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, BROXTON_SMBUS,			FEATURES_ICH5)			 },
103341acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, LEWISBURG_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_SPT) },
103441acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, LEWISBURG_SSKU_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_SPT) },
103541acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, KABYLAKE_PCH_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_SPT) },
103641acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, CANNONLAKE_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
103741acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, CANNONLAKE_LP_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
103841acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ICELAKE_LP_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
103941acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ICELAKE_N_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104041acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, COMETLAKE_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104141acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, COMETLAKE_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104241acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, COMETLAKE_V_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_SPT) },
104341acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ELKHART_LAKE_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104441acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, TIGERLAKE_LP_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104541acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, TIGERLAKE_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104641acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, JASPER_LAKE_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104741acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ALDER_LAKE_S_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104841acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ALDER_LAKE_P_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
104941acd4b0SHeiner Kallweit 	{ PCI_DEVICE_DATA(INTEL, ALDER_LAKE_M_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
10509c02d401SJarkko Nikula 	{ PCI_DEVICE_DATA(INTEL, RAPTOR_LAKE_S_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
105124fff66fSJarkko Nikula 	{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_P_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
1052e755ef00SJarkko Nikula 	{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_SOC_S_SMBUS,	FEATURES_ICH5 | FEATURE_TCO_CNL) },
1053bcfc2ab7SJarkko Nikula 	{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS,	FEATURES_ICH5 | FEATURE_TCO_CNL) },
1054c0015277SJarkko Nikula 	{ PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
1055f38ca98bSJarkko Nikula 	{ PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
1056*6e6a3479SJarkko Nikula 	{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
1057*6e6a3479SJarkko Nikula 	{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
10581da177e4SLinus Torvalds 	{ 0, }
10591da177e4SLinus Torvalds };
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, i801_ids);
10621da177e4SLinus Torvalds 
10638eacfcebSJean Delvare #if defined CONFIG_X86 && defined CONFIG_DMI
1064e0cd887aSHeiner Kallweit static unsigned char apanel_addr __ro_after_init;
10651561bfe5SJean Delvare 
10661561bfe5SJean Delvare /* Scan the system ROM for the signature "FJKEYINF" */
bios_signature(const void __iomem * bios)10671561bfe5SJean Delvare static __init const void __iomem *bios_signature(const void __iomem *bios)
10681561bfe5SJean Delvare {
10691561bfe5SJean Delvare 	ssize_t offset;
10701561bfe5SJean Delvare 	const unsigned char signature[] = "FJKEYINF";
10711561bfe5SJean Delvare 
10721561bfe5SJean Delvare 	for (offset = 0; offset < 0x10000; offset += 0x10) {
10731561bfe5SJean Delvare 		if (check_signature(bios + offset, signature,
10741561bfe5SJean Delvare 				    sizeof(signature)-1))
10751561bfe5SJean Delvare 			return bios + offset;
10761561bfe5SJean Delvare 	}
10771561bfe5SJean Delvare 	return NULL;
10781561bfe5SJean Delvare }
10791561bfe5SJean Delvare 
input_apanel_init(void)10801561bfe5SJean Delvare static void __init input_apanel_init(void)
10811561bfe5SJean Delvare {
10821561bfe5SJean Delvare 	void __iomem *bios;
10831561bfe5SJean Delvare 	const void __iomem *p;
10841561bfe5SJean Delvare 
10851561bfe5SJean Delvare 	bios = ioremap(0xF0000, 0x10000); /* Can't fail */
10861561bfe5SJean Delvare 	p = bios_signature(bios);
10871561bfe5SJean Delvare 	if (p) {
10881561bfe5SJean Delvare 		/* just use the first address */
10891561bfe5SJean Delvare 		apanel_addr = readb(p + 8 + 3) >> 1;
10901561bfe5SJean Delvare 	}
10911561bfe5SJean Delvare 	iounmap(bios);
10921561bfe5SJean Delvare }
10931561bfe5SJean Delvare 
1094fa5bfab7SHans de Goede struct dmi_onboard_device_info {
1095fa5bfab7SHans de Goede 	const char *name;
1096fa5bfab7SHans de Goede 	u8 type;
1097fa5bfab7SHans de Goede 	unsigned short i2c_addr;
1098fa5bfab7SHans de Goede 	const char *i2c_type;
1099fa5bfab7SHans de Goede };
1100fa5bfab7SHans de Goede 
11010b255e92SBill Pemberton static const struct dmi_onboard_device_info dmi_devices[] = {
1102fa5bfab7SHans de Goede 	{ "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" },
1103fa5bfab7SHans de Goede 	{ "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" },
1104fa5bfab7SHans de Goede 	{ "Hades",  DMI_DEV_TYPE_OTHER, 0x73, "fschds" },
1105fa5bfab7SHans de Goede };
1106fa5bfab7SHans de Goede 
dmi_check_onboard_device(u8 type,const char * name,struct i2c_adapter * adap)11070b255e92SBill Pemberton static void dmi_check_onboard_device(u8 type, const char *name,
1108fa5bfab7SHans de Goede 				     struct i2c_adapter *adap)
1109fa5bfab7SHans de Goede {
1110fa5bfab7SHans de Goede 	int i;
1111fa5bfab7SHans de Goede 	struct i2c_board_info info;
1112fa5bfab7SHans de Goede 
1113fa5bfab7SHans de Goede 	for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) {
1114fa5bfab7SHans de Goede 		/* & ~0x80, ignore enabled/disabled bit */
1115fa5bfab7SHans de Goede 		if ((type & ~0x80) != dmi_devices[i].type)
1116fa5bfab7SHans de Goede 			continue;
1117faabd47fSJean Delvare 		if (strcasecmp(name, dmi_devices[i].name))
1118fa5bfab7SHans de Goede 			continue;
1119fa5bfab7SHans de Goede 
1120fa5bfab7SHans de Goede 		memset(&info, 0, sizeof(struct i2c_board_info));
1121fa5bfab7SHans de Goede 		info.addr = dmi_devices[i].i2c_addr;
1122ea1558ceSWolfram Sang 		strscpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
112341d06630SWolfram Sang 		i2c_new_client_device(adap, &info);
1124fa5bfab7SHans de Goede 		break;
1125fa5bfab7SHans de Goede 	}
1126fa5bfab7SHans de Goede }
1127fa5bfab7SHans de Goede 
1128fa5bfab7SHans de Goede /* We use our own function to check for onboard devices instead of
1129fa5bfab7SHans de Goede    dmi_find_device() as some buggy BIOS's have the devices we are interested
1130fa5bfab7SHans de Goede    in marked as disabled */
dmi_check_onboard_devices(const struct dmi_header * dm,void * adap)11310b255e92SBill Pemberton static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap)
1132fa5bfab7SHans de Goede {
1133fa5bfab7SHans de Goede 	int i, count;
1134fa5bfab7SHans de Goede 
1135fa5bfab7SHans de Goede 	if (dm->type != 10)
1136fa5bfab7SHans de Goede 		return;
1137fa5bfab7SHans de Goede 
1138fa5bfab7SHans de Goede 	count = (dm->length - sizeof(struct dmi_header)) / 2;
1139fa5bfab7SHans de Goede 	for (i = 0; i < count; i++) {
1140fa5bfab7SHans de Goede 		const u8 *d = (char *)(dm + 1) + (i * 2);
1141fa5bfab7SHans de Goede 		const char *name = ((char *) dm) + dm->length;
1142fa5bfab7SHans de Goede 		u8 type = d[0];
1143fa5bfab7SHans de Goede 		u8 s = d[1];
1144fa5bfab7SHans de Goede 
1145fa5bfab7SHans de Goede 		if (!s)
1146fa5bfab7SHans de Goede 			continue;
1147fa5bfab7SHans de Goede 		s--;
1148fa5bfab7SHans de Goede 		while (s > 0 && name[0]) {
1149fa5bfab7SHans de Goede 			name += strlen(name) + 1;
1150fa5bfab7SHans de Goede 			s--;
1151fa5bfab7SHans de Goede 		}
1152fa5bfab7SHans de Goede 		if (name[0] == 0) /* Bogus string reference */
1153fa5bfab7SHans de Goede 			continue;
1154fa5bfab7SHans de Goede 
1155fa5bfab7SHans de Goede 		dmi_check_onboard_device(type, name, adap);
1156fa5bfab7SHans de Goede 	}
1157fa5bfab7SHans de Goede }
1158fa5bfab7SHans de Goede 
115919b07cb4SPali Rohár /* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */
116019b07cb4SPali Rohár static const char *const acpi_smo8800_ids[] = {
116119b07cb4SPali Rohár 	"SMO8800",
116219b07cb4SPali Rohár 	"SMO8801",
116319b07cb4SPali Rohár 	"SMO8810",
116419b07cb4SPali Rohár 	"SMO8811",
116519b07cb4SPali Rohár 	"SMO8820",
116619b07cb4SPali Rohár 	"SMO8821",
116719b07cb4SPali Rohár 	"SMO8830",
116819b07cb4SPali Rohár 	"SMO8831",
116919b07cb4SPali Rohár };
117019b07cb4SPali Rohár 
check_acpi_smo88xx_device(acpi_handle obj_handle,u32 nesting_level,void * context,void ** return_value)117119b07cb4SPali Rohár static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle,
117219b07cb4SPali Rohár 					     u32 nesting_level,
117319b07cb4SPali Rohár 					     void *context,
117419b07cb4SPali Rohár 					     void **return_value)
117519b07cb4SPali Rohár {
117619b07cb4SPali Rohár 	struct acpi_device_info *info;
117719b07cb4SPali Rohár 	acpi_status status;
117819b07cb4SPali Rohár 	char *hid;
117919b07cb4SPali Rohár 	int i;
118019b07cb4SPali Rohár 
118119b07cb4SPali Rohár 	status = acpi_get_object_info(obj_handle, &info);
118201641b26SAndy Shevchenko 	if (ACPI_FAILURE(status))
118319b07cb4SPali Rohár 		return AE_OK;
118419b07cb4SPali Rohár 
118501641b26SAndy Shevchenko 	if (!(info->valid & ACPI_VALID_HID))
118601641b26SAndy Shevchenko 		goto smo88xx_not_found;
118701641b26SAndy Shevchenko 
118819b07cb4SPali Rohár 	hid = info->hardware_id.string;
118919b07cb4SPali Rohár 	if (!hid)
119001641b26SAndy Shevchenko 		goto smo88xx_not_found;
119119b07cb4SPali Rohár 
1192af668d65SAndy Shevchenko 	i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid);
1193af668d65SAndy Shevchenko 	if (i < 0)
119401641b26SAndy Shevchenko 		goto smo88xx_not_found;
119501641b26SAndy Shevchenko 
119601641b26SAndy Shevchenko 	kfree(info);
1197af668d65SAndy Shevchenko 
11982b3db4dbSHeiner Kallweit 	*return_value = NULL;
119919b07cb4SPali Rohár 	return AE_CTRL_TERMINATE;
120001641b26SAndy Shevchenko 
120101641b26SAndy Shevchenko smo88xx_not_found:
120201641b26SAndy Shevchenko 	kfree(info);
120301641b26SAndy Shevchenko 	return AE_OK;
120419b07cb4SPali Rohár }
120519b07cb4SPali Rohár 
is_dell_system_with_lis3lv02d(void)120619b07cb4SPali Rohár static bool is_dell_system_with_lis3lv02d(void)
120719b07cb4SPali Rohár {
12082b3db4dbSHeiner Kallweit 	void *err = ERR_PTR(-ENOENT);
120919b07cb4SPali Rohár 
12102b3db4dbSHeiner Kallweit 	if (!dmi_match(DMI_SYS_VENDOR, "Dell Inc."))
121119b07cb4SPali Rohár 		return false;
121219b07cb4SPali Rohár 
121319b07cb4SPali Rohár 	/*
121419b07cb4SPali Rohár 	 * Check that ACPI device SMO88xx is present and is functioning.
121519b07cb4SPali Rohár 	 * Function acpi_get_devices() already filters all ACPI devices
121619b07cb4SPali Rohár 	 * which are not present or are not functioning.
121719b07cb4SPali Rohár 	 * ACPI device SMO88xx represents our ST microelectronics lis3lv02d
121819b07cb4SPali Rohár 	 * accelerometer but unfortunately ACPI does not provide any other
121919b07cb4SPali Rohár 	 * information (like I2C address).
122019b07cb4SPali Rohár 	 */
12212b3db4dbSHeiner Kallweit 	acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, &err);
122219b07cb4SPali Rohár 
12232b3db4dbSHeiner Kallweit 	return !IS_ERR(err);
122419b07cb4SPali Rohár }
122519b07cb4SPali Rohár 
122619b07cb4SPali Rohár /*
122719b07cb4SPali Rohár  * Accelerometer's I2C address is not specified in DMI nor ACPI,
122819b07cb4SPali Rohár  * so it is needed to define mapping table based on DMI product names.
122919b07cb4SPali Rohár  */
123019b07cb4SPali Rohár static const struct {
123119b07cb4SPali Rohár 	const char *dmi_product_name;
123219b07cb4SPali Rohár 	unsigned short i2c_addr;
123319b07cb4SPali Rohár } dell_lis3lv02d_devices[] = {
123419b07cb4SPali Rohár 	/*
123519b07cb4SPali Rohár 	 * Dell platform team told us that these Latitude devices have
123619b07cb4SPali Rohár 	 * ST microelectronics accelerometer at I2C address 0x29.
123719b07cb4SPali Rohár 	 */
123819b07cb4SPali Rohár 	{ "Latitude E5250",     0x29 },
123919b07cb4SPali Rohár 	{ "Latitude E5450",     0x29 },
124019b07cb4SPali Rohár 	{ "Latitude E5550",     0x29 },
124119b07cb4SPali Rohár 	{ "Latitude E6440",     0x29 },
124219b07cb4SPali Rohár 	{ "Latitude E6440 ATG", 0x29 },
124319b07cb4SPali Rohár 	{ "Latitude E6540",     0x29 },
124419b07cb4SPali Rohár 	/*
124519b07cb4SPali Rohár 	 * Additional individual entries were added after verification.
124619b07cb4SPali Rohár 	 */
124762df579aSJeffrey Lin 	{ "Latitude 5480",      0x29 },
124819b07cb4SPali Rohár 	{ "Vostro V131",        0x1d },
1249d6643d72SNam Cao 	{ "Vostro 5568",        0x29 },
125019b07cb4SPali Rohár };
125119b07cb4SPali Rohár 
register_dell_lis3lv02d_i2c_device(struct i801_priv * priv)125219b07cb4SPali Rohár static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
125319b07cb4SPali Rohár {
125419b07cb4SPali Rohár 	struct i2c_board_info info;
125519b07cb4SPali Rohár 	const char *dmi_product_name;
125619b07cb4SPali Rohár 	int i;
125719b07cb4SPali Rohár 
125819b07cb4SPali Rohár 	dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
125919b07cb4SPali Rohár 	for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) {
126019b07cb4SPali Rohár 		if (strcmp(dmi_product_name,
126119b07cb4SPali Rohár 			   dell_lis3lv02d_devices[i].dmi_product_name) == 0)
126219b07cb4SPali Rohár 			break;
126319b07cb4SPali Rohár 	}
126419b07cb4SPali Rohár 
126519b07cb4SPali Rohár 	if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) {
126619b07cb4SPali Rohár 		dev_warn(&priv->pci_dev->dev,
126719b07cb4SPali Rohár 			 "Accelerometer lis3lv02d is present on SMBus but its"
126819b07cb4SPali Rohár 			 " address is unknown, skipping registration\n");
126919b07cb4SPali Rohár 		return;
127019b07cb4SPali Rohár 	}
127119b07cb4SPali Rohár 
127219b07cb4SPali Rohár 	memset(&info, 0, sizeof(struct i2c_board_info));
127319b07cb4SPali Rohár 	info.addr = dell_lis3lv02d_devices[i].i2c_addr;
1274ea1558ceSWolfram Sang 	strscpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
127541d06630SWolfram Sang 	i2c_new_client_device(&priv->adapter, &info);
127619b07cb4SPali Rohár }
127719b07cb4SPali Rohár 
1278e7198fbfSJean Delvare /* Register optional slaves */
i801_probe_optional_slaves(struct i801_priv * priv)12790b255e92SBill Pemberton static void i801_probe_optional_slaves(struct i801_priv *priv)
1280e7198fbfSJean Delvare {
1281e7198fbfSJean Delvare 	/* Only register slaves on main SMBus channel */
1282e7198fbfSJean Delvare 	if (priv->features & FEATURE_IDF)
1283e7198fbfSJean Delvare 		return;
1284e7198fbfSJean Delvare 
1285e7198fbfSJean Delvare 	if (apanel_addr) {
12868d83973eSHeiner Kallweit 		struct i2c_board_info info = {
12878d83973eSHeiner Kallweit 			.addr = apanel_addr,
12888d83973eSHeiner Kallweit 			.type = "fujitsu_apanel",
12898d83973eSHeiner Kallweit 		};
1290e7198fbfSJean Delvare 
129141d06630SWolfram Sang 		i2c_new_client_device(&priv->adapter, &info);
1292e7198fbfSJean Delvare 	}
12938eacfcebSJean Delvare 
1294e7198fbfSJean Delvare 	if (dmi_name_in_vendors("FUJITSU"))
1295e7198fbfSJean Delvare 		dmi_walk(dmi_check_onboard_devices, &priv->adapter);
129619b07cb4SPali Rohár 
129719b07cb4SPali Rohár 	if (is_dell_system_with_lis3lv02d())
129819b07cb4SPali Rohár 		register_dell_lis3lv02d_i2c_device(priv);
129901590f36SJean Delvare 
130001590f36SJean Delvare 	/* Instantiate SPD EEPROMs unless the SMBus is multiplexed */
130101590f36SJean Delvare #if IS_ENABLED(CONFIG_I2C_MUX_GPIO)
130201590f36SJean Delvare 	if (!priv->mux_drvdata)
130301590f36SJean Delvare #endif
130401590f36SJean Delvare 		i2c_register_spd(&priv->adapter);
1305e7198fbfSJean Delvare }
13068eacfcebSJean Delvare #else
input_apanel_init(void)13078eacfcebSJean Delvare static void __init input_apanel_init(void) {}
i801_probe_optional_slaves(struct i801_priv * priv)13080b255e92SBill Pemberton static void i801_probe_optional_slaves(struct i801_priv *priv) {}
13098eacfcebSJean Delvare #endif	/* CONFIG_X86 && CONFIG_DMI */
1310e7198fbfSJean Delvare 
1311175c7080SJavier Martinez Canillas #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
13123ad7ea18SJean Delvare static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
13133ad7ea18SJean Delvare 	.gpio_chip = "gpio_ich",
13143ad7ea18SJean Delvare 	.values = { 0x02, 0x03 },
13153ad7ea18SJean Delvare 	.n_values = 2,
13163ad7ea18SJean Delvare 	.classes = { I2C_CLASS_SPD, I2C_CLASS_SPD },
13173ad7ea18SJean Delvare 	.gpios = { 52, 53 },
13183ad7ea18SJean Delvare 	.n_gpios = 2,
13193ad7ea18SJean Delvare };
13203ad7ea18SJean Delvare 
13213ad7ea18SJean Delvare static struct i801_mux_config i801_mux_config_asus_z8_d18 = {
13223ad7ea18SJean Delvare 	.gpio_chip = "gpio_ich",
13233ad7ea18SJean Delvare 	.values = { 0x02, 0x03, 0x01 },
13243ad7ea18SJean Delvare 	.n_values = 3,
13253ad7ea18SJean Delvare 	.classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD },
13263ad7ea18SJean Delvare 	.gpios = { 52, 53 },
13273ad7ea18SJean Delvare 	.n_gpios = 2,
13283ad7ea18SJean Delvare };
13293ad7ea18SJean Delvare 
13300b255e92SBill Pemberton static const struct dmi_system_id mux_dmi_table[] = {
13313ad7ea18SJean Delvare 	{
13323ad7ea18SJean Delvare 		.matches = {
13333ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13343ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"),
13353ad7ea18SJean Delvare 		},
13363ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d12,
13373ad7ea18SJean Delvare 	},
13383ad7ea18SJean Delvare 	{
13393ad7ea18SJean Delvare 		.matches = {
13403ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13413ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"),
13423ad7ea18SJean Delvare 		},
13433ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d12,
13443ad7ea18SJean Delvare 	},
13453ad7ea18SJean Delvare 	{
13463ad7ea18SJean Delvare 		.matches = {
13473ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13483ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"),
13493ad7ea18SJean Delvare 		},
13503ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d12,
13513ad7ea18SJean Delvare 	},
13523ad7ea18SJean Delvare 	{
13533ad7ea18SJean Delvare 		.matches = {
13543ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13553ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"),
13563ad7ea18SJean Delvare 		},
13573ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d12,
13583ad7ea18SJean Delvare 	},
13593ad7ea18SJean Delvare 	{
13603ad7ea18SJean Delvare 		.matches = {
13613ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13623ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"),
13633ad7ea18SJean Delvare 		},
13643ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d12,
13653ad7ea18SJean Delvare 	},
13663ad7ea18SJean Delvare 	{
13673ad7ea18SJean Delvare 		.matches = {
13683ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13693ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"),
13703ad7ea18SJean Delvare 		},
13713ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d12,
13723ad7ea18SJean Delvare 	},
13733ad7ea18SJean Delvare 	{
13743ad7ea18SJean Delvare 		.matches = {
13753ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13763ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"),
13773ad7ea18SJean Delvare 		},
13783ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d18,
13793ad7ea18SJean Delvare 	},
13803ad7ea18SJean Delvare 	{
13813ad7ea18SJean Delvare 		.matches = {
13823ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13833ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"),
13843ad7ea18SJean Delvare 		},
13853ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d18,
13863ad7ea18SJean Delvare 	},
13873ad7ea18SJean Delvare 	{
13883ad7ea18SJean Delvare 		.matches = {
13893ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
13903ad7ea18SJean Delvare 			DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"),
13913ad7ea18SJean Delvare 		},
13923ad7ea18SJean Delvare 		.driver_data = &i801_mux_config_asus_z8_d12,
13933ad7ea18SJean Delvare 	},
13943ad7ea18SJean Delvare 	{ }
13953ad7ea18SJean Delvare };
13963ad7ea18SJean Delvare 
13973ad7ea18SJean Delvare /* Setup multiplexing if needed */
i801_add_mux(struct i801_priv * priv)13984c591063SHeiner Kallweit static void i801_add_mux(struct i801_priv *priv)
13993ad7ea18SJean Delvare {
14003ad7ea18SJean Delvare 	struct device *dev = &priv->adapter.dev;
14013ad7ea18SJean Delvare 	const struct i801_mux_config *mux_config;
14023ad7ea18SJean Delvare 	struct i2c_mux_gpio_platform_data gpio_data;
1403d308dfbfSLinus Walleij 	struct gpiod_lookup_table *lookup;
14045581b416SAndy Shevchenko 	int i;
14053ad7ea18SJean Delvare 
14063ad7ea18SJean Delvare 	if (!priv->mux_drvdata)
14074c591063SHeiner Kallweit 		return;
14083ad7ea18SJean Delvare 	mux_config = priv->mux_drvdata;
14093ad7ea18SJean Delvare 
14103ad7ea18SJean Delvare 	/* Prepare the platform data */
14113ad7ea18SJean Delvare 	memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data));
14123ad7ea18SJean Delvare 	gpio_data.parent = priv->adapter.nr;
14133ad7ea18SJean Delvare 	gpio_data.values = mux_config->values;
14143ad7ea18SJean Delvare 	gpio_data.n_values = mux_config->n_values;
14153ad7ea18SJean Delvare 	gpio_data.classes = mux_config->classes;
14163ad7ea18SJean Delvare 	gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
14173ad7ea18SJean Delvare 
1418d308dfbfSLinus Walleij 	/* Register GPIO descriptor lookup table */
1419d308dfbfSLinus Walleij 	lookup = devm_kzalloc(dev,
14200b3ea2a0SHans de Goede 			      struct_size(lookup, table, mux_config->n_gpios + 1),
1421d308dfbfSLinus Walleij 			      GFP_KERNEL);
1422d308dfbfSLinus Walleij 	if (!lookup)
14234c591063SHeiner Kallweit 		return;
1424d308dfbfSLinus Walleij 	lookup->dev_id = "i2c-mux-gpio";
14254c591063SHeiner Kallweit 	for (i = 0; i < mux_config->n_gpios; i++)
14264c591063SHeiner Kallweit 		lookup->table[i] = GPIO_LOOKUP(mux_config->gpio_chip,
1427be1b92c1SGeert Uytterhoeven 					       mux_config->gpios[i], "mux", 0);
1428d308dfbfSLinus Walleij 	gpiod_add_lookup_table(lookup);
1429d308dfbfSLinus Walleij 
1430d308dfbfSLinus Walleij 	/*
1431d308dfbfSLinus Walleij 	 * Register the mux device, we use PLATFORM_DEVID_NONE here
1432d308dfbfSLinus Walleij 	 * because since we are referring to the GPIO chip by name we are
1433d308dfbfSLinus Walleij 	 * anyways in deep trouble if there is more than one of these
1434d308dfbfSLinus Walleij 	 * devices, and there should likely only be one platform controller
1435d308dfbfSLinus Walleij 	 * hub.
1436d308dfbfSLinus Walleij 	 */
14373ad7ea18SJean Delvare 	priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
1438d308dfbfSLinus Walleij 				PLATFORM_DEVID_NONE, &gpio_data,
14393ad7ea18SJean Delvare 				sizeof(struct i2c_mux_gpio_platform_data));
14403ad7ea18SJean Delvare 	if (IS_ERR(priv->mux_pdev)) {
1441d308dfbfSLinus Walleij 		gpiod_remove_lookup_table(lookup);
1442d017ec50SHeiner Kallweit 		devm_kfree(dev, lookup);
14433ad7ea18SJean Delvare 		dev_err(dev, "Failed to register i2c-mux-gpio device\n");
1444d017ec50SHeiner Kallweit 	} else {
1445d017ec50SHeiner Kallweit 		priv->lookup = lookup;
14463ad7ea18SJean Delvare 	}
14473ad7ea18SJean Delvare }
14483ad7ea18SJean Delvare 
i801_del_mux(struct i801_priv * priv)14490b255e92SBill Pemberton static void i801_del_mux(struct i801_priv *priv)
14503ad7ea18SJean Delvare {
14513ad7ea18SJean Delvare 	platform_device_unregister(priv->mux_pdev);
1452d308dfbfSLinus Walleij 	gpiod_remove_lookup_table(priv->lookup);
14533ad7ea18SJean Delvare }
14543ad7ea18SJean Delvare 
i801_get_adapter_class(struct i801_priv * priv)14550b255e92SBill Pemberton static unsigned int i801_get_adapter_class(struct i801_priv *priv)
14563ad7ea18SJean Delvare {
14573ad7ea18SJean Delvare 	const struct dmi_system_id *id;
14583ad7ea18SJean Delvare 	const struct i801_mux_config *mux_config;
14593ad7ea18SJean Delvare 	unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
14603ad7ea18SJean Delvare 	int i;
14613ad7ea18SJean Delvare 
14623ad7ea18SJean Delvare 	id = dmi_first_match(mux_dmi_table);
14633ad7ea18SJean Delvare 	if (id) {
146428901f57SJean Delvare 		/* Remove branch classes from trunk */
14653ad7ea18SJean Delvare 		mux_config = id->driver_data;
14663ad7ea18SJean Delvare 		for (i = 0; i < mux_config->n_values; i++)
14673ad7ea18SJean Delvare 			class &= ~mux_config->classes[i];
14683ad7ea18SJean Delvare 
14693ad7ea18SJean Delvare 		/* Remember for later */
14703ad7ea18SJean Delvare 		priv->mux_drvdata = mux_config;
14713ad7ea18SJean Delvare 	}
14723ad7ea18SJean Delvare 
14733ad7ea18SJean Delvare 	return class;
14743ad7ea18SJean Delvare }
14753ad7ea18SJean Delvare #else
i801_add_mux(struct i801_priv * priv)14764c591063SHeiner Kallweit static inline void i801_add_mux(struct i801_priv *priv) { }
i801_del_mux(struct i801_priv * priv)14773ad7ea18SJean Delvare static inline void i801_del_mux(struct i801_priv *priv) { }
14783ad7ea18SJean Delvare 
i801_get_adapter_class(struct i801_priv * priv)14793ad7ea18SJean Delvare static inline unsigned int i801_get_adapter_class(struct i801_priv *priv)
14803ad7ea18SJean Delvare {
14813ad7ea18SJean Delvare 	return I2C_CLASS_HWMON | I2C_CLASS_SPD;
14823ad7ea18SJean Delvare }
14833ad7ea18SJean Delvare #endif
14843ad7ea18SJean Delvare 
1485b84398d6SMika Westerberg static struct platform_device *
i801_add_tco_spt(struct i801_priv * priv,struct pci_dev * pci_dev,struct resource * tco_res)1486b84398d6SMika Westerberg i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
1487b84398d6SMika Westerberg 		 struct resource *tco_res)
148894246930SMika Westerberg {
14892352b05fSHeiner Kallweit 	static const struct itco_wdt_platform_data pldata = {
14902352b05fSHeiner Kallweit 		.name = "Intel PCH",
14912352b05fSHeiner Kallweit 		.version = 4,
14922352b05fSHeiner Kallweit 	};
1493b84398d6SMika Westerberg 	struct resource *res;
14945c7b9167SAndy Shevchenko 	int ret;
149594246930SMika Westerberg 
149694246930SMika Westerberg 	/*
149794246930SMika Westerberg 	 * We must access the NO_REBOOT bit over the Primary to Sideband
14985c7b9167SAndy Shevchenko 	 * (P2SB) bridge.
149994246930SMika Westerberg 	 */
150094246930SMika Westerberg 
150104bbb97dSMika Westerberg 	res = &tco_res[1];
15025c7b9167SAndy Shevchenko 	ret = p2sb_bar(pci_dev->bus, 0, res);
15035c7b9167SAndy Shevchenko 	if (ret)
15045c7b9167SAndy Shevchenko 		return ERR_PTR(ret);
15055c7b9167SAndy Shevchenko 
1506851a1511SFelipe Balbi 	if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS)
15075c7b9167SAndy Shevchenko 		res->start += SBREG_SMBCTRL_DNV;
1508851a1511SFelipe Balbi 	else
15095c7b9167SAndy Shevchenko 		res->start += SBREG_SMBCTRL;
1510851a1511SFelipe Balbi 
151194246930SMika Westerberg 	res->end = res->start + 3;
151294246930SMika Westerberg 
1513b84398d6SMika Westerberg 	return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
15142352b05fSHeiner Kallweit 					tco_res, 2, &pldata, sizeof(pldata));
151594246930SMika Westerberg }
151694246930SMika Westerberg 
1517b84398d6SMika Westerberg static struct platform_device *
i801_add_tco_cnl(struct i801_priv * priv,struct pci_dev * pci_dev,struct resource * tco_res)1518b84398d6SMika Westerberg i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev,
1519b84398d6SMika Westerberg 		 struct resource *tco_res)
1520b84398d6SMika Westerberg {
15212352b05fSHeiner Kallweit 	static const struct itco_wdt_platform_data pldata = {
15222352b05fSHeiner Kallweit 		.name = "Intel PCH",
15232352b05fSHeiner Kallweit 		.version = 6,
15242352b05fSHeiner Kallweit 	};
15252352b05fSHeiner Kallweit 
15262352b05fSHeiner Kallweit 	return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
15272352b05fSHeiner Kallweit 						 tco_res, 1, &pldata, sizeof(pldata));
1528b84398d6SMika Westerberg }
1529b84398d6SMika Westerberg 
i801_add_tco(struct i801_priv * priv)1530b84398d6SMika Westerberg static void i801_add_tco(struct i801_priv *priv)
1531b84398d6SMika Westerberg {
1532b84398d6SMika Westerberg 	struct pci_dev *pci_dev = priv->pci_dev;
153304bbb97dSMika Westerberg 	struct resource tco_res[2], *res;
153404bbb97dSMika Westerberg 	u32 tco_base, tco_ctl;
1535b84398d6SMika Westerberg 
1536b84398d6SMika Westerberg 	/* If we have ACPI based watchdog use that instead */
1537b84398d6SMika Westerberg 	if (acpi_has_watchdog())
1538b84398d6SMika Westerberg 		return;
1539b84398d6SMika Westerberg 
1540b84398d6SMika Westerberg 	if (!(priv->features & (FEATURE_TCO_SPT | FEATURE_TCO_CNL)))
1541b84398d6SMika Westerberg 		return;
1542b84398d6SMika Westerberg 
1543b84398d6SMika Westerberg 	pci_read_config_dword(pci_dev, TCOBASE, &tco_base);
1544b84398d6SMika Westerberg 	pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl);
1545b84398d6SMika Westerberg 	if (!(tco_ctl & TCOCTL_EN))
1546b84398d6SMika Westerberg 		return;
1547b84398d6SMika Westerberg 
1548b84398d6SMika Westerberg 	memset(tco_res, 0, sizeof(tco_res));
154904bbb97dSMika Westerberg 	/*
155004bbb97dSMika Westerberg 	 * Always populate the main iTCO IO resource here. The second entry
155104bbb97dSMika Westerberg 	 * for NO_REBOOT MMIO is filled by the SPT specific function.
155204bbb97dSMika Westerberg 	 */
155304bbb97dSMika Westerberg 	res = &tco_res[0];
1554b84398d6SMika Westerberg 	res->start = tco_base & ~1;
1555b84398d6SMika Westerberg 	res->end = res->start + 32 - 1;
1556b84398d6SMika Westerberg 	res->flags = IORESOURCE_IO;
1557b84398d6SMika Westerberg 
1558b84398d6SMika Westerberg 	if (priv->features & FEATURE_TCO_CNL)
1559b84398d6SMika Westerberg 		priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res);
1560b84398d6SMika Westerberg 	else
1561b84398d6SMika Westerberg 		priv->tco_pdev = i801_add_tco_spt(priv, pci_dev, tco_res);
1562b84398d6SMika Westerberg 
1563b84398d6SMika Westerberg 	if (IS_ERR(priv->tco_pdev))
1564b84398d6SMika Westerberg 		dev_warn(&pci_dev->dev, "failed to create iTCO device\n");
156594246930SMika Westerberg }
156694246930SMika Westerberg 
1567a7ae8195SMika Westerberg #ifdef CONFIG_ACPI
i801_acpi_is_smbus_ioport(const struct i801_priv * priv,acpi_physical_address address)15687fd6d98bSMika Westerberg static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
15697fd6d98bSMika Westerberg 				      acpi_physical_address address)
15707fd6d98bSMika Westerberg {
15717fd6d98bSMika Westerberg 	return address >= priv->smba &&
15727fd6d98bSMika Westerberg 	       address <= pci_resource_end(priv->pci_dev, SMBBAR);
15737fd6d98bSMika Westerberg }
15747fd6d98bSMika Westerberg 
1575a7ae8195SMika Westerberg static acpi_status
i801_acpi_io_handler(u32 function,acpi_physical_address address,u32 bits,u64 * value,void * handler_context,void * region_context)1576a7ae8195SMika Westerberg i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
1577a7ae8195SMika Westerberg 		     u64 *value, void *handler_context, void *region_context)
1578a7ae8195SMika Westerberg {
1579a7ae8195SMika Westerberg 	struct i801_priv *priv = handler_context;
1580a7ae8195SMika Westerberg 	struct pci_dev *pdev = priv->pci_dev;
1581a7ae8195SMika Westerberg 	acpi_status status;
1582a7ae8195SMika Westerberg 
1583a7ae8195SMika Westerberg 	/*
1584a7ae8195SMika Westerberg 	 * Once BIOS AML code touches the OpRegion we warn and inhibit any
1585a7ae8195SMika Westerberg 	 * further access from the driver itself. This device is now owned
1586a7ae8195SMika Westerberg 	 * by the system firmware.
1587a7ae8195SMika Westerberg 	 */
1588a7ae8195SMika Westerberg 	mutex_lock(&priv->acpi_lock);
1589a7ae8195SMika Westerberg 
15907fd6d98bSMika Westerberg 	if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
1591a7ae8195SMika Westerberg 		priv->acpi_reserved = true;
1592a7ae8195SMika Westerberg 
1593a7ae8195SMika Westerberg 		dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
1594a7ae8195SMika Westerberg 		dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n");
1595a7ae8195SMika Westerberg 
1596a7ae8195SMika Westerberg 		/*
1597a7ae8195SMika Westerberg 		 * BIOS is accessing the host controller so prevent it from
1598a7ae8195SMika Westerberg 		 * suspending automatically from now on.
1599a7ae8195SMika Westerberg 		 */
1600c073b25dSHeiner Kallweit 		pm_runtime_get_sync(&pdev->dev);
1601a7ae8195SMika Westerberg 	}
1602a7ae8195SMika Westerberg 
1603a7ae8195SMika Westerberg 	if ((function & ACPI_IO_MASK) == ACPI_READ)
1604a7ae8195SMika Westerberg 		status = acpi_os_read_port(address, (u32 *)value, bits);
1605a7ae8195SMika Westerberg 	else
1606a7ae8195SMika Westerberg 		status = acpi_os_write_port(address, (u32)*value, bits);
1607a7ae8195SMika Westerberg 
1608a7ae8195SMika Westerberg 	mutex_unlock(&priv->acpi_lock);
1609a7ae8195SMika Westerberg 
1610a7ae8195SMika Westerberg 	return status;
1611a7ae8195SMika Westerberg }
1612a7ae8195SMika Westerberg 
i801_acpi_probe(struct i801_priv * priv)1613a7ae8195SMika Westerberg static int i801_acpi_probe(struct i801_priv *priv)
1614a7ae8195SMika Westerberg {
16154811a411SHeiner Kallweit 	acpi_handle ah = ACPI_HANDLE(&priv->pci_dev->dev);
1616a7ae8195SMika Westerberg 	acpi_status status;
1617a7ae8195SMika Westerberg 
16184811a411SHeiner Kallweit 	status = acpi_install_address_space_handler(ah, ACPI_ADR_SPACE_SYSTEM_IO,
16194811a411SHeiner Kallweit 						    i801_acpi_io_handler, NULL, priv);
1620a7ae8195SMika Westerberg 	if (ACPI_SUCCESS(status))
1621a7ae8195SMika Westerberg 		return 0;
1622a7ae8195SMika Westerberg 
1623a7ae8195SMika Westerberg 	return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]);
1624a7ae8195SMika Westerberg }
1625a7ae8195SMika Westerberg 
i801_acpi_remove(struct i801_priv * priv)1626a7ae8195SMika Westerberg static void i801_acpi_remove(struct i801_priv *priv)
1627a7ae8195SMika Westerberg {
16284811a411SHeiner Kallweit 	acpi_handle ah = ACPI_HANDLE(&priv->pci_dev->dev);
1629a7ae8195SMika Westerberg 
16304811a411SHeiner Kallweit 	acpi_remove_address_space_handler(ah, ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler);
1631a7ae8195SMika Westerberg }
1632a7ae8195SMika Westerberg #else
i801_acpi_probe(struct i801_priv * priv)1633a7ae8195SMika Westerberg static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
i801_acpi_remove(struct i801_priv * priv)1634a7ae8195SMika Westerberg static inline void i801_acpi_remove(struct i801_priv *priv) { }
1635a7ae8195SMika Westerberg #endif
1636a7ae8195SMika Westerberg 
i801_setup_hstcfg(struct i801_priv * priv)1637c601610cSHeiner Kallweit static void i801_setup_hstcfg(struct i801_priv *priv)
163866d402e2SVolker Rümelin {
163966d402e2SVolker Rümelin 	unsigned char hstcfg = priv->original_hstcfg;
164066d402e2SVolker Rümelin 
164166d402e2SVolker Rümelin 	hstcfg &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */
164266d402e2SVolker Rümelin 	hstcfg |= SMBHSTCFG_HST_EN;
164366d402e2SVolker Rümelin 	pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg);
164466d402e2SVolker Rümelin }
164566d402e2SVolker Rümelin 
i801_probe(struct pci_dev * dev,const struct pci_device_id * id)16460b255e92SBill Pemberton static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
16471da177e4SLinus Torvalds {
1648adff687dSJean Delvare 	int err, i;
16490cd96eb0SDavid Woodhouse 	struct i801_priv *priv;
16501da177e4SLinus Torvalds 
16511621c59dSJarkko Nikula 	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
16520cd96eb0SDavid Woodhouse 	if (!priv)
16530cd96eb0SDavid Woodhouse 		return -ENOMEM;
16540cd96eb0SDavid Woodhouse 
16550cd96eb0SDavid Woodhouse 	i2c_set_adapdata(&priv->adapter, priv);
16560cd96eb0SDavid Woodhouse 	priv->adapter.owner = THIS_MODULE;
16573ad7ea18SJean Delvare 	priv->adapter.class = i801_get_adapter_class(priv);
16580cd96eb0SDavid Woodhouse 	priv->adapter.algo = &smbus_algorithm;
16598eb5c87aSDustin Byford 	priv->adapter.dev.parent = &dev->dev;
16608eb5c87aSDustin Byford 	ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
16618eb5c87aSDustin Byford 	priv->adapter.retries = 3;
1662a7ae8195SMika Westerberg 	mutex_init(&priv->acpi_lock);
16630cd96eb0SDavid Woodhouse 
16640cd96eb0SDavid Woodhouse 	priv->pci_dev = dev;
166541acd4b0SHeiner Kallweit 	priv->features = id->driver_data;
166602dd7ae2SJean Delvare 
1667adff687dSJean Delvare 	/* Disable features on user request */
1668adff687dSJean Delvare 	for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
16690cd96eb0SDavid Woodhouse 		if (priv->features & disable_features & (1 << i))
1670adff687dSJean Delvare 			dev_notice(&dev->dev, "%s disabled by user\n",
1671adff687dSJean Delvare 				   i801_feature_names[i]);
1672adff687dSJean Delvare 	}
16730cd96eb0SDavid Woodhouse 	priv->features &= ~disable_features;
1674adff687dSJean Delvare 
1675e98a3bc0SHeiner Kallweit 	/* The block process call uses block buffer mode */
1676e98a3bc0SHeiner Kallweit 	if (!(priv->features & FEATURE_BLOCK_BUFFER))
1677e98a3bc0SHeiner Kallweit 		priv->features &= ~FEATURE_BLOCK_PROC;
1678e98a3bc0SHeiner Kallweit 
1679fef220daSJarkko Nikula 	err = pcim_enable_device(dev);
168002dd7ae2SJean Delvare 	if (err) {
168102dd7ae2SJean Delvare 		dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
168202dd7ae2SJean Delvare 			err);
1683fef220daSJarkko Nikula 		return err;
168402dd7ae2SJean Delvare 	}
1685fef220daSJarkko Nikula 	pcim_pin_device(dev);
168602dd7ae2SJean Delvare 
168702dd7ae2SJean Delvare 	/* Determine the address of the SMBus area */
16880cd96eb0SDavid Woodhouse 	priv->smba = pci_resource_start(dev, SMBBAR);
16890cd96eb0SDavid Woodhouse 	if (!priv->smba) {
16909cbbf3dcSJarkko Nikula 		dev_err(&dev->dev,
16919cbbf3dcSJarkko Nikula 			"SMBus base address uninitialized, upgrade BIOS\n");
1692fef220daSJarkko Nikula 		return -ENODEV;
169302dd7ae2SJean Delvare 	}
169402dd7ae2SJean Delvare 
1695a7ae8195SMika Westerberg 	if (i801_acpi_probe(priv))
1696fef220daSJarkko Nikula 		return -ENODEV;
169754fb4a05SJean Delvare 
1698d4a994f6SHeiner Kallweit 	err = pcim_iomap_regions(dev, 1 << SMBBAR, DRV_NAME);
169902dd7ae2SJean Delvare 	if (err) {
17009cbbf3dcSJarkko Nikula 		dev_err(&dev->dev,
17019cbbf3dcSJarkko Nikula 			"Failed to request SMBus region 0x%lx-0x%Lx\n",
17029cbbf3dcSJarkko Nikula 			priv->smba,
1703598736c5SAndrew Morton 			(unsigned long long)pci_resource_end(dev, SMBBAR));
1704a7ae8195SMika Westerberg 		i801_acpi_remove(priv);
1705fef220daSJarkko Nikula 		return err;
170602dd7ae2SJean Delvare 	}
170702dd7ae2SJean Delvare 
170866d402e2SVolker Rümelin 	pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg);
1709c601610cSHeiner Kallweit 	i801_setup_hstcfg(priv);
171066d402e2SVolker Rümelin 	if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN))
171102dd7ae2SJean Delvare 		dev_info(&dev->dev, "Enabling SMBus device\n");
171202dd7ae2SJean Delvare 
1713c601610cSHeiner Kallweit 	if (priv->original_hstcfg & SMBHSTCFG_SMB_SMI_EN) {
171402dd7ae2SJean Delvare 		dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
1715636752bcSDaniel Kurtz 		/* Disable SMBus interrupt feature if SMBus using SMI# */
1716636752bcSDaniel Kurtz 		priv->features &= ~FEATURE_IRQ;
1717636752bcSDaniel Kurtz 	}
1718c601610cSHeiner Kallweit 	if (priv->original_hstcfg & SMBHSTCFG_SPD_WD)
1719ba9ad2afSJean Delvare 		dev_info(&dev->dev, "SPD Write Disable is set\n");
17201da177e4SLinus Torvalds 
1721a0921b6cSJean Delvare 	/* Clear special mode bits */
17220cd96eb0SDavid Woodhouse 	if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
17230cd96eb0SDavid Woodhouse 		outb_p(inb_p(SMBAUXCTL(priv)) &
17240cd96eb0SDavid Woodhouse 		       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
1725a0921b6cSJean Delvare 
1726b3b8df97SJean Delvare 	/* Default timeout in interrupt mode: 200 ms */
1727b3b8df97SJean Delvare 	priv->adapter.timeout = HZ / 5;
1728b3b8df97SJean Delvare 
17296e0c9507SHans de Goede 	if (dev->irq == IRQ_NOTCONNECTED)
17306e0c9507SHans de Goede 		priv->features &= ~FEATURE_IRQ;
17316e0c9507SHans de Goede 
1732636752bcSDaniel Kurtz 	if (priv->features & FEATURE_IRQ) {
1733e462aa7eSHeiner Kallweit 		u16 pcists;
1734aeb8a3d1SJean Delvare 
1735aeb8a3d1SJean Delvare 		/* Complain if an interrupt is already pending */
17360d3f1e45SHeiner Kallweit 		pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists);
17370d3f1e45SHeiner Kallweit 		if (pcists & PCI_STATUS_INTERRUPT)
1738aeb8a3d1SJean Delvare 			dev_warn(&dev->dev, "An interrupt is pending!\n");
1739aeb8a3d1SJean Delvare 	}
1740aeb8a3d1SJean Delvare 
1741aeb8a3d1SJean Delvare 	if (priv->features & FEATURE_IRQ) {
17421de93d5dSHeiner Kallweit 		init_completion(&priv->done);
1743636752bcSDaniel Kurtz 
17441621c59dSJarkko Nikula 		err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
1745d4a994f6SHeiner Kallweit 				       IRQF_SHARED, DRV_NAME, priv);
1746636752bcSDaniel Kurtz 		if (err) {
1747636752bcSDaniel Kurtz 			dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
1748636752bcSDaniel Kurtz 				dev->irq, err);
1749ae944717SJean Delvare 			priv->features &= ~FEATURE_IRQ;
1750636752bcSDaniel Kurtz 		}
1751636752bcSDaniel Kurtz 	}
1752ae944717SJean Delvare 	dev_info(&dev->dev, "SMBus using %s\n",
1753ae944717SJean Delvare 		 priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling");
1754636752bcSDaniel Kurtz 
1755f0c8f0eeSHeiner Kallweit 	/* Host notification uses an interrupt */
1756f0c8f0eeSHeiner Kallweit 	if (!(priv->features & FEATURE_IRQ))
1757f0c8f0eeSHeiner Kallweit 		priv->features &= ~FEATURE_HOST_NOTIFY;
1758f0c8f0eeSHeiner Kallweit 
1759f0c8f0eeSHeiner Kallweit 	/* Remember original Interrupt and Host Notify settings */
1760f0c8f0eeSHeiner Kallweit 	priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
1761f0c8f0eeSHeiner Kallweit 	if (priv->features & FEATURE_HOST_NOTIFY)
1762f0c8f0eeSHeiner Kallweit 		priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
1763f0c8f0eeSHeiner Kallweit 
176494246930SMika Westerberg 	i801_add_tco(priv);
176594246930SMika Westerberg 
1766f8e2a041SHans de Goede 	/*
1767f8e2a041SHans de Goede 	 * adapter.name is used by platform code to find the main I801 adapter
1768f8e2a041SHans de Goede 	 * to instantiante i2c_clients, do not change.
1769f8e2a041SHans de Goede 	 */
17700cd96eb0SDavid Woodhouse 	snprintf(priv->adapter.name, sizeof(priv->adapter.name),
1771f8e2a041SHans de Goede 		 "SMBus %s adapter at %04lx",
1772f8e2a041SHans de Goede 		 (priv->features & FEATURE_IDF) ? "I801 IDF" : "I801",
1773f8e2a041SHans de Goede 		 priv->smba);
1774f8e2a041SHans de Goede 
17750cd96eb0SDavid Woodhouse 	err = i2c_add_adapter(&priv->adapter);
177602dd7ae2SJean Delvare 	if (err) {
177739147845SHeiner Kallweit 		platform_device_unregister(priv->tco_pdev);
1778a7ae8195SMika Westerberg 		i801_acpi_remove(priv);
1779fef220daSJarkko Nikula 		return err;
178002dd7ae2SJean Delvare 	}
17811561bfe5SJean Delvare 
17824d5538f5SBenjamin Tissoires 	i801_enable_host_notify(&priv->adapter);
17837b0ed334SBenjamin Tissoires 
1784e7198fbfSJean Delvare 	i801_probe_optional_slaves(priv);
17853ad7ea18SJean Delvare 	/* We ignore errors - multiplexing is optional */
17863ad7ea18SJean Delvare 	i801_add_mux(priv);
17871561bfe5SJean Delvare 
17880cd96eb0SDavid Woodhouse 	pci_set_drvdata(dev, priv);
1789636752bcSDaniel Kurtz 
1790845b8912SJean Delvare 	dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
1791a7401ca5SJarkko Nikula 	pm_runtime_set_autosuspend_delay(&dev->dev, 1000);
1792a7401ca5SJarkko Nikula 	pm_runtime_use_autosuspend(&dev->dev);
1793a7401ca5SJarkko Nikula 	pm_runtime_put_autosuspend(&dev->dev);
1794a7401ca5SJarkko Nikula 	pm_runtime_allow(&dev->dev);
1795a7401ca5SJarkko Nikula 
1796d6fcb3b9SDaniel Ritz 	return 0;
17971da177e4SLinus Torvalds }
17981da177e4SLinus Torvalds 
i801_remove(struct pci_dev * dev)17990b255e92SBill Pemberton static void i801_remove(struct pci_dev *dev)
18001da177e4SLinus Torvalds {
18010cd96eb0SDavid Woodhouse 	struct i801_priv *priv = pci_get_drvdata(dev);
18020cd96eb0SDavid Woodhouse 
18039b5bf587SJean Delvare 	outb_p(priv->original_hstcnt, SMBHSTCNT(priv));
180422e94bd6SBenjamin Tissoires 	i801_disable_host_notify(priv);
18053ad7ea18SJean Delvare 	i801_del_mux(priv);
18060cd96eb0SDavid Woodhouse 	i2c_del_adapter(&priv->adapter);
1807a7ae8195SMika Westerberg 	i801_acpi_remove(priv);
18080cd96eb0SDavid Woodhouse 	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
1809636752bcSDaniel Kurtz 
181094246930SMika Westerberg 	platform_device_unregister(priv->tco_pdev);
181194246930SMika Westerberg 
1812c073b25dSHeiner Kallweit 	/* if acpi_reserved is set then usage_count is incremented already */
1813c073b25dSHeiner Kallweit 	if (!priv->acpi_reserved)
1814c073b25dSHeiner Kallweit 		pm_runtime_get_noresume(&dev->dev);
1815c073b25dSHeiner Kallweit 
1816d6fcb3b9SDaniel Ritz 	/*
1817d6fcb3b9SDaniel Ritz 	 * do not call pci_disable_device(dev) since it can cause hard hangs on
1818d6fcb3b9SDaniel Ritz 	 * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
1819d6fcb3b9SDaniel Ritz 	 */
18201da177e4SLinus Torvalds }
18211da177e4SLinus Torvalds 
i801_shutdown(struct pci_dev * dev)1822f7f6d915SJean Delvare static void i801_shutdown(struct pci_dev *dev)
1823f7f6d915SJean Delvare {
1824f7f6d915SJean Delvare 	struct i801_priv *priv = pci_get_drvdata(dev);
1825f7f6d915SJean Delvare 
1826f7f6d915SJean Delvare 	/* Restore config registers to avoid hard hang on some systems */
18279b5bf587SJean Delvare 	outb_p(priv->original_hstcnt, SMBHSTCNT(priv));
1828f7f6d915SJean Delvare 	i801_disable_host_notify(priv);
1829f7f6d915SJean Delvare 	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
1830f7f6d915SJean Delvare }
1831f7f6d915SJean Delvare 
i801_suspend(struct device * dev)18322ee73c48SJarkko Nikula static int i801_suspend(struct device *dev)
1833a5aaea37SJean Delvare {
1834811a6e18SJean Delvare 	struct i801_priv *priv = dev_get_drvdata(dev);
18350cd96eb0SDavid Woodhouse 
18369b5bf587SJean Delvare 	outb_p(priv->original_hstcnt, SMBHSTCNT(priv));
1837811a6e18SJean Delvare 	pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg);
1838a5aaea37SJean Delvare 	return 0;
1839a5aaea37SJean Delvare }
1840a5aaea37SJean Delvare 
i801_resume(struct device * dev)18412ee73c48SJarkko Nikula static int i801_resume(struct device *dev)
1842a5aaea37SJean Delvare {
18437735eeebSChuhong Yuan 	struct i801_priv *priv = dev_get_drvdata(dev);
18447b0ed334SBenjamin Tissoires 
184566d402e2SVolker Rümelin 	i801_setup_hstcfg(priv);
18464d5538f5SBenjamin Tissoires 	i801_enable_host_notify(&priv->adapter);
18477b0ed334SBenjamin Tissoires 
1848f85da3f5SJarkko Nikula 	return 0;
1849a5aaea37SJean Delvare }
1850a5aaea37SJean Delvare 
1851a6273e41SPaul Cercueil static DEFINE_SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume);
18522ee73c48SJarkko Nikula 
18531da177e4SLinus Torvalds static struct pci_driver i801_driver = {
1854d4a994f6SHeiner Kallweit 	.name		= DRV_NAME,
18551da177e4SLinus Torvalds 	.id_table	= i801_ids,
18561da177e4SLinus Torvalds 	.probe		= i801_probe,
18570b255e92SBill Pemberton 	.remove		= i801_remove,
1858f7f6d915SJean Delvare 	.shutdown	= i801_shutdown,
18592ee73c48SJarkko Nikula 	.driver		= {
1860a6273e41SPaul Cercueil 		.pm	= pm_sleep_ptr(&i801_pm_ops),
1861342530f7SMani Milani 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
18622ee73c48SJarkko Nikula 	},
18631da177e4SLinus Torvalds };
18641da177e4SLinus Torvalds 
i2c_i801_init(void)18651da177e4SLinus Torvalds static int __init i2c_i801_init(void)
18661da177e4SLinus Torvalds {
18676aa1464dSJean Delvare 	if (dmi_name_in_vendors("FUJITSU"))
18681561bfe5SJean Delvare 		input_apanel_init();
18691da177e4SLinus Torvalds 	return pci_register_driver(&i801_driver);
18701da177e4SLinus Torvalds }
18711da177e4SLinus Torvalds 
i2c_i801_exit(void)18721da177e4SLinus Torvalds static void __exit i2c_i801_exit(void)
18731da177e4SLinus Torvalds {
18741da177e4SLinus Torvalds 	pci_unregister_driver(&i801_driver);
18751da177e4SLinus Torvalds }
18761da177e4SLinus Torvalds 
1877f80531c8SJarkko Nikula MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
1878f80531c8SJarkko Nikula MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
18791da177e4SLinus Torvalds MODULE_DESCRIPTION("I801 SMBus driver");
18801da177e4SLinus Torvalds MODULE_LICENSE("GPL");
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds module_init(i2c_i801_init);
18831da177e4SLinus Torvalds module_exit(i2c_i801_exit);
1884