| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 1 | /* | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 2 |  *  pca953x.c - 4/8/16 bit I/O ports | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 3 |  * | 
 | 4 |  *  Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> | 
 | 5 |  *  Copyright (C) 2007 Marvell International Ltd. | 
 | 6 |  * | 
 | 7 |  *  Derived from drivers/i2c/chips/pca9539.c | 
 | 8 |  * | 
 | 9 |  *  This program is free software; you can redistribute it and/or modify | 
 | 10 |  *  it under the terms of the GNU General Public License as published by | 
 | 11 |  *  the Free Software Foundation; version 2 of the License. | 
 | 12 |  */ | 
 | 13 |  | 
 | 14 | #include <linux/module.h> | 
 | 15 | #include <linux/init.h> | 
| H Hartley Sweeten | d120c17 | 2009-09-22 16:46:37 -0700 | [diff] [blame] | 16 | #include <linux/gpio.h> | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 17 | #include <linux/interrupt.h> | 
 | 18 | #include <linux/irq.h> | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 19 | #include <linux/i2c.h> | 
| Guennadi Liakhovetski | d1c057e3 | 2008-02-06 01:39:02 -0800 | [diff] [blame] | 20 | #include <linux/i2c/pca953x.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 21 | #include <linux/slab.h> | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 22 | #ifdef CONFIG_OF_GPIO | 
 | 23 | #include <linux/of_platform.h> | 
 | 24 | #include <linux/of_gpio.h> | 
 | 25 | #endif | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 26 |  | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 27 | #define PCA953X_INPUT          0 | 
 | 28 | #define PCA953X_OUTPUT         1 | 
 | 29 | #define PCA953X_INVERT         2 | 
 | 30 | #define PCA953X_DIRECTION      3 | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 31 |  | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 32 | #define PCA953X_GPIOS	       0x00FF | 
 | 33 | #define PCA953X_INT	       0x0100 | 
 | 34 |  | 
