1// SPDX-License-Identifier: GPL-2.0+
2/*
3 *  Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#include <dm.h>
7#include <asm/gpio.h>
8#include <power/max77663.h>
9#include <power/pmic.h>
10
11#define NUM_ENTRIES				11 /* 8 GPIOs + 3 KEYs  */
12#define NUM_GPIOS				8
13
14#define MAX77663_CNFG1_GPIO			0x36
15#define GPIO_REG_ADDR(offset)			(MAX77663_CNFG1_GPIO + (offset))
16
17#define MAX77663_CNFG_GPIO_DIR_MASK		BIT(1)
18#define MAX77663_CNFG_GPIO_DIR_INPUT		BIT(1)
19#define MAX77663_CNFG_GPIO_DIR_OUTPUT		0
20#define MAX77663_CNFG_GPIO_INPUT_VAL_MASK	BIT(2)
21#define MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK	BIT(3)
22#define MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH	BIT(3)
23#define MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW	0
24#define MAX77663_CNFG_IRQ			GENMASK(5, 4)
25
26#define MAX77663_ONOFFSTAT_REG			0x15
27#define   EN0					BIT(2) /* KEY 2 */
28#define   ACOK					BIT(1) /* KEY 1 */
29#define   LID					BIT(0) /* KEY 0 */
30
31static int max77663_gpio_direction_input(struct udevice *dev, unsigned int offset)
32{
33	int ret;
34
35	if (offset >= NUM_GPIOS)
36		return 0;
37
38	ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset),
39			      MAX77663_CNFG_GPIO_DIR_MASK,
40			      MAX77663_CNFG_GPIO_DIR_INPUT);
41	if (ret < 0)
42		log_debug("%s: CNFG_GPIOx dir update failed: %d\n", __func__, ret);
43
44	return ret;
45}
46
47static int max77663_gpio_direction_output(struct udevice *dev, unsigned int offset,
48					  int value)
49{
50	u8 val;
51	int ret;
52
53	if (offset >= NUM_GPIOS)
54		return -EINVAL;
55
56	val = (value) ? MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH :
57				MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW;
58
59	ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset),
60			      MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK, val);
61	if (ret < 0) {
62		log_debug("%s: CNFG_GPIOx val update failed: %d\n", __func__, ret);
63		return ret;
64	}
65
66	ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset),
67			      MAX77663_CNFG_GPIO_DIR_MASK,
68			      MAX77663_CNFG_GPIO_DIR_OUTPUT);
69	if (ret < 0)
70		log_debug("%s: CNFG_GPIOx dir update failed: %d\n", __func__, ret);
71
72	return ret;
73}
74
75static int max77663_gpio_get_value(struct udevice *dev, unsigned int offset)
76{
77	int ret;
78
79	if (offset >= NUM_GPIOS) {
80		ret = pmic_reg_read(dev->parent, MAX77663_ONOFFSTAT_REG);
81		if (ret < 0) {
82			log_debug("%s: ONOFFSTAT_REG read failed: %d\n", __func__, ret);
83			return ret;
84		}
85
86		return !!(ret & BIT(offset - NUM_GPIOS));
87	}
88
89	ret = pmic_reg_read(dev->parent, GPIO_REG_ADDR(offset));
90	if (ret < 0) {
91		log_debug("%s: CNFG_GPIOx read failed: %d\n", __func__, ret);
92		return ret;
93	}
94
95	if (ret & MAX77663_CNFG_GPIO_DIR_MASK)
96		return !!(ret & MAX77663_CNFG_GPIO_INPUT_VAL_MASK);
97	else
98		return !!(ret & MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK);
99}
100
101static int max77663_gpio_set_value(struct udevice *dev, unsigned int offset,
102				   int value)
103{
104	u8 val;
105	int ret;
106
107	if (offset >= NUM_GPIOS)
108		return -EINVAL;
109
110	val = (value) ? MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH :
111				MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW;
112
113	ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset),
114			      MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK, val);
115	if (ret < 0)
116		log_debug("%s: CNFG_GPIO_OUT update failed: %d\n", __func__, ret);
117
118	return ret;
119}
120
121static int max77663_gpio_get_function(struct udevice *dev, unsigned int offset)
122{
123	int ret;
124
125	if (offset >= NUM_GPIOS)
126		return GPIOF_INPUT;
127
128	ret = pmic_reg_read(dev->parent, GPIO_REG_ADDR(offset));
129	if (ret < 0) {
130		log_debug("%s: CNFG_GPIOx read failed: %d\n", __func__, ret);
131		return ret;
132	}
133
134	if (ret & MAX77663_CNFG_GPIO_DIR_MASK)
135		return GPIOF_INPUT;
136	else
137		return GPIOF_OUTPUT;
138}
139
140static const struct dm_gpio_ops max77663_gpio_ops = {
141	.direction_input	= max77663_gpio_direction_input,
142	.direction_output	= max77663_gpio_direction_output,
143	.get_value		= max77663_gpio_get_value,
144	.set_value		= max77663_gpio_set_value,
145	.get_function		= max77663_gpio_get_function,
146};
147
148static int max77663_gpio_probe(struct udevice *dev)
149{
150	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
151	int i, ret;
152
153	uc_priv->gpio_count = NUM_ENTRIES;
154	uc_priv->bank_name = "GPIO";
155
156	/*
157	 * GPIO interrupts may be left ON after bootloader, hence let's
158	 * pre-initialize hardware to the expected state by disabling all
159	 * the interrupts.
160	 */
161	for (i = 0; i < NUM_GPIOS; i++) {
162		ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(i),
163				      MAX77663_CNFG_IRQ, 0);
164		if (ret < 0) {
165			log_debug("%s: failed to disable interrupt: %d\n", __func__, ret);
166			return ret;
167		}
168	}
169
170	return 0;
171}
172
173U_BOOT_DRIVER(max77663_gpio) = {
174	.name	= MAX77663_GPIO_DRIVER,
175	.id	= UCLASS_GPIO,
176	.probe	= max77663_gpio_probe,
177	.ops	= &max77663_gpio_ops,
178};
179