xref: /linux/drivers/gpio/gpio-macsmc.c (revision ca220141fa8ebae09765a242076b2b77338106b0)
1 // SPDX-License-Identifier: GPL-2.0-only OR MIT
2 /*
3  * Apple SMC GPIO driver
4  * Copyright The Asahi Linux Contributors
5  *
6  * This driver implements basic SMC PMU GPIO support that can read inputs
7  * and write outputs. Mode changes and IRQ config are not yet implemented.
8  */
9 
10 #include <linux/bitmap.h>
11 #include <linux/device.h>
12 #include <linux/gpio/driver.h>
13 #include <linux/hex.h>
14 #include <linux/mfd/core.h>
15 #include <linux/mfd/macsmc.h>
16 
17 #define MAX_GPIO 64
18 
19 /*
20  * Commands 0-6 are, presumably, the intended API.
21  * Command 0xff lets you get/set the pin configuration in detail directly,
22  * but the bit meanings seem not to be stable between devices/PMU hardware
23  * versions.
24  *
25  * We're going to try to make do with the low commands for now.
26  * We don't implement pin mode changes at this time.
27  */
28 
29 #define CMD_ACTION	(0 << 24)
30 #define CMD_OUTPUT	(1 << 24)
31 #define CMD_INPUT	(2 << 24)
32 #define CMD_PINMODE	(3 << 24)
33 #define CMD_IRQ_ENABLE	(4 << 24)
34 #define CMD_IRQ_ACK	(5 << 24)
35 #define CMD_IRQ_MODE	(6 << 24)
36 #define CMD_CONFIG	(0xff << 24)
37 
38 #define MODE_INPUT	0
39 #define MODE_OUTPUT	1
40 #define MODE_VALUE_0	0
41 #define MODE_VALUE_1	2
42 
43 #define IRQ_MODE_HIGH		0
44 #define IRQ_MODE_LOW		1
45 #define IRQ_MODE_RISING		2
46 #define IRQ_MODE_FALLING	3
47 #define IRQ_MODE_BOTH		4
48 
49 #define CONFIG_MASK	GENMASK(23, 16)
50 #define CONFIG_VAL	GENMASK(7, 0)
51 
52 #define CONFIG_OUTMODE	GENMASK(7, 6)
53 #define CONFIG_IRQMODE	GENMASK(5, 3)
54 #define CONFIG_PULLDOWN	BIT(2)
55 #define CONFIG_PULLUP	BIT(1)
56 #define CONFIG_OUTVAL	BIT(0)
57 
58 /*
59  * Output modes seem to differ depending on the PMU in use... ?
60  * j274 / M1 (Sera PMU):
61  *   0 = input
62  *   1 = output
63  *   2 = open drain
64  *   3 = disable
65  * j314 / M1Pro (Maverick PMU):
66  *   0 = input
67  *   1 = open drain
68  *   2 = output
69  *   3 = ?
70  */
71 
72 struct macsmc_gpio {
73 	struct device *dev;
74 	struct apple_smc *smc;
75 	struct gpio_chip gc;
76 
77 	int first_index;
78 };
79 
80 static int macsmc_gpio_nr(smc_key key)
81 {
82 	int low = hex_to_bin(key & 0xff);
83 	int high = hex_to_bin((key >> 8) & 0xff);
84 
85 	if (low < 0 || high < 0)
86 		return -1;
87 
88 	return low | (high << 4);
89 }
90 
91 static int macsmc_gpio_key(unsigned int offset)
92 {
93 	return _SMC_KEY("gP\0\0") | hex_asc_hi(offset) << 8 | hex_asc_lo(offset);
94 }
95 
96 static int macsmc_gpio_find_first_gpio_index(struct macsmc_gpio *smcgp)
97 {
98 	struct apple_smc *smc = smcgp->smc;
99 	smc_key key = macsmc_gpio_key(0);
100 	smc_key first_key, last_key;
101 	int start, count, ret;
102 
103 	/* Return early if the key is out of bounds */
104 	ret = apple_smc_get_key_by_index(smc, 0, &first_key);
105 	if (ret)
106 		return ret;
107 	if (key <= first_key)
108 		return -ENODEV;
109 
110 	ret = apple_smc_get_key_by_index(smc, smc->key_count - 1, &last_key);
111 	if (ret)
112 		return ret;
113 	if (key > last_key)
114 		return -ENODEV;
115 
116 	/* Binary search to find index of first SMC key bigger or equal to key */
117 	start = 0;
118 	count = smc->key_count;
119 	while (count > 1) {
120 		smc_key pkey;
121 		int pivot = start + ((count - 1) >> 1);
122 
123 		ret = apple_smc_get_key_by_index(smc, pivot, &pkey);
124 		if (ret < 0)
125 			return ret;
126 
127 		if (pkey == key)
128 			return pivot;
129 
130 		pivot++;
131 
132 		if (pkey < key) {
133 			count -= pivot - start;
134 			start = pivot;
135 		} else {
136 			count = pivot - start;
137 		}
138 	}
139 
140 	return start;
141 }
142 
143 static int macsmc_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
144 {
145 	struct macsmc_gpio *smcgp = gpiochip_get_data(gc);
146 	smc_key key = macsmc_gpio_key(offset);
147 	u32 val;
148 	int ret;
149 
150 	/* First try reading the explicit pin mode register */
151 	ret = apple_smc_rw_u32(smcgp->smc, key, CMD_PINMODE, &val);
152 	if (!ret)
153 		return (val & MODE_OUTPUT) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
154 
155 	/*
156 	 * Less common IRQ configs cause CMD_PINMODE to fail, and so does open drain mode.
157 	 * Fall back to reading IRQ mode, which will only succeed for inputs.
158 	 */
159 	ret = apple_smc_rw_u32(smcgp->smc, key, CMD_IRQ_MODE, &val);
160 	return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
161 }
162 
163 static int macsmc_gpio_get(struct gpio_chip *gc, unsigned int offset)
164 {
165 	struct macsmc_gpio *smcgp = gpiochip_get_data(gc);
166 	smc_key key = macsmc_gpio_key(offset);
167 	u32 cmd, val;
168 	int ret;
169 
170 	ret = macsmc_gpio_get_direction(gc, offset);
171 	if (ret < 0)
172 		return ret;
173 
174 	if (ret == GPIO_LINE_DIRECTION_OUT)
175 		cmd = CMD_OUTPUT;
176 	else
177 		cmd = CMD_INPUT;
178 
179 	ret = apple_smc_rw_u32(smcgp->smc, key, cmd, &val);
180 	if (ret < 0)
181 		return ret;
182 
183 	return val ? 1 : 0;
184 }
185 
186 static int macsmc_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
187 {
188 	struct macsmc_gpio *smcgp = gpiochip_get_data(gc);
189 	smc_key key = macsmc_gpio_key(offset);
190 	int ret;
191 
192 	value |= CMD_OUTPUT;
193 	ret = apple_smc_write_u32(smcgp->smc, key, CMD_OUTPUT | value);
194 	if (ret < 0)
195 		dev_err(smcgp->dev, "GPIO set failed %p4ch = 0x%x\n",
196 			&key, value);
197 
198 	return ret;
199 }
200 
201 static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc,
202 				       unsigned long *valid_mask, unsigned int ngpios)
203 {
204 	struct macsmc_gpio *smcgp = gpiochip_get_data(gc);
205 	int count;
206 	int i;
207 
208 	count = min(smcgp->smc->key_count, MAX_GPIO);
209 
210 	bitmap_zero(valid_mask, ngpios);
211 
212 	for (i = 0; i < count; i++) {
213 		int ret, gpio_nr;
214 		smc_key key;
215 
216 		ret = apple_smc_get_key_by_index(smcgp->smc, smcgp->first_index + i, &key);
217 		if (ret < 0)
218 			return ret;
219 
220 		if (key > SMC_KEY(gPff))
221 			break;
222 
223 		gpio_nr = macsmc_gpio_nr(key);
224 		if (gpio_nr < 0 || gpio_nr > MAX_GPIO) {
225 			dev_err(smcgp->dev, "Bad GPIO key %p4ch\n", &key);
226 			continue;
227 		}
228 
229 		set_bit(gpio_nr, valid_mask);
230 	}
231 
232 	return 0;
233 }
234 
235 static int macsmc_gpio_probe(struct platform_device *pdev)
236 {
237 	struct macsmc_gpio *smcgp;
238 	struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
239 	smc_key key;
240 	int ret;
241 
242 	smcgp = devm_kzalloc(&pdev->dev, sizeof(*smcgp), GFP_KERNEL);
243 	if (!smcgp)
244 		return -ENOMEM;
245 
246 	smcgp->dev = &pdev->dev;
247 	smcgp->smc = smc;
248 
249 	smcgp->first_index = macsmc_gpio_find_first_gpio_index(smcgp);
250 	if (smcgp->first_index < 0)
251 		return smcgp->first_index;
252 
253 	ret = apple_smc_get_key_by_index(smc, smcgp->first_index, &key);
254 	if (ret < 0)
255 		return ret;
256 
257 	if (key > macsmc_gpio_key(MAX_GPIO - 1))
258 		return -ENODEV;
259 
260 	dev_info(smcgp->dev, "First GPIO key: %p4ch\n", &key);
261 
262 	smcgp->gc.label = "macsmc-pmu-gpio";
263 	smcgp->gc.owner = THIS_MODULE;
264 	smcgp->gc.get = macsmc_gpio_get;
265 	smcgp->gc.set = macsmc_gpio_set;
266 	smcgp->gc.get_direction = macsmc_gpio_get_direction;
267 	smcgp->gc.init_valid_mask = macsmc_gpio_init_valid_mask;
268 	smcgp->gc.can_sleep = true;
269 	smcgp->gc.ngpio = MAX_GPIO;
270 	smcgp->gc.base = -1;
271 	smcgp->gc.parent = &pdev->dev;
272 
273 	return devm_gpiochip_add_data(&pdev->dev, &smcgp->gc, smcgp);
274 }
275 
276 static const struct of_device_id macsmc_gpio_of_table[] = {
277 	{ .compatible = "apple,smc-gpio", },
278 	{}
279 };
280 MODULE_DEVICE_TABLE(of, macsmc_gpio_of_table);
281 
282 static struct platform_driver macsmc_gpio_driver = {
283 	.driver = {
284 		.name = "macsmc-gpio",
285 		.of_match_table = macsmc_gpio_of_table,
286 	},
287 	.probe = macsmc_gpio_probe,
288 };
289 module_platform_driver(macsmc_gpio_driver);
290 
291 MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
292 MODULE_LICENSE("Dual MIT/GPL");
293 MODULE_DESCRIPTION("Apple SMC GPIO driver");
294