diff options
author | Andreas Schallenberg <Andreas.Schallenberg@3alitytechnica.com> | 2012-05-09 03:46:17 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2012-05-18 18:48:34 -0400 |
commit | ae79c19049b75af476adcbcfda6fc29bd93fc6f8 (patch) | |
tree | 8fef28f94ddf49b8c0679ec7de0ae9680b0fb90b /drivers/gpio/gpio-pca953x.c | |
parent | 453007cf472a2b4c1034e850c3004ee9027005f6 (diff) |
Add support for TCA6424A
This patch extends the PCA953x driver to support TI's TCA6424A 24 bit I2C I/O expander. The patch is based on code by Michele
Bevilacqua.
Changes in v2:
- Compare ngpio against 24 in both places, not >16
- Larger datatype now u32 instead of uint.
Bit fields not used for struct members since their address is taken.
- Be precise: TCA6424A (untested for older TCA6424)
Signed-off-by: Andreas Schallenberg<Andreas.Schallenberg@3alitytechnica.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio/gpio-pca953x.c')
-rw-r--r-- | drivers/gpio/gpio-pca953x.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index d3f3e8f54561..1c313c710be3 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #define PCA953X_INVERT 2 | 28 | #define PCA953X_INVERT 2 |
29 | #define PCA953X_DIRECTION 3 | 29 | #define PCA953X_DIRECTION 3 |
30 | 30 | ||
31 | #define REG_ADDR_AI 0x80 | ||
32 | |||
31 | #define PCA957X_IN 0 | 33 | #define PCA957X_IN 0 |
32 | #define PCA957X_INVRT 1 | 34 | #define PCA957X_INVRT 1 |
33 | #define PCA957X_BKEN 2 | 35 | #define PCA957X_BKEN 2 |
@@ -63,15 +65,15 @@ static const struct i2c_device_id pca953x_id[] = { | |||
63 | { "pca6107", 8 | PCA953X_TYPE | PCA_INT, }, | 65 | { "pca6107", 8 | PCA953X_TYPE | PCA_INT, }, |
64 | { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, | 66 | { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, |
65 | { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, | 67 | { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, |
66 | /* NYET: { "tca6424", 24, }, */ | 68 | { "tca6424", 24 | PCA953X_TYPE | PCA_INT, }, |
67 | { } | 69 | { } |
68 | }; | 70 | }; |
69 | MODULE_DEVICE_TABLE(i2c, pca953x_id); | 71 | MODULE_DEVICE_TABLE(i2c, pca953x_id); |
70 | 72 | ||
71 | struct pca953x_chip { | 73 | struct pca953x_chip { |
72 | unsigned gpio_start; | 74 | unsigned gpio_start; |
73 | uint16_t reg_output; | 75 | u32 reg_output; |
74 | uint16_t reg_direction; | 76 | u32 reg_direction; |
75 | struct mutex i2c_lock; | 77 | struct mutex i2c_lock; |
76 | 78 | ||
77 | #ifdef CONFIG_GPIO_PCA953X_IRQ | 79 | #ifdef CONFIG_GPIO_PCA953X_IRQ |
@@ -89,12 +91,20 @@ struct pca953x_chip { | |||
89 | int chip_type; | 91 | int chip_type; |
90 | }; | 92 | }; |
91 | 93 | ||
92 | static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) | 94 | static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) |
93 | { | 95 | { |
94 | int ret = 0; | 96 | int ret = 0; |
95 | 97 | ||
96 | if (chip->gpio_chip.ngpio <= 8) | 98 | if (chip->gpio_chip.ngpio <= 8) |
97 | ret = i2c_smbus_write_byte_data(chip->client, reg, val); | 99 | ret = i2c_smbus_write_byte_data(chip->client, reg, val); |
100 | else if (chip->gpio_chip.ngpio == 24) { | ||
101 | ret = i2c_smbus_write_word_data(chip->client, | ||
102 | (reg << 2) | REG_ADDR_AI, | ||
103 | val & 0xffff); | ||
104 | ret = i2c_smbus_write_byte_data(chip->client, | ||
105 | (reg << 2) + 2, | ||
106 | (val & 0xff0000) >> 16); | ||
107 | } | ||
98 | else { | 108 | else { |
99 | switch (chip->chip_type) { | 109 | switch (chip->chip_type) { |
100 | case PCA953X_TYPE: | 110 | case PCA953X_TYPE: |
@@ -121,12 +131,17 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) | |||
121 | return 0; | 131 | return 0; |
122 | } | 132 | } |
123 | 133 | ||
124 | static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) | 134 | static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) |
125 | { | 135 | { |
126 | int ret; | 136 | int ret; |
127 | 137 | ||
128 | if (chip->gpio_chip.ngpio <= 8) | 138 | if (chip->gpio_chip.ngpio <= 8) |
129 | ret = i2c_smbus_read_byte_data(chip->client, reg); | 139 | ret = i2c_smbus_read_byte_data(chip->client, reg); |
140 | else if (chip->gpio_chip.ngpio == 24) { | ||
141 | ret = i2c_smbus_read_word_data(chip->client, reg << 2); | ||
142 | ret |= (i2c_smbus_read_byte_data(chip->client, | ||
143 | (reg << 2) + 2)<<16); | ||
144 | } | ||
130 | else | 145 | else |
131 | ret = i2c_smbus_read_word_data(chip->client, reg << 1); | 146 | ret = i2c_smbus_read_word_data(chip->client, reg << 1); |
132 | 147 | ||
@@ -135,14 +150,14 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) | |||
135 | return ret; | 150 | return ret; |
136 | } | 151 | } |
137 | 152 | ||
138 | *val = (uint16_t)ret; | 153 | *val = (u32)ret; |
139 | return 0; | 154 | return 0; |
140 | } | 155 | } |
141 | 156 | ||
142 | static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) | 157 | static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) |
143 | { | 158 | { |
144 | struct pca953x_chip *chip; | 159 | struct pca953x_chip *chip; |
145 | uint16_t reg_val; | 160 | uint reg_val; |
146 | int ret, offset = 0; | 161 | int ret, offset = 0; |
147 | 162 | ||
148 | chip = container_of(gc, struct pca953x_chip, gpio_chip); | 163 | chip = container_of(gc, struct pca953x_chip, gpio_chip); |
@@ -173,7 +188,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, | |||
173 | unsigned off, int val) | 188 | unsigned off, int val) |
174 | { | 189 | { |
175 | struct pca953x_chip *chip; | 190 | struct pca953x_chip *chip; |
176 | uint16_t reg_val; | 191 | uint reg_val; |
177 | int ret, offset = 0; | 192 | int ret, offset = 0; |
178 | 193 | ||
179 | chip = container_of(gc, struct pca953x_chip, gpio_chip); | 194 | chip = container_of(gc, struct pca953x_chip, gpio_chip); |
@@ -223,7 +238,7 @@ exit: | |||
223 | static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) | 238 | static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) |
224 | { | 239 | { |
225 | struct pca953x_chip *chip; | 240 | struct pca953x_chip *chip; |
226 | uint16_t reg_val; | 241 | u32 reg_val; |
227 | int ret, offset = 0; | 242 | int ret, offset = 0; |
228 | 243 | ||
229 | chip = container_of(gc, struct pca953x_chip, gpio_chip); | 244 | chip = container_of(gc, struct pca953x_chip, gpio_chip); |
@@ -253,7 +268,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) | |||
253 | static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) | 268 | static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) |
254 | { | 269 | { |
255 | struct pca953x_chip *chip; | 270 | struct pca953x_chip *chip; |
256 | uint16_t reg_val; | 271 | u32 reg_val; |
257 | int ret, offset = 0; | 272 | int ret, offset = 0; |
258 | 273 | ||
259 | chip = container_of(gc, struct pca953x_chip, gpio_chip); | 274 | chip = container_of(gc, struct pca953x_chip, gpio_chip); |
@@ -386,7 +401,7 @@ static struct irq_chip pca953x_irq_chip = { | |||
386 | 401 | ||
387 | static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) | 402 | static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) |
388 | { | 403 | { |
389 | uint16_t cur_stat; | 404 | u32 cur_stat; |
390 | uint16_t old_stat; | 405 | uint16_t old_stat; |
391 | uint16_t pending; | 406 | uint16_t pending; |
392 | uint16_t trigger; | 407 | uint16_t trigger; |
@@ -449,6 +464,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, | |||
449 | { | 464 | { |
450 | struct i2c_client *client = chip->client; | 465 | struct i2c_client *client = chip->client; |
451 | int ret, offset = 0; | 466 | int ret, offset = 0; |
467 | u32 temporary; | ||
452 | 468 | ||
453 | if (irq_base != -1 | 469 | if (irq_base != -1 |
454 | && (id->driver_data & PCA_INT)) { | 470 | && (id->driver_data & PCA_INT)) { |
@@ -462,7 +478,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, | |||
462 | offset = PCA957X_IN; | 478 | offset = PCA957X_IN; |
463 | break; | 479 | break; |
464 | } | 480 | } |
465 | ret = pca953x_read_reg(chip, offset, &chip->irq_stat); | 481 | ret = pca953x_read_reg(chip, offset, &temporary); |
482 | chip->irq_stat = temporary; | ||
466 | if (ret) | 483 | if (ret) |
467 | goto out_failed; | 484 | goto out_failed; |
468 | 485 | ||
@@ -603,7 +620,7 @@ out: | |||
603 | static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert) | 620 | static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert) |
604 | { | 621 | { |
605 | int ret; | 622 | int ret; |
606 | uint16_t val = 0; | 623 | u32 val = 0; |
607 | 624 | ||
608 | /* Let every port in proper state, that could save power */ | 625 | /* Let every port in proper state, that could save power */ |
609 | pca953x_write_reg(chip, PCA957X_PUPD, 0x0); | 626 | pca953x_write_reg(chip, PCA957X_PUPD, 0x0); |