at master 6.9 kB view raw
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 71struct macsmc_gpio { 72 struct device *dev; 73 struct apple_smc *smc; 74 struct gpio_chip gc; 75 76 int first_index; 77}; 78 79static 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 90static 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 95static 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 142static 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 162static 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 185static 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 200static 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 234static 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 275static const struct of_device_id macsmc_gpio_of_table[] = { 276 { .compatible = "apple,smc-gpio", }, 277 {} 278}; 279MODULE_DEVICE_TABLE(of, macsmc_gpio_of_table); 280 281static 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}; 288module_platform_driver(macsmc_gpio_driver); 289 290MODULE_AUTHOR("Hector Martin <marcan@marcan.st>"); 291MODULE_LICENSE("Dual MIT/GPL"); 292MODULE_DESCRIPTION("Apple SMC GPIO driver");