1 /* 2 * TI TPS6591x GPIO driver 3 * 4 * Copyright 2010 Texas Instruments Inc. 5 * 6 * Author: Graeme Gregory <gg@slimlogic.co.uk> 7 * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 * 14 */ 15 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/errno.h> 19 #include <linux/gpio.h> 20 #include <linux/i2c.h> 21 #include <linux/platform_device.h> 22 #include <linux/mfd/tps65910.h> 23 #include <linux/of_device.h> 24 25 struct tps65910_gpio { 26 struct gpio_chip gpio_chip; 27 struct tps65910 *tps65910; 28 }; 29 30 static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset) 31 { 32 struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc); 33 struct tps65910 *tps65910 = tps65910_gpio->tps65910; 34 unsigned int val; 35 36 tps65910_reg_read(tps65910, TPS65910_GPIO0 + offset, &val); 37 38 if (val & GPIO_STS_MASK) 39 return 1; 40 41 return 0; 42 } 43 44 static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset, 45 int value) 46 { 47 struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc); 48 struct tps65910 *tps65910 = tps65910_gpio->tps65910; 49 50 if (value) 51 tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset, 52 GPIO_SET_MASK); 53 else 54 tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset, 55 GPIO_SET_MASK); 56 } 57 58 static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset, 59 int value) 60 { 61 struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc); 62 struct tps65910 *tps65910 = tps65910_gpio->tps65910; 63 64 /* Set the initial value */ 65 tps65910_gpio_set(gc, offset, value); 66 67 return tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset, 68 GPIO_CFG_MASK); 69 } 70 71 static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset) 72 { 73 struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc); 74 struct tps65910 *tps65910 = tps65910_gpio->tps65910; 75 76 return tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset, 77 GPIO_CFG_MASK); 78 } 79 80 #ifdef CONFIG_OF 81 static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev, 82 struct tps65910 *tps65910, int chip_ngpio) 83 { 84 struct tps65910_board *tps65910_board = tps65910->of_plat_data; 85 unsigned int prop_array[TPS6591X_MAX_NUM_GPIO]; 86 int ngpio = min(chip_ngpio, TPS6591X_MAX_NUM_GPIO); 87 int ret; 88 int idx; 89 90 tps65910_board->gpio_base = -1; 91 ret = of_property_read_u32_array(tps65910->dev->of_node, 92 "ti,en-gpio-sleep", prop_array, ngpio); 93 if (ret < 0) { 94 dev_dbg(dev, "ti,en-gpio-sleep not specified\n"); 95 return tps65910_board; 96 } 97 98 for (idx = 0; idx < ngpio; idx++) 99 tps65910_board->en_gpio_sleep[idx] = (prop_array[idx] != 0); 100 101 return tps65910_board; 102 } 103 #else 104 static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev, 105 struct tps65910 *tps65910, int chip_ngpio) 106 { 107 return NULL; 108 } 109 #endif 110 111 static int tps65910_gpio_probe(struct platform_device *pdev) 112 { 113 struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); 114 struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); 115 struct tps65910_gpio *tps65910_gpio; 116 int ret; 117 int i; 118 119 tps65910_gpio = devm_kzalloc(&pdev->dev, 120 sizeof(*tps65910_gpio), GFP_KERNEL); 121 if (!tps65910_gpio) 122 return -ENOMEM; 123 124 tps65910_gpio->tps65910 = tps65910; 125 126 tps65910_gpio->gpio_chip.owner = THIS_MODULE; 127 tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name; 128 129 switch (tps65910_chip_id(tps65910)) { 130 case TPS65910: 131 tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO; 132 break; 133 case TPS65911: 134 tps65910_gpio->gpio_chip.ngpio = TPS65911_NUM_GPIO; 135 break; 136 default: 137 return -EINVAL; 138 } 139 tps65910_gpio->gpio_chip.can_sleep = true; 140 tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input; 141 tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output; 142 tps65910_gpio->gpio_chip.set = tps65910_gpio_set; 143 tps65910_gpio->gpio_chip.get = tps65910_gpio_get; 144 tps65910_gpio->gpio_chip.parent = &pdev->dev; 145 #ifdef CONFIG_OF_GPIO 146 tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node; 147 #endif 148 if (pdata && pdata->gpio_base) 149 tps65910_gpio->gpio_chip.base = pdata->gpio_base; 150 else 151 tps65910_gpio->gpio_chip.base = -1; 152 153 if (!pdata && tps65910->dev->of_node) 154 pdata = tps65910_parse_dt_for_gpio(&pdev->dev, tps65910, 155 tps65910_gpio->gpio_chip.ngpio); 156 157 if (!pdata) 158 goto skip_init; 159 160 /* Configure sleep control for gpios if provided */ 161 for (i = 0; i < tps65910_gpio->gpio_chip.ngpio; ++i) { 162 if (!pdata->en_gpio_sleep[i]) 163 continue; 164 165 ret = tps65910_reg_set_bits(tps65910, 166 TPS65910_GPIO0 + i, GPIO_SLEEP_MASK); 167 if (ret < 0) 168 dev_warn(tps65910->dev, 169 "GPIO Sleep setting failed with err %d\n", ret); 170 } 171 172 skip_init: 173 ret = gpiochip_add_data(&tps65910_gpio->gpio_chip, tps65910_gpio); 174 if (ret < 0) { 175 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 176 return ret; 177 } 178 179 platform_set_drvdata(pdev, tps65910_gpio); 180 181 return ret; 182 } 183 184 static int tps65910_gpio_remove(struct platform_device *pdev) 185 { 186 struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev); 187 188 gpiochip_remove(&tps65910_gpio->gpio_chip); 189 return 0; 190 } 191 192 static struct platform_driver tps65910_gpio_driver = { 193 .driver.name = "tps65910-gpio", 194 .driver.owner = THIS_MODULE, 195 .probe = tps65910_gpio_probe, 196 .remove = tps65910_gpio_remove, 197 }; 198 199 static int __init tps65910_gpio_init(void) 200 { 201 return platform_driver_register(&tps65910_gpio_driver); 202 } 203 subsys_initcall(tps65910_gpio_init); 204 205 static void __exit tps65910_gpio_exit(void) 206 { 207 platform_driver_unregister(&tps65910_gpio_driver); 208 } 209 module_exit(tps65910_gpio_exit); 210 211 MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); 212 MODULE_AUTHOR("Jorge Eduardo Candelaria jedu@slimlogic.co.uk>"); 213 MODULE_DESCRIPTION("GPIO interface for TPS65910/TPS6511 PMICs"); 214 MODULE_LICENSE("GPL v2"); 215 MODULE_ALIAS("platform:tps65910-gpio"); 216