| Jean Delvare | 3760f73 | 2008-04-29 23:11:40 +0200 | [diff] [blame] | 35 | static const struct i2c_device_id pca953x_id[] = { | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 36 | 	{ "pca9534", 8  | PCA953X_INT, }, | 
 | 37 | 	{ "pca9535", 16 | PCA953X_INT, }, | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 38 | 	{ "pca9536", 4, }, | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 39 | 	{ "pca9537", 4  | PCA953X_INT, }, | 
 | 40 | 	{ "pca9538", 8  | PCA953X_INT, }, | 
 | 41 | 	{ "pca9539", 16 | PCA953X_INT, }, | 
 | 42 | 	{ "pca9554", 8  | PCA953X_INT, }, | 
 | 43 | 	{ "pca9555", 16 | PCA953X_INT, }, | 
| Nate Case | 10dfb54 | 2009-06-17 16:26:18 -0700 | [diff] [blame] | 44 | 	{ "pca9556", 8, }, | 
| Will Newton | f39e578 | 2008-05-01 04:35:10 -0700 | [diff] [blame] | 45 | 	{ "pca9557", 8, }, | 
| David Brownell | ab5dc37 | 2009-01-06 14:42:27 -0800 | [diff] [blame] | 46 |  | 
| David Brownell | 7059d4b | 2008-07-04 09:59:37 -0700 | [diff] [blame] | 47 | 	{ "max7310", 8, }, | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 48 | 	{ "max7312", 16 | PCA953X_INT, }, | 
 | 49 | 	{ "max7313", 16 | PCA953X_INT, }, | 
 | 50 | 	{ "max7315", 8  | PCA953X_INT, }, | 
 | 51 | 	{ "pca6107", 8  | PCA953X_INT, }, | 
 | 52 | 	{ "tca6408", 8  | PCA953X_INT, }, | 
 | 53 | 	{ "tca6416", 16 | PCA953X_INT, }, | 
| David Brownell | ab5dc37 | 2009-01-06 14:42:27 -0800 | [diff] [blame] | 54 | 	/* NYET:  { "tca6424", 24, }, */ | 
| Jean Delvare | 3760f73 | 2008-04-29 23:11:40 +0200 | [diff] [blame] | 55 | 	{ } | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 56 | }; | 
| Jean Delvare | 3760f73 | 2008-04-29 23:11:40 +0200 | [diff] [blame] | 57 | MODULE_DEVICE_TABLE(i2c, pca953x_id); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 58 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 59 | struct pca953x_chip { | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 60 | 	unsigned gpio_start; | 
 | 61 | 	uint16_t reg_output; | 
 | 62 | 	uint16_t reg_direction; | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 63 | 	struct mutex i2c_lock; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 64 |  | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 65 | #ifdef CONFIG_GPIO_PCA953X_IRQ | 
 | 66 | 	struct mutex irq_lock; | 
 | 67 | 	uint16_t irq_mask; | 
 | 68 | 	uint16_t irq_stat; | 
 | 69 | 	uint16_t irq_trig_raise; | 
 | 70 | 	uint16_t irq_trig_fall; | 
 | 71 | 	int	 irq_base; | 
 | 72 | #endif | 
 | 73 |  | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 74 | 	struct i2c_client *client; | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 75 | 	struct pca953x_platform_data *dyn_pdata; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 76 | 	struct gpio_chip gpio_chip; | 
| Uwe Kleine-König | 6215499 | 2010-05-26 14:42:17 -0700 | [diff] [blame] | 77 | 	const char *const *names; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 78 | }; | 
 | 79 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 80 | static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 81 | { | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 82 | 	int ret; | 
 | 83 |  | 
 | 84 | 	if (chip->gpio_chip.ngpio <= 8) | 
 | 85 | 		ret = i2c_smbus_write_byte_data(chip->client, reg, val); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 86 | 	else | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 87 | 		ret = i2c_smbus_write_word_data(chip->client, reg << 1, val); | 
 | 88 |  | 
 | 89 | 	if (ret < 0) { | 
 | 90 | 		dev_err(&chip->client->dev, "failed writing register\n"); | 
| David Brownell | ab5dc37 | 2009-01-06 14:42:27 -0800 | [diff] [blame] | 91 | 		return ret; | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 92 | 	} | 
 | 93 |  | 
 | 94 | 	return 0; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 95 | } | 
 | 96 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 97 | static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 98 | { | 
 | 99 | 	int ret; | 
 | 100 |  | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 101 | 	if (chip->gpio_chip.ngpio <= 8) | 
 | 102 | 		ret = i2c_smbus_read_byte_data(chip->client, reg); | 
 | 103 | 	else | 
 | 104 | 		ret = i2c_smbus_read_word_data(chip->client, reg << 1); | 
 | 105 |  | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 106 | 	if (ret < 0) { | 
 | 107 | 		dev_err(&chip->client->dev, "failed reading register\n"); | 
| David Brownell | ab5dc37 | 2009-01-06 14:42:27 -0800 | [diff] [blame] | 108 | 		return ret; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 109 | 	} | 
 | 110 |  | 
 | 111 | 	*val = (uint16_t)ret; | 
 | 112 | 	return 0; | 
 | 113 | } | 
 | 114 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 115 | static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 116 | { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 117 | 	struct pca953x_chip *chip; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 118 | 	uint16_t reg_val; | 
 | 119 | 	int ret; | 
 | 120 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 121 | 	chip = container_of(gc, struct pca953x_chip, gpio_chip); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 122 |  | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 123 | 	mutex_lock(&chip->i2c_lock); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 124 | 	reg_val = chip->reg_direction | (1u << off); | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 125 | 	ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 126 | 	if (ret) | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 127 | 		goto exit; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 128 |  | 
 | 129 | 	chip->reg_direction = reg_val; | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 130 | 	ret = 0; | 
 | 131 | exit: | 
 | 132 | 	mutex_unlock(&chip->i2c_lock); | 
 | 133 | 	return ret; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 134 | } | 
 | 135 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 136 | static int pca953x_gpio_direction_output(struct gpio_chip *gc, | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 137 | 		unsigned off, int val) | 
 | 138 | { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 139 | 	struct pca953x_chip *chip; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 140 | 	uint16_t reg_val; | 
 | 141 | 	int ret; | 
 | 142 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 143 | 	chip = container_of(gc, struct pca953x_chip, gpio_chip); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 144 |  | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 145 | 	mutex_lock(&chip->i2c_lock); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 146 | 	/* set output level */ | 
 | 147 | 	if (val) | 
 | 148 | 		reg_val = chip->reg_output | (1u << off); | 
 | 149 | 	else | 
 | 150 | 		reg_val = chip->reg_output & ~(1u << off); | 
 | 151 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 152 | 	ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 153 | 	if (ret) | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 154 | 		goto exit; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 155 |  | 
 | 156 | 	chip->reg_output = reg_val; | 
 | 157 |  | 
 | 158 | 	/* then direction */ | 
 | 159 | 	reg_val = chip->reg_direction & ~(1u << off); | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 160 | 	ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 161 | 	if (ret) | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 162 | 		goto exit; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 163 |  | 
 | 164 | 	chip->reg_direction = reg_val; | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 165 | 	ret = 0; | 
 | 166 | exit: | 
 | 167 | 	mutex_unlock(&chip->i2c_lock); | 
 | 168 | 	return ret; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 169 | } | 
 | 170 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 171 | static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 172 | { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 173 | 	struct pca953x_chip *chip; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 174 | 	uint16_t reg_val; | 
 | 175 | 	int ret; | 
 | 176 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 177 | 	chip = container_of(gc, struct pca953x_chip, gpio_chip); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 178 |  | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 179 | 	mutex_lock(&chip->i2c_lock); | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 180 | 	ret = pca953x_read_reg(chip, PCA953X_INPUT, ®_val); | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 181 | 	mutex_unlock(&chip->i2c_lock); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 182 | 	if (ret < 0) { | 
 | 183 | 		/* NOTE:  diagnostic already emitted; that's all we should | 
 | 184 | 		 * do unless gpio_*_value_cansleep() calls become different | 
 | 185 | 		 * from their nonsleeping siblings (and report faults). | 
 | 186 | 		 */ | 
 | 187 | 		return 0; | 
 | 188 | 	} | 
 | 189 |  | 
 | 190 | 	return (reg_val & (1u << off)) ? 1 : 0; | 
 | 191 | } | 
 | 192 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 193 | static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 194 | { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 195 | 	struct pca953x_chip *chip; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 196 | 	uint16_t reg_val; | 
 | 197 | 	int ret; | 
 | 198 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 199 | 	chip = container_of(gc, struct pca953x_chip, gpio_chip); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 200 |  | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 201 | 	mutex_lock(&chip->i2c_lock); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 202 | 	if (val) | 
 | 203 | 		reg_val = chip->reg_output | (1u << off); | 
 | 204 | 	else | 
 | 205 | 		reg_val = chip->reg_output & ~(1u << off); | 
 | 206 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 207 | 	ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 208 | 	if (ret) | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 209 | 		goto exit; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 210 |  | 
 | 211 | 	chip->reg_output = reg_val; | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 212 | exit: | 
 | 213 | 	mutex_unlock(&chip->i2c_lock); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 214 | } | 
 | 215 |  | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 216 | static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 217 | { | 
 | 218 | 	struct gpio_chip *gc; | 
 | 219 |  | 
 | 220 | 	gc = &chip->gpio_chip; | 
 | 221 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 222 | 	gc->direction_input  = pca953x_gpio_direction_input; | 
 | 223 | 	gc->direction_output = pca953x_gpio_direction_output; | 
 | 224 | 	gc->get = pca953x_gpio_get_value; | 
 | 225 | 	gc->set = pca953x_gpio_set_value; | 
| Arnaud Patard | 8420780 | 2008-03-10 11:43:48 -0700 | [diff] [blame] | 226 | 	gc->can_sleep = 1; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 227 |  | 
 | 228 | 	gc->base = chip->gpio_start; | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 229 | 	gc->ngpio = gpios; | 
 | 230 | 	gc->label = chip->client->name; | 
| David Brownell | d8f388d | 2008-07-25 01:46:07 -0700 | [diff] [blame] | 231 | 	gc->dev = &chip->client->dev; | 
| Guennadi Liakhovetski | d72cbed | 2008-04-28 02:14:45 -0700 | [diff] [blame] | 232 | 	gc->owner = THIS_MODULE; | 
| Daniel Silverstone | 77906a54 | 2009-06-17 16:26:15 -0700 | [diff] [blame] | 233 | 	gc->names = chip->names; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 234 | } | 
 | 235 |  | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 236 | #ifdef CONFIG_GPIO_PCA953X_IRQ | 
 | 237 | static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) | 
 | 238 | { | 
 | 239 | 	struct pca953x_chip *chip; | 
 | 240 |  | 
 | 241 | 	chip = container_of(gc, struct pca953x_chip, gpio_chip); | 
 | 242 | 	return chip->irq_base + off; | 
 | 243 | } | 
 | 244 |  | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 245 | static void pca953x_irq_mask(struct irq_data *d) | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 246 | { | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 247 | 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 248 |  | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 249 | 	chip->irq_mask &= ~(1 << (d->irq - chip->irq_base)); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 250 | } | 
 | 251 |  | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 252 | static void pca953x_irq_unmask(struct irq_data *d) | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 253 | { | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 254 | 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 255 |  | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 256 | 	chip->irq_mask |= 1 << (d->irq - chip->irq_base); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 257 | } | 
 | 258 |  | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 259 | static void pca953x_irq_bus_lock(struct irq_data *d) | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 260 | { | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 261 | 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 262 |  | 
 | 263 | 	mutex_lock(&chip->irq_lock); | 
 | 264 | } | 
 | 265 |  | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 266 | static void pca953x_irq_bus_sync_unlock(struct irq_data *d) | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 267 | { | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 268 | 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); | 
