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