summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/eeprom/at24.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 2199c42e1623..a466e40acb2c 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -24,6 +24,7 @@
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
#include <linux/platform_data/at24.h>
+#include <linux/pm_runtime.h>
/*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
@@ -501,11 +502,21 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
static int at24_read(void *priv, unsigned int off, void *val, size_t count)
{
struct at24_data *at24 = priv;
+ struct i2c_client *client;
char *buf = val;
+ int ret;
if (unlikely(!count))
return count;
+ client = at24_translate_offset(at24, &off);
+
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ return ret;
+ }
+
/*
* Read data from chip, protecting against concurrent updates
* from this host, but not from other I2C masters.
@@ -518,6 +529,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
status = at24->read_func(at24, buf, off, count);
if (status < 0) {
mutex_unlock(&at24->lock);
+ pm_runtime_put(&client->dev);
return status;
}
buf += status;
@@ -527,17 +539,29 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
mutex_unlock(&at24->lock);
+ pm_runtime_put(&client->dev);
+
return 0;
}
static int at24_write(void *priv, unsigned int off, void *val, size_t count)
{
struct at24_data *at24 = priv;
+ struct i2c_client *client;
char *buf = val;
+ int ret;
if (unlikely(!count))
return -EINVAL;
+ client = at24_translate_offset(at24, &off);
+
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ return ret;
+ }
+
/*
* Write data to chip, protecting against concurrent updates
* from this host, but not from other I2C masters.
@@ -550,6 +574,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
status = at24->write_func(at24, buf, off, count);
if (status < 0) {
mutex_unlock(&at24->lock);
+ pm_runtime_put(&client->dev);
return status;
}
buf += status;
@@ -559,6 +584,8 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
mutex_unlock(&at24->lock);
+ pm_runtime_put(&client->dev);
+
return 0;
}
@@ -743,11 +770,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, at24);
+ /* enable runtime pm */
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+
/*
* Perform a one-byte test read to verify that the
* chip is functional.
*/
err = at24_read(at24, 0, &test_byte, 1);
+ pm_runtime_idle(&client->dev);
if (err) {
err = -ENODEV;
goto err_clients;
@@ -795,6 +827,8 @@ err_clients:
if (at24->client[i])
i2c_unregister_device(at24->client[i]);
+ pm_runtime_disable(&client->dev);
+
return err;
}
@@ -810,6 +844,9 @@ static int at24_remove(struct i2c_client *client)
for (i = 1; i < at24->num_addresses; i++)
i2c_unregister_device(at24->client[i]);
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
return 0;
}