aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiaolong Chen <xiaolong.chen@gmail.com>2010-07-26 04:01:11 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-07-26 04:17:41 -0400
commitba9f507a1bea5ca2fc4a19e227c56b60fd5faca3 (patch)
treee3eb50ca1716f9230022eac5497b1ed058e75949
parentf1cba532e8c1001a39650379aa7e04ad974d0592 (diff)
Input: adp5588-keys - export unused GPIO pins
This patch allows exporting GPIO pins not used by the keypad itself to be accessible from elsewhere. Signed-off-by: Xiaolong Chen <xiao-long.chen@motorola.com> Signed-off-by: Yuanbo Ye <yuan-bo.ye@motorola.com> Signed-off-by: Tao Hu <taohu@motorola.com> Acked-by: Michael Hennerich <michael.hennerich@analog.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/keyboard/adp5588-keys.c209
-rw-r--r--include/linux/i2c/adp5588.h1
2 files changed, 208 insertions, 2 deletions
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 9096db73c3c8..c39ec93c0c58 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -19,6 +19,7 @@
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/input.h> 20#include <linux/input.h>
21#include <linux/i2c.h> 21#include <linux/i2c.h>
22#include <linux/gpio.h>
22#include <linux/slab.h> 23#include <linux/slab.h>
23 24
24#include <linux/i2c/adp5588.h> 25#include <linux/i2c/adp5588.h>
@@ -54,6 +55,10 @@
54 55
55#define KEYP_MAX_EVENT 10 56#define KEYP_MAX_EVENT 10
56 57
58#define MAXGPIO 18
59#define ADP_BANK(offs) ((offs) >> 3)
60#define ADP_BIT(offs) (1u << ((offs) & 0x7))
61
57/* 62/*
58 * Early pre 4.0 Silicon required to delay readout by at least 25ms, 63 * Early pre 4.0 Silicon required to delay readout by at least 25ms,
59 * since the Event Counter Register updated 25ms after the interrupt 64 * since the Event Counter Register updated 25ms after the interrupt
@@ -69,6 +74,14 @@ struct adp5588_kpad {
69 unsigned short keycode[ADP5588_KEYMAPSIZE]; 74 unsigned short keycode[ADP5588_KEYMAPSIZE];
70 const struct adp5588_gpi_map *gpimap; 75 const struct adp5588_gpi_map *gpimap;
71 unsigned short gpimapsize; 76 unsigned short gpimapsize;
77#ifdef CONFIG_GPIOLIB
78 unsigned char gpiomap[MAXGPIO];
79 bool export_gpio;
80 struct gpio_chip gc;
81 struct mutex gpio_lock; /* Protect cached dir, dat_out */
82 u8 dat_out[3];
83 u8 dir[3];
84#endif
72}; 85};
73 86
74static int adp5588_read(struct i2c_client *client, u8 reg) 87static int adp5588_read(struct i2c_client *client, u8 reg)
@@ -86,6 +99,183 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
86 return i2c_smbus_write_byte_data(client, reg, val); 99 return i2c_smbus_write_byte_data(client, reg, val);
87} 100}
88 101
102#ifdef CONFIG_GPIOLIB
103static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
104{
105 struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
106 unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
107 unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
108
109 return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
110}
111
112static void adp5588_gpio_set_value(struct gpio_chip *chip,
113 unsigned off, int val)
114{
115 struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
116 unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
117 unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
118
119 mutex_lock(&kpad->gpio_lock);
120
121 if (val)
122 kpad->dat_out[bank] |= bit;
123 else
124 kpad->dat_out[bank] &= ~bit;
125
126 adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
127 kpad->dat_out[bank]);
128
129 mutex_unlock(&kpad->gpio_lock);
130}
131
132static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
133{
134 struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
135 unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
136 unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
137 int ret;
138
139 mutex_lock(&kpad->gpio_lock);
140
141 kpad->dir[bank] &= ~bit;
142 ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
143
144 mutex_unlock(&kpad->gpio_lock);
145
146 return ret;
147}
148
149static int adp5588_gpio_direction_output(struct gpio_chip *chip,
150 unsigned off, int val)
151{
152 struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
153 unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
154 unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
155 int ret;
156
157 mutex_lock(&kpad->gpio_lock);
158
159 kpad->dir[bank] |= bit;
160
161 if (val)
162 kpad->dat_out[bank] |= bit;
163 else
164 kpad->dat_out[bank] &= ~bit;
165
166 ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
167 kpad->dat_out[bank]);
168 ret |= adp5588_write(kpad->client, GPIO_DIR1 + bank,
169 kpad->dir[bank]);
170
171 mutex_unlock(&kpad->gpio_lock);
172
173 return ret;
174}
175
176static int __devinit adp5588_gpio_add(struct device *dev)
177{
178 struct adp5588_kpad *kpad = dev_get_drvdata(dev);
179 const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
180 const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
181 int i, error;
182
183 if (gpio_data) {
184 int j = 0;
185 bool pin_used[MAXGPIO];
186
187 for (i = 0; i < pdata->rows; i++)
188 pin_used[i] = true;
189
190 for (i = 0; i < pdata->cols; i++)
191 pin_used[i + GPI_PIN_COL_BASE - GPI_PIN_BASE] = true;
192
193 for (i = 0; i < kpad->gpimapsize; i++)
194 pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
195
196 for (i = 0; i < MAXGPIO; i++) {
197 if (!pin_used[i])
198 kpad->gpiomap[j++] = i;
199 }
200 kpad->gc.ngpio = j;
201
202 if (kpad->gc.ngpio)
203 kpad->export_gpio = true;
204 }
205
206 if (!kpad->export_gpio) {
207 dev_info(dev, "No unused gpios left to export\n");
208 return 0;
209 }
210
211 kpad->gc.direction_input = adp5588_gpio_direction_input;
212 kpad->gc.direction_output = adp5588_gpio_direction_output;
213 kpad->gc.get = adp5588_gpio_get_value;
214 kpad->gc.set = adp5588_gpio_set_value;
215 kpad->gc.can_sleep = 1;
216
217 kpad->gc.base = gpio_data->gpio_start;
218 kpad->gc.label = kpad->client->name;
219 kpad->gc.owner = THIS_MODULE;
220
221 mutex_init(&kpad->gpio_lock);
222
223 error = gpiochip_add(&kpad->gc);
224 if (error) {
225 dev_err(dev, "gpiochip_add failed, err: %d\n", error);
226 return error;
227 }
228
229 for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
230 kpad->dat_out[i] = adp5588_read(kpad->client,
231 GPIO_DAT_OUT1 + i);
232 kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
233 }
234
235 if (gpio_data->setup) {
236 error = gpio_data->setup(kpad->client,
237 kpad->gc.base, kpad->gc.ngpio,
238 gpio_data->context);
239 if (error)
240 dev_warn(dev, "setup failed, %d\n", error);
241 }
242
243 return 0;
244}
245
246static void __devexit adp5588_gpio_remove(struct device *dev)
247{
248 struct adp5588_kpad *kpad = dev_get_drvdata(dev);
249 const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
250 const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
251 int error;
252
253 if (!kpad->export_gpio)
254 return;
255
256 if (gpio_data->teardown) {
257 error = gpio_data->teardown(kpad->client,
258 kpad->gc.base, kpad->gc.ngpio,
259 gpio_data->context);
260 if (error)
261 dev_warn(dev, "teardown failed %d\n", error);
262 }
263
264 error = gpiochip_remove(&kpad->gc);
265 if (error)
266 dev_warn(dev, "gpiochip_remove failed %d\n", error);
267}
268#else
269static inline int adp5588_gpio_add(struct device *dev)
270{
271 return 0;
272}
273
274static inline void adp5588_gpio_remove(struct device *dev)
275{
276}
277#endif
278
89static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt) 279static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
90{ 280{
91 int i, j; 281 int i, j;
@@ -150,7 +340,8 @@ static irqreturn_t adp5588_irq(int irq, void *handle)
150 340
151static int __devinit adp5588_setup(struct i2c_client *client) 341static int __devinit adp5588_setup(struct i2c_client *client)
152{ 342{
153 struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; 343 const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
344 const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
154 int i, ret; 345 int i, ret;
155 unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; 346 unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
156 347
@@ -184,6 +375,15 @@ static int __devinit adp5588_setup(struct i2c_client *client)
184 ret |= adp5588_write(client, GPI_EM3, evt_mode3); 375 ret |= adp5588_write(client, GPI_EM3, evt_mode3);
185 } 376 }
186 377
378 if (gpio_data) {
379 for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
380 int pull_mask = gpio_data->pullup_dis_mask;
381
382 ret |= adp5588_write(client, GPIO_PULL1 + i,
383 (pull_mask >> (8 * i)) & 0xFF);
384 }
385 }
386
187 ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT | 387 ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
188 OVR_FLOW_INT | K_LCK_INT | 388 OVR_FLOW_INT | K_LCK_INT |
189 GPI_INT | KE_INT); /* Status is W1C */ 389 GPI_INT | KE_INT); /* Status is W1C */
@@ -240,7 +440,7 @@ static int __devinit adp5588_probe(struct i2c_client *client,
240 const struct i2c_device_id *id) 440 const struct i2c_device_id *id)
241{ 441{
242 struct adp5588_kpad *kpad; 442 struct adp5588_kpad *kpad;
243 struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; 443 const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
244 struct input_dev *input; 444 struct input_dev *input;
245 unsigned int revid; 445 unsigned int revid;
246 int ret, i; 446 int ret, i;
@@ -381,6 +581,10 @@ static int __devinit adp5588_probe(struct i2c_client *client,
381 if (kpad->gpimapsize) 581 if (kpad->gpimapsize)
382 adp5588_report_switch_state(kpad); 582 adp5588_report_switch_state(kpad);
383 583
584 error = adp5588_gpio_add(&client->dev);
585 if (error)
586 goto err_free_irq;
587
384 device_init_wakeup(&client->dev, 1); 588 device_init_wakeup(&client->dev, 1);
385 i2c_set_clientdata(client, kpad); 589 i2c_set_clientdata(client, kpad);
386 590
@@ -407,6 +611,7 @@ static int __devexit adp5588_remove(struct i2c_client *client)
407 free_irq(client->irq, kpad); 611 free_irq(client->irq, kpad);
408 cancel_delayed_work_sync(&kpad->work); 612 cancel_delayed_work_sync(&kpad->work);
409 input_unregister_device(kpad->input); 613 input_unregister_device(kpad->input);
614 adp5588_gpio_remove(&client->dev);
410 kfree(kpad); 615 kfree(kpad);
411 616
412 return 0; 617 return 0;
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
index b5f57c498e24..269181b8f623 100644
--- a/include/linux/i2c/adp5588.h
+++ b/include/linux/i2c/adp5588.h
@@ -123,6 +123,7 @@ struct adp5588_kpad_platform_data {
123 unsigned short unlock_key2; /* Unlock Key 2 */ 123 unsigned short unlock_key2; /* Unlock Key 2 */
124 const struct adp5588_gpi_map *gpimap; 124 const struct adp5588_gpi_map *gpimap;
125 unsigned short gpimapsize; 125 unsigned short gpimapsize;
126 const struct adp5588_gpio_platform_data *gpio_data;
126}; 127};
127 128
128struct adp5588_gpio_platform_data { 129struct adp5588_gpio_platform_data {