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