Merge remote-tracking branch 'regulator/topic/gpio' into v3.9-rc8
authorMark Brown <broonie@sirena.org.uk>
Sun, 28 Apr 2013 01:13:40 +0000 (02:13 +0100)
committerMark Brown <broonie@sirena.org.uk>
Sun, 28 Apr 2013 01:13:40 +0000 (02:13 +0100)
drivers/regulator/core.c
drivers/regulator/lp8788-ldo.c
include/linux/regulator/driver.h

index 2434e2e1afcc20b56549f239cd9253e7ad4d9724..6e501784158266d990fc6cad8fb6e0ee7733d923 100644 (file)
@@ -51,6 +51,7 @@
 static DEFINE_MUTEX(regulator_list_mutex);
 static LIST_HEAD(regulator_list);
 static LIST_HEAD(regulator_map_list);
+static LIST_HEAD(regulator_ena_gpio_list);
 static bool has_full_constraints;
 static bool board_wants_dummy_regulator;
 
@@ -68,6 +69,19 @@ struct regulator_map {
        struct regulator_dev *regulator;
 };
 
+/*
+ * struct regulator_enable_gpio
+ *
+ * Management for shared enable GPIO pin
+ */
+struct regulator_enable_gpio {
+       struct list_head list;
+       int gpio;
+       u32 enable_count;       /* a number of enabled shared GPIO */
+       u32 request_count;      /* a number of requested shared GPIO */
+       unsigned int ena_gpio_invert:1;
+};
+
 /*
  * struct regulator
  *
@@ -1465,6 +1479,101 @@ void devm_regulator_put(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(devm_regulator_put);
 
+/* Manage enable GPIO list. Same GPIO pin can be shared among regulators */
+static int regulator_ena_gpio_request(struct regulator_dev *rdev,
+                               const struct regulator_config *config)
+{
+       struct regulator_enable_gpio *pin;
+       int ret;
+
+       list_for_each_entry(pin, &regulator_ena_gpio_list, list) {
+               if (pin->gpio == config->ena_gpio) {
+                       rdev_dbg(rdev, "GPIO %d is already used\n",
+                               config->ena_gpio);
+                       goto update_ena_gpio_to_rdev;
+               }
+       }
+
+       ret = gpio_request_one(config->ena_gpio,
+                               GPIOF_DIR_OUT | config->ena_gpio_flags,
+                               rdev_get_name(rdev));
+       if (ret)
+               return ret;
+
+       pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
+       if (pin == NULL) {
+               gpio_free(config->ena_gpio);
+               return -ENOMEM;
+       }
+
+       pin->gpio = config->ena_gpio;
+       pin->ena_gpio_invert = config->ena_gpio_invert;
+       list_add(&pin->list, &regulator_ena_gpio_list);
+
+update_ena_gpio_to_rdev:
+       pin->request_count++;
+       rdev->ena_pin = pin;
+       return 0;
+}
+
+static void regulator_ena_gpio_free(struct regulator_dev *rdev)
+{
+       struct regulator_enable_gpio *pin, *n;
+
+       if (!rdev->ena_pin)
+               return;
+
+       /* Free the GPIO only in case of no use */
+       list_for_each_entry_safe(pin, n, &regulator_ena_gpio_list, list) {
+               if (pin->gpio == rdev->ena_pin->gpio) {
+                       if (pin->request_count <= 1) {
+                               pin->request_count = 0;
+                               gpio_free(pin->gpio);
+                               list_del(&pin->list);
+                               kfree(pin);
+                       } else {
+                               pin->request_count--;
+                       }
+               }
+       }
+}
+
+/**
+ * Balance enable_count of each GPIO and actual GPIO pin control.
+ * GPIO is enabled in case of initial use. (enable_count is 0)
+ * GPIO is disabled when it is not shared any more. (enable_count <= 1)
+ */
+static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
+{
+       struct regulator_enable_gpio *pin = rdev->ena_pin;
+
+       if (!pin)
+               return -EINVAL;
+
+       if (enable) {
+               /* Enable GPIO at initial use */
+               if (pin->enable_count == 0)
+                       gpio_set_value_cansleep(pin->gpio,
+                                               !pin->ena_gpio_invert);
+
+               pin->enable_count++;
+       } else {
+               if (pin->enable_count > 1) {
+                       pin->enable_count--;
+                       return 0;
+               }
+
+               /* Disable GPIO if not used */
+               if (pin->enable_count <= 1) {
+                       gpio_set_value_cansleep(pin->gpio,
+                                               pin->ena_gpio_invert);
+                       pin->enable_count = 0;
+               }
+       }
+
+       return 0;
+}
+
 static int _regulator_do_enable(struct regulator_dev *rdev)
 {
        int ret, delay;
@@ -1480,9 +1589,10 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
 
        trace_regulator_enable(rdev_get_name(rdev));
 
-       if (rdev->ena_gpio) {
-               gpio_set_value_cansleep(rdev->ena_gpio,
-                                       !rdev->ena_gpio_invert);
+       if (rdev->ena_pin) {
+               ret = regulator_ena_gpio_ctrl(rdev, true);
+               if (ret < 0)
+                       return ret;
                rdev->ena_gpio_state = 1;
        } else if (rdev->desc->ops->enable) {
                ret = rdev->desc->ops->enable(rdev);
@@ -1584,9 +1694,10 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
 
        trace_regulator_disable(rdev_get_name(rdev));
 
-       if (rdev->ena_gpio) {
-               gpio_set_value_cansleep(rdev->ena_gpio,
-                                       rdev->ena_gpio_invert);
+       if (rdev->ena_pin) {
+               ret = regulator_ena_gpio_ctrl(rdev, false);
+               if (ret < 0)
+                       return ret;
                rdev->ena_gpio_state = 0;
 
        } else if (rdev->desc->ops->disable) {
@@ -1859,7 +1970,7 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap);
 static int _regulator_is_enabled(struct regulator_dev *rdev)
 {
        /* A GPIO control always takes precedence */
-       if (rdev->ena_gpio)
+       if (rdev->ena_pin)
                return rdev->ena_gpio_state;
 
        /* If we don't know then assume that the regulator is always on */
@@ -3293,7 +3404,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
                if (status < 0)
                        return status;
        }
-       if (rdev->ena_gpio || ops->is_enabled) {
+       if (rdev->ena_pin || ops->is_enabled) {
                status = device_create_file(dev, &dev_attr_state);
                if (status < 0)
                        return status;
@@ -3495,22 +3606,17 @@ regulator_register(const struct regulator_desc *regulator_desc,
        dev_set_drvdata(&rdev->dev, rdev);
 
        if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
-               ret = gpio_request_one(config->ena_gpio,
-                                      GPIOF_DIR_OUT | config->ena_gpio_flags,
-                                      rdev_get_name(rdev));
+               ret = regulator_ena_gpio_request(rdev, config);
                if (ret != 0) {
                        rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
                                 config->ena_gpio, ret);
                        goto wash;
                }
 
-               rdev->ena_gpio = config->ena_gpio;
-               rdev->ena_gpio_invert = config->ena_gpio_invert;
-
                if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
                        rdev->ena_gpio_state = 1;
 
-               if (rdev->ena_gpio_invert)
+               if (config->ena_gpio_invert)
                        rdev->ena_gpio_state = !rdev->ena_gpio_state;
        }
 
@@ -3590,8 +3696,7 @@ unset_supplies:
 scrub:
        if (rdev->supply)
                _regulator_put(rdev->supply);
-       if (rdev->ena_gpio)
-               gpio_free(rdev->ena_gpio);
+       regulator_ena_gpio_free(rdev);
        kfree(rdev->constraints);
 wash:
        device_unregister(&rdev->dev);
@@ -3626,8 +3731,7 @@ void regulator_unregister(struct regulator_dev *rdev)
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
        kfree(rdev->constraints);
-       if (rdev->ena_gpio)
-               gpio_free(rdev->ena_gpio);
+       regulator_ena_gpio_free(rdev);
        device_unregister(&rdev->dev);
        mutex_unlock(&regulator_list_mutex);
 }
index cd5a14ad9263c7d0e095eab699620032d4286987..fcba90a4c26c9867dabe09f5246a2cb072f836c3 100644 (file)
@@ -184,40 +184,6 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = {
        ALDO10,
 };
 
-static int lp8788_ldo_enable(struct regulator_dev *rdev)
-{
-       struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-
-       if (ldo->en_pin) {
-               gpio_set_value(ldo->en_pin->gpio, ENABLE);
-               return 0;
-       } else {
-               return regulator_enable_regmap(rdev);
-       }
-}
-
-static int lp8788_ldo_disable(struct regulator_dev *rdev)
-{
-       struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-
-       if (ldo->en_pin) {
-               gpio_set_value(ldo->en_pin->gpio, DISABLE);
-               return 0;
-       } else {
-               return regulator_disable_regmap(rdev);
-       }
-}
-
-static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
-{
-       struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-
-       if (ldo->en_pin)
-               return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0;
-       else
-               return regulator_is_enabled_regmap(rdev);
-}
-
 static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
 {
        struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
@@ -253,17 +219,17 @@ static struct regulator_ops lp8788_ldo_voltage_table_ops = {
        .list_voltage = regulator_list_voltage_table,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .enable = lp8788_ldo_enable,
-       .disable = lp8788_ldo_disable,
-       .is_enabled = lp8788_ldo_is_enabled,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
        .enable_time = lp8788_ldo_enable_time,
 };
 
 static struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
        .get_voltage = lp8788_ldo_fixed_get_voltage,
-       .enable = lp8788_ldo_enable,
-       .disable = lp8788_ldo_disable,
-       .is_enabled = lp8788_ldo_is_enabled,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
        .enable_time = lp8788_ldo_enable_time,
 };
 
@@ -535,43 +501,10 @@ static struct regulator_desc lp8788_aldo_desc[] = {
        },
 };
 
-static int lp8788_gpio_request_ldo_en(struct platform_device *pdev,
-                               struct lp8788_ldo *ldo,
-                               enum lp8788_ext_ldo_en_id id)
-{
-       struct device *dev = &pdev->dev;
-       struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
-       int ret, gpio, pinstate;
-       char *name[] = {
-               [EN_ALDO1]   = "LP8788_EN_ALDO1",
-               [EN_ALDO234] = "LP8788_EN_ALDO234",
-               [EN_ALDO5]   = "LP8788_EN_ALDO5",
-               [EN_ALDO7]   = "LP8788_EN_ALDO7",
-               [EN_DLDO7]   = "LP8788_EN_DLDO7",
-               [EN_DLDO911] = "LP8788_EN_DLDO911",
-       };
-
-       gpio = pin->gpio;
-       if (!gpio_is_valid(gpio)) {
-               dev_err(dev, "invalid gpio: %d\n", gpio);
-               return -EINVAL;
-       }
-
-       pinstate = pin->init_state;
-       ret = devm_gpio_request_one(dev, gpio, pinstate, name[id]);
-       if (ret == -EBUSY) {
-               dev_warn(dev, "gpio%d already used\n", gpio);
-               return 0;
-       }
-
-       return ret;
-}
-
 static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
                                        struct lp8788_ldo *ldo,
                                        enum lp8788_ldo_id id)
 {
-       int ret;
        struct lp8788 *lp = ldo->lp;
        struct lp8788_platform_data *pdata = lp->pdata;
        enum lp8788_ext_ldo_en_id enable_id;
@@ -613,14 +546,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
                goto set_default_ldo_enable_mode;
 
        ldo->en_pin = pdata->ldo_pin[enable_id];
-
-       ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id);
-       if (ret) {
-               ldo->en_pin = NULL;
-               goto set_default_ldo_enable_mode;
-       }
-
-       return ret;
+       return 0;
 
 set_default_ldo_enable_mode:
        return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], 0);
