370 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * MAXIM MAX77620 GPIO driver4 *5 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.6 */7 8#include <linux/gpio/driver.h>9#include <linux/interrupt.h>10#include <linux/mfd/max77620.h>11#include <linux/module.h>12#include <linux/platform_device.h>13#include <linux/regmap.h>14 15#define GPIO_REG_ADDR(offset) (MAX77620_REG_GPIO0 + offset)16 17struct max77620_gpio {18 struct gpio_chip gpio_chip;19 struct regmap *rmap;20 struct device *dev;21 struct mutex buslock; /* irq_bus_lock */22 unsigned int irq_type[MAX77620_GPIO_NR];23 bool irq_enabled[MAX77620_GPIO_NR];24};25 26static irqreturn_t max77620_gpio_irqhandler(int irq, void *data)27{28 struct max77620_gpio *gpio = data;29 unsigned int value, offset;30 unsigned long pending;31 int err;32 33 err = regmap_read(gpio->rmap, MAX77620_REG_IRQ_LVL2_GPIO, &value);34 if (err < 0) {35 dev_err(gpio->dev, "REG_IRQ_LVL2_GPIO read failed: %d\n", err);36 return IRQ_NONE;37 }38 39 pending = value;40 41 for_each_set_bit(offset, &pending, MAX77620_GPIO_NR) {42 unsigned int virq;43 44 virq = irq_find_mapping(gpio->gpio_chip.irq.domain, offset);45 handle_nested_irq(virq);46 }47 48 return IRQ_HANDLED;49}50 51static void max77620_gpio_irq_mask(struct irq_data *data)52{53 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);54 struct max77620_gpio *gpio = gpiochip_get_data(chip);55 56 gpio->irq_enabled[data->hwirq] = false;57 gpiochip_disable_irq(chip, data->hwirq);58}59 60static void max77620_gpio_irq_unmask(struct irq_data *data)61{62 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);63 struct max77620_gpio *gpio = gpiochip_get_data(chip);64 65 gpiochip_enable_irq(chip, data->hwirq);66 gpio->irq_enabled[data->hwirq] = true;67}68 69static int max77620_gpio_set_irq_type(struct irq_data *data, unsigned int type)70{71 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);72 struct max77620_gpio *gpio = gpiochip_get_data(chip);73 unsigned int irq_type;74 75 switch (type) {76 case IRQ_TYPE_EDGE_RISING:77 irq_type = MAX77620_CNFG_GPIO_INT_RISING;78 break;79 80 case IRQ_TYPE_EDGE_FALLING:81 irq_type = MAX77620_CNFG_GPIO_INT_FALLING;82 break;83 84 case IRQ_TYPE_EDGE_BOTH:85 irq_type = MAX77620_CNFG_GPIO_INT_RISING |86 MAX77620_CNFG_GPIO_INT_FALLING;87 break;88 89 default:90 return -EINVAL;91 }92 93 gpio->irq_type[data->hwirq] = irq_type;94 95 return 0;96}97 98static void max77620_gpio_bus_lock(struct irq_data *data)99{100 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);101 struct max77620_gpio *gpio = gpiochip_get_data(chip);102 103 mutex_lock(&gpio->buslock);104}105 106static void max77620_gpio_bus_sync_unlock(struct irq_data *data)107{108 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);109 struct max77620_gpio *gpio = gpiochip_get_data(chip);110 unsigned int value, offset = data->hwirq;111 int err;112 113 value = gpio->irq_enabled[offset] ? gpio->irq_type[offset] : 0;114 115 err = regmap_update_bits(gpio->rmap, GPIO_REG_ADDR(offset),116 MAX77620_CNFG_GPIO_INT_MASK, value);117 if (err < 0)118 dev_err(chip->parent, "failed to update interrupt mask: %d\n",119 err);120 121 mutex_unlock(&gpio->buslock);122}123 124static const struct irq_chip max77620_gpio_irqchip = {125 .name = "max77620-gpio",126 .irq_mask = max77620_gpio_irq_mask,127 .irq_unmask = max77620_gpio_irq_unmask,128 .irq_set_type = max77620_gpio_set_irq_type,129 .irq_bus_lock = max77620_gpio_bus_lock,130 .irq_bus_sync_unlock = max77620_gpio_bus_sync_unlock,131 .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND,132 GPIOCHIP_IRQ_RESOURCE_HELPERS,133};134 135static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)136{137 struct max77620_gpio *mgpio = gpiochip_get_data(gc);138 int ret;139 140 ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),141 MAX77620_CNFG_GPIO_DIR_MASK,142 MAX77620_CNFG_GPIO_DIR_INPUT);143 if (ret < 0)144 dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret);145 146 return ret;147}148 149static int max77620_gpio_get(struct gpio_chip *gc, unsigned int offset)150{151 struct max77620_gpio *mgpio = gpiochip_get_data(gc);152 unsigned int val;153 int ret;154 155 ret = regmap_read(mgpio->rmap, GPIO_REG_ADDR(offset), &val);156 if (ret < 0) {157 dev_err(mgpio->dev, "CNFG_GPIOx read failed: %d\n", ret);158 return ret;159 }160 161 if (val & MAX77620_CNFG_GPIO_DIR_MASK)162 return !!(val & MAX77620_CNFG_GPIO_INPUT_VAL_MASK);163 else164 return !!(val & MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK);165}166 167static int max77620_gpio_dir_output(struct gpio_chip *gc, unsigned int offset,168 int value)169{170 struct max77620_gpio *mgpio = gpiochip_get_data(gc);171 u8 val;172 int ret;173 174 val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH :175 MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW;176 177 ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),178 MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val);179 if (ret < 0) {180 dev_err(mgpio->dev, "CNFG_GPIOx val update failed: %d\n", ret);181 return ret;182 }183 184 ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),185 MAX77620_CNFG_GPIO_DIR_MASK,186 MAX77620_CNFG_GPIO_DIR_OUTPUT);187 if (ret < 0)188 dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret);189 190 return ret;191}192 193static int max77620_gpio_set_debounce(struct max77620_gpio *mgpio,194 unsigned int offset,195 unsigned int debounce)196{197 u8 val;198 int ret;199 200 switch (debounce) {201 case 0:202 val = MAX77620_CNFG_GPIO_DBNC_None;203 break;204 case 1 ... 8000:205 val = MAX77620_CNFG_GPIO_DBNC_8ms;206 break;207 case 8001 ... 16000:208 val = MAX77620_CNFG_GPIO_DBNC_16ms;209 break;210 case 16001 ... 32000:211 val = MAX77620_CNFG_GPIO_DBNC_32ms;212 break;213 default:214 dev_err(mgpio->dev, "Illegal value %u\n", debounce);215 return -EINVAL;216 }217 218 ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),219 MAX77620_CNFG_GPIO_DBNC_MASK, val);220 if (ret < 0)221 dev_err(mgpio->dev, "CNFG_GPIOx_DBNC update failed: %d\n", ret);222 223 return ret;224}225 226static void max77620_gpio_set(struct gpio_chip *gc, unsigned int offset,227 int value)228{229 struct max77620_gpio *mgpio = gpiochip_get_data(gc);230 u8 val;231 int ret;232 233 val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH :234 MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW;235 236 ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),237 MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val);238 if (ret < 0)239 dev_err(mgpio->dev, "CNFG_GPIO_OUT update failed: %d\n", ret);240}241 242static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset,243 unsigned long config)244{245 struct max77620_gpio *mgpio = gpiochip_get_data(gc);246 247 switch (pinconf_to_config_param(config)) {248 case PIN_CONFIG_DRIVE_OPEN_DRAIN:249 return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),250 MAX77620_CNFG_GPIO_DRV_MASK,251 MAX77620_CNFG_GPIO_DRV_OPENDRAIN);252 case PIN_CONFIG_DRIVE_PUSH_PULL:253 return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),254 MAX77620_CNFG_GPIO_DRV_MASK,255 MAX77620_CNFG_GPIO_DRV_PUSHPULL);256 case PIN_CONFIG_INPUT_DEBOUNCE:257 return max77620_gpio_set_debounce(mgpio, offset,258 pinconf_to_config_argument(config));259 default:260 break;261 }262 263 return -ENOTSUPP;264}265 266static int max77620_gpio_irq_init_hw(struct gpio_chip *gc)267{268 struct max77620_gpio *gpio = gpiochip_get_data(gc);269 unsigned int i;270 int err;271 272 /*273 * GPIO interrupts may be left ON after bootloader, hence let's274 * pre-initialize hardware to the expected state by disabling all275 * the interrupts.276 */277 for (i = 0; i < MAX77620_GPIO_NR; i++) {278 err = regmap_update_bits(gpio->rmap, GPIO_REG_ADDR(i),279 MAX77620_CNFG_GPIO_INT_MASK, 0);280 if (err < 0) {281 dev_err(gpio->dev,282 "failed to disable interrupt: %d\n", err);283 return err;284 }285 }286 287 return 0;288}289 290static int max77620_gpio_probe(struct platform_device *pdev)291{292 struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent);293 struct max77620_gpio *mgpio;294 struct gpio_irq_chip *girq;295 unsigned int gpio_irq;296 int ret;297 298 ret = platform_get_irq(pdev, 0);299 if (ret < 0)300 return ret;301 302 gpio_irq = ret;303 304 mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);305 if (!mgpio)306 return -ENOMEM;307 308 mutex_init(&mgpio->buslock);309 mgpio->rmap = chip->rmap;310 mgpio->dev = &pdev->dev;311 312 mgpio->gpio_chip.label = pdev->name;313 mgpio->gpio_chip.parent = pdev->dev.parent;314 mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;315 mgpio->gpio_chip.get = max77620_gpio_get;316 mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;317 mgpio->gpio_chip.set = max77620_gpio_set;318 mgpio->gpio_chip.set_config = max77620_gpio_set_config;319 mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;320 mgpio->gpio_chip.can_sleep = 1;321 mgpio->gpio_chip.base = -1;322 323 girq = &mgpio->gpio_chip.irq;324 gpio_irq_chip_set_chip(girq, &max77620_gpio_irqchip);325 /* This will let us handle the parent IRQ in the driver */326 girq->parent_handler = NULL;327 girq->num_parents = 0;328 girq->parents = NULL;329 girq->default_type = IRQ_TYPE_NONE;330 girq->handler = handle_edge_irq;331 girq->init_hw = max77620_gpio_irq_init_hw;332 girq->threaded = true;333 334 ret = devm_gpiochip_add_data(&pdev->dev, &mgpio->gpio_chip, mgpio);335 if (ret < 0) {336 dev_err(&pdev->dev, "gpio_init: Failed to add max77620_gpio\n");337 return ret;338 }339 340 ret = devm_request_threaded_irq(&pdev->dev, gpio_irq, NULL,341 max77620_gpio_irqhandler, IRQF_ONESHOT,342 "max77620-gpio", mgpio);343 if (ret < 0) {344 dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);345 return ret;346 }347 348 return 0;349}350 351static const struct platform_device_id max77620_gpio_devtype[] = {352 { .name = "max77620-gpio", },353 { .name = "max20024-gpio", },354 {},355};356MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype);357 358static struct platform_driver max77620_gpio_driver = {359 .driver.name = "max77620-gpio",360 .probe = max77620_gpio_probe,361 .id_table = max77620_gpio_devtype,362};363 364module_platform_driver(max77620_gpio_driver);365 366MODULE_DESCRIPTION("GPIO interface for MAX77620 and MAX20024 PMIC");367MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");368MODULE_AUTHOR("Chaitanya Bandi <bandik@nvidia.com>");369MODULE_LICENSE("GPL v2");370