1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019 Disruptive Technologies Research AS
4 * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <log.h>
10#include <asm/gpio.h>
11#include <linux/delay.h>
12#include <power/regulator.h>
13#include "regulator_common.h"
14
15#include "regulator_common.h"
16
17int regulator_common_of_to_plat(struct udevice *dev,
18				struct regulator_common_plat *plat,
19				const char *enable_gpio_name)
20{
21	struct gpio_desc *gpio;
22	int flags = GPIOD_IS_OUT;
23	int ret;
24
25	if (!dev_read_bool(dev, "enable-active-high"))
26		flags |= GPIOD_ACTIVE_LOW;
27	if (dev_read_bool(dev, "regulator-boot-on"))
28		flags |= GPIOD_IS_OUT_ACTIVE;
29
30	/* Get optional enable GPIO desc */
31	gpio = &plat->gpio;
32	ret = gpio_request_by_name(dev, enable_gpio_name, 0, gpio, flags);
33	if (ret) {
34		debug("Regulator '%s' optional enable GPIO - not found! Error: %d\n",
35		      dev->name, ret);
36		if (ret != -ENOENT)
37			return ret;
38	}
39
40	/* Get optional ramp up delay */
41	plat->startup_delay_us = dev_read_u32_default(dev,
42						      "startup-delay-us", 0);
43	plat->off_on_delay_us = dev_read_u32_default(dev, "off-on-delay-us", 0);
44	if (!plat->off_on_delay_us) {
45		plat->off_on_delay_us =
46			dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0);
47	}
48
49	return 0;
50}
51
52int regulator_common_get_enable(const struct udevice *dev,
53	struct regulator_common_plat *plat)
54{
55	/* Enable GPIO is optional */
56	if (!plat->gpio.dev)
57		return true;
58
59	return dm_gpio_get_value(&plat->gpio);
60}
61
62int regulator_common_set_enable(const struct udevice *dev,
63	struct regulator_common_plat *plat, bool enable)
64{
65	int ret;
66
67	debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__,
68	      dev->name, enable, plat->startup_delay_us,
69	      dm_gpio_is_valid(&plat->gpio));
70	/* Enable GPIO is optional */
71	if (!dm_gpio_is_valid(&plat->gpio)) {
72		if (!enable)
73			return -ENOSYS;
74		return 0;
75	}
76
77	/* If previously enabled, increase count */
78	if (enable && plat->enable_count > 0) {
79		plat->enable_count++;
80		return -EALREADY;
81	}
82
83	if (!enable) {
84		if (plat->enable_count > 1) {
85			/* If enabled multiple times, decrease count */
86			plat->enable_count--;
87			return -EBUSY;
88		} else if (!plat->enable_count) {
89			/* If already disabled, do nothing */
90			return -EALREADY;
91		}
92	}
93
94	ret = dm_gpio_set_value(&plat->gpio, enable);
95	if (ret) {
96		pr_err("Can't set regulator : %s gpio to: %d\n", dev->name,
97		      enable);
98		return ret;
99	}
100
101	if (enable && plat->startup_delay_us)
102		udelay(plat->startup_delay_us);
103	debug("%s: done\n", __func__);
104
105	if (!enable && plat->off_on_delay_us)
106		udelay(plat->off_on_delay_us);
107
108	if (enable)
109		plat->enable_count++;
110	else
111		plat->enable_count--;
112
113	return 0;
114}
115