linux/drivers/i2c/busses/i2c-i801.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
    Copyright (c) 1998 - 2002  Frodo Looijaard <[email protected]>,
    Philip Edelbrock <[email protected]>, and Mark D. Studebaker
    <[email protected]>
    Copyright (C) 2007 - 2014  Jean Delvare <[email protected]>
    Copyright (C) 2010         Intel Corporation,
                               David Woodhouse <[email protected]>

*/

/*
 * Supports the following Intel I/O Controller Hubs (ICH):
 *
 *					I/O			Block	I2C
 *					region	SMBus	Block	proc.	block
 * Chip name			PCI ID	size	PEC	buffer	call	read
 * ---------------------------------------------------------------------------
 * 82801AA (ICH)		0x2413	16	no	no	no	no
 * 82801AB (ICH0)		0x2423	16	no	no	no	no
 * 82801BA (ICH2)		0x2443	16	no	no	no	no
 * 82801CA (ICH3)		0x2483	32	soft	no	no	no
 * 82801DB (ICH4)		0x24c3	32	hard	yes	no	no
 * 82801E (ICH5)		0x24d3	32	hard	yes	yes	yes
 * 6300ESB			0x25a4	32	hard	yes	yes	yes
 * 82801F (ICH6)		0x266a	32	hard	yes	yes	yes
 * 6310ESB/6320ESB		0x269b	32	hard	yes	yes	yes
 * 82801G (ICH7)		0x27da	32	hard	yes	yes	yes
 * 82801H (ICH8)		0x283e	32	hard	yes	yes	yes
 * 82801I (ICH9)		0x2930	32	hard	yes	yes	yes
 * EP80579 (Tolapai)		0x5032	32	hard	yes	yes	yes
 * ICH10			0x3a30	32	hard	yes	yes	yes
 * ICH10			0x3a60	32	hard	yes	yes	yes
 * 5/3400 Series (PCH)		0x3b30	32	hard	yes	yes	yes
 * 6 Series (PCH)		0x1c22	32	hard	yes	yes	yes
 * Patsburg (PCH)		0x1d22	32	hard	yes	yes	yes
 * Patsburg (PCH) IDF		0x1d70	32	hard	yes	yes	yes
 * Patsburg (PCH) IDF		0x1d71	32	hard	yes	yes	yes
 * Patsburg (PCH) IDF		0x1d72	32	hard	yes	yes	yes
 * DH89xxCC (PCH)		0x2330	32	hard	yes	yes	yes
 * Panther Point (PCH)		0x1e22	32	hard	yes	yes	yes
 * Lynx Point (PCH)		0x8c22	32	hard	yes	yes	yes
 * Lynx Point-LP (PCH)		0x9c22	32	hard	yes	yes	yes
 * Avoton (SOC)			0x1f3c	32	hard	yes	yes	yes
 * Wellsburg (PCH)		0x8d22	32	hard	yes	yes	yes
 * Wellsburg (PCH) MS		0x8d7d	32	hard	yes	yes	yes
 * Wellsburg (PCH) MS		0x8d7e	32	hard	yes	yes	yes
 * Wellsburg (PCH) MS		0x8d7f	32	hard	yes	yes	yes
 * Coleto Creek (PCH)		0x23b0	32	hard	yes	yes	yes
 * Wildcat Point (PCH)		0x8ca2	32	hard	yes	yes	yes
 * Wildcat Point-LP (PCH)	0x9ca2	32	hard	yes	yes	yes
 * BayTrail (SOC)		0x0f12	32	hard	yes	yes	yes
 * Braswell (SOC)		0x2292	32	hard	yes	yes	yes
 * Sunrise Point-H (PCH) 	0xa123  32	hard	yes	yes	yes
 * Sunrise Point-LP (PCH)	0x9d23	32	hard	yes	yes	yes
 * DNV (SOC)			0x19df	32	hard	yes	yes	yes
 * Emmitsburg (PCH)		0x1bc9	32	hard	yes	yes	yes
 * Broxton (SOC)		0x5ad4	32	hard	yes	yes	yes
 * Lewisburg (PCH)		0xa1a3	32	hard	yes	yes	yes
 * Lewisburg Supersku (PCH)	0xa223	32	hard	yes	yes	yes
 * Kaby Lake PCH-H (PCH)	0xa2a3	32	hard	yes	yes	yes
 * Gemini Lake (SOC)		0x31d4	32	hard	yes	yes	yes
 * Cannon Lake-H (PCH)		0xa323	32	hard	yes	yes	yes
 * Cannon Lake-LP (PCH)		0x9da3	32	hard	yes	yes	yes
 * Cedar Fork (PCH)		0x18df	32	hard	yes	yes	yes
 * Ice Lake-LP (PCH)		0x34a3	32	hard	yes	yes	yes
 * Ice Lake-N (PCH)		0x38a3	32	hard	yes	yes	yes
 * Comet Lake (PCH)		0x02a3	32	hard	yes	yes	yes
 * Comet Lake-H (PCH)		0x06a3	32	hard	yes	yes	yes
 * Elkhart Lake (PCH)		0x4b23	32	hard	yes	yes	yes
 * Tiger Lake-LP (PCH)		0xa0a3	32	hard	yes	yes	yes
 * Tiger Lake-H (PCH)		0x43a3	32	hard	yes	yes	yes
 * Jasper Lake (SOC)		0x4da3	32	hard	yes	yes	yes
 * Comet Lake-V (PCH)		0xa3a3	32	hard	yes	yes	yes
 * Alder Lake-S (PCH)		0x7aa3	32	hard	yes	yes	yes
 * Alder Lake-P (PCH)		0x51a3	32	hard	yes	yes	yes
 * Alder Lake-M (PCH)		0x54a3	32	hard	yes	yes	yes
 * Raptor Lake-S (PCH)		0x7a23	32	hard	yes	yes	yes
 * Meteor Lake-P (SOC)		0x7e22	32	hard	yes	yes	yes
 * Meteor Lake SoC-S (SOC)	0xae22	32	hard	yes	yes	yes
 * Meteor Lake PCH-S (PCH)	0x7f23	32	hard	yes	yes	yes
 * Birch Stream (SOC)		0x5796	32	hard	yes	yes	yes
 * Arrow Lake-H (SOC)		0x7722	32	hard	yes	yes	yes
 *
 * Features supported by this driver:
 * Software PEC				no
 * Hardware PEC				yes
 * Block buffer				yes
 * Block process call transaction	yes
 * I2C block read transaction		yes (doesn't use the block buffer)
 * Target mode				no
 * SMBus Host Notify			yes
 * Interrupt processing			yes
 *
 * See the file Documentation/i2c/busses/i2c-i801.rst for details.
 */

