blob: ecb6047808850dc4b2fa83f8df1baa6b5bbbeaf1 [file] [log] [blame]
Svyatoslav Ryhel6b24c372023-07-15 22:25:03 +03001// 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};