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