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
macsmc_gpio_nr(smc_key key)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
macsmc_gpio_key(unsigned int offset)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
macsmc_gpio_find_first_gpio_index(struct macsmc_gpio * smcgp)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
macsmc_gpio_get_direction(struct gpio_chip * gc,unsigned int offset)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
macsmc_gpio_get(struct gpio_chip * gc,unsigned int offset)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
macsmc_gpio_set(struct gpio_chip * gc,unsigned int offset,int value)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
macsmc_gpio_init_valid_mask(struct gpio_chip * gc,unsigned long * valid_mask,unsigned int ngpios)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
macsmc_gpio_probe(struct platform_device * pdev)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