Blame view
drivers/gpio/max7301.c
7.62 KB
0c36ec314 gpio: gpio driver... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
/** * drivers/gpio/max7301.c * * Copyright (C) 2006 Juergen Beisert, Pengutronix * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * The Maxim's MAX7301 device is an SPI driven GPIO expander. There are * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more * details * Note: * - DIN must be stable at the rising edge of clock. * - when writing: * - always clock in 16 clocks at once * - at DIN: D15 first, D0 last * - D0..D7 = databyte, D8..D14 = commandbyte * - D15 = low -> write command * - when reading * - always clock in 16 clocks at once * - at DIN: D15 first, D0 last * - D0..D7 = dummy, D8..D14 = register address * - D15 = high -> read command * - raise CS and assert it again * - always clock in 16 clocks at once * - at DOUT: D15 first, D0 last * - D0..D7 contains the data from the first cycle * * The driver exports a standard gpiochip interface */ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/spi/spi.h> #include <linux/spi/max7301.h> #include <linux/gpio.h> #define DRIVER_NAME "max7301" /* * Pin configurations, see MAX7301 datasheet page 6 */ #define PIN_CONFIG_MASK 0x03 #define PIN_CONFIG_IN_PULLUP 0x03 #define PIN_CONFIG_IN_WO_PULLUP 0x02 #define PIN_CONFIG_OUT 0x01 #define PIN_NUMBER 28 /* * Some registers must be read back to modify. * To save time we cache them here in memory */ struct max7301 { struct mutex lock; u8 port_config[8]; /* field 0 is unused */ u32 out_level; /* cached output levels */ struct gpio_chip chip; struct spi_device *spi; }; /** * max7301_write - Write a new register content * @spi: The SPI device * @reg: Register offset * @val: Value to write * * A write to the MAX7301 means one message with one transfer * * Returns 0 if successful or a negative value on error */ static int max7301_write(struct spi_device *spi, unsigned int reg, unsigned int val) { u16 word = ((reg & 0x7F) << 8) | (val & 0xFF); return spi_write(spi, (const u8 *)&word, sizeof(word)); } /** * max7301_read - Read back register content * @spi: The SPI device * @reg: Register offset * * A read from the MAX7301 means two transfers; here, one message each * * Returns positive 8 bit value from device if successful or a * negative value on error */ static int max7301_read(struct spi_device *spi, unsigned int reg) { int ret; u16 word; word = 0x8000 | (reg << 8); ret = spi_write(spi, (const u8 *)&word, sizeof(word)); if (ret) return ret; /* * This relies on the fact, that a transfer with NULL tx_buf shifts out * zero bytes (=NOOP for MAX7301) */ ret = spi_read(spi, (u8 *)&word, sizeof(word)); if (ret) return ret; return word & 0xff; } static int max7301_direction_input(struct gpio_chip *chip, unsigned offset) { struct max7301 *ts = container_of(chip, struct max7301, chip); u8 *config; int ret; /* First 4 pins are unused in the controller */ offset += 4; config = &ts->port_config[offset >> 2]; mutex_lock(&ts->lock); /* Standard GPIO API doesn't support pull-ups, has to be extended. * Hard-coding no pollup for now. */ *config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3)); ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config); mutex_unlock(&ts->lock); return ret; } static int __max7301_set(struct max7301 *ts, unsigned offset, int value) { if (value) { ts->out_level |= 1 << offset; return max7301_write(ts->spi, 0x20 + offset, 0x01); } else { ts->out_level &= ~(1 << offset); return max7301_write(ts->spi, 0x20 + offset, 0x00); } } static int max7301_direction_output(struct gpio_chip *chip, unsigned offset, int value) { struct max7301 *ts = container_of(chip, struct max7301, chip); u8 *config; int ret; /* First 4 pins are unused in the controller */ offset += 4; config = &ts->port_config[offset >> 2]; mutex_lock(&ts->lock); *config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3)); ret = __max7301_set(ts, offset, value); if (!ret) ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config); mutex_unlock(&ts->lock); return ret; } static int max7301_get(struct gpio_chip *chip, unsigned offset) { struct max7301 *ts = container_of(chip, struct max7301, chip); int config, level = -EINVAL; /* First 4 pins are unused in the controller */ offset += 4; mutex_lock(&ts->lock); config = (ts->port_config[offset >> 2] >> ((offset & 3) * 2)) & 3; switch (config) { case 1: /* Output: return cached level */ level = !!(ts->out_level & (1 << offset)); break; case 2: case 3: /* Input: read out */ level = max7301_read(ts->spi, 0x20 + offset) & 0x01; } mutex_unlock(&ts->lock); return level; } static void max7301_set(struct gpio_chip *chip, unsigned offset, int value) { struct max7301 *ts = container_of(chip, struct max7301, chip); /* First 4 pins are unused in the controller */ offset += 4; mutex_lock(&ts->lock); __max7301_set(ts, offset, value); mutex_unlock(&ts->lock); } static int __devinit max7301_probe(struct spi_device *spi) { struct max7301 *ts; struct max7301_platform_data *pdata; int i, ret; pdata = spi->dev.platform_data; if (!pdata || !pdata->base) return -ENODEV; /* * bits_per_word cannot be configured in platform data */ spi->bits_per_word = 16; ret = spi_setup(spi); if (ret < 0) return ret; ts = kzalloc(sizeof(struct max7301), GFP_KERNEL); if (!ts) return -ENOMEM; mutex_init(&ts->lock); dev_set_drvdata(&spi->dev, ts); /* Power up the chip and disable IRQ output */ max7301_write(spi, 0x04, 0x01); ts->spi = spi; ts->chip.label = DRIVER_NAME, ts->chip.direction_input = max7301_direction_input; ts->chip.get = max7301_get; ts->chip.direction_output = max7301_direction_output; ts->chip.set = max7301_set; ts->chip.base = pdata->base; ts->chip.ngpio = PIN_NUMBER; ts->chip.can_sleep = 1; ts->chip.dev = &spi->dev; ts->chip.owner = THIS_MODULE; ret = gpiochip_add(&ts->chip); if (ret) goto exit_destroy; /* * tristate all pins in hardware and cache the * register values for later use. */ for (i = 1; i < 8; i++) { int j; /* 0xAA means input with internal pullup disabled */ max7301_write(spi, 0x08 + i, 0xAA); ts->port_config[i] = 0xAA; for (j = 0; j < 4; j++) { int idx = ts->chip.base + (i - 1) * 4 + j; ret = gpio_direction_input(idx); if (ret) goto exit_remove; gpio_free(idx); } } return ret; exit_remove: gpiochip_remove(&ts->chip); exit_destroy: dev_set_drvdata(&spi->dev, NULL); mutex_destroy(&ts->lock); kfree(ts); return ret; } static int max7301_remove(struct spi_device *spi) { struct max7301 *ts; int ret; ts = dev_get_drvdata(&spi->dev); if (ts == NULL) return -ENODEV; dev_set_drvdata(&spi->dev, NULL); /* Power down the chip and disable IRQ output */ max7301_write(spi, 0x04, 0x00); ret = gpiochip_remove(&ts->chip); if (!ret) { mutex_destroy(&ts->lock); kfree(ts); } else dev_err(&spi->dev, "Failed to remove the GPIO controller: %d ", ret); return ret; } static struct spi_driver max7301_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, }, .probe = max7301_probe, .remove = __devexit_p(max7301_remove), }; static int __init max7301_init(void) { return spi_register_driver(&max7301_driver); } static void __exit max7301_exit(void) { spi_unregister_driver(&max7301_driver); } module_init(max7301_init); module_exit(max7301_exit); MODULE_AUTHOR("Juergen Beisert"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MAX7301 SPI based GPIO-Expander"); |