@@ -644,6 +570,11 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       if (ldo->en_pin) {
+               cfg.ena_gpio = ldo->en_pin->gpio;
+               cfg.ena_gpio_flags = ldo->en_pin->init_state;
+       }
+
        cfg.dev = pdev->dev.parent;
        cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
        cfg.driver_data = ldo;
@@ -700,6 +631,11 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       if (ldo->en_pin) {
+               cfg.ena_gpio = ldo->en_pin->gpio;
+               cfg.ena_gpio_flags = ldo->en_pin->init_state;
+       }
+
        cfg.dev = pdev->dev.parent;
        cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
        cfg.driver_data = ldo;
index 0dccc91b8ab41cefa39fa9b3007f8be07b1b9e41..6700cc94bdd12275df1b8be822939c298b811aff 100644 (file)
@@ -22,6 +22,7 @@
 struct regmap;
 struct regulator_dev;
 struct regulator_init_data;
+struct regulator_enable_gpio;
 
 enum regulator_status {
        REGULATOR_STATUS_OFF,
@@ -305,8 +306,7 @@ struct regulator_dev {
 
        struct dentry *debugfs;
 
-       int ena_gpio;
-       unsigned int ena_gpio_invert:1;
+       struct regulator_enable_gpio *ena_pin;
        unsigned int ena_gpio_state:1;
 };