Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: adp5588-gpio: new driver for ADP5588 GPIO expanders

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Michael Hennerich and committed by
Linus Torvalds
80884094 5787536e

+288
+9
drivers/gpio/Kconfig
··· 172 172 To compile this driver as a module, choose M here: the module will 173 173 be called adp5520-gpio. 174 174 175 + config GPIO_ADP5588 176 + tristate "ADP5588 I2C GPIO expander" 177 + depends on I2C 178 + help 179 + This option enables support for 18 GPIOs found 180 + on Analog Devices ADP5588 GPIO Expanders. 181 + To compile this driver as a module, choose M here: the module will be 182 + called adp5588-gpio. 183 + 175 184 comment "PCI GPIO expanders:" 176 185 177 186 config GPIO_CS5535
+1
drivers/gpio/Makefile
··· 5 5 obj-$(CONFIG_GPIOLIB) += gpiolib.o 6 6 7 7 obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o 8 + obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o 8 9 obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o 9 10 obj-$(CONFIG_GPIO_MAX7301) += max7301.o 10 11 obj-$(CONFIG_GPIO_MAX732X) += max732x.o
+266
drivers/gpio/adp5588-gpio.c
··· 1 + /* 2 + * GPIO Chip driver for Analog Devices 3 + * ADP5588 I/O Expander and QWERTY Keypad Controller 4 + * 5 + * Copyright 2009 Analog Devices Inc. 6 + * 7 + * Licensed under the GPL-2 or later. 8 + */ 9 + 10 + #include <linux/module.h> 11 + #include <linux/kernel.h> 12 + #include <linux/init.h> 13 + #include <linux/i2c.h> 14 + #include <linux/gpio.h> 15 + 16 + #include <linux/i2c/adp5588.h> 17 + 18 + #define DRV_NAME "adp5588-gpio" 19 + #define MAXGPIO 18 20 + #define ADP_BANK(offs) ((offs) >> 3) 21 + #define ADP_BIT(offs) (1u << ((offs) & 0x7)) 22 + 23 + struct adp5588_gpio { 24 + struct i2c_client *client; 25 + struct gpio_chip gpio_chip; 26 + struct mutex lock; /* protect cached dir, dat_out */ 27 + unsigned gpio_start; 28 + uint8_t dat_out[3]; 29 + uint8_t dir[3]; 30 + }; 31 + 32 + static int adp5588_gpio_read(struct i2c_client *client, u8 reg) 33 + { 34 + int ret = i2c_smbus_read_byte_data(client, reg); 35 + 36 + if (ret < 0) 37 + dev_err(&client->dev, "Read Error\n"); 38 + 39 + return ret; 40 + } 41 + 42 + static int adp5588_gpio_write(struct i2c_client *client, u8 reg, u8 val) 43 + { 44 + int ret = i2c_smbus_write_byte_data(client, reg, val); 45 + 46 + if (ret < 0) 47 + dev_err(&client->dev, "Write Error\n"); 48 + 49 + return ret; 50 + } 51 + 52 + static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) 53 + { 54 + struct adp5588_gpio *dev = 55 + container_of(chip, struct adp5588_gpio, gpio_chip); 56 + 57 + return !!(adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + ADP_BANK(off)) 58 + & ADP_BIT(off)); 59 + } 60 + 61 + static void adp5588_gpio_set_value(struct gpio_chip *chip, 62 + unsigned off, int val) 63 + { 64 + unsigned bank, bit; 65 + struct adp5588_gpio *dev = 66 + container_of(chip, struct adp5588_gpio, gpio_chip); 67 + 68 + bank = ADP_BANK(off); 69 + bit = ADP_BIT(off); 70 + 71 + mutex_lock(&dev->lock); 72 + if (val) 73 + dev->dat_out[bank] |= bit; 74 + else 75 + dev->dat_out[bank] &= ~bit; 76 + 77 + adp5588_gpio_write(dev->client, GPIO_DAT_OUT1 + bank, 78 + dev->dat_out[bank]); 79 + mutex_unlock(&dev->lock); 80 + } 81 + 82 + static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off) 83 + { 84 + int ret; 85 + unsigned bank; 86 + struct adp5588_gpio *dev = 87 + container_of(chip, struct adp5588_gpio, gpio_chip); 88 + 89 + bank = ADP_BANK(off); 90 + 91 + mutex_lock(&dev->lock); 92 + dev->dir[bank] &= ~ADP_BIT(off); 93 + ret = adp5588_gpio_write(dev->client, GPIO_DIR1 + bank, dev->dir[bank]); 94 + mutex_unlock(&dev->lock); 95 + 96 + return ret; 97 + } 98 + 99 + static int adp5588_gpio_direction_output(struct gpio_chip *chip, 100 + unsigned off, int val) 101 + { 102 + int ret; 103 + unsigned bank, bit; 104 + struct adp5588_gpio *dev = 105 + container_of(chip, struct adp5588_gpio, gpio_chip); 106 + 107 + bank = ADP_BANK(off); 108 + bit = ADP_BIT(off); 109 + 110 + mutex_lock(&dev->lock); 111 + dev->dir[bank] |= bit; 112 + 113 + if (val) 114 + dev->dat_out[bank] |= bit; 115 + else 116 + dev->dat_out[bank] &= ~bit; 117 + 118 + ret = adp5588_gpio_write(dev->client, GPIO_DAT_OUT1 + bank, 119 + dev->dat_out[bank]); 120 + ret |= adp5588_gpio_write(dev->client, GPIO_DIR1 + bank, 121 + dev->dir[bank]); 122 + mutex_unlock(&dev->lock); 123 + 124 + return ret; 125 + } 126 + 127 + static int __devinit adp5588_gpio_probe(struct i2c_client *client, 128 + const struct i2c_device_id *id) 129 + { 130 + struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; 131 + struct adp5588_gpio *dev; 132 + struct gpio_chip *gc; 133 + int ret, i, revid; 134 + 135 + if (pdata == NULL) { 136 + dev_err(&client->dev, "missing platform data\n"); 137 + return -ENODEV; 138 + } 139 + 140 + if (!i2c_check_functionality(client->adapter, 141 + I2C_FUNC_SMBUS_BYTE_DATA)) { 142 + dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); 143 + return -EIO; 144 + } 145 + 146 + dev = kzalloc(sizeof(*dev), GFP_KERNEL); 147 + if (dev == NULL) { 148 + dev_err(&client->dev, "failed to alloc memory\n"); 149 + return -ENOMEM; 150 + } 151 + 152 + dev->client = client; 153 + 154 + gc = &dev->gpio_chip; 155 + gc->direction_input = adp5588_gpio_direction_input; 156 + gc->direction_output = adp5588_gpio_direction_output; 157 + gc->get = adp5588_gpio_get_value; 158 + gc->set = adp5588_gpio_set_value; 159 + gc->can_sleep = 1; 160 + 161 + gc->base = pdata->gpio_start; 162 + gc->ngpio = MAXGPIO; 163 + gc->label = client->name; 164 + gc->owner = THIS_MODULE; 165 + 166 + mutex_init(&dev->lock); 167 + 168 + 169 + ret = adp5588_gpio_read(dev->client, DEV_ID); 170 + if (ret < 0) 171 + goto err; 172 + 173 + revid = ret & ADP5588_DEVICE_ID_MASK; 174 + 175 + for (i = 0, ret = 0; i <= ADP_BANK(MAXGPIO); i++) { 176 + dev->dat_out[i] = adp5588_gpio_read(client, GPIO_DAT_OUT1 + i); 177 + dev->dir[i] = adp5588_gpio_read(client, GPIO_DIR1 + i); 178 + ret |= adp5588_gpio_write(client, KP_GPIO1 + i, 0); 179 + ret |= adp5588_gpio_write(client, GPIO_PULL1 + i, 180 + (pdata->pullup_dis_mask >> (8 * i)) & 0xFF); 181 + 182 + if (ret) 183 + goto err; 184 + } 185 + 186 + ret = gpiochip_add(&dev->gpio_chip); 187 + if (ret) 188 + goto err; 189 + 190 + dev_info(&client->dev, "gpios %d..%d on a %s Rev. %d\n", 191 + gc->base, gc->base + gc->ngpio - 1, 192 + client->name, revid); 193 + 194 + if (pdata->setup) { 195 + ret = pdata->setup(client, gc->base, gc->ngpio, pdata->context); 196 + if (ret < 0) 197 + dev_warn(&client->dev, "setup failed, %d\n", ret); 198 + } 199 + 200 + i2c_set_clientdata(client, dev); 201 + return 0; 202 + 203 + err: 204 + kfree(dev); 205 + return ret; 206 + } 207 + 208 + static int __devexit adp5588_gpio_remove(struct i2c_client *client) 209 + { 210 + struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; 211 + struct adp5588_gpio *dev = i2c_get_clientdata(client); 212 + int ret; 213 + 214 + if (pdata->teardown) { 215 + ret = pdata->teardown(client, 216 + dev->gpio_chip.base, dev->gpio_chip.ngpio, 217 + pdata->context); 218 + if (ret < 0) { 219 + dev_err(&client->dev, "teardown failed %d\n", ret); 220 + return ret; 221 + } 222 + } 223 + 224 + ret = gpiochip_remove(&dev->gpio_chip); 225 + if (ret) { 226 + dev_err(&client->dev, "gpiochip_remove failed %d\n", ret); 227 + return ret; 228 + } 229 + 230 + kfree(dev); 231 + return 0; 232 + } 233 + 234 + static const struct i2c_device_id adp5588_gpio_id[] = { 235 + {DRV_NAME, 0}, 236 + {} 237 + }; 238 + 239 + MODULE_DEVICE_TABLE(i2c, adp5588_gpio_id); 240 + 241 + static struct i2c_driver adp5588_gpio_driver = { 242 + .driver = { 243 + .name = DRV_NAME, 244 + }, 245 + .probe = adp5588_gpio_probe, 246 + .remove = __devexit_p(adp5588_gpio_remove), 247 + .id_table = adp5588_gpio_id, 248 + }; 249 + 250 + static int __init adp5588_gpio_init(void) 251 + { 252 + return i2c_add_driver(&adp5588_gpio_driver); 253 + } 254 + 255 + module_init(adp5588_gpio_init); 256 + 257 + static void __exit adp5588_gpio_exit(void) 258 + { 259 + i2c_del_driver(&adp5588_gpio_driver); 260 + } 261 + 262 + module_exit(adp5588_gpio_exit); 263 + 264 + MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 265 + MODULE_DESCRIPTION("GPIO ADP5588 Driver"); 266 + MODULE_LICENSE("GPL");
+12
include/linux/i2c/adp5588.h
··· 89 89 unsigned short unlock_key2; /* Unlock Key 2 */ 90 90 }; 91 91 92 + struct adp5588_gpio_platform_data { 93 + unsigned gpio_start; /* GPIO Chip base # */ 94 + unsigned pullup_dis_mask; /* Pull-Up Disable Mask */ 95 + int (*setup)(struct i2c_client *client, 96 + int gpio, unsigned ngpio, 97 + void *context); 98 + int (*teardown)(struct i2c_client *client, 99 + int gpio, unsigned ngpio, 100 + void *context); 101 + void *context; 102 + }; 103 + 92 104 #endif