i2c: i801: Add runtime PM support with autosuspend
Allow runtime PM so that PM and PCI core can put the device into low-power state when idle and resume it back when needed in those platforms that support PM for i801 device. Enable also autosuspend with 1 second delay in order to not needlessly toggle power state on and off if there are multiple transactions during short time. Device is resumed at the beginning of bus access and marked idle ready for autosuspend at the end of it. Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Tested-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
Родитель
2ee73c484d
Коммит
a7401ca559
|
@ -94,6 +94,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/itco_wdt.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
|
||||
defined CONFIG_DMI
|
||||
|
@ -714,9 +715,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
|||
{
|
||||
int hwpec;
|
||||
int block = 0;
|
||||
int ret, xact = 0;
|
||||
int ret = 0, xact = 0;
|
||||
struct i801_priv *priv = i2c_get_adapdata(adap);
|
||||
|
||||
pm_runtime_get_sync(&priv->pci_dev->dev);
|
||||
|
||||
hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
|
||||
&& size != I2C_SMBUS_QUICK
|
||||
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
|
||||
|
@ -773,7 +776,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
|||
default:
|
||||
dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
|
||||
size);
|
||||
return -EOPNOTSUPP;
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hwpec) /* enable/disable hardware PEC */
|
||||
|
@ -796,11 +800,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
|||
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
|
||||
|
||||
if (block)
|
||||
return ret;
|
||||
goto out;
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
switch (xact & 0x7f) {
|
||||
case I801_BYTE: /* Result put in SMBHSTDAT0 */
|
||||
|
@ -812,7 +816,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
|||
(inb_p(SMBHSTDAT1(priv)) << 8);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
|
||||
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1413,6 +1421,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
|
||||
pci_set_drvdata(dev, priv);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&dev->dev, 1000);
|
||||
pm_runtime_use_autosuspend(&dev->dev);
|
||||
pm_runtime_put_autosuspend(&dev->dev);
|
||||
pm_runtime_allow(&dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1420,6 +1433,9 @@ static void i801_remove(struct pci_dev *dev)
|
|||
{
|
||||
struct i801_priv *priv = pci_get_drvdata(dev);
|
||||
|
||||
pm_runtime_forbid(&dev->dev);
|
||||
pm_runtime_get_noresume(&dev->dev);
|
||||
|
||||
i801_del_mux(priv);
|
||||
i2c_del_adapter(&priv->adapter);
|
||||
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
|
||||
|
|
Загрузка…
Ссылка в новой задаче