1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * TI Palma series PMIC's GPIO driver. 4 * 5 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 6 * 7 * Author: Laxman Dewangan <ldewangan@nvidia.com> 8 */ 9 10 #include <linux/gpio/driver.h> 11 #include <linux/kernel.h> 12 #include <linux/init.h> 13 #include <linux/mfd/palmas.h> 14 #include <linux/of.h> 15 #include <linux/platform_device.h> 16 17 struct palmas_gpio { 18 struct gpio_chip gpio_chip; 19 struct palmas *palmas; 20 }; 21 22 struct palmas_device_data { 23 int ngpio; 24 }; 25 26 static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset) 27 { 28 struct palmas_gpio *pg = gpiochip_get_data(gc); 29 struct palmas *palmas = pg->palmas; 30 unsigned int val; 31 int ret; 32 unsigned int reg; 33 int gpio16 = (offset/8); 34 35 offset %= 8; 36 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; 37 38 ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); 39 if (ret < 0) { 40 dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret); 41 return ret; 42 } 43 44 if (val & BIT(offset)) 45 reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT; 46 else 47 reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN; 48 49 ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); 50 if (ret < 0) { 51 dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret); 52 return ret; 53 } 54 return !!(val & BIT(offset)); 55 } 56 57 static int palmas_gpio_set(struct gpio_chip *gc, unsigned int offset, 58 int value) 59 { 60 struct palmas_gpio *pg = gpiochip_get_data(gc); 61 struct palmas *palmas = pg->palmas; 62 unsigned int reg; 63 int gpio16 = (offset/8); 64 65 offset %= 8; 66 if (gpio16) 67 reg = (value) ? 68 PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2; 69 else 70 reg = (value) ? 71 PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT; 72 73 return palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset)); 74 } 75 76 static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, 77 int value) 78 { 79 struct palmas_gpio *pg = gpiochip_get_data(gc); 80 struct palmas *palmas = pg->palmas; 81 int ret; 82 unsigned int reg; 83 int gpio16 = (offset/8); 84 85 offset %= 8; 86 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; 87 88 /* Set the initial value */ 89 ret = palmas_gpio_set(gc, offset, value); 90 if (ret) 91 return ret; 92 93 ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, 94 BIT(offset), BIT(offset)); 95 if (ret < 0) 96 dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg, 97 ret); 98 return ret; 99 } 100 101 static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset) 102 { 103 struct palmas_gpio *pg = gpiochip_get_data(gc); 104 struct palmas *palmas = pg->palmas; 105 int ret; 106 unsigned int reg; 107 int gpio16 = (offset/8); 108 109 offset %= 8; 110 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; 111 112 ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0); 113 if (ret < 0) 114 dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg, 115 ret); 116 return ret; 117 } 118 119 static int palmas_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) 120 { 121 struct palmas_gpio *pg = gpiochip_get_data(gc); 122 struct palmas *palmas = pg->palmas; 123 unsigned int val; 124 unsigned int reg; 125 int ret; 126 int gpio16 = (offset/8); 127 128 offset %= 8; 129 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; 130 ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); 131 if (ret) 132 return ret; 133 134 return (val & BIT(offset)) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; 135 } 136 137 static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset) 138 { 139 struct palmas_gpio *pg = gpiochip_get_data(gc); 140 struct palmas *palmas = pg->palmas; 141 142 return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset); 143 } 144 145 static const struct palmas_device_data palmas_dev_data = { 146 .ngpio = 8, 147 }; 148 149 static const struct palmas_device_data tps80036_dev_data = { 150 .ngpio = 16, 151 }; 152 153 static const struct of_device_id of_palmas_gpio_match[] = { 154 { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,}, 155 { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,}, 156 { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,}, 157 { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,}, 158 { }, 159 }; 160 MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); 161 162 static int palmas_gpio_probe(struct platform_device *pdev) 163 { 164 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); 165 struct palmas_platform_data *palmas_pdata; 166 struct palmas_gpio *palmas_gpio; 167 int ret; 168 const struct palmas_device_data *dev_data; 169 170 dev_data = of_device_get_match_data(&pdev->dev); 171 if (!dev_data) 172 dev_data = &palmas_dev_data; 173 174 palmas_gpio = devm_kzalloc(&pdev->dev, 175 sizeof(*palmas_gpio), GFP_KERNEL); 176 if (!palmas_gpio) 177 return -ENOMEM; 178 179 palmas_gpio->palmas = palmas; 180 palmas_gpio->gpio_chip.owner = THIS_MODULE; 181 palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); 182 palmas_gpio->gpio_chip.ngpio = dev_data->ngpio; 183 palmas_gpio->gpio_chip.can_sleep = true; 184 palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; 185 palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; 186 palmas_gpio->gpio_chip.get_direction = palmas_gpio_get_direction; 187 palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq; 188 palmas_gpio->gpio_chip.set = palmas_gpio_set; 189 palmas_gpio->gpio_chip.get = palmas_gpio_get; 190 palmas_gpio->gpio_chip.parent = &pdev->dev; 191 192 palmas_pdata = dev_get_platdata(palmas->dev); 193 if (palmas_pdata && palmas_pdata->gpio_base) 194 palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base; 195 else 196 palmas_gpio->gpio_chip.base = -1; 197 198 ret = devm_gpiochip_add_data(&pdev->dev, &palmas_gpio->gpio_chip, 199 palmas_gpio); 200 if (ret < 0) { 201 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 202 return ret; 203 } 204 205 return ret; 206 } 207 208 static struct platform_driver palmas_gpio_driver = { 209 .driver.name = "palmas-gpio", 210 .driver.of_match_table = of_palmas_gpio_match, 211 .probe = palmas_gpio_probe, 212 }; 213 214 static int __init palmas_gpio_init(void) 215 { 216 return platform_driver_register(&palmas_gpio_driver); 217 } 218 subsys_initcall(palmas_gpio_init); 219 220 static void __exit palmas_gpio_exit(void) 221 { 222 platform_driver_unregister(&palmas_gpio_driver); 223 } 224 module_exit(palmas_gpio_exit); 225 226 MODULE_DESCRIPTION("TI PALMAS series GPIO driver"); 227 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 228 MODULE_LICENSE("GPL"); 229