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 17struct palmas_gpio { 18 struct gpio_chip gpio_chip; 19 struct palmas *palmas; 20}; 21 22struct palmas_device_data { 23 int ngpio; 24}; 25 26static 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 57static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset, 58 int value) 59{ 60 struct palmas_gpio *pg = gpiochip_get_data(gc); 61 struct palmas *palmas = pg->palmas; 62 int ret; 63 unsigned int reg; 64 int gpio16 = (offset/8); 65 66 offset %= 8; 67 if (gpio16) 68 reg = (value) ? 69 PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2; 70 else 71 reg = (value) ? 72 PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT; 73 74 ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset)); 75 if (ret < 0) 76 dev_err(gc->parent, "Reg 0x%02x write failed, %d\n", reg, ret); 77} 78 79static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, 80 int value) 81{ 82 struct palmas_gpio *pg = gpiochip_get_data(gc); 83 struct palmas *palmas = pg->palmas; 84 int ret; 85 unsigned int reg; 86 int gpio16 = (offset/8); 87 88 offset %= 8; 89 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; 90 91 /* Set the initial value */ 92 palmas_gpio_set(gc, offset, value); 93 94 ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, 95 BIT(offset), BIT(offset)); 96 if (ret < 0) 97 dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg, 98 ret); 99 return ret; 100} 101 102static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset) 103{ 104 struct palmas_gpio *pg = gpiochip_get_data(gc); 105 struct palmas *palmas = pg->palmas; 106 int ret; 107 unsigned int reg; 108 int gpio16 = (offset/8); 109 110 offset %= 8; 111 reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; 112 113 ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0); 114 if (ret < 0) 115 dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg, 116 ret); 117 return ret; 118} 119 120static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset) 121{ 122 struct palmas_gpio *pg = gpiochip_get_data(gc); 123 struct palmas *palmas = pg->palmas; 124 125 return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset); 126} 127 128static const struct palmas_device_data palmas_dev_data = { 129 .ngpio = 8, 130}; 131 132static const struct palmas_device_data tps80036_dev_data = { 133 .ngpio = 16, 134}; 135 136static const struct of_device_id of_palmas_gpio_match[] = { 137 { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,}, 138 { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,}, 139 { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,}, 140 { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,}, 141 { }, 142}; 143 144static int palmas_gpio_probe(struct platform_device *pdev) 145{ 146 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); 147 struct palmas_platform_data *palmas_pdata; 148 struct palmas_gpio *palmas_gpio; 149 int ret; 150 const struct palmas_device_data *dev_data; 151 152 dev_data = of_device_get_match_data(&pdev->dev); 153 if (!dev_data) 154 dev_data = &palmas_dev_data; 155 156 palmas_gpio = devm_kzalloc(&pdev->dev, 157 sizeof(*palmas_gpio), GFP_KERNEL); 158 if (!palmas_gpio) 159 return -ENOMEM; 160 161 palmas_gpio->palmas = palmas; 162 palmas_gpio->gpio_chip.owner = THIS_MODULE; 163 palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); 164 palmas_gpio->gpio_chip.ngpio = dev_data->ngpio; 165 palmas_gpio->gpio_chip.can_sleep = true; 166 palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; 167 palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; 168 palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq; 169 palmas_gpio->gpio_chip.set = palmas_gpio_set; 170 palmas_gpio->gpio_chip.get = palmas_gpio_get; 171 palmas_gpio->gpio_chip.parent = &pdev->dev; 172 173 palmas_pdata = dev_get_platdata(palmas->dev); 174 if (palmas_pdata && palmas_pdata->gpio_base) 175 palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base; 176 else 177 palmas_gpio->gpio_chip.base = -1; 178 179 ret = devm_gpiochip_add_data(&pdev->dev, &palmas_gpio->gpio_chip, 180 palmas_gpio); 181 if (ret < 0) { 182 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 183 return ret; 184 } 185 186 return ret; 187} 188 189static struct platform_driver palmas_gpio_driver = { 190 .driver.name = "palmas-gpio", 191 .driver.of_match_table = of_palmas_gpio_match, 192 .probe = palmas_gpio_probe, 193}; 194 195static int __init palmas_gpio_init(void) 196{ 197 return platform_driver_register(&palmas_gpio_driver); 198} 199subsys_initcall(palmas_gpio_init); 200