Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.34-rc4 249 lines 6.0 kB view raw
1/** 2 * drivers/gpio/max7301.c 3 * 4 * Copyright (C) 2006 Juergen Beisert, Pengutronix 5 * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix 6 * Copyright (C) 2009 Wolfram Sang, Pengutronix 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 * The Maxim MAX7300/1 device is an I2C/SPI driven GPIO expander. There are 13 * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more 14 * details 15 * Note: 16 * - DIN must be stable at the rising edge of clock. 17 * - when writing: 18 * - always clock in 16 clocks at once 19 * - at DIN: D15 first, D0 last 20 * - D0..D7 = databyte, D8..D14 = commandbyte 21 * - D15 = low -> write command 22 * - when reading 23 * - always clock in 16 clocks at once 24 * - at DIN: D15 first, D0 last 25 * - D0..D7 = dummy, D8..D14 = register address 26 * - D15 = high -> read command 27 * - raise CS and assert it again 28 * - always clock in 16 clocks at once 29 * - at DOUT: D15 first, D0 last 30 * - D0..D7 contains the data from the first cycle 31 * 32 * The driver exports a standard gpiochip interface 33 */ 34 35#include <linux/module.h> 36#include <linux/init.h> 37#include <linux/platform_device.h> 38#include <linux/mutex.h> 39#include <linux/spi/max7301.h> 40#include <linux/gpio.h> 41#include <linux/slab.h> 42 43/* 44 * Pin configurations, see MAX7301 datasheet page 6 45 */ 46#define PIN_CONFIG_MASK 0x03 47#define PIN_CONFIG_IN_PULLUP 0x03 48#define PIN_CONFIG_IN_WO_PULLUP 0x02 49#define PIN_CONFIG_OUT 0x01 50 51#define PIN_NUMBER 28 52 53static int max7301_direction_input(struct gpio_chip *chip, unsigned offset) 54{ 55 struct max7301 *ts = container_of(chip, struct max7301, chip); 56 u8 *config; 57 u8 offset_bits; 58 int ret; 59 60 /* First 4 pins are unused in the controller */ 61 offset += 4; 62 offset_bits = (offset & 3) << 1; 63 64 config = &ts->port_config[offset >> 2]; 65 66 mutex_lock(&ts->lock); 67 68 /* Standard GPIO API doesn't support pull-ups, has to be extended. 69 * Hard-coding no pollup for now. */ 70 *config = (*config & ~(PIN_CONFIG_MASK << offset_bits)) 71 | (PIN_CONFIG_IN_WO_PULLUP << offset_bits); 72 73 ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config); 74 75 mutex_unlock(&ts->lock); 76 77 return ret; 78} 79 80static int __max7301_set(struct max7301 *ts, unsigned offset, int value) 81{ 82 if (value) { 83 ts->out_level |= 1 << offset; 84 return ts->write(ts->dev, 0x20 + offset, 0x01); 85 } else { 86 ts->out_level &= ~(1 << offset); 87 return ts->write(ts->dev, 0x20 + offset, 0x00); 88 } 89} 90 91static int max7301_direction_output(struct gpio_chip *chip, unsigned offset, 92 int value) 93{ 94 struct max7301 *ts = container_of(chip, struct max7301, chip); 95 u8 *config; 96 u8 offset_bits; 97 int ret; 98 99 /* First 4 pins are unused in the controller */ 100 offset += 4; 101 offset_bits = (offset & 3) << 1; 102 103 config = &ts->port_config[offset >> 2]; 104 105 mutex_lock(&ts->lock); 106 107 *config = (*config & ~(PIN_CONFIG_MASK << offset_bits)) 108 | (PIN_CONFIG_OUT << offset_bits); 109 110 ret = __max7301_set(ts, offset, value); 111 112 if (!ret) 113 ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config); 114 115 mutex_unlock(&ts->lock); 116 117 return ret; 118} 119 120static int max7301_get(struct gpio_chip *chip, unsigned offset) 121{ 122 struct max7301 *ts = container_of(chip, struct max7301, chip); 123 int config, level = -EINVAL; 124 125 /* First 4 pins are unused in the controller */ 126 offset += 4; 127 128 mutex_lock(&ts->lock); 129 130 config = (ts->port_config[offset >> 2] >> ((offset & 3) << 1)) 131 & PIN_CONFIG_MASK; 132 133 switch (config) { 134 case PIN_CONFIG_OUT: 135 /* Output: return cached level */ 136 level = !!(ts->out_level & (1 << offset)); 137 break; 138 case PIN_CONFIG_IN_WO_PULLUP: 139 case PIN_CONFIG_IN_PULLUP: 140 /* Input: read out */ 141 level = ts->read(ts->dev, 0x20 + offset) & 0x01; 142 } 143 mutex_unlock(&ts->lock); 144 145 return level; 146} 147 148static void max7301_set(struct gpio_chip *chip, unsigned offset, int value) 149{ 150 struct max7301 *ts = container_of(chip, struct max7301, chip); 151 152 /* First 4 pins are unused in the controller */ 153 offset += 4; 154 155 mutex_lock(&ts->lock); 156 157 __max7301_set(ts, offset, value); 158 159 mutex_unlock(&ts->lock); 160} 161 162int __devinit __max730x_probe(struct max7301 *ts) 163{ 164 struct device *dev = ts->dev; 165 struct max7301_platform_data *pdata; 166 int i, ret; 167 168 pdata = dev->platform_data; 169 if (!pdata || !pdata->base) { 170 dev_err(dev, "incorrect or missing platform data\n"); 171 return -EINVAL; 172 } 173 174 mutex_init(&ts->lock); 175 dev_set_drvdata(dev, ts); 176 177 /* Power up the chip and disable IRQ output */ 178 ts->write(dev, 0x04, 0x01); 179 180 ts->chip.label = dev->driver->name; 181 182 ts->chip.direction_input = max7301_direction_input; 183 ts->chip.get = max7301_get; 184 ts->chip.direction_output = max7301_direction_output; 185 ts->chip.set = max7301_set; 186 187 ts->chip.base = pdata->base; 188 ts->chip.ngpio = PIN_NUMBER; 189 ts->chip.can_sleep = 1; 190 ts->chip.dev = dev; 191 ts->chip.owner = THIS_MODULE; 192 193 /* 194 * tristate all pins in hardware and cache the 195 * register values for later use. 196 */ 197 for (i = 1; i < 8; i++) { 198 int j; 199 /* 0xAA means input with internal pullup disabled */ 200 ts->write(dev, 0x08 + i, 0xAA); 201 ts->port_config[i] = 0xAA; 202 for (j = 0; j < 4; j++) { 203 int offset = (i - 1) * 4 + j; 204 ret = max7301_direction_input(&ts->chip, offset); 205 if (ret) 206 goto exit_destroy; 207 } 208 } 209 210 ret = gpiochip_add(&ts->chip); 211 if (ret) 212 goto exit_destroy; 213 214 return ret; 215 216exit_destroy: 217 dev_set_drvdata(dev, NULL); 218 mutex_destroy(&ts->lock); 219 return ret; 220} 221EXPORT_SYMBOL_GPL(__max730x_probe); 222 223int __devexit __max730x_remove(struct device *dev) 224{ 225 struct max7301 *ts = dev_get_drvdata(dev); 226 int ret; 227 228 if (ts == NULL) 229 return -ENODEV; 230 231 dev_set_drvdata(dev, NULL); 232 233 /* Power down the chip and disable IRQ output */ 234 ts->write(dev, 0x04, 0x00); 235 236 ret = gpiochip_remove(&ts->chip); 237 if (!ret) { 238 mutex_destroy(&ts->lock); 239 kfree(ts); 240 } else 241 dev_err(dev, "Failed to remove GPIO controller: %d\n", ret); 242 243 return ret; 244} 245EXPORT_SYMBOL_GPL(__max730x_remove); 246 247MODULE_AUTHOR("Juergen Beisert, Wolfram Sang"); 248MODULE_LICENSE("GPL v2"); 249MODULE_DESCRIPTION("MAX730x GPIO-Expanders, generic parts");