xref: /linux/drivers/gpio/gpio-macsmc.c (revision d9d87d90cc0b10cd56ae353f50b11417e7d21712)
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 
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 
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 
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 
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 
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 
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 
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 
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