#define DRV_NAME

#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/i2c-smbus.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/platform_data/itco_wdt.h>
#include <linux/platform_data/x86/p2sb.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>

#ifdef CONFIG_I2C_I801_MUX
#include <linux/gpio/machine.h>
#include <linux/platform_data/i2c-mux-gpio.h>
#endif

/* I801 SMBus address offsets */
#define SMBHSTSTS(p)
#define SMBHSTCNT(p)
#define SMBHSTCMD(p)
#define SMBHSTADD(p)
#define SMBHSTDAT0(p)
#define SMBHSTDAT1(p)
#define SMBBLKDAT(p)
#define SMBPEC(p)
#define SMBAUXSTS(p)
#define SMBAUXCTL(p)
#define SMBSLVSTS(p)
#define SMBSLVCMD(p)
#define SMBNTFDADD(p)

/* PCI Address Constants */
#define SMBBAR
#define SMBHSTCFG
#define TCOBASE
#define TCOCTL

#define SBREG_SMBCTRL
#define SBREG_SMBCTRL_DNV

/* Host configuration bits for SMBHSTCFG */
#define SMBHSTCFG_HST_EN
#define SMBHSTCFG_SMB_SMI_EN
#define SMBHSTCFG_I2C_EN
#define SMBHSTCFG_SPD_WD

/* TCO configuration bits for TCOCTL */
#define TCOCTL_EN

/* Auxiliary status register bits, ICH4+ only */
#define SMBAUXSTS_CRCE
#define SMBAUXSTS_STCO

/* Auxiliary control register bits, ICH4+ only */
#define SMBAUXCTL_CRC
#define SMBAUXCTL_E32B

/* I801 command constants */
#define I801_QUICK
#define I801_BYTE
#define I801_BYTE_DATA
#define I801_WORD_DATA
#define I801_PROC_CALL
#define I801_BLOCK_DATA
#define I801_I2C_BLOCK_DATA
#define I801_BLOCK_PROC_CALL

