1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2477dfe2fSKeerthy /*
3477dfe2fSKeerthy  * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
4477dfe2fSKeerthy  * Keerthy <j-keerthy@ti.com>
5477dfe2fSKeerthy  */
6477dfe2fSKeerthy 
7477dfe2fSKeerthy #include <common.h>
8477dfe2fSKeerthy #include <fdtdec.h>
9477dfe2fSKeerthy #include <errno.h>
10477dfe2fSKeerthy #include <dm.h>
11477dfe2fSKeerthy #include <i2c.h>
12477dfe2fSKeerthy #include <asm/gpio.h>
13477dfe2fSKeerthy #include <power/pmic.h>
14477dfe2fSKeerthy #include <power/regulator.h>
15477dfe2fSKeerthy 
16477dfe2fSKeerthy #define GPIO_REGULATOR_MAX_STATES	2
17477dfe2fSKeerthy 
18477dfe2fSKeerthy DECLARE_GLOBAL_DATA_PTR;
19477dfe2fSKeerthy 
20477dfe2fSKeerthy struct gpio_regulator_platdata {
21477dfe2fSKeerthy 	struct gpio_desc gpio; /* GPIO for regulator voltage control */
22477dfe2fSKeerthy 	int states[GPIO_REGULATOR_MAX_STATES];
23477dfe2fSKeerthy 	int voltages[GPIO_REGULATOR_MAX_STATES];
24477dfe2fSKeerthy };
25477dfe2fSKeerthy 
gpio_regulator_ofdata_to_platdata(struct udevice * dev)26477dfe2fSKeerthy static int gpio_regulator_ofdata_to_platdata(struct udevice *dev)
27477dfe2fSKeerthy {
28477dfe2fSKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
29477dfe2fSKeerthy 	struct gpio_regulator_platdata *dev_pdata;
30477dfe2fSKeerthy 	struct gpio_desc *gpio;
31477dfe2fSKeerthy 	const void *blob = gd->fdt_blob;
32e160f7d4SSimon Glass 	int node = dev_of_offset(dev);
33477dfe2fSKeerthy 	int ret, count, i, j;
34477dfe2fSKeerthy 	u32 states_array[8];
35477dfe2fSKeerthy 
36477dfe2fSKeerthy 	dev_pdata = dev_get_platdata(dev);
37477dfe2fSKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
38477dfe2fSKeerthy 	if (!uc_pdata)
39477dfe2fSKeerthy 		return -ENXIO;
40477dfe2fSKeerthy 
41477dfe2fSKeerthy 	/* Set type to gpio */
42477dfe2fSKeerthy 	uc_pdata->type = REGULATOR_TYPE_GPIO;
43477dfe2fSKeerthy 
44477dfe2fSKeerthy 	/*
45477dfe2fSKeerthy 	 * Get gpio regulator gpio desc
46477dfe2fSKeerthy 	 * Assuming one GPIO per regulator.
47477dfe2fSKeerthy 	 * Can be extended later to multiple GPIOs
48477dfe2fSKeerthy 	 * per gpio-regulator. As of now no instance with multiple
49477dfe2fSKeerthy 	 * gpios is presnt
50477dfe2fSKeerthy 	 */
51477dfe2fSKeerthy 	gpio = &dev_pdata->gpio;
52477dfe2fSKeerthy 	ret = gpio_request_by_name(dev, "gpios", 0, gpio, GPIOD_IS_OUT);
53477dfe2fSKeerthy 	if (ret)
54477dfe2fSKeerthy 		debug("regulator gpio - not found! Error: %d", ret);
55477dfe2fSKeerthy 
56477dfe2fSKeerthy 	count = fdtdec_get_int_array_count(blob, node, "states",
57477dfe2fSKeerthy 					   states_array, 8);
58477dfe2fSKeerthy 
59477dfe2fSKeerthy 	if (!count)
60477dfe2fSKeerthy 		return -EINVAL;
61477dfe2fSKeerthy 
62477dfe2fSKeerthy 	for (i = 0, j = 0; i < count; i += 2) {
63477dfe2fSKeerthy 		dev_pdata->voltages[j] = states_array[i];
64477dfe2fSKeerthy 		dev_pdata->states[j] = states_array[i + 1];
65477dfe2fSKeerthy 		j++;
66477dfe2fSKeerthy 	}
67477dfe2fSKeerthy 
68477dfe2fSKeerthy 	return 0;
69477dfe2fSKeerthy }
70477dfe2fSKeerthy 
gpio_regulator_get_value(struct udevice * dev)71477dfe2fSKeerthy static int gpio_regulator_get_value(struct udevice *dev)
72477dfe2fSKeerthy {
73477dfe2fSKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
74477dfe2fSKeerthy 	struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev);
75477dfe2fSKeerthy 	int enable;
76477dfe2fSKeerthy 
77477dfe2fSKeerthy 	if (!dev_pdata->gpio.dev)
78477dfe2fSKeerthy 		return -ENOSYS;
79477dfe2fSKeerthy 
80477dfe2fSKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
81477dfe2fSKeerthy 	if (uc_pdata->min_uV > uc_pdata->max_uV) {
82477dfe2fSKeerthy 		debug("Invalid constraints for: %s\n", uc_pdata->name);
83477dfe2fSKeerthy 		return -EINVAL;
84477dfe2fSKeerthy 	}
85477dfe2fSKeerthy 
86477dfe2fSKeerthy 	enable = dm_gpio_get_value(&dev_pdata->gpio);
87477dfe2fSKeerthy 	if (enable == dev_pdata->states[0])
88477dfe2fSKeerthy 		return dev_pdata->voltages[0];
89477dfe2fSKeerthy 	else
90477dfe2fSKeerthy 		return dev_pdata->voltages[1];
91477dfe2fSKeerthy }
92477dfe2fSKeerthy 
gpio_regulator_set_value(struct udevice * dev,int uV)93477dfe2fSKeerthy static int gpio_regulator_set_value(struct udevice *dev, int uV)
94477dfe2fSKeerthy {
95477dfe2fSKeerthy 	struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev);
96477dfe2fSKeerthy 	int ret;
97477dfe2fSKeerthy 	bool enable;
98477dfe2fSKeerthy 
99477dfe2fSKeerthy 	if (!dev_pdata->gpio.dev)
100477dfe2fSKeerthy 		return -ENOSYS;
101477dfe2fSKeerthy 
102477dfe2fSKeerthy 	if (uV == dev_pdata->voltages[0])
103477dfe2fSKeerthy 		enable = dev_pdata->states[0];
104477dfe2fSKeerthy 	else if (uV == dev_pdata->voltages[1])
105477dfe2fSKeerthy 		enable = dev_pdata->states[1];
106477dfe2fSKeerthy 	else
107477dfe2fSKeerthy 		return -EINVAL;
108477dfe2fSKeerthy 
109477dfe2fSKeerthy 	ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
110477dfe2fSKeerthy 	if (ret) {
1119b643e31SMasahiro Yamada 		pr_err("Can't set regulator : %s gpio to: %d\n", dev->name,
112477dfe2fSKeerthy 		      enable);
113477dfe2fSKeerthy 		return ret;
114477dfe2fSKeerthy 	}
115477dfe2fSKeerthy 
116477dfe2fSKeerthy 	return 0;
117477dfe2fSKeerthy }
118477dfe2fSKeerthy 
119477dfe2fSKeerthy static const struct dm_regulator_ops gpio_regulator_ops = {
120477dfe2fSKeerthy 	.get_value	= gpio_regulator_get_value,
121477dfe2fSKeerthy 	.set_value	= gpio_regulator_set_value,
122477dfe2fSKeerthy };
123477dfe2fSKeerthy 
124477dfe2fSKeerthy static const struct udevice_id gpio_regulator_ids[] = {
125477dfe2fSKeerthy 	{ .compatible = "regulator-gpio" },
126477dfe2fSKeerthy 	{ },
127477dfe2fSKeerthy };
128477dfe2fSKeerthy 
129477dfe2fSKeerthy U_BOOT_DRIVER(gpio_regulator) = {
130477dfe2fSKeerthy 	.name = "gpio regulator",
131477dfe2fSKeerthy 	.id = UCLASS_REGULATOR,
132477dfe2fSKeerthy 	.ops = &gpio_regulator_ops,
133477dfe2fSKeerthy 	.of_match = gpio_regulator_ids,
134477dfe2fSKeerthy 	.ofdata_to_platdata = gpio_regulator_ofdata_to_platdata,
135477dfe2fSKeerthy 	.platdata_auto_alloc_size = sizeof(struct gpio_regulator_platdata),
136477dfe2fSKeerthy };
137