| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * Copyright (C) 2019 Disruptive Technologies Research AS | |
| * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com> | |
| */ | |
| #include <dm.h> | |
| #include <log.h> | |
| #include <asm/gpio.h> | |
| #include <linux/delay.h> | |
| #include <power/regulator.h> | |
| #include "regulator_common.h" | |
| #include "regulator_common.h" | |
| int regulator_common_of_to_plat(struct udevice *dev, | |
| struct regulator_common_plat *plat, | |
| const char *enable_gpio_name) | |
| { | |
| struct gpio_desc *gpio; | |
| int flags = GPIOD_IS_OUT; | |
| int ret; | |
| if (!dev_read_bool(dev, "enable-active-high")) | |
| flags |= GPIOD_ACTIVE_LOW; | |
| if (dev_read_bool(dev, "regulator-boot-on")) | |
| flags |= GPIOD_IS_OUT_ACTIVE; | |
| /* Get optional enable GPIO desc */ | |
| gpio = &plat->gpio; | |
| ret = gpio_request_by_name(dev, enable_gpio_name, 0, gpio, flags); | |
| if (ret) { | |
| debug("Regulator '%s' optional enable GPIO - not found! Error: %d\n", | |
| dev->name, ret); | |
| if (ret != -ENOENT) | |
| return ret; | |
| } | |
| /* Get optional ramp up delay */ | |
| plat->startup_delay_us = dev_read_u32_default(dev, | |
| "startup-delay-us", 0); | |
| plat->off_on_delay_us = dev_read_u32_default(dev, "off-on-delay-us", 0); | |
| if (!plat->off_on_delay_us) { | |
| plat->off_on_delay_us = | |
| dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0); | |
| } | |
| return 0; | |
| } | |
| int regulator_common_get_enable(const struct udevice *dev, | |
| struct regulator_common_plat *plat) | |
| { | |
| /* Enable GPIO is optional */ | |
| if (!plat->gpio.dev) | |
| return true; | |
| return dm_gpio_get_value(&plat->gpio); | |
| } | |
| int regulator_common_set_enable(const struct udevice *dev, | |
| struct regulator_common_plat *plat, bool enable) | |
| { | |
| int ret; | |
| debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__, | |
| dev->name, enable, plat->startup_delay_us, | |
| dm_gpio_is_valid(&plat->gpio)); | |
| /* Enable GPIO is optional */ | |
| if (!dm_gpio_is_valid(&plat->gpio)) { | |
| if (!enable) | |
| return -ENOSYS; | |
| return 0; | |
| } | |
| /* If previously enabled, increase count */ | |
| if (enable && plat->enable_count > 0) { | |
| plat->enable_count++; | |
| return -EALREADY; | |
| } | |
| if (!enable) { | |
| if (plat->enable_count > 1) { | |
| /* If enabled multiple times, decrease count */ | |
| plat->enable_count--; | |
| return -EBUSY; | |
| } else if (!plat->enable_count) { | |
| /* If already disabled, do nothing */ | |
| return -EALREADY; | |
| } | |
| } | |
| ret = dm_gpio_set_value(&plat->gpio, enable); | |
| if (ret) { | |
| pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, | |
| enable); | |
| return ret; | |
| } | |
| if (enable && plat->startup_delay_us) | |
| udelay(plat->startup_delay_us); | |
| debug("%s: done\n", __func__); | |
| if (!enable && plat->off_on_delay_us) | |
| udelay(plat->off_on_delay_us); | |
| if (enable) | |
| plat->enable_count++; | |
| else | |
| plat->enable_count--; | |
| return 0; | |
| } |