/* I801 Host Control register bits */
#define SMBHSTCNT_INTREN
#define SMBHSTCNT_KILL
#define SMBHSTCNT_LAST_BYTE
#define SMBHSTCNT_START
#define SMBHSTCNT_PEC_EN

/* I801 Hosts Status register bits */
#define SMBHSTSTS_BYTE_DONE
#define SMBHSTSTS_INUSE_STS
#define SMBHSTSTS_SMBALERT_STS
#define SMBHSTSTS_FAILED
#define SMBHSTSTS_BUS_ERR
#define SMBHSTSTS_DEV_ERR
#define SMBHSTSTS_INTR
#define SMBHSTSTS_HOST_BUSY

/* Host Notify Status register bits */
#define SMBSLVSTS_HST_NTFY_STS

/* Host Notify Command register bits */
#define SMBSLVCMD_SMBALERT_DISABLE
#define SMBSLVCMD_HST_NTFY_INTREN

#define STATUS_ERROR_FLAGS

#define STATUS_FLAGS

#define SMBUS_LEN_SENTINEL

/* Older devices have their ID defined in <linux/pci_ids.h> */
#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS
#define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS
#define PCI_DEVICE_ID_INTEL_CDF_SMBUS
#define PCI_DEVICE_ID_INTEL_DNV_SMBUS
#define PCI_DEVICE_ID_INTEL_EBG_SMBUS
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS
/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS
#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS
#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS
#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS
#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS
#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS
#define PCI_DEVICE_ID_INTEL_ICELAKE_N_SMBUS
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS
#define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS
#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS
#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS
#define PCI_DEVICE_ID_INTEL_BIRCH_STREAM_SMBUS
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS
#define PCI_DEVICE_ID_INTEL_ARROW_LAKE_H_SMBUS
#define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS
#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_P_SMBUS
#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_PCH_S_SMBUS
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS
#define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS
#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS
#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS
#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_SOC_S_SMBUS

struct i801_mux_config {};

struct i801_priv {};

#define FEATURE_SMBUS_PEC
#define FEATURE_BLOCK_BUFFER
#define FEATURE_BLOCK_PROC
#define FEATURE_I2C_BLOCK_READ
#define FEATURE_IRQ
#define FEATURE_HOST_NOTIFY
/* Not really a feature, but it's convenient to handle it as such */
#define FEATURE_IDF
#define FEATURE_TCO_SPT
#define FEATURE_TCO_CNL

static const char *i801_feature_names[] =;

static unsigned int disable_features;
module_param(disable_features, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC();

static int i801_get_block_len(struct i801_priv *priv)
{}

static int i801_check_and_clear_pec_error(struct i801_priv *priv)
{}

/* Make sure the SMBus host is ready to start transmitting.
   Return 0 if it is, -EBUSY if it is not. */
static int i801_check_pre(struct i801_priv *priv)
{}

static int i801_check_post(struct i801_priv *priv, int status)
{}

/* Wait for BUSY being cleared and either INTR or an error flag being set */
static int i801_wait_intr(struct i801_priv *priv)
{}

/* Wait for either BYTE_DONE or an error flag being set */
static int i801_wait_byte_done(struct i801_priv *priv)
{}

static int i801_transaction(struct i801_priv *priv, int xact)
{}

static int i801_block_transaction_by_block(struct i801_priv *priv,
					   union i2c_smbus_data *data,
					   char read_write, int command)
{}

static void i801_isr_byte_done(struct i801_priv *priv)
{}

static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
{}

/*
 * There are three kinds of interrupts:
 *
 * 1) i801 signals transaction completion with one of these interrupts:
 *      INTR - Success
 *      DEV_ERR - Invalid command, NAK or communication timeout
 *      BUS_ERR - SMI# transaction collision
 *      FAILED - transaction was canceled due to a KILL request
 *    When any of these occur, update ->status and signal completion.
 *
 * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
 *    occurs for each byte of a byte-by-byte to prepare the next byte.
 *
 * 3) Host Notify interrupts
 */
static irqreturn_t i801_isr(int irq, void *dev_id)
{}

/*
 * For "byte-by-byte" block transactions:
 *   I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1
 *   I2C read uses cmd=I801_I2C_BLOCK_DATA
 */
static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
					       union i2c_smbus_data *data,
					       char read_write, int command)
{}