| Marc Zyngier | a2cb9ae | 2010-04-27 13:13:07 -0700 | [diff] [blame] | 269 | 	uint16_t new_irqs; | 
 | 270 | 	uint16_t level; | 
 | 271 |  | 
 | 272 | 	/* Look for any newly setup interrupt */ | 
 | 273 | 	new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; | 
 | 274 | 	new_irqs &= ~chip->reg_direction; | 
 | 275 |  | 
 | 276 | 	while (new_irqs) { | 
 | 277 | 		level = __ffs(new_irqs); | 
 | 278 | 		pca953x_gpio_direction_input(&chip->gpio_chip, level); | 
 | 279 | 		new_irqs &= ~(1 << level); | 
 | 280 | 	} | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 281 |  | 
 | 282 | 	mutex_unlock(&chip->irq_lock); | 
 | 283 | } | 
 | 284 |  | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 285 | static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 286 | { | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 287 | 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); | 
 | 288 | 	uint16_t level = d->irq - chip->irq_base; | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 289 | 	uint16_t mask = 1 << level; | 
 | 290 |  | 
 | 291 | 	if (!(type & IRQ_TYPE_EDGE_BOTH)) { | 
 | 292 | 		dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 293 | 			d->irq, type); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 294 | 		return -EINVAL; | 
 | 295 | 	} | 
 | 296 |  | 
 | 297 | 	if (type & IRQ_TYPE_EDGE_FALLING) | 
 | 298 | 		chip->irq_trig_fall |= mask; | 
 | 299 | 	else | 
 | 300 | 		chip->irq_trig_fall &= ~mask; | 
 | 301 |  | 
 | 302 | 	if (type & IRQ_TYPE_EDGE_RISING) | 
 | 303 | 		chip->irq_trig_raise |= mask; | 
 | 304 | 	else | 
 | 305 | 		chip->irq_trig_raise &= ~mask; | 
 | 306 |  | 
