diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/eeprom/at24.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 764ff5df0dbc..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; } @@ -570,6 +597,10 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip) if (device_property_present(dev, "read-only")) chip->flags |= AT24_FLAG_READONLY; + err = device_property_read_u32(dev, "size", &val); + if (!err) + chip->byte_len = val; + err = device_property_read_u32(dev, "pagesize", &val); if (!err) { chip->page_size = val; @@ -739,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; @@ -791,6 +827,8 @@ err_clients: if (at24->client[i]) i2c_unregister_device(at24->client[i]); + pm_runtime_disable(&client->dev); + return err; } @@ -806,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; } |