static void i801_set_hstadd(struct i801_priv *priv, u8 addr, char read_write)
{}

/* Single value transaction function */
static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
				   u8 addr, u8 hstcmd, char read_write, int command)
{}

static int i801_smbus_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
					u8 addr, u8 hstcmd, char read_write, int command)
{}

static int i801_i2c_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
				      u8 addr, u8 hstcmd, char read_write, int command)
{}

/* Return negative errno on error. */
static s32 i801_access(struct i2c_adapter *adap, u16 addr,
		       unsigned short flags, char read_write, u8 command,
		       int size, union i2c_smbus_data *data)
{}


static u32 i801_func(struct i2c_adapter *adapter)
{}

static void i801_enable_host_notify(struct i2c_adapter *adapter)
{}

static void i801_disable_host_notify(struct i801_priv *priv)
{}

static const struct i2c_algorithm smbus_algorithm =;

#define FEATURES_ICH4
#define FEATURES_ICH5

static const struct pci_device_id i801_ids[] =;

MODULE_DEVICE_TABLE(pci, i801_ids);

#if defined CONFIG_X86 && defined CONFIG_DMI
static unsigned char apanel_addr __ro_after_init;

/* Scan the system ROM for the signature "FJKEYINF" */
static __init const void __iomem *bios_signature(const void __iomem *bios)
{}

static void __init input_apanel_init(void)
{}

struct dmi_onboard_device_info {};

static const struct dmi_onboard_device_info dmi_devices[] =;

static void dmi_check_onboard_device(u8 type, const char *name,
				     struct i2c_adapter *adap)
{}

/* We use our own function to check for onboard devices instead of
   dmi_find_device() as some buggy BIOS's have the devices we are interested
   in marked as disabled */
static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap)
{}

/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */
static const char *const acpi_smo8800_ids[] =;

static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle,
					     u32 nesting_level,
					     void *context,
					     void **return_value)
{}

static bool is_dell_system_with_lis3lv02d(void)
{}

/*
 * Accelerometer's I2C address is not specified in DMI nor ACPI,
 * so it is needed to define mapping table based on DMI product names.
 */
static const struct {} dell_lis3lv02d_devices[] =;

static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
{}

/* Register optional targets */
static void i801_probe_optional_targets(struct i801_priv *priv)
{}
#else
static void __init input_apanel_init(void) {}
static void i801_probe_optional_targets(struct i801_priv *priv) {}
#endif	/* CONFIG_X86 && CONFIG_DMI */

#ifdef CONFIG_I2C_I801_MUX
static struct i801_mux_config i801_mux_config_asus_z8_d12 =;

static struct i801_mux_config i801_mux_config_asus_z8_d18 =;

static const struct dmi_system_id mux_dmi_table[] =;

static int i801_notifier_call(struct notifier_block *nb, unsigned long action,
			      void *data)
{}

/* Setup multiplexing if needed */
static void i801_add_mux(struct i801_priv *priv)
{}

static void i801_del_mux(struct i801_priv *priv)
{}
#else
static inline void i801_add_mux(struct i801_priv *priv) { }
static inline void i801_del_mux(struct i801_priv *priv) { }
#endif

static struct platform_device *
i801_add_tco_spt(struct pci_dev *pci_dev, struct resource *tco_res)
{}

static struct platform_device *
i801_add_tco_cnl(struct pci_dev *pci_dev, struct resource *tco_res)
{}

static void i801_add_tco(struct i801_priv *priv)
{}

#ifdef CONFIG_ACPI
static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
				      acpi_physical_address address)
{}

static acpi_status
i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
		     u64 *value, void *handler_context, void *region_context)
{}

static int i801_acpi_probe(struct i801_priv *priv)
{}

static void i801_acpi_remove(struct i801_priv *priv)
{}
#else
static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
static inline void i801_acpi_remove(struct i801_priv *priv) { }
#endif

static void i801_setup_hstcfg(struct i801_priv *priv)
{}

static void i801_restore_regs(struct i801_priv *priv)
{}

static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{}

static void i801_remove(struct pci_dev *dev)
{}

static void i801_shutdown(struct pci_dev *dev)
{}

static int i801_suspend(struct device *dev)
{}

static int i801_resume(struct device *dev)
{}

static DEFINE_SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume);

static struct pci_driver i801_driver =;

static int __init i2c_i801_init(struct pci_driver *drv)
{}

MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();

module_driver();