| Marc Zyngier | a2cb9ae | 2010-04-27 13:13:07 -0700 | [diff] [blame] | 307 | 	return 0; | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 308 | } | 
 | 309 |  | 
 | 310 | static struct irq_chip pca953x_irq_chip = { | 
 | 311 | 	.name			= "pca953x", | 
| Lennert Buytenhek | 6f5cfc0 | 2011-01-12 17:00:15 -0800 | [diff] [blame] | 312 | 	.irq_mask		= pca953x_irq_mask, | 
 | 313 | 	.irq_unmask		= pca953x_irq_unmask, | 
 | 314 | 	.irq_bus_lock		= pca953x_irq_bus_lock, | 
 | 315 | 	.irq_bus_sync_unlock	= pca953x_irq_bus_sync_unlock, | 
 | 316 | 	.irq_set_type		= pca953x_irq_set_type, | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 317 | }; | 
 | 318 |  | 
 | 319 | static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) | 
 | 320 | { | 
 | 321 | 	uint16_t cur_stat; | 
 | 322 | 	uint16_t old_stat; | 
 | 323 | 	uint16_t pending; | 
 | 324 | 	uint16_t trigger; | 
 | 325 | 	int ret; | 
 | 326 |  | 
 | 327 | 	ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat); | 
 | 328 | 	if (ret) | 
 | 329 | 		return 0; | 
 | 330 |  | 
 | 331 | 	/* Remove output pins from the equation */ | 
 | 332 | 	cur_stat &= chip->reg_direction; | 
 | 333 |  | 
 | 334 | 	old_stat = chip->irq_stat; | 
 | 335 | 	trigger = (cur_stat ^ old_stat) & chip->irq_mask; | 
 | 336 |  | 
 | 337 | 	if (!trigger) | 
 | 338 | 		return 0; | 
 | 339 |  | 
 | 340 | 	chip->irq_stat = cur_stat; | 
 | 341 |  | 
 | 342 | 	pending = (old_stat & chip->irq_trig_fall) | | 
 | 343 | 		  (cur_stat & chip->irq_trig_raise); | 
 | 344 | 	pending &= trigger; | 
 | 345 |  | 
 | 346 | 	return pending; | 
 | 347 | } | 
 | 348 |  | 
 | 349 | static irqreturn_t pca953x_irq_handler(int irq, void *devid) | 
 | 350 | { | 
 | 351 | 	struct pca953x_chip *chip = devid; | 
 | 352 | 	uint16_t pending; | 
 | 353 | 	uint16_t level; | 
 | 354 |  | 
 | 355 | 	pending = pca953x_irq_pending(chip); | 
 | 356 |  | 
 | 357 | 	if (!pending) | 
 | 358 | 		return IRQ_HANDLED; | 
 | 359 |  | 
 | 360 | 	do { | 
 | 361 | 		level = __ffs(pending); | 
| Alek Du | 8a233f0 | 2010-10-26 14:22:41 -0700 | [diff] [blame] | 362 | 		generic_handle_irq(level + chip->irq_base); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 363 |  | 
 | 364 | 		pending &= ~(1 << level); | 
 | 365 | 	} while (pending); | 
 | 366 |  | 
 | 367 | 	return IRQ_HANDLED; | 
 | 368 | } | 
 | 369 |  | 
 | 370 | static int pca953x_irq_setup(struct pca953x_chip *chip, | 
 | 371 | 			     const struct i2c_device_id *id) | 
 | 372 | { | 
 | 373 | 	struct i2c_client *client = chip->client; | 
 | 374 | 	struct pca953x_platform_data *pdata = client->dev.platform_data; | 
 | 375 | 	int ret; | 
 | 376 |  | 
| Alek Du | 8a233f0 | 2010-10-26 14:22:41 -0700 | [diff] [blame] | 377 | 	if (pdata->irq_base != -1 | 
 | 378 | 			&& (id->driver_data & PCA953X_INT)) { | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 379 | 		int lvl; | 
 | 380 |  | 
 | 381 | 		ret = pca953x_read_reg(chip, PCA953X_INPUT, | 
 | 382 | 				       &chip->irq_stat); | 
 | 383 | 		if (ret) | 
 | 384 | 			goto out_failed; | 
 | 385 |  | 
 | 386 | 		/* | 
 | 387 | 		 * There is no way to know which GPIO line generated the | 
 | 388 | 		 * interrupt.  We have to rely on the previous read for | 
 | 389 | 		 * this purpose. | 
 | 390 | 		 */ | 
 | 391 | 		chip->irq_stat &= chip->reg_direction; | 
 | 392 | 		chip->irq_base = pdata->irq_base; | 
 | 393 | 		mutex_init(&chip->irq_lock); | 
 | 394 |  | 
 | 395 | 		for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { | 
 | 396 | 			int irq = lvl + chip->irq_base; | 
 | 397 |  | 
| Thomas Gleixner | b51804b | 2011-03-24 21:27:36 +0000 | [diff] [blame] | 398 | 			irq_set_chip_data(irq, chip); | 
 | 399 | 			irq_set_chip_and_handler(irq, &pca953x_irq_chip, | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 400 | 						 handle_edge_irq); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 401 | #ifdef CONFIG_ARM | 
 | 402 | 			set_irq_flags(irq, IRQF_VALID); | 
 | 403 | #else | 
| Thomas Gleixner | b51804b | 2011-03-24 21:27:36 +0000 | [diff] [blame] | 404 | 			irq_set_noprobe(irq); | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 405 | #endif | 
 | 406 | 		} | 
 | 407 |  | 
 | 408 | 		ret = request_threaded_irq(client->irq, | 
 | 409 | 					   NULL, | 
 | 410 | 					   pca953x_irq_handler, | 
| Alek Du | 8a233f0 | 2010-10-26 14:22:41 -0700 | [diff] [blame] | 411 | 					   IRQF_TRIGGER_RISING | | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 412 | 					   IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 
 | 413 | 					   dev_name(&client->dev), chip); | 
 | 414 | 		if (ret) { | 
 | 415 | 			dev_err(&client->dev, "failed to request irq %d\n", | 
 | 416 | 				client->irq); | 
 | 417 | 			goto out_failed; | 
 | 418 | 		} | 
 | 419 |  | 
 | 420 | 		chip->gpio_chip.to_irq = pca953x_gpio_to_irq; | 
 | 421 | 	} | 
 | 422 |  | 
 | 423 | 	return 0; | 
 | 424 |  | 
 | 425 | out_failed: | 
| Alek Du | 8a233f0 | 2010-10-26 14:22:41 -0700 | [diff] [blame] | 426 | 	chip->irq_base = -1; | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 427 | 	return ret; | 
 | 428 | } | 
 | 429 |  | 
 | 430 | static void pca953x_irq_teardown(struct pca953x_chip *chip) | 
 | 431 | { | 
| Alek Du | 8a233f0 | 2010-10-26 14:22:41 -0700 | [diff] [blame] | 432 | 	if (chip->irq_base != -1) | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 433 | 		free_irq(chip->client->irq, chip); | 
 | 434 | } | 
 | 435 | #else /* CONFIG_GPIO_PCA953X_IRQ */ | 
 | 436 | static int pca953x_irq_setup(struct pca953x_chip *chip, | 
 | 437 | 			     const struct i2c_device_id *id) | 
 | 438 | { | 
 | 439 | 	struct i2c_client *client = chip->client; | 
 | 440 | 	struct pca953x_platform_data *pdata = client->dev.platform_data; | 
 | 441 |  | 
| Alek Du | 8a233f0 | 2010-10-26 14:22:41 -0700 | [diff] [blame] | 442 | 	if (pdata->irq_base != -1 && (id->driver_data & PCA953X_INT)) | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 443 | 		dev_warn(&client->dev, "interrupt support not compiled in\n"); | 
 | 444 |  | 
 | 445 | 	return 0; | 
 | 446 | } | 
 | 447 |  | 
 | 448 | static void pca953x_irq_teardown(struct pca953x_chip *chip) | 
 | 449 | { | 
 | 450 | } | 
 | 451 | #endif | 
 | 452 |  | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 453 | /* | 
 | 454 |  * Handlers for alternative sources of platform_data | 
 | 455 |  */ | 
 | 456 | #ifdef CONFIG_OF_GPIO | 
 | 457 | /* | 
 | 458 |  * Translate OpenFirmware node properties into platform_data | 
 | 459 |  */ | 
 | 460 | static struct pca953x_platform_data * | 
 | 461 | pca953x_get_alt_pdata(struct i2c_client *client) | 
 | 462 | { | 
 | 463 | 	struct pca953x_platform_data *pdata; | 
 | 464 | 	struct device_node *node; | 
| Dirk Eibach | 1648237 | 2011-02-24 10:20:43 +0100 | [diff] [blame] | 465 | 	const __be32 *val; | 
 | 466 | 	int size; | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 467 |  | 
| Grant Likely | 61c7a08 | 2010-04-13 16:12:29 -0700 | [diff] [blame] | 468 | 	node = client->dev.of_node; | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 469 | 	if (node == NULL) | 
 | 470 | 		return NULL; | 
 | 471 |  | 
 | 472 | 	pdata = kzalloc(sizeof(struct pca953x_platform_data), GFP_KERNEL); | 
 | 473 | 	if (pdata == NULL) { | 
 | 474 | 		dev_err(&client->dev, "Unable to allocate platform_data\n"); | 
 | 475 | 		return NULL; | 
 | 476 | 	} | 
 | 477 |  | 
 | 478 | 	pdata->gpio_base = -1; | 
| Dirk Eibach | 1648237 | 2011-02-24 10:20:43 +0100 | [diff] [blame] | 479 | 	val = of_get_property(node, "linux,gpio-base", &size); | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 480 | 	if (val) { | 
| Dirk Eibach | 1648237 | 2011-02-24 10:20:43 +0100 | [diff] [blame] | 481 | 		if (size != sizeof(*val)) | 
 | 482 | 			dev_warn(&client->dev, "%s: wrong linux,gpio-base\n", | 
 | 483 | 				 node->full_name); | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 484 | 		else | 
| Dirk Eibach | 1648237 | 2011-02-24 10:20:43 +0100 | [diff] [blame] | 485 | 			pdata->gpio_base = be32_to_cpup(val); | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 486 | 	} | 
 | 487 |  | 
 | 488 | 	val = of_get_property(node, "polarity", NULL); | 
 | 489 | 	if (val) | 
 | 490 | 		pdata->invert = *val; | 
 | 491 |  | 
 | 492 | 	return pdata; | 
 | 493 | } | 
 | 494 | #else | 
 | 495 | static struct pca953x_platform_data * | 
 | 496 | pca953x_get_alt_pdata(struct i2c_client *client) | 
 | 497 | { | 
 | 498 | 	return NULL; | 
 | 499 | } | 
 | 500 | #endif | 
 | 501 |  | 
