OSDN Git Service

misc: eeprom: at24: support pm_runtime control
authorBibby Hsieh <bibby.hsieh@mediatek.com>
Thu, 23 Jan 2020 11:52:57 +0000 (12:52 +0100)
committerBartosz Golaszewski <bgolaszewski@baylibre.com>
Thu, 23 Jan 2020 11:52:57 +0000 (12:52 +0100)
Although in the most platforms, the power of eeprom are alway
on, some platforms disable the eeprom power in order to meet
low power request. This patch add the pm_runtime ops to control
power to support all platforms.

Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
[Bartosz: rebased on top of current at24/for-next]
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
drivers/misc/eeprom/at24.c

index 896c1fe..031eb64 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 
 /* Address pointer is 16 bit. */
@@ -87,6 +88,7 @@ struct at24_data {
        u8 flags;
 
        struct nvmem_device *nvmem;
+       struct regulator *vcc_reg;
 
        /*
         * Some chips tie up multiple I2C addresses; dummy devices reserve
@@ -656,6 +658,9 @@ static int at24_probe(struct i2c_client *client)
        at24->client[0].client = client;
        at24->client[0].regmap = regmap;
 
+       at24->vcc_reg = devm_regulator_get(dev, "vcc");
+       if (IS_ERR(at24->vcc_reg))
+               return PTR_ERR(at24->vcc_reg);
 
        writable = !(flags & AT24_FLAG_READONLY);
        if (writable) {
@@ -692,6 +697,12 @@ static int at24_probe(struct i2c_client *client)
 
        i2c_set_clientdata(client, at24);
 
+       err = regulator_enable(at24->vcc_reg);
+       if (err) {
+               dev_err(dev, "Failed to enable vcc regulator\n");
+               return err;
+       }
+
        /* enable runtime pm */
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
@@ -704,6 +715,7 @@ static int at24_probe(struct i2c_client *client)
        pm_runtime_idle(dev);
        if (err) {
                pm_runtime_disable(dev);
+               regulator_disable(at24->vcc_reg);
                return -ENODEV;
        }
 
@@ -719,15 +731,42 @@ static int at24_probe(struct i2c_client *client)
 
 static int at24_remove(struct i2c_client *client)
 {
+       struct at24_data *at24 = i2c_get_clientdata(client);
+
        pm_runtime_disable(&client->dev);
+       if (!pm_runtime_status_suspended(&client->dev))
+               regulator_disable(at24->vcc_reg);
        pm_runtime_set_suspended(&client->dev);
 
        return 0;
 }
 
+static int __maybe_unused at24_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct at24_data *at24 = i2c_get_clientdata(client);
+
+       return regulator_disable(at24->vcc_reg);
+}
+
+static int __maybe_unused at24_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct at24_data *at24 = i2c_get_clientdata(client);
+
+       return regulator_enable(at24->vcc_reg);
+}
+
+static const struct dev_pm_ops at24_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(at24_suspend, at24_resume, NULL)
+};
+
 static struct i2c_driver at24_driver = {
        .driver = {
                .name = "at24",
+               .pm = &at24_pm_ops,
                .of_match_table = at24_of_match,
                .acpi_match_table = ACPI_PTR(at24_acpi_ids),
        },