19b21051bSHector Martin // SPDX-License-Identifier: GPL-2.0-only OR MIT
29b21051bSHector Martin /*
39b21051bSHector Martin * Apple SMC GPIO driver
49b21051bSHector Martin * Copyright The Asahi Linux Contributors
59b21051bSHector Martin *
69b21051bSHector Martin * This driver implements basic SMC PMU GPIO support that can read inputs
79b21051bSHector Martin * and write outputs. Mode changes and IRQ config are not yet implemented.
89b21051bSHector Martin */
99b21051bSHector Martin
109b21051bSHector Martin #include <linux/bitmap.h>
119b21051bSHector Martin #include <linux/device.h>
129b21051bSHector Martin #include <linux/gpio/driver.h>
139b21051bSHector Martin #include <linux/mfd/core.h>
149b21051bSHector Martin #include <linux/mfd/macsmc.h>
159b21051bSHector Martin
169b21051bSHector Martin #define MAX_GPIO 64
179b21051bSHector Martin
189b21051bSHector Martin /*
199b21051bSHector Martin * Commands 0-6 are, presumably, the intended API.
209b21051bSHector Martin * Command 0xff lets you get/set the pin configuration in detail directly,
219b21051bSHector Martin * but the bit meanings seem not to be stable between devices/PMU hardware
229b21051bSHector Martin * versions.
239b21051bSHector Martin *
249b21051bSHector Martin * We're going to try to make do with the low commands for now.
259b21051bSHector Martin * We don't implement pin mode changes at this time.
269b21051bSHector Martin */
279b21051bSHector Martin
289b21051bSHector Martin #define CMD_ACTION (0 << 24)
299b21051bSHector Martin #define CMD_OUTPUT (1 << 24)
309b21051bSHector Martin #define CMD_INPUT (2 << 24)
319b21051bSHector Martin #define CMD_PINMODE (3 << 24)
329b21051bSHector Martin #define CMD_IRQ_ENABLE (4 << 24)
339b21051bSHector Martin #define CMD_IRQ_ACK (5 << 24)
349b21051bSHector Martin #define CMD_IRQ_MODE (6 << 24)
359b21051bSHector Martin #define CMD_CONFIG (0xff << 24)
369b21051bSHector Martin
379b21051bSHector Martin #define MODE_INPUT 0
389b21051bSHector Martin #define MODE_OUTPUT 1
399b21051bSHector Martin #define MODE_VALUE_0 0
409b21051bSHector Martin #define MODE_VALUE_1 2
419b21051bSHector Martin
429b21051bSHector Martin #define IRQ_MODE_HIGH 0
439b21051bSHector Martin #define IRQ_MODE_LOW 1
449b21051bSHector Martin #define IRQ_MODE_RISING 2
459b21051bSHector Martin #define IRQ_MODE_FALLING 3
469b21051bSHector Martin #define IRQ_MODE_BOTH 4
479b21051bSHector Martin
489b21051bSHector Martin #define CONFIG_MASK GENMASK(23, 16)
499b21051bSHector Martin #define CONFIG_VAL GENMASK(7, 0)
509b21051bSHector Martin
519b21051bSHector Martin #define CONFIG_OUTMODE GENMASK(7, 6)
529b21051bSHector Martin #define CONFIG_IRQMODE GENMASK(5, 3)
539b21051bSHector Martin #define CONFIG_PULLDOWN BIT(2)
549b21051bSHector Martin #define CONFIG_PULLUP BIT(1)
559b21051bSHector Martin #define CONFIG_OUTVAL BIT(0)
569b21051bSHector Martin
579b21051bSHector Martin /*
589b21051bSHector Martin * Output modes seem to differ depending on the PMU in use... ?
599b21051bSHector Martin * j274 / M1 (Sera PMU):
609b21051bSHector Martin * 0 = input
619b21051bSHector Martin * 1 = output
629b21051bSHector Martin * 2 = open drain
639b21051bSHector Martin * 3 = disable
649b21051bSHector Martin * j314 / M1Pro (Maverick PMU):
659b21051bSHector Martin * 0 = input
669b21051bSHector Martin * 1 = open drain
679b21051bSHector Martin * 2 = output
689b21051bSHector Martin * 3 = ?
699b21051bSHector Martin */
709b21051bSHector Martin
719b21051bSHector Martin struct macsmc_gpio {
729b21051bSHector Martin struct device *dev;
739b21051bSHector Martin struct apple_smc *smc;
749b21051bSHector Martin struct gpio_chip gc;
759b21051bSHector Martin
769b21051bSHector Martin int first_index;
779b21051bSHector Martin };
789b21051bSHector Martin
macsmc_gpio_nr(smc_key key)799b21051bSHector Martin static int macsmc_gpio_nr(smc_key key)
809b21051bSHector Martin {
819b21051bSHector Martin int low = hex_to_bin(key & 0xff);
829b21051bSHector Martin int high = hex_to_bin((key >> 8) & 0xff);
839b21051bSHector Martin
849b21051bSHector Martin if (low < 0 || high < 0)
859b21051bSHector Martin return -1;
869b21051bSHector Martin
879b21051bSHector Martin return low | (high << 4);
889b21051bSHector Martin }
899b21051bSHector Martin
macsmc_gpio_key(unsigned int offset)909b21051bSHector Martin static int macsmc_gpio_key(unsigned int offset)
919b21051bSHector Martin {
929b21051bSHector Martin return _SMC_KEY("gP\0\0") | hex_asc_hi(offset) << 8 | hex_asc_lo(offset);
939b21051bSHector Martin }
949b21051bSHector Martin
macsmc_gpio_find_first_gpio_index(struct macsmc_gpio * smcgp)959b21051bSHector Martin static int macsmc_gpio_find_first_gpio_index(struct macsmc_gpio *smcgp)
969b21051bSHector Martin {
979b21051bSHector Martin struct apple_smc *smc = smcgp->smc;
989b21051bSHector Martin smc_key key = macsmc_gpio_key(0);
999b21051bSHector Martin smc_key first_key, last_key;
1009b21051bSHector Martin int start, count, ret;
1019b21051bSHector Martin
1029b21051bSHector Martin /* Return early if the key is out of bounds */
1039b21051bSHector Martin ret = apple_smc_get_key_by_index(smc, 0, &first_key);
1049b21051bSHector Martin if (ret)
1059b21051bSHector Martin return ret;
1069b21051bSHector Martin if (key <= first_key)
1079b21051bSHector Martin return -ENODEV;
1089b21051bSHector Martin
1099b21051bSHector Martin ret = apple_smc_get_key_by_index(smc, smc->key_count - 1, &last_key);
1109b21051bSHector Martin if (ret)
1119b21051bSHector Martin return ret;
1129b21051bSHector Martin if (key > last_key)
1139b21051bSHector Martin return -ENODEV;
1149b21051bSHector Martin
1159b21051bSHector Martin /* Binary search to find index of first SMC key bigger or equal to key */
1169b21051bSHector Martin start = 0;
1179b21051bSHector Martin count = smc->key_count;
1189b21051bSHector Martin while (count > 1) {
1199b21051bSHector Martin smc_key pkey;
1209b21051bSHector Martin int pivot = start + ((count - 1) >> 1);
1219b21051bSHector Martin
1229b21051bSHector Martin ret = apple_smc_get_key_by_index(smc, pivot, &pkey);
1239b21051bSHector Martin if (ret < 0)
1249b21051bSHector Martin return ret;
1259b21051bSHector Martin
1269b21051bSHector Martin if (pkey == key)
1279b21051bSHector Martin return pivot;
1289b21051bSHector Martin
1299b21051bSHector Martin pivot++;
1309b21051bSHector Martin
1319b21051bSHector Martin if (pkey < key) {
1329b21051bSHector Martin count -= pivot - start;
1339b21051bSHector Martin start = pivot;
1349b21051bSHector Martin } else {
1359b21051bSHector Martin count = pivot - start;
1369b21051bSHector Martin }
1379b21051bSHector Martin }
1389b21051bSHector Martin
1399b21051bSHector Martin return start;
1409b21051bSHector Martin }
1419b21051bSHector Martin
macsmc_gpio_get_direction(struct gpio_chip * gc,unsigned int offset)1429b21051bSHector Martin static int macsmc_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
1439b21051bSHector Martin {
1449b21051bSHector Martin struct macsmc_gpio *smcgp = gpiochip_get_data(gc);
1459b21051bSHector Martin smc_key key = macsmc_gpio_key(offset);
1469b21051bSHector Martin u32 val;
1479b21051bSHector Martin int ret;
1489b21051bSHector Martin
1499b21051bSHector Martin /* First try reading the explicit pin mode register */
1509b21051bSHector Martin ret = apple_smc_rw_u32(smcgp->smc, key, CMD_PINMODE, &val);
1519b21051bSHector Martin if (!ret)
1529b21051bSHector Martin return (val & MODE_OUTPUT) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
1539b21051bSHector Martin
1549b21051bSHector Martin /*
1559b21051bSHector Martin * Less common IRQ configs cause CMD_PINMODE to fail, and so does open drain mode.
1569b21051bSHector Martin * Fall back to reading IRQ mode, which will only succeed for inputs.
1579b21051bSHector Martin */
1589b21051bSHector Martin ret = apple_smc_rw_u32(smcgp->smc, key, CMD_IRQ_MODE, &val);
1599b21051bSHector Martin return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
1609b21051bSHector Martin }
1619b21051bSHector Martin
macsmc_gpio_get(struct gpio_chip * gc,unsigned int offset)1629b21051bSHector Martin static int macsmc_gpio_get(struct gpio_chip *gc, unsigned int offset)
1639b21051bSHector Martin {
1649b21051bSHector Martin struct macsmc_gpio *smcgp = gpiochip_get_data(gc);
1659b21051bSHector Martin smc_key key = macsmc_gpio_key(offset);
1669b21051bSHector Martin u32 cmd, val;
1679b21051bSHector Martin int ret;
1689b21051bSHector Martin
1699b21051bSHector Martin ret = macsmc_gpio_get_direction(gc, offset);
1709b21051bSHector Martin if (ret < 0)
1719b21051bSHector Martin return ret;
1729b21051bSHector Martin
1739b21051bSHector Martin if (ret == GPIO_LINE_DIRECTION_OUT)
1749b21051bSHector Martin cmd = CMD_OUTPUT;
1759b21051bSHector Martin else
1769b21051bSHector Martin cmd = CMD_INPUT;
1779b21051bSHector Martin
1789b21051bSHector Martin ret = apple_smc_rw_u32(smcgp->smc, key, cmd, &val);
1799b21051bSHector Martin if (ret < 0)
1809b21051bSHector Martin return ret;
1819b21051bSHector Martin
1829b21051bSHector Martin return val ? 1 : 0;
1839b21051bSHector Martin }
1849b21051bSHector Martin
macsmc_gpio_set(struct gpio_chip * gc,unsigned int offset,int value)1859b21051bSHector Martin static int macsmc_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
1869b21051bSHector Martin {
1879b21051bSHector Martin struct macsmc_gpio *smcgp = gpiochip_get_data(gc);
1889b21051bSHector Martin smc_key key = macsmc_gpio_key(offset);
1899b21051bSHector Martin int ret;
1909b21051bSHector Martin
1919b21051bSHector Martin value |= CMD_OUTPUT;
1929b21051bSHector Martin ret = apple_smc_write_u32(smcgp->smc, key, CMD_OUTPUT | value);
1939b21051bSHector Martin if (ret < 0)
1949b21051bSHector Martin dev_err(smcgp->dev, "GPIO set failed %p4ch = 0x%x\n",
1959b21051bSHector Martin &key, value);
1969b21051bSHector Martin
1979b21051bSHector Martin return ret;
1989b21051bSHector Martin }
1999b21051bSHector Martin
macsmc_gpio_init_valid_mask(struct gpio_chip * gc,unsigned long * valid_mask,unsigned int ngpios)2009b21051bSHector Martin static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc,
2019b21051bSHector Martin unsigned long *valid_mask, unsigned int ngpios)
2029b21051bSHector Martin {
2039b21051bSHector Martin struct macsmc_gpio *smcgp = gpiochip_get_data(gc);
2049b21051bSHector Martin int count;
2059b21051bSHector Martin int i;
2069b21051bSHector Martin
2079b21051bSHector Martin count = min(smcgp->smc->key_count, MAX_GPIO);
2089b21051bSHector Martin
2099b21051bSHector Martin bitmap_zero(valid_mask, ngpios);
2109b21051bSHector Martin
2119b21051bSHector Martin for (i = 0; i < count; i++) {
2129b21051bSHector Martin int ret, gpio_nr;
2139b21051bSHector Martin smc_key key;
2149b21051bSHector Martin
2159b21051bSHector Martin ret = apple_smc_get_key_by_index(smcgp->smc, smcgp->first_index + i, &key);
2169b21051bSHector Martin if (ret < 0)
2179b21051bSHector Martin return ret;
2189b21051bSHector Martin
2199b21051bSHector Martin if (key > SMC_KEY(gPff))
2209b21051bSHector Martin break;
2219b21051bSHector Martin
2229b21051bSHector Martin gpio_nr = macsmc_gpio_nr(key);
2239b21051bSHector Martin if (gpio_nr < 0 || gpio_nr > MAX_GPIO) {
2249b21051bSHector Martin dev_err(smcgp->dev, "Bad GPIO key %p4ch\n", &key);
2259b21051bSHector Martin continue;
2269b21051bSHector Martin }
2279b21051bSHector Martin
2289b21051bSHector Martin set_bit(gpio_nr, valid_mask);
2299b21051bSHector Martin }
2309b21051bSHector Martin
2319b21051bSHector Martin return 0;
2329b21051bSHector Martin }
2339b21051bSHector Martin
macsmc_gpio_probe(struct platform_device * pdev)2349b21051bSHector Martin static int macsmc_gpio_probe(struct platform_device *pdev)
2359b21051bSHector Martin {
2369b21051bSHector Martin struct macsmc_gpio *smcgp;
2379b21051bSHector Martin struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
2389b21051bSHector Martin smc_key key;
2399b21051bSHector Martin int ret;
2409b21051bSHector Martin
2419b21051bSHector Martin smcgp = devm_kzalloc(&pdev->dev, sizeof(*smcgp), GFP_KERNEL);
2429b21051bSHector Martin if (!smcgp)
2439b21051bSHector Martin return -ENOMEM;
2449b21051bSHector Martin
2459b21051bSHector Martin smcgp->dev = &pdev->dev;
2469b21051bSHector Martin smcgp->smc = smc;
2479b21051bSHector Martin
2489b21051bSHector Martin smcgp->first_index = macsmc_gpio_find_first_gpio_index(smcgp);
2499b21051bSHector Martin if (smcgp->first_index < 0)
2509b21051bSHector Martin return smcgp->first_index;
2519b21051bSHector Martin
2529b21051bSHector Martin ret = apple_smc_get_key_by_index(smc, smcgp->first_index, &key);
2539b21051bSHector Martin if (ret < 0)
2549b21051bSHector Martin return ret;
2559b21051bSHector Martin
2569b21051bSHector Martin if (key > macsmc_gpio_key(MAX_GPIO - 1))
2579b21051bSHector Martin return -ENODEV;
2589b21051bSHector Martin
2599b21051bSHector Martin dev_info(smcgp->dev, "First GPIO key: %p4ch\n", &key);
2609b21051bSHector Martin
2619b21051bSHector Martin smcgp->gc.label = "macsmc-pmu-gpio";
2629b21051bSHector Martin smcgp->gc.owner = THIS_MODULE;
2639b21051bSHector Martin smcgp->gc.get = macsmc_gpio_get;
264*d9d87d90SBartosz Golaszewski smcgp->gc.set = macsmc_gpio_set;
2659b21051bSHector Martin smcgp->gc.get_direction = macsmc_gpio_get_direction;
2669b21051bSHector Martin smcgp->gc.init_valid_mask = macsmc_gpio_init_valid_mask;
2679b21051bSHector Martin smcgp->gc.can_sleep = true;
2689b21051bSHector Martin smcgp->gc.ngpio = MAX_GPIO;
2699b21051bSHector Martin smcgp->gc.base = -1;
2709b21051bSHector Martin smcgp->gc.parent = &pdev->dev;
2719b21051bSHector Martin
2729b21051bSHector Martin return devm_gpiochip_add_data(&pdev->dev, &smcgp->gc, smcgp);
2739b21051bSHector Martin }
2749b21051bSHector Martin
2759b21051bSHector Martin static const struct of_device_id macsmc_gpio_of_table[] = {
2769b21051bSHector Martin { .compatible = "apple,smc-gpio", },
2779b21051bSHector Martin {}
2789b21051bSHector Martin };
2799b21051bSHector Martin MODULE_DEVICE_TABLE(of, macsmc_gpio_of_table);
2809b21051bSHector Martin
2819b21051bSHector Martin static struct platform_driver macsmc_gpio_driver = {
2829b21051bSHector Martin .driver = {
2839b21051bSHector Martin .name = "macsmc-gpio",
2849b21051bSHector Martin .of_match_table = macsmc_gpio_of_table,
2859b21051bSHector Martin },
2869b21051bSHector Martin .probe = macsmc_gpio_probe,
2879b21051bSHector Martin };
2889b21051bSHector Martin module_platform_driver(macsmc_gpio_driver);
2899b21051bSHector Martin
2909b21051bSHector Martin MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
2919b21051bSHector Martin MODULE_LICENSE("Dual MIT/GPL");
2929b21051bSHector Martin MODULE_DESCRIPTION("Apple SMC GPIO driver");
293