Commit a7401ca5 authored by Jarkko Nikula's avatar Jarkko Nikula Committed by Wolfram Sang

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: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 2ee73c48
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/itco_wdt.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) && \ #if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
defined CONFIG_DMI defined CONFIG_DMI
...@@ -714,9 +715,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -714,9 +715,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
{ {
int hwpec; int hwpec;
int block = 0; int block = 0;
int ret, xact = 0; int ret = 0, xact = 0;
struct i801_priv *priv = i2c_get_adapdata(adap); 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) hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
&& size != I2C_SMBUS_QUICK && size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA; && size != I2C_SMBUS_I2C_BLOCK_DATA;
...@@ -773,7 +776,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -773,7 +776,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
default: default:
dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
size); size);
return -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out;
} }
if (hwpec) /* enable/disable hardware PEC */ if (hwpec) /* enable/disable hardware PEC */
...@@ -796,11 +800,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -796,11 +800,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
if (block) if (block)
return ret; goto out;
if (ret) if (ret)
return ret; goto out;
if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
return 0; goto out;
switch (xact & 0x7f) { switch (xact & 0x7f) {
case I801_BYTE: /* Result put in SMBHSTDAT0 */ case I801_BYTE: /* Result put in SMBHSTDAT0 */
...@@ -812,7 +816,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -812,7 +816,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
(inb_p(SMBHSTDAT1(priv)) << 8); (inb_p(SMBHSTDAT1(priv)) << 8);
break; 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) ...@@ -1413,6 +1421,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_drvdata(dev, priv); 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; return 0;
} }
...@@ -1420,6 +1433,9 @@ static void i801_remove(struct pci_dev *dev) ...@@ -1420,6 +1433,9 @@ static void i801_remove(struct pci_dev *dev)
{ {
struct i801_priv *priv = pci_get_drvdata(dev); struct i801_priv *priv = pci_get_drvdata(dev);
pm_runtime_forbid(&dev->dev);
pm_runtime_get_noresume(&dev->dev);
i801_del_mux(priv); i801_del_mux(priv);
i2c_del_adapter(&priv->adapter); i2c_del_adapter(&priv->adapter);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment