Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / drivers / i2c / busses / i2c-taos-evm.c
1 /*
2  * Driver for the TAOS evaluation modules
3  * These devices include an I2C master which can be controlled over the
4  * serial port.
5  *
6  * Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
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 as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21
22 #include <linux/delay.h>
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include <linux/interrupt.h>
26 #include <linux/input.h>
27 #include <linux/serio.h>
28 #include <linux/init.h>
29 #include <linux/i2c.h>
30
31 #define TAOS_BUFFER_SIZE        63
32
33 #define TAOS_STATE_INIT         0
34 #define TAOS_STATE_IDLE         1
35 #define TAOS_STATE_SEND         2
36 #define TAOS_STATE_RECV         3
37
38 #define TAOS_CMD_RESET          0x12
39
40 static DECLARE_WAIT_QUEUE_HEAD(wq);
41
42 struct taos_data {
43         struct i2c_adapter adapter;
44         struct i2c_client *client;
45         int state;
46         u8 addr;                /* last used address */
47         unsigned char buffer[TAOS_BUFFER_SIZE];
48         unsigned int pos;       /* position inside the buffer */
49 };
50
51 /* TAOS TSL2550 EVM */
52 static struct i2c_board_info tsl2550_info = {
53         I2C_BOARD_INFO("tsl2550", 0x39),
54 };
55
56 /* Instantiate i2c devices based on the adapter name */
57 static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
58 {
59         if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
60                 dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
61                         tsl2550_info.type, tsl2550_info.addr);
62                 return i2c_new_device(adapter, &tsl2550_info);
63         }
64
65         return NULL;
66 }
67
68 static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
69                            unsigned short flags, char read_write, u8 command,
70                            int size, union i2c_smbus_data *data)
71 {
72         struct serio *serio = adapter->algo_data;
73         struct taos_data *taos = serio_get_drvdata(serio);
74         char *p;
75
76         /* Encode our transaction. "@" is for the device address, "$" for the
77            SMBus command and "#" for the data. */
78         p = taos->buffer;
79
80         /* The device remembers the last used address, no need to send it
81            again if it's the same */
82         if (addr != taos->addr)
83                 p += sprintf(p, "@%02X", addr);
84
85         switch (size) {
86         case I2C_SMBUS_BYTE:
87                 if (read_write == I2C_SMBUS_WRITE)
88                         sprintf(p, "$#%02X", command);
89                 else
90                         sprintf(p, "$");
91                 break;
92         case I2C_SMBUS_BYTE_DATA:
93                 if (read_write == I2C_SMBUS_WRITE)
94                         sprintf(p, "$%02X#%02X", command, data->byte);
95                 else
96                         sprintf(p, "$%02X", command);
97                 break;
98         default:
99                 dev_dbg(&adapter->dev, "Unsupported transaction size %d\n",
100                         size);
101                 return -EINVAL;
102         }
103
104         /* Send the transaction to the TAOS EVM */
105         dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
106         taos->pos = 0;
107         taos->state = TAOS_STATE_SEND;
108         serio_write(serio, taos->buffer[0]);
109         wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
110                                          msecs_to_jiffies(250));
111         if (taos->state != TAOS_STATE_IDLE) {
112                 dev_err(&adapter->dev, "Transaction failed "
113                         "(state=%d, pos=%d)\n", taos->state, taos->pos);
114                 taos->addr = 0;
115                 return -EIO;
116         }
117         taos->addr = addr;
118
119         /* Start the transaction and read the answer */
120         taos->pos = 0;
121         taos->state = TAOS_STATE_RECV;
122         serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<');
123         wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
124                                          msecs_to_jiffies(150));
125         if (taos->state != TAOS_STATE_IDLE
126          || taos->pos != 6) {
127                 dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
128                         taos->pos);
129                 return -EIO;
130         }
131         dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
132
133         /* Interpret the returned string */
134         p = taos->buffer + 2;
135         p[3] = '\0';
136         if (!strcmp(p, "NAK"))
137                 return -ENODEV;
138
139         if (read_write == I2C_SMBUS_WRITE) {
140                 if (!strcmp(p, "ACK"))
141                         return 0;
142         } else {
143                 if (p[0] == 'x') {
144                         data->byte = simple_strtol(p + 1, NULL, 16);
145                         return 0;
146                 }
147         }
148
149         return -EIO;
150 }
151
152 static u32 taos_smbus_func(struct i2c_adapter *adapter)
153 {
154         return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA;
155 }
156
157 static const struct i2c_algorithm taos_algorithm = {
158         .smbus_xfer     = taos_smbus_xfer,
159         .functionality  = taos_smbus_func,
160 };
161
162 static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
163                                   unsigned int flags)
164 {
165         struct taos_data *taos = serio_get_drvdata(serio);
166
167         switch (taos->state) {
168         case TAOS_STATE_INIT:
169                 taos->buffer[taos->pos++] = data;
170                 if (data == ':'
171                  || taos->pos == TAOS_BUFFER_SIZE - 1) {
172                         taos->buffer[taos->pos] = '\0';
173                         taos->state = TAOS_STATE_IDLE;
174                         wake_up_interruptible(&wq);
175                 }
176                 break;
177         case TAOS_STATE_SEND:
178                 if (taos->buffer[++taos->pos])
179                         serio_write(serio, taos->buffer[taos->pos]);
180                 else {
181                         taos->state = TAOS_STATE_IDLE;
182                         wake_up_interruptible(&wq);
183                 }
184                 break;
185         case TAOS_STATE_RECV:
186                 taos->buffer[taos->pos++] = data;
187                 if (data == ']') {
188                         taos->buffer[taos->pos] = '\0';
189                         taos->state = TAOS_STATE_IDLE;
190                         wake_up_interruptible(&wq);
191                 }
192                 break;
193         }
194
195         return IRQ_HANDLED;
196 }
197
198 /* Extract the adapter name from the buffer received after reset.
199    The buffer is modified and a pointer inside the buffer is returned. */
200 static char *taos_adapter_name(char *buffer)
201 {
202         char *start, *end;
203
204         start = strstr(buffer, "TAOS ");
205         if (!start)
206                 return NULL;
207
208         end = strchr(start, '\r');
209         if (!end)
210                 return NULL;
211         *end = '\0';
212
213         return start;
214 }
215
216 static int taos_connect(struct serio *serio, struct serio_driver *drv)
217 {
218         struct taos_data *taos;
219         struct i2c_adapter *adapter;
220         char *name;
221         int err;
222
223         taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL);
224         if (!taos) {
225                 err = -ENOMEM;
226                 goto exit;
227         }
228         taos->state = TAOS_STATE_INIT;
229         serio_set_drvdata(serio, taos);
230
231         err = serio_open(serio, drv);
232         if (err)
233                 goto exit_kfree;
234
235         adapter = &taos->adapter;
236         adapter->owner = THIS_MODULE;
237         adapter->algo = &taos_algorithm;
238         adapter->algo_data = serio;
239         adapter->dev.parent = &serio->dev;
240
241         /* Reset the TAOS evaluation module to identify it */
242         serio_write(serio, TAOS_CMD_RESET);
243         wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
244                                          msecs_to_jiffies(2000));
245
246         if (taos->state != TAOS_STATE_IDLE) {
247                 err = -ENODEV;
248                 dev_dbg(&serio->dev, "TAOS EVM reset failed (state=%d, "
249                         "pos=%d)\n", taos->state, taos->pos);
250                 goto exit_close;
251         }
252
253         name = taos_adapter_name(taos->buffer);
254         if (!name) {
255                 err = -ENODEV;
256                 dev_err(&serio->dev, "TAOS EVM identification failed\n");
257                 goto exit_close;
258         }
259         strlcpy(adapter->name, name, sizeof(adapter->name));
260
261         err = i2c_add_adapter(adapter);
262         if (err)
263                 goto exit_close;
264         dev_dbg(&serio->dev, "Connected to TAOS EVM\n");
265
266         taos->client = taos_instantiate_device(adapter);
267         return 0;
268
269  exit_close:
270         serio_close(serio);
271  exit_kfree:
272         serio_set_drvdata(serio, NULL);
273         kfree(taos);
274  exit:
275         return err;
276 }
277
278 static void taos_disconnect(struct serio *serio)
279 {
280         struct taos_data *taos = serio_get_drvdata(serio);
281
282         if (taos->client)
283                 i2c_unregister_device(taos->client);
284         i2c_del_adapter(&taos->adapter);
285         serio_close(serio);
286         serio_set_drvdata(serio, NULL);
287         kfree(taos);
288
289         dev_dbg(&serio->dev, "Disconnected from TAOS EVM\n");
290 }
291
292 static struct serio_device_id taos_serio_ids[] = {
293         {
294                 .type   = SERIO_RS232,
295                 .proto  = SERIO_TAOSEVM,
296                 .id     = SERIO_ANY,
297                 .extra  = SERIO_ANY,
298         },
299         { 0 }
300 };
301 MODULE_DEVICE_TABLE(serio, taos_serio_ids);
302
303 static struct serio_driver taos_drv = {
304         .driver         = {
305                 .name   = "taos-evm",
306         },
307         .description    = "TAOS evaluation module driver",
308         .id_table       = taos_serio_ids,
309         .connect        = taos_connect,
310         .disconnect     = taos_disconnect,
311         .interrupt      = taos_interrupt,
312 };
313
314 static int __init taos_init(void)
315 {
316         return serio_register_driver(&taos_drv);
317 }
318
319 static void __exit taos_exit(void)
320 {
321         serio_unregister_driver(&taos_drv);
322 }
323
324 MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
325 MODULE_DESCRIPTION("TAOS evaluation module driver");
326 MODULE_LICENSE("GPL");
327
328 module_init(taos_init);
329 module_exit(taos_exit);