1/* 2 * TI TPS6586x GPIO driver 3 * 4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 5 * Author: Laxman dewangan <ldewangan@nvidia.com> 6 * 7 * Based on tps6586x.c 8 * Copyright (c) 2010 CompuLab Ltd. 9 * Mike Rapoport <mike@compulab.co.il> 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms and conditions of the GNU General Public License, 13 * version 2, as published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 18 * more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program. If not, see <http://www.gnu.org/licenses/>. 22 */ 23 24#include <linux/errno.h> 25#include <linux/gpio.h> 26#include <linux/kernel.h> 27#include <linux/module.h> 28#include <linux/mfd/tps6586x.h> 29#include <linux/of_device.h> 30#include <linux/platform_device.h> 31 32/* GPIO control registers */ 33#define TPS6586X_GPIOSET1 0x5d 34#define TPS6586X_GPIOSET2 0x5e 35 36struct tps6586x_gpio { 37 struct gpio_chip gpio_chip; 38 struct device *parent; 39}; 40 41static inline struct tps6586x_gpio *to_tps6586x_gpio(struct gpio_chip *chip) 42{ 43 return container_of(chip, struct tps6586x_gpio, gpio_chip); 44} 45 46static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset) 47{ 48 struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); 49 uint8_t val; 50 int ret; 51 52 ret = tps6586x_read(tps6586x_gpio->parent, TPS6586X_GPIOSET2, &val); 53 if (ret) 54 return ret; 55 56 return !!(val & (1 << offset)); 57} 58 59static void tps6586x_gpio_set(struct gpio_chip *gc, unsigned offset, 60 int value) 61{ 62 struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); 63 64 tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET2, 65 value << offset, 1 << offset); 66} 67 68static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, 69 int value) 70{ 71 struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); 72 uint8_t val, mask; 73 74 tps6586x_gpio_set(gc, offset, value); 75 76 val = 0x1 << (offset * 2); 77 mask = 0x3 << (offset * 2); 78 79 return tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET1, 80 val, mask); 81} 82 83static int tps6586x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) 84{ 85 struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); 86 87 return tps6586x_irq_get_virq(tps6586x_gpio->parent, 88 TPS6586X_INT_PLDO_0 + offset); 89} 90 91static int tps6586x_gpio_probe(struct platform_device *pdev) 92{ 93 struct tps6586x_platform_data *pdata; 94 struct tps6586x_gpio *tps6586x_gpio; 95 int ret; 96 97 pdata = dev_get_platdata(pdev->dev.parent); 98 tps6586x_gpio = devm_kzalloc(&pdev->dev, 99 sizeof(*tps6586x_gpio), GFP_KERNEL); 100 if (!tps6586x_gpio) 101 return -ENOMEM; 102 103 tps6586x_gpio->parent = pdev->dev.parent; 104 105 tps6586x_gpio->gpio_chip.owner = THIS_MODULE; 106 tps6586x_gpio->gpio_chip.label = pdev->name; 107 tps6586x_gpio->gpio_chip.dev = &pdev->dev; 108 tps6586x_gpio->gpio_chip.ngpio = 4; 109 tps6586x_gpio->gpio_chip.can_sleep = true; 110 111 /* FIXME: add handling of GPIOs as dedicated inputs */ 112 tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; 113 tps6586x_gpio->gpio_chip.set = tps6586x_gpio_set; 114 tps6586x_gpio->gpio_chip.get = tps6586x_gpio_get; 115 tps6586x_gpio->gpio_chip.to_irq = tps6586x_gpio_to_irq; 116 117#ifdef CONFIG_OF_GPIO 118 tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node; 119#endif 120 if (pdata && pdata->gpio_base) 121 tps6586x_gpio->gpio_chip.base = pdata->gpio_base; 122 else 123 tps6586x_gpio->gpio_chip.base = -1; 124 125 ret = gpiochip_add(&tps6586x_gpio->gpio_chip); 126 if (ret < 0) { 127 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 128 return ret; 129 } 130 131 platform_set_drvdata(pdev, tps6586x_gpio); 132 133 return ret; 134} 135 136static int tps6586x_gpio_remove(struct platform_device *pdev) 137{ 138 struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev); 139 140 gpiochip_remove(&tps6586x_gpio->gpio_chip); 141 return 0; 142} 143 144static struct platform_driver tps6586x_gpio_driver = { 145 .driver.name = "tps6586x-gpio", 146 .driver.owner = THIS_MODULE, 147 .probe = tps6586x_gpio_probe, 148 .remove = tps6586x_gpio_remove, 149}; 150 151static int __init tps6586x_gpio_init(void) 152{ 153 return platform_driver_register(&tps6586x_gpio_driver); 154} 155subsys_initcall(tps6586x_gpio_init); 156 157static void __exit tps6586x_gpio_exit(void) 158{ 159 platform_driver_unregister(&tps6586x_gpio_driver); 160} 161module_exit(tps6586x_gpio_exit); 162 163MODULE_ALIAS("platform:tps6586x-gpio"); 164MODULE_DESCRIPTION("GPIO interface for TPS6586X PMIC"); 165MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 166MODULE_LICENSE("GPL"); 167