Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: Add support for TPS68470 GPIOs

This patch adds support for TPS68470 GPIOs.
There are 7 GPIOs and a few sensor related GPIOs.
These GPIOs can be requested and configured as
appropriate.

The GPIOs are also provided with descriptive names.
However, the typical use case is that the OS GPIO
driver will interact with TPS68470 GPIO driver
to configure these GPIOs, as requested by the
platform firmware.

Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Rajmohan Mani and committed by
Linus Walleij
275b13a6 5e7a0ce7

+192
+15
drivers/gpio/Kconfig
··· 1065 1065 help 1066 1066 This driver supports TPS65912 gpio chip 1067 1067 1068 + config GPIO_TPS68470 1069 + bool "TPS68470 GPIO" 1070 + depends on MFD_TPS68470 1071 + help 1072 + Select this option to enable GPIO driver for the TPS68470 1073 + chip family. 1074 + There are 7 GPIOs and few sensor related GPIOs supported 1075 + by the TPS68470. While the 7 GPIOs can be configured as 1076 + input or output as appropriate, the sensor related GPIOs 1077 + are "output only" GPIOs. 1078 + 1079 + This driver config is bool, as the GPIO functionality 1080 + of the TPS68470 must be available before dependent 1081 + drivers are loaded. 1082 + 1068 1083 config GPIO_TWL4030 1069 1084 tristate "TWL4030, TWL5030, and TPS659x0 GPIOs" 1070 1085 depends on TWL4030_CORE
+1
drivers/gpio/Makefile
··· 121 121 obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o 122 122 obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o 123 123 obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o 124 + obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o 124 125 obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o 125 126 obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o 126 127 obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
+176
drivers/gpio/gpio-tps68470.c
··· 1 + /* 2 + * GPIO driver for TPS68470 PMIC 3 + * 4 + * Copyright (C) 2017 Intel Corporation 5 + * 6 + * Authors: 7 + * Antti Laakso <antti.laakso@intel.com> 8 + * Tianshu Qiu <tian.shu.qiu@intel.com> 9 + * Jian Xu Zheng <jian.xu.zheng@intel.com> 10 + * Yuning Pu <yuning.pu@intel.com> 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License as 14 + * published by the Free Software Foundation version 2. 15 + * 16 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any 17 + * kind, whether express or implied; without even the implied warranty 18 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 + * GNU General Public License for more details. 20 + */ 21 + 22 + #include <linux/gpio/driver.h> 23 + #include <linux/mfd/tps68470.h> 24 + #include <linux/module.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/regmap.h> 27 + 28 + #define TPS68470_N_LOGIC_OUTPUT 3 29 + #define TPS68470_N_REGULAR_GPIO 7 30 + #define TPS68470_N_GPIO (TPS68470_N_LOGIC_OUTPUT + TPS68470_N_REGULAR_GPIO) 31 + 32 + struct tps68470_gpio_data { 33 + struct regmap *tps68470_regmap; 34 + struct gpio_chip gc; 35 + }; 36 + 37 + static int tps68470_gpio_get(struct gpio_chip *gc, unsigned int offset) 38 + { 39 + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); 40 + struct regmap *regmap = tps68470_gpio->tps68470_regmap; 41 + unsigned int reg = TPS68470_REG_GPDO; 42 + int val, ret; 43 + 44 + if (offset >= TPS68470_N_REGULAR_GPIO) { 45 + offset -= TPS68470_N_REGULAR_GPIO; 46 + reg = TPS68470_REG_SGPO; 47 + } 48 + 49 + ret = regmap_read(regmap, reg, &val); 50 + if (ret) { 51 + dev_err(tps68470_gpio->gc.parent, "reg 0x%x read failed\n", 52 + TPS68470_REG_SGPO); 53 + return ret; 54 + } 55 + return !!(val & BIT(offset)); 56 + } 57 + 58 + /* Return 0 if output, 1 if input */ 59 + static int tps68470_gpio_get_direction(struct gpio_chip *gc, 60 + unsigned int offset) 61 + { 62 + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); 63 + struct regmap *regmap = tps68470_gpio->tps68470_regmap; 64 + int val, ret; 65 + 66 + /* rest are always outputs */ 67 + if (offset >= TPS68470_N_REGULAR_GPIO) 68 + return 0; 69 + 70 + ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val); 71 + if (ret) { 72 + dev_err(tps68470_gpio->gc.parent, "reg 0x%x read failed\n", 73 + TPS68470_GPIO_CTL_REG_A(offset)); 74 + return ret; 75 + } 76 + 77 + val &= TPS68470_GPIO_MODE_MASK; 78 + return val >= TPS68470_GPIO_MODE_OUT_CMOS ? 0 : 1; 79 + } 80 + 81 + static void tps68470_gpio_set(struct gpio_chip *gc, unsigned int offset, 82 + int value) 83 + { 84 + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); 85 + struct regmap *regmap = tps68470_gpio->tps68470_regmap; 86 + unsigned int reg = TPS68470_REG_GPDO; 87 + 88 + if (offset >= TPS68470_N_REGULAR_GPIO) { 89 + reg = TPS68470_REG_SGPO; 90 + offset -= TPS68470_N_REGULAR_GPIO; 91 + } 92 + 93 + regmap_update_bits(regmap, reg, BIT(offset), value ? BIT(offset) : 0); 94 + } 95 + 96 + static int tps68470_gpio_output(struct gpio_chip *gc, unsigned int offset, 97 + int value) 98 + { 99 + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); 100 + struct regmap *regmap = tps68470_gpio->tps68470_regmap; 101 + 102 + /* rest are always outputs */ 103 + if (offset >= TPS68470_N_REGULAR_GPIO) 104 + return 0; 105 + 106 + /* Set the initial value */ 107 + tps68470_gpio_set(gc, offset, value); 108 + 109 + return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset), 110 + TPS68470_GPIO_MODE_MASK, 111 + TPS68470_GPIO_MODE_OUT_CMOS); 112 + } 113 + 114 + static int tps68470_gpio_input(struct gpio_chip *gc, unsigned int offset) 115 + { 116 + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); 117 + struct regmap *regmap = tps68470_gpio->tps68470_regmap; 118 + 119 + /* rest are always outputs */ 120 + if (offset >= TPS68470_N_REGULAR_GPIO) 121 + return -EINVAL; 122 + 123 + return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset), 124 + TPS68470_GPIO_MODE_MASK, 0x00); 125 + } 126 + 127 + static const char *tps68470_names[TPS68470_N_GPIO] = { 128 + "gpio.0", "gpio.1", "gpio.2", "gpio.3", 129 + "gpio.4", "gpio.5", "gpio.6", 130 + "s_enable", "s_idle", "s_resetn", 131 + }; 132 + 133 + static int tps68470_gpio_probe(struct platform_device *pdev) 134 + { 135 + struct tps68470_gpio_data *tps68470_gpio; 136 + int ret; 137 + 138 + tps68470_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps68470_gpio), 139 + GFP_KERNEL); 140 + if (!tps68470_gpio) 141 + return -ENOMEM; 142 + 143 + tps68470_gpio->tps68470_regmap = dev_get_drvdata(pdev->dev.parent); 144 + tps68470_gpio->gc.label = "tps68470-gpio"; 145 + tps68470_gpio->gc.owner = THIS_MODULE; 146 + tps68470_gpio->gc.direction_input = tps68470_gpio_input; 147 + tps68470_gpio->gc.direction_output = tps68470_gpio_output; 148 + tps68470_gpio->gc.get = tps68470_gpio_get; 149 + tps68470_gpio->gc.get_direction = tps68470_gpio_get_direction; 150 + tps68470_gpio->gc.set = tps68470_gpio_set; 151 + tps68470_gpio->gc.can_sleep = true; 152 + tps68470_gpio->gc.names = tps68470_names; 153 + tps68470_gpio->gc.ngpio = TPS68470_N_GPIO; 154 + tps68470_gpio->gc.base = -1; 155 + tps68470_gpio->gc.parent = &pdev->dev; 156 + 157 + ret = devm_gpiochip_add_data(&pdev->dev, &tps68470_gpio->gc, 158 + tps68470_gpio); 159 + if (ret < 0) { 160 + dev_err(&pdev->dev, "Failed to register gpio_chip: %d\n", ret); 161 + return ret; 162 + } 163 + 164 + platform_set_drvdata(pdev, tps68470_gpio); 165 + 166 + return ret; 167 + } 168 + 169 + static struct platform_driver tps68470_gpio_driver = { 170 + .driver = { 171 + .name = "tps68470-gpio", 172 + }, 173 + .probe = tps68470_gpio_probe, 174 + }; 175 + 176 + builtin_platform_driver(tps68470_gpio_driver)