diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-i801.c')
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 111 |
1 files changed, 43 insertions, 68 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 73ae06432133..070999139c6d 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -79,6 +79,7 @@ * 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 * * Features supported by this driver: * Software PEC no @@ -231,6 +232,7 @@ #define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS 0x54a3 +#define PCI_DEVICE_ID_INTEL_BIRCH_STREAM_SMBUS 0x5796 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 #define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS 0x7a23 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3 @@ -285,7 +287,6 @@ struct i801_priv { u8 *data; #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI - const struct i801_mux_config *mux_drvdata; struct platform_device *mux_pdev; struct gpiod_lookup_table *lookup; #endif @@ -293,10 +294,9 @@ struct i801_priv { /* * If set to true the host controller registers are reserved for - * ACPI AML use. Protected by acpi_lock. + * ACPI AML use. */ bool acpi_reserved; - struct mutex acpi_lock; }; #define FEATURE_SMBUS_PEC BIT(0) @@ -679,15 +679,11 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, return result ? priv->status : -ETIMEDOUT; } - for (i = 1; i <= len; i++) { - if (i == len && read_write == I2C_SMBUS_READ) - smbcmd |= SMBHSTCNT_LAST_BYTE; - outb_p(smbcmd, SMBHSTCNT(priv)); - - if (i == 1) - outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, - SMBHSTCNT(priv)); + if (len == 1 && read_write == I2C_SMBUS_READ) + smbcmd |= SMBHSTCNT_LAST_BYTE; + outb_p(smbcmd | SMBHSTCNT_START, SMBHSTCNT(priv)); + for (i = 1; i <= len; i++) { status = i801_wait_byte_done(priv); if (status) return status; @@ -710,9 +706,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, data->block[0] = len; } - /* Retrieve/store value in SMBBLKDAT */ - if (read_write == I2C_SMBUS_READ) + if (read_write == I2C_SMBUS_READ) { data->block[i] = inb_p(SMBBLKDAT(priv)); + if (i == len - 1) + outb_p(smbcmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv)); + } + if (read_write == I2C_SMBUS_WRITE && i+1 <= len) outb_p(data->block[i+1], SMBBLKDAT(priv)); @@ -875,11 +874,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, int hwpec, ret; struct i801_priv *priv = i2c_get_adapdata(adap); - mutex_lock(&priv->acpi_lock); - if (priv->acpi_reserved) { - mutex_unlock(&priv->acpi_lock); + if (priv->acpi_reserved) return -EBUSY; - } pm_runtime_get_sync(&priv->pci_dev->dev); @@ -920,7 +916,6 @@ out: pm_runtime_mark_last_busy(&priv->pci_dev->dev); pm_runtime_put_autosuspend(&priv->pci_dev->dev); - mutex_unlock(&priv->acpi_lock); return ret; } @@ -1044,6 +1039,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_SOC_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { 0, } }; @@ -1288,7 +1284,7 @@ static void i801_probe_optional_slaves(struct i801_priv *priv) /* Instantiate SPD EEPROMs unless the SMBus is multiplexed */ #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) - if (!priv->mux_drvdata) + if (!priv->mux_pdev) #endif i2c_register_spd(&priv->adapter); } @@ -1390,11 +1386,14 @@ static void i801_add_mux(struct i801_priv *priv) const struct i801_mux_config *mux_config; struct i2c_mux_gpio_platform_data gpio_data; struct gpiod_lookup_table *lookup; + const struct dmi_system_id *id; int i; - if (!priv->mux_drvdata) + id = dmi_first_match(mux_dmi_table); + if (!id) return; - mux_config = priv->mux_drvdata; + + mux_config = id->driver_data; /* Prepare the platform data */ memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data)); @@ -1438,35 +1437,9 @@ static void i801_del_mux(struct i801_priv *priv) platform_device_unregister(priv->mux_pdev); gpiod_remove_lookup_table(priv->lookup); } - -static unsigned int i801_get_adapter_class(struct i801_priv *priv) -{ - const struct dmi_system_id *id; - const struct i801_mux_config *mux_config; - unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - int i; - - id = dmi_first_match(mux_dmi_table); - if (id) { - /* Remove branch classes from trunk */ - mux_config = id->driver_data; - for (i = 0; i < mux_config->n_values; i++) - class &= ~mux_config->classes[i]; - - /* Remember for later */ - priv->mux_drvdata = mux_config; - } - - return class; -} #else static inline void i801_add_mux(struct i801_priv *priv) { } static inline void i801_del_mux(struct i801_priv *priv) { } - -static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) -{ - return I2C_CLASS_HWMON | I2C_CLASS_SPD; -} #endif static struct platform_device * @@ -1572,7 +1545,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, * further access from the driver itself. This device is now owned * by the system firmware. */ - mutex_lock(&priv->acpi_lock); + i2c_lock_bus(&priv->adapter, I2C_LOCK_SEGMENT); if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { priv->acpi_reserved = true; @@ -1592,7 +1565,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, else status = acpi_os_write_port(address, (u32)*value, bits); - mutex_unlock(&priv->acpi_lock); + i2c_unlock_bus(&priv->adapter, I2C_LOCK_SEGMENT); return status; } @@ -1630,6 +1603,12 @@ static void i801_setup_hstcfg(struct i801_priv *priv) pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg); } +static void i801_restore_regs(struct i801_priv *priv) +{ + outb_p(priv->original_hstcnt, SMBHSTCNT(priv)); + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); +} + static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) { int err, i; @@ -1641,12 +1620,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) i2c_set_adapdata(&priv->adapter, priv); priv->adapter.owner = THIS_MODULE; - priv->adapter.class = i801_get_adapter_class(priv); + priv->adapter.class = I2C_CLASS_HWMON; priv->adapter.algo = &smbus_algorithm; priv->adapter.dev.parent = &dev->dev; - ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); + acpi_use_parent_companion(&priv->adapter.dev); priv->adapter.retries = 3; - mutex_init(&priv->acpi_lock); priv->pci_dev = dev; priv->features = id->driver_data; @@ -1754,7 +1732,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) "SMBus I801 adapter at %04lx", priv->smba); err = i2c_add_adapter(&priv->adapter); if (err) { + platform_device_unregister(priv->tco_pdev); i801_acpi_remove(priv); + i801_restore_regs(priv); return err; } @@ -1779,12 +1759,10 @@ static void i801_remove(struct pci_dev *dev) { struct i801_priv *priv = pci_get_drvdata(dev); - outb_p(priv->original_hstcnt, SMBHSTCNT(priv)); i801_disable_host_notify(priv); i801_del_mux(priv); i2c_del_adapter(&priv->adapter); i801_acpi_remove(priv); - pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); platform_device_unregister(priv->tco_pdev); @@ -1792,6 +1770,8 @@ static void i801_remove(struct pci_dev *dev) if (!priv->acpi_reserved) pm_runtime_get_noresume(&dev->dev); + i801_restore_regs(priv); + /* * do not call pci_disable_device(dev) since it can cause hard hangs on * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) @@ -1802,18 +1782,18 @@ static void i801_shutdown(struct pci_dev *dev) { struct i801_priv *priv = pci_get_drvdata(dev); - /* Restore config registers to avoid hard hang on some systems */ - outb_p(priv->original_hstcnt, SMBHSTCNT(priv)); i801_disable_host_notify(priv); - pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); + /* Restore config registers to avoid hard hang on some systems */ + i801_restore_regs(priv); } static int i801_suspend(struct device *dev) { struct i801_priv *priv = dev_get_drvdata(dev); - outb_p(priv->original_hstcnt, SMBHSTCNT(priv)); - pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); + i2c_mark_adapter_suspended(&priv->adapter); + i801_restore_regs(priv); + return 0; } @@ -1823,6 +1803,7 @@ static int i801_resume(struct device *dev) i801_setup_hstcfg(priv); i801_enable_host_notify(&priv->adapter); + i2c_mark_adapter_resumed(&priv->adapter); return 0; } @@ -1841,16 +1822,11 @@ static struct pci_driver i801_driver = { }, }; -static int __init i2c_i801_init(void) +static int __init i2c_i801_init(struct pci_driver *drv) { if (dmi_name_in_vendors("FUJITSU")) input_apanel_init(); - return pci_register_driver(&i801_driver); -} - -static void __exit i2c_i801_exit(void) -{ - pci_unregister_driver(&i801_driver); + return pci_register_driver(drv); } MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>"); @@ -1858,5 +1834,4 @@ MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); MODULE_DESCRIPTION("I801 SMBus driver"); MODULE_LICENSE("GPL"); -module_init(i2c_i801_init); -module_exit(i2c_i801_exit); +module_driver(i801_driver, i2c_i801_init, pci_unregister_driver); |