Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
i2c-taos-evm.c
Go to the documentation of this file.
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 <[email protected]>
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_EOFF 2
36 #define TAOS_STATE_RECV 3
37 
38 #define TAOS_CMD_RESET 0x12
39 #define TAOS_CMD_ECHO_ON '+'
40 #define TAOS_CMD_ECHO_OFF '-'
41 
42 static DECLARE_WAIT_QUEUE_HEAD(wq);
43 
44 struct taos_data {
46  struct i2c_client *client;
47  int state;
48  u8 addr; /* last used address */
49  unsigned char buffer[TAOS_BUFFER_SIZE];
50  unsigned int pos; /* position inside the buffer */
51 };
52 
53 /* TAOS TSL2550 EVM */
54 static struct i2c_board_info tsl2550_info = {
55  I2C_BOARD_INFO("tsl2550", 0x39),
56 };
57 
58 /* Instantiate i2c devices based on the adapter name */
59 static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
60 {
61  if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
62  dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
63  tsl2550_info.type, tsl2550_info.addr);
64  return i2c_new_device(adapter, &tsl2550_info);
65  }
66 
67  return NULL;
68 }
69 
70 static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
71  unsigned short flags, char read_write, u8 command,
72  int size, union i2c_smbus_data *data)
73 {
74  struct serio *serio = adapter->algo_data;
75  struct taos_data *taos = serio_get_drvdata(serio);
76  char *p;
77 
78  /* Encode our transaction. "@" is for the device address, "$" for the
79  SMBus command and "#" for the data. */
80  p = taos->buffer;
81 
82  /* The device remembers the last used address, no need to send it
83  again if it's the same */
84  if (addr != taos->addr)
85  p += sprintf(p, "@%02X", addr);
86 
87  switch (size) {
88  case I2C_SMBUS_BYTE:
89  if (read_write == I2C_SMBUS_WRITE)
90  sprintf(p, "$#%02X", command);
91  else
92  sprintf(p, "$");
93  break;
95  if (read_write == I2C_SMBUS_WRITE)
96  sprintf(p, "$%02X#%02X", command, data->byte);
97  else
98  sprintf(p, "$%02X", command);
99  break;
100  default:
101  dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
102  return -EOPNOTSUPP;
103  }
104 
105  /* Send the transaction to the TAOS EVM */
106  dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
107  for (p = taos->buffer; *p; p++)
108  serio_write(serio, *p);
109 
110  taos->addr = addr;
111 
112  /* Start the transaction and read the answer */
113  taos->pos = 0;
114  taos->state = TAOS_STATE_RECV;
115  serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<');
117  msecs_to_jiffies(150));
118  if (taos->state != TAOS_STATE_IDLE
119  || taos->pos != 5) {
120  dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
121  taos->pos);
122  return -EIO;
123  }
124  dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
125 
126  /* Interpret the returned string */
127  p = taos->buffer + 1;
128  p[3] = '\0';
129  if (!strcmp(p, "NAK"))
130  return -ENODEV;
131 
132  if (read_write == I2C_SMBUS_WRITE) {
133  if (!strcmp(p, "ACK"))
134  return 0;
135  } else {
136  if (p[0] == 'x') {
137  data->byte = simple_strtol(p + 1, NULL, 16);
138  return 0;
139  }
140  }
141 
142  return -EIO;
143 }
144 
145 static u32 taos_smbus_func(struct i2c_adapter *adapter)
146 {
148 }
149 
150 static const struct i2c_algorithm taos_algorithm = {
151  .smbus_xfer = taos_smbus_xfer,
152  .functionality = taos_smbus_func,
153 };
154 
155 static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
156  unsigned int flags)
157 {
158  struct taos_data *taos = serio_get_drvdata(serio);
159 
160  switch (taos->state) {
161  case TAOS_STATE_INIT:
162  taos->buffer[taos->pos++] = data;
163  if (data == ':'
164  || taos->pos == TAOS_BUFFER_SIZE - 1) {
165  taos->buffer[taos->pos] = '\0';
166  taos->state = TAOS_STATE_IDLE;
168  }
169  break;
170  case TAOS_STATE_EOFF:
171  taos->state = TAOS_STATE_IDLE;
173  break;
174  case TAOS_STATE_RECV:
175  taos->buffer[taos->pos++] = data;
176  if (data == ']') {
177  taos->buffer[taos->pos] = '\0';
178  taos->state = TAOS_STATE_IDLE;
180  }
181  break;
182  }
183 
184  return IRQ_HANDLED;
185 }
186 
187 /* Extract the adapter name from the buffer received after reset.
188  The buffer is modified and a pointer inside the buffer is returned. */
189 static char *taos_adapter_name(char *buffer)
190 {
191  char *start, *end;
192 
193  start = strstr(buffer, "TAOS ");
194  if (!start)
195  return NULL;
196 
197  end = strchr(start, '\r');
198  if (!end)
199  return NULL;
200  *end = '\0';
201 
202  return start;
203 }
204 
205 static int taos_connect(struct serio *serio, struct serio_driver *drv)
206 {
207  struct taos_data *taos;
208  struct i2c_adapter *adapter;
209  char *name;
210  int err;
211 
212  taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL);
213  if (!taos) {
214  err = -ENOMEM;
215  goto exit;
216  }
217  taos->state = TAOS_STATE_INIT;
218  serio_set_drvdata(serio, taos);
219 
220  err = serio_open(serio, drv);
221  if (err)
222  goto exit_kfree;
223 
224  adapter = &taos->adapter;
225  adapter->owner = THIS_MODULE;
226  adapter->algo = &taos_algorithm;
227  adapter->algo_data = serio;
228  adapter->dev.parent = &serio->dev;
229 
230  /* Reset the TAOS evaluation module to identify it */
231  serio_write(serio, TAOS_CMD_RESET);
233  msecs_to_jiffies(2000));
234 
235  if (taos->state != TAOS_STATE_IDLE) {
236  err = -ENODEV;
237  dev_err(&serio->dev, "TAOS EVM reset failed (state=%d, "
238  "pos=%d)\n", taos->state, taos->pos);
239  goto exit_close;
240  }
241 
242  name = taos_adapter_name(taos->buffer);
243  if (!name) {
244  err = -ENODEV;
245  dev_err(&serio->dev, "TAOS EVM identification failed\n");
246  goto exit_close;
247  }
248  strlcpy(adapter->name, name, sizeof(adapter->name));
249 
250  /* Turn echo off for better performance */
251  taos->state = TAOS_STATE_EOFF;
252  serio_write(serio, TAOS_CMD_ECHO_OFF);
253 
255  msecs_to_jiffies(250));
256  if (taos->state != TAOS_STATE_IDLE) {
257  err = -ENODEV;
258  dev_err(&serio->dev, "TAOS EVM echo off failed "
259  "(state=%d)\n", taos->state);
260  goto exit_close;
261  }
262 
263  err = i2c_add_adapter(adapter);
264  if (err)
265  goto exit_close;
266  dev_info(&serio->dev, "Connected to TAOS EVM\n");
267 
268  taos->client = taos_instantiate_device(adapter);
269  return 0;
270 
271  exit_close:
272  serio_close(serio);
273  exit_kfree:
274  serio_set_drvdata(serio, NULL);
275  kfree(taos);
276  exit:
277  return err;
278 }
279 
280 static void taos_disconnect(struct serio *serio)
281 {
282  struct taos_data *taos = serio_get_drvdata(serio);
283 
284  if (taos->client)
286  i2c_del_adapter(&taos->adapter);
287  serio_close(serio);
288  serio_set_drvdata(serio, NULL);
289  kfree(taos);
290 
291  dev_info(&serio->dev, "Disconnected from TAOS EVM\n");
292 }
293 
294 static struct serio_device_id taos_serio_ids[] = {
295  {
296  .type = SERIO_RS232,
297  .proto = SERIO_TAOSEVM,
298  .id = SERIO_ANY,
299  .extra = SERIO_ANY,
300  },
301  { 0 }
302 };
303 MODULE_DEVICE_TABLE(serio, taos_serio_ids);
304 
305 static struct serio_driver taos_drv = {
306  .driver = {
307  .name = "taos-evm",
308  },
309  .description = "TAOS evaluation module driver",
310  .id_table = taos_serio_ids,
311  .connect = taos_connect,
312  .disconnect = taos_disconnect,
313  .interrupt = taos_interrupt,
314 };
315 
316 static int __init taos_init(void)
317 {
318  return serio_register_driver(&taos_drv);
319 }
320 
321 static void __exit taos_exit(void)
322 {
323  serio_unregister_driver(&taos_drv);
324 }
325 
326 MODULE_AUTHOR("Jean Delvare <[email protected]>");
327 MODULE_DESCRIPTION("TAOS evaluation module driver");
328 MODULE_LICENSE("GPL");
329 
330 module_init(taos_init);
331 module_exit(taos_exit);