| Jean Delvare | d2653e9 | 2008-04-29 23:11:39 +0200 | [diff] [blame] | 502 | static int __devinit pca953x_probe(struct i2c_client *client, | 
| Jean Delvare | 3760f73 | 2008-04-29 23:11:40 +0200 | [diff] [blame] | 503 | 				   const struct i2c_device_id *id) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 504 | { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 505 | 	struct pca953x_platform_data *pdata; | 
 | 506 | 	struct pca953x_chip *chip; | 
| Will Newton | f39e578 | 2008-05-01 04:35:10 -0700 | [diff] [blame] | 507 | 	int ret; | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 508 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 509 | 	chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 510 | 	if (chip == NULL) | 
 | 511 | 		return -ENOMEM; | 
 | 512 |  | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 513 | 	pdata = client->dev.platform_data; | 
 | 514 | 	if (pdata == NULL) { | 
 | 515 | 		pdata = pca953x_get_alt_pdata(client); | 
 | 516 | 		/* | 
 | 517 | 		 * Unlike normal platform_data, this is allocated | 
 | 518 | 		 * dynamically and must be freed in the driver | 
 | 519 | 		 */ | 
 | 520 | 		chip->dyn_pdata = pdata; | 
 | 521 | 	} | 
 | 522 |  | 
 | 523 | 	if (pdata == NULL) { | 
 | 524 | 		dev_dbg(&client->dev, "no platform data\n"); | 
 | 525 | 		ret = -EINVAL; | 
 | 526 | 		goto out_failed; | 
 | 527 | 	} | 
 | 528 |  | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 529 | 	chip->client = client; | 
 | 530 |  | 
 | 531 | 	chip->gpio_start = pdata->gpio_base; | 
 | 532 |  | 
| Daniel Silverstone | 77906a54 | 2009-06-17 16:26:15 -0700 | [diff] [blame] | 533 | 	chip->names = pdata->names; | 
 | 534 |  | 
| Roland Stigge | 6e20fb1 | 2011-02-10 15:01:23 -0800 | [diff] [blame] | 535 | 	mutex_init(&chip->i2c_lock); | 
 | 536 |  | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 537 | 	/* initialize cached registers from their original values. | 
 | 538 | 	 * we can't share this chip with another i2c master. | 
 | 539 | 	 */ | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 540 | 	pca953x_setup_gpio(chip, id->driver_data & PCA953X_GPIOS); | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 541 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 542 | 	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 543 | 	if (ret) | 
 | 544 | 		goto out_failed; | 
 | 545 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 546 | 	ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 547 | 	if (ret) | 
 | 548 | 		goto out_failed; | 
 | 549 |  | 
 | 550 | 	/* set platform specific polarity inversion */ | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 551 | 	ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 552 | 	if (ret) | 
 | 553 | 		goto out_failed; | 
 | 554 |  | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 555 | 	ret = pca953x_irq_setup(chip, id); | 
 | 556 | 	if (ret) | 
 | 557 | 		goto out_failed; | 
| Guennadi Liakhovetski | f5e8ff4 | 2008-02-06 01:39:04 -0800 | [diff] [blame] | 558 |  | 
 | 559 | 	ret = gpiochip_add(&chip->gpio_chip); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 560 | 	if (ret) | 
 | 561 | 		goto out_failed; | 
 | 562 |  | 
 | 563 | 	if (pdata->setup) { | 
 | 564 | 		ret = pdata->setup(client, chip->gpio_chip.base, | 
 | 565 | 				chip->gpio_chip.ngpio, pdata->context); | 
 | 566 | 		if (ret < 0) | 
 | 567 | 			dev_warn(&client->dev, "setup failed, %d\n", ret); | 
 | 568 | 	} | 
 | 569 |  | 
 | 570 | 	i2c_set_clientdata(client, chip); | 
 | 571 | 	return 0; | 
 | 572 |  | 
 | 573 | out_failed: | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 574 | 	pca953x_irq_teardown(chip); | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 575 | 	kfree(chip->dyn_pdata); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 576 | 	kfree(chip); | 
 | 577 | 	return ret; | 
 | 578 | } | 
 | 579 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 580 | static int pca953x_remove(struct i2c_client *client) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 581 | { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 582 | 	struct pca953x_platform_data *pdata = client->dev.platform_data; | 
 | 583 | 	struct pca953x_chip *chip = i2c_get_clientdata(client); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 584 | 	int ret = 0; | 
 | 585 |  | 
 | 586 | 	if (pdata->teardown) { | 
 | 587 | 		ret = pdata->teardown(client, chip->gpio_chip.base, | 
 | 588 | 				chip->gpio_chip.ngpio, pdata->context); | 
 | 589 | 		if (ret < 0) { | 
 | 590 | 			dev_err(&client->dev, "%s failed, %d\n", | 
 | 591 | 					"teardown", ret); | 
 | 592 | 			return ret; | 
 | 593 | 		} | 
 | 594 | 	} | 
 | 595 |  | 
 | 596 | 	ret = gpiochip_remove(&chip->gpio_chip); | 
 | 597 | 	if (ret) { | 
 | 598 | 		dev_err(&client->dev, "%s failed, %d\n", | 
 | 599 | 				"gpiochip_remove()", ret); | 
 | 600 | 		return ret; | 
 | 601 | 	} | 
 | 602 |  | 
| Marc Zyngier | 89ea8bb | 2010-03-05 13:44:36 -0800 | [diff] [blame] | 603 | 	pca953x_irq_teardown(chip); | 
| Nate Case | 1965d30 | 2009-06-17 16:26:17 -0700 | [diff] [blame] | 604 | 	kfree(chip->dyn_pdata); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 605 | 	kfree(chip); | 
 | 606 | 	return 0; | 
 | 607 | } | 
 | 608 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 609 | static struct i2c_driver pca953x_driver = { | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 610 | 	.driver = { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 611 | 		.name	= "pca953x", | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 612 | 	}, | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 613 | 	.probe		= pca953x_probe, | 
 | 614 | 	.remove		= pca953x_remove, | 
| Jean Delvare | 3760f73 | 2008-04-29 23:11:40 +0200 | [diff] [blame] | 615 | 	.id_table	= pca953x_id, | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 616 | }; | 
 | 617 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 618 | static int __init pca953x_init(void) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 619 | { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 620 | 	return i2c_add_driver(&pca953x_driver); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 621 | } | 
| David Brownell | 2f8d119 | 2008-10-15 22:03:13 -0700 | [diff] [blame] | 622 | /* register after i2c postcore initcall and before | 
 | 623 |  * subsys initcalls that may rely on these GPIOs | 
 | 624 |  */ | 
 | 625 | subsys_initcall(pca953x_init); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 626 |  | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 627 | static void __exit pca953x_exit(void) | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 628 | { | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 629 | 	i2c_del_driver(&pca953x_driver); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 630 | } | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 631 | module_exit(pca953x_exit); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 632 |  | 
 | 633 | MODULE_AUTHOR("eric miao <eric.miao@marvell.com>"); | 
| Guennadi Liakhovetski | f3dc363 | 2008-02-06 01:39:03 -0800 | [diff] [blame] | 634 | MODULE_DESCRIPTION("GPIO expander driver for PCA953x"); | 
| eric miao | 9e60fdc | 2008-02-04 22:28:26 -0800 | [diff] [blame] | 635 | MODULE_LICENSE("GPL"); |