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 inline struct tps65910_gpio *to_tps65910_gpio(struct gpio_chip *chip) 31 { 32 return container_of(chip, struct tps65910_gpio, gpio_chip); 33 } 34 35 static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset) 36 { 37 struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc); 38 struct tps65910 *tps65910 = tps65910_gpio->tps65910; 39 unsigned int val; 40 41 tps65910_reg_read(tps65910, TPS65910_GPIO0 + offset, &val); 42 43 if (val & GPIO_STS_MASK) 44 return 1; 45 46 return 0; 47 } 48 49 static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset, 50 int value) 51 { 52 struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc); 53 struct tps65910 *tps65910 = tps65910_gpio->tps65910; 54 55 if (value) 56 tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset, 57 GPIO_SET_MASK); 58 else 59 tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset, 60 GPIO_SET_MASK); 61 } 62 63 static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset, 64 int value) 65 { 66 struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc); 67 struct tps65910 *tps65910 = tps65910_gpio->tps65910; 68 69 /* Set the initial value */ 70 tps65910_gpio_set(gc, offset, value); 71 72 return tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset, 73 GPIO_CFG_MASK); 74 } 75 76 static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset) 77 { 78 struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc); 79 struct tps65910 *tps65910 = tps65910_gpio->tps65910; 80 81 return tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset, 82 GPIO_CFG_MASK); 83 } 84 85 #ifdef CONFIG_OF 86 static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev, 87 struct tps65910 *tps65910, int chip_ngpio) 88 { 89 struct tps65910_board *tps65910_board = tps65910->of_plat_data; 90 unsigned int prop_array[TPS6591X_MAX_NUM_GPIO]; 91 int ngpio = min(chip_ngpio, TPS6591X_MAX_NUM_GPIO); 92 int ret; 93 int idx; 94 95 tps65910_board->gpio_base = -1; 96 ret = of_property_read_u32_array(tps65910->dev->of_node, 97 "ti,en-gpio-sleep", prop_array, ngpio); 98 if (ret < 0) { 99 dev_dbg(dev, "ti,en-gpio-sleep not specified\n"); 100 return tps65910_board; 101 } 102 103 for (idx = 0; idx < ngpio; idx++) 104 tps65910_board->en_gpio_sleep[idx] = (prop_array[idx] != 0); 105 106 return tps65910_board; 107 } 108 #else 109 static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev, 110 struct tps65910 *tps65910, int chip_ngpio) 111 { 112 return NULL; 113 } 114 #endif 115 116 static int tps65910_gpio_probe(struct platform_device *pdev) 117 { 118 struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); 119 struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); 120 struct tps65910_gpio *tps65910_gpio; 121 int ret; 122 int i; 123 124 tps65910_gpio = devm_kzalloc(&pdev->dev, 125 sizeof(*tps65910_gpio), GFP_KERNEL); 126 if (!tps65910_gpio) 127 return -ENOMEM; 128 129 tps65910_gpio->tps65910 = tps65910; 130 131 tps65910_gpio->gpio_chip.owner = THIS_MODULE; 132 tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name; 133 134 switch (tps65910_chip_id(tps65910)) { 135 case TPS65910: 136 tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO; 137 break; 138 case TPS65911: 139 tps65910_gpio->gpio_chip.ngpio = TPS65911_NUM_GPIO; 140 break; 141 default: 142 return -EINVAL; 143 } 144 tps65910_gpio->gpio_chip.can_sleep = true; 145 tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input; 146 tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output; 147 tps65910_gpio->gpio_chip.set = tps65910_gpio_set; 148 tps65910_gpio->gpio_chip.get = tps65910_gpio_get; 149 tps65910_gpio->gpio_chip.dev = &pdev->dev; 150 #ifdef CONFIG_OF_GPIO 151 tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node; 152 #endif 153 if (pdata && pdata->gpio_base) 154 tps65910_gpio->gpio_chip.base = pdata->gpio_base; 155 else 156 tps65910_gpio->gpio_chip.base = -1; 157 158 if (!pdata && tps65910->dev->of_node) 159 pdata = tps65910_parse_dt_for_gpio(&pdev->dev, tps65910, 160 tps65910_gpio->gpio_chip.ngpio); 161 162 if (!pdata) 163 goto skip_init; 164 165 /* Configure sleep control for gpios if provided */ 166 for (i = 0; i < tps65910_gpio->gpio_chip.ngpio; ++i) { 167 if (!pdata->en_gpio_sleep[i]) 168 continue; 169 170 ret = tps65910_reg_set_bits(tps65910, 171 TPS65910_GPIO0 + i, GPIO_SLEEP_MASK); 172 if (ret < 0) 173 dev_warn(tps65910->dev, 174 "GPIO Sleep setting failed with err %d\n", ret); 175 } 176 177 skip_init: 178 ret = gpiochip_add(&tps65910_gpio->gpio_chip); 179 if (ret < 0) { 180 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 181 return ret; 182 } 183 184 platform_set_drvdata(pdev, tps65910_gpio); 185 186 return ret; 187 } 188 189 static int tps65910_gpio_remove(struct platform_device *pdev) 190 { 191 struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev); 192 193 gpiochip_remove(&tps65910_gpio->gpio_chip); 194 return 0; 195 } 196 197 static struct platform_driver tps65910_gpio_driver = { 198 .driver.name = "tps65910-gpio", 199 .driver.owner = THIS_MODULE, 200 .probe = tps65910_gpio_probe, 201 .remove = tps65910_gpio_remove, 202 }; 203 204 static int __init tps65910_gpio_init(void) 205 { 206 return platform_driver_register(&tps65910_gpio_driver); 207 } 208 subsys_initcall(tps65910_gpio_init); 209 210 static void __exit tps65910_gpio_exit(void) 211 { 212 platform_driver_unregister(&tps65910_gpio_driver); 213 } 214 module_exit(tps65910_gpio_exit); 215 216 MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); 217 MODULE_AUTHOR("Jorge Eduardo Candelaria jedu@slimlogic.co.uk>"); 218 MODULE_DESCRIPTION("GPIO interface for TPS65910/TPS6511 PMICs"); 219 MODULE_LICENSE("GPL v2"); 220 MODULE_ALIAS("platform:tps65910-gpio"); 221