1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * GPIO driver for TI TPS65912x PMICs 4 * 5 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ 6 * Andrew F. Davis <afd@ti.com> 7 * 8 * Based on the Arizona GPIO driver and the previous TPS65912 driver by 9 * Margarita Olaya Cabrera <magi@slimlogic.co.uk> 10 */ 11 12 #include <linux/gpio/driver.h> 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 16 #include <linux/mfd/tps65912.h> 17 18 struct tps65912_gpio { 19 struct gpio_chip gpio_chip; 20 struct tps65912 *tps; 21 }; 22 23 static int tps65912_gpio_get_direction(struct gpio_chip *gc, 24 unsigned offset) 25 { 26 struct tps65912_gpio *gpio = gpiochip_get_data(gc); 27 28 int ret, val; 29 30 ret = regmap_read(gpio->tps->regmap, TPS65912_GPIO1 + offset, &val); 31 if (ret) 32 return ret; 33 34 if (val & GPIO_CFG_MASK) 35 return 0; 36 else 37 return 1; 38 } 39 40 static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset) 41 { 42 struct tps65912_gpio *gpio = gpiochip_get_data(gc); 43 44 return regmap_update_bits(gpio->tps->regmap, TPS65912_GPIO1 + offset, 45 GPIO_CFG_MASK, 0); 46 } 47 48 static int tps65912_gpio_direction_output(struct gpio_chip *gc, 49 unsigned offset, int value) 50 { 51 struct tps65912_gpio *gpio = gpiochip_get_data(gc); 52 53 /* Set the initial value */ 54 regmap_update_bits(gpio->tps->regmap, TPS65912_GPIO1 + offset, 55 GPIO_SET_MASK, value ? GPIO_SET_MASK : 0); 56 57 return regmap_update_bits(gpio->tps->regmap, TPS65912_GPIO1 + offset, 58 GPIO_CFG_MASK, GPIO_CFG_MASK); 59 } 60 61 static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset) 62 { 63 struct tps65912_gpio *gpio = gpiochip_get_data(gc); 64 int ret, val; 65 66 ret = regmap_read(gpio->tps->regmap, TPS65912_GPIO1 + offset, &val); 67 if (ret) 68 return ret; 69 70 if (val & GPIO_STS_MASK) 71 return 1; 72 73 return 0; 74 } 75 76 static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset, 77 int value) 78 { 79 struct tps65912_gpio *gpio = gpiochip_get_data(gc); 80 81 regmap_update_bits(gpio->tps->regmap, TPS65912_GPIO1 + offset, 82 GPIO_SET_MASK, value ? GPIO_SET_MASK : 0); 83 } 84 85 static const struct gpio_chip template_chip = { 86 .label = "tps65912-gpio", 87 .owner = THIS_MODULE, 88 .get_direction = tps65912_gpio_get_direction, 89 .direction_input = tps65912_gpio_direction_input, 90 .direction_output = tps65912_gpio_direction_output, 91 .get = tps65912_gpio_get, 92 .set = tps65912_gpio_set, 93 .base = -1, 94 .ngpio = 5, 95 .can_sleep = true, 96 }; 97 98 static int tps65912_gpio_probe(struct platform_device *pdev) 99 { 100 struct tps65912 *tps = dev_get_drvdata(pdev->dev.parent); 101 struct tps65912_gpio *gpio; 102 int ret; 103 104 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 105 if (!gpio) 106 return -ENOMEM; 107 108 gpio->tps = dev_get_drvdata(pdev->dev.parent); 109 gpio->gpio_chip = template_chip; 110 gpio->gpio_chip.parent = tps->dev; 111 112 ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gpio_chip, 113 gpio); 114 if (ret < 0) { 115 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 116 return ret; 117 } 118 119 platform_set_drvdata(pdev, gpio); 120 121 return 0; 122 } 123 124 static const struct platform_device_id tps65912_gpio_id_table[] = { 125 { "tps65912-gpio", }, 126 { /* sentinel */ } 127 }; 128 MODULE_DEVICE_TABLE(platform, tps65912_gpio_id_table); 129 130 static struct platform_driver tps65912_gpio_driver = { 131 .driver = { 132 .name = "tps65912-gpio", 133 }, 134 .probe = tps65912_gpio_probe, 135 .id_table = tps65912_gpio_id_table, 136 }; 137 module_platform_driver(tps65912_gpio_driver); 138 139 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); 140 MODULE_DESCRIPTION("TPS65912 GPIO driver"); 141 MODULE_LICENSE("GPL v2"); 142