|
@@ -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
|
|
|
*
|
|
@@ -1456,6 +1470,65 @@ 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, ®ulator_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, ®ulator_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, ®ulator_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--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int _regulator_do_enable(struct regulator_dev *rdev)
|
|
|
{
|
|
|
int ret, delay;
|
|
@@ -3435,18 +3508,13 @@ 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;
|
|
|
|
|
@@ -3522,8 +3590,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);
|
|
@@ -3558,8 +3625,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(®ulator_list_mutex);
|
|
|
}
|