Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
420 | giacomo | 1 | /* linux/drivers/i2c/scx200_acb.c |
2 | |||
3 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> |
||
4 | |||
5 | National Semiconductor SCx200 ACCESS.bus support |
||
6 | |||
7 | Based on i2c-keywest.c which is: |
||
8 | Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org> |
||
9 | Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> |
||
10 | |||
11 | This program is free software; you can redistribute it and/or |
||
12 | modify it under the terms of the GNU General Public License as |
||
13 | published by the Free Software Foundation; either version 2 of the |
||
14 | License, or (at your option) any later version. |
||
15 | |||
16 | This program is distributed in the hope that it will be useful, |
||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
19 | General Public License for more details. |
||
20 | |||
21 | You should have received a copy of the GNU General Public License |
||
22 | along with this program; if not, write to the Free Software |
||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
24 | |||
25 | */ |
||
26 | |||
27 | #include <linux/config.h> |
||
28 | #include <linux/module.h> |
||
29 | #include <linux/errno.h> |
||
30 | #include <linux/kernel.h> |
||
31 | #include <linux/init.h> |
||
32 | #include <linux/i2c.h> |
||
33 | #include <linux/smp_lock.h> |
||
34 | #include <linux/pci.h> |
||
35 | #include <asm/io.h> |
||
36 | |||
37 | #include <linux/scx200.h> |
||
38 | |||
39 | #define NAME "scx200_acb" |
||
40 | |||
41 | MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); |
||
42 | MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver"); |
||
43 | MODULE_LICENSE("GPL"); |
||
44 | |||
45 | #define MAX_DEVICES 4 |
||
46 | static int base[MAX_DEVICES] = { 0x840 }; |
||
47 | MODULE_PARM(base, "1-4i"); |
||
48 | MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers"); |
||
49 | |||
50 | #define DEBUG 0 |
||
51 | |||
52 | #if DEBUG |
||
53 | #define DBG(x...) printk(KERN_DEBUG NAME ": " x) |
||
54 | #else |
||
55 | #define DBG(x...) |
||
56 | #endif |
||
57 | |||
58 | /* The hardware supports interrupt driven mode too, but I haven't |
||
59 | implemented that. */ |
||
60 | #define POLLED_MODE 1 |
||
61 | #define POLL_TIMEOUT (HZ) |
||
62 | |||
63 | enum scx200_acb_state { |
||
64 | state_idle, |
||
65 | state_address, |
||
66 | state_command, |
||
67 | state_repeat_start, |
||
68 | state_quick, |
||
69 | state_read, |
||
70 | state_write, |
||
71 | }; |
||
72 | |||
73 | static const char *scx200_acb_state_name[] = { |
||
74 | "idle", |
||
75 | "address", |
||
76 | "command", |
||
77 | "repeat_start", |
||
78 | "quick", |
||
79 | "read", |
||
80 | "write", |
||
81 | }; |
||
82 | |||
83 | /* Physical interface */ |
||
84 | struct scx200_acb_iface |
||
85 | { |
||
86 | struct scx200_acb_iface *next; |
||
87 | struct i2c_adapter adapter; |
||
88 | unsigned base; |
||
89 | struct semaphore sem; |
||
90 | |||
91 | /* State machine data */ |
||
92 | enum scx200_acb_state state; |
||
93 | int result; |
||
94 | u8 address_byte; |
||
95 | u8 command; |
||
96 | u8 *ptr; |
||
97 | char needs_reset; |
||
98 | unsigned len; |
||
99 | }; |
||
100 | |||
101 | /* Register Definitions */ |
||
102 | #define ACBSDA (iface->base + 0) |
||
103 | #define ACBST (iface->base + 1) |
||
104 | #define ACBST_SDAST 0x40 /* SDA Status */ |
||
105 | #define ACBST_BER 0x20 |
||
106 | #define ACBST_NEGACK 0x10 /* Negative Acknowledge */ |
||
107 | #define ACBST_STASTR 0x08 /* Stall After Start */ |
||
108 | #define ACBST_MASTER 0x02 |
||
109 | #define ACBCST (iface->base + 2) |
||
110 | #define ACBCST_BB 0x02 |
||
111 | #define ACBCTL1 (iface->base + 3) |
||
112 | #define ACBCTL1_STASTRE 0x80 |
||
113 | #define ACBCTL1_NMINTE 0x40 |
||
114 | #define ACBCTL1_ACK 0x10 |
||
115 | #define ACBCTL1_STOP 0x02 |
||
116 | #define ACBCTL1_START 0x01 |
||
117 | #define ACBADDR (iface->base + 4) |
||
118 | #define ACBCTL2 (iface->base + 5) |
||
119 | #define ACBCTL2_ENABLE 0x01 |
||
120 | |||
121 | /************************************************************************/ |
||
122 | |||
123 | static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) |
||
124 | { |
||
125 | const char *errmsg; |
||
126 | |||
127 | DBG("state %s, status = 0x%02x\n", |
||
128 | scx200_acb_state_name[iface->state], status); |
||
129 | |||
130 | if (status & ACBST_BER) { |
||
131 | errmsg = "bus error"; |
||
132 | goto error; |
||
133 | } |
||
134 | if (!(status & ACBST_MASTER)) { |
||
135 | errmsg = "not master"; |
||
136 | goto error; |
||
137 | } |
||
138 | if (status & ACBST_NEGACK) |
||
139 | goto negack; |
||
140 | |||
141 | switch (iface->state) { |
||
142 | case state_idle: |
||
143 | dev_warn(&iface->adapter.dev, "interrupt in idle state\n"); |
||
144 | break; |
||
145 | |||
146 | case state_address: |
||
147 | /* Do a pointer write first */ |
||
148 | outb(iface->address_byte & ~1, ACBSDA); |
||
149 | |||
150 | iface->state = state_command; |
||
151 | break; |
||
152 | |||
153 | case state_command: |
||
154 | outb(iface->command, ACBSDA); |
||
155 | |||
156 | if (iface->address_byte & 1) |
||
157 | iface->state = state_repeat_start; |
||
158 | else |
||
159 | iface->state = state_write; |
||
160 | break; |
||
161 | |||
162 | case state_repeat_start: |
||
163 | outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1); |
||
164 | /* fallthrough */ |
||
165 | |||
166 | case state_quick: |
||
167 | if (iface->address_byte & 1) { |
||
168 | if (iface->len == 1) |
||
169 | outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1); |
||
170 | else |
||
171 | outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1); |
||
172 | outb(iface->address_byte, ACBSDA); |
||
173 | |||
174 | iface->state = state_read; |
||
175 | } else { |
||
176 | outb(iface->address_byte, ACBSDA); |
||
177 | |||
178 | iface->state = state_write; |
||
179 | } |
||
180 | break; |
||
181 | |||
182 | case state_read: |
||
183 | /* Set ACK if receiving the last byte */ |
||
184 | if (iface->len == 1) |
||
185 | outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1); |
||
186 | else |
||
187 | outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1); |
||
188 | |||
189 | *iface->ptr++ = inb(ACBSDA); |
||
190 | --iface->len; |
||
191 | |||
192 | if (iface->len == 0) { |
||
193 | iface->result = 0; |
||
194 | iface->state = state_idle; |
||
195 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); |
||
196 | } |
||
197 | |||
198 | break; |
||
199 | |||
200 | case state_write: |
||
201 | if (iface->len == 0) { |
||
202 | iface->result = 0; |
||
203 | iface->state = state_idle; |
||
204 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); |
||
205 | break; |
||
206 | } |
||
207 | |||
208 | outb(*iface->ptr++, ACBSDA); |
||
209 | --iface->len; |
||
210 | |||
211 | break; |
||
212 | } |
||
213 | |||
214 | return; |
||
215 | |||
216 | negack: |
||
217 | DBG("negative acknowledge in state %s\n", |
||
218 | scx200_acb_state_name[iface->state]); |
||
219 | |||
220 | iface->state = state_idle; |
||
221 | iface->result = -ENXIO; |
||
222 | |||
223 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); |
||
224 | outb(ACBST_STASTR | ACBST_NEGACK, ACBST); |
||
225 | return; |
||
226 | |||
227 | error: |
||
228 | dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg, |
||
229 | scx200_acb_state_name[iface->state]); |
||
230 | |||
231 | iface->state = state_idle; |
||
232 | iface->result = -EIO; |
||
233 | iface->needs_reset = 1; |
||
234 | } |
||
235 | |||
236 | static void scx200_acb_timeout(struct scx200_acb_iface *iface) |
||
237 | { |
||
238 | dev_err(&iface->adapter.dev, "timeout in state %s\n", |
||
239 | scx200_acb_state_name[iface->state]); |
||
240 | |||
241 | iface->state = state_idle; |
||
242 | iface->result = -EIO; |
||
243 | iface->needs_reset = 1; |
||
244 | } |
||
245 | |||
246 | #ifdef POLLED_MODE |
||
247 | static void scx200_acb_poll(struct scx200_acb_iface *iface) |
||
248 | { |
||
249 | u8 status = 0; |
||
250 | unsigned long timeout; |
||
251 | |||
252 | timeout = jiffies + POLL_TIMEOUT; |
||
253 | while (time_before(jiffies, timeout)) { |
||
254 | status = inb(ACBST); |
||
255 | if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) { |
||
256 | scx200_acb_machine(iface, status); |
||
257 | return; |
||
258 | } |
||
259 | schedule_timeout(HZ/100+1); |
||
260 | } |
||
261 | |||
262 | scx200_acb_timeout(iface); |
||
263 | } |
||
264 | #endif /* POLLED_MODE */ |
||
265 | |||
266 | static void scx200_acb_reset(struct scx200_acb_iface *iface) |
||
267 | { |
||
268 | /* Disable the ACCESS.bus device and Configure the SCL |
||
269 | frequency: 16 clock cycles */ |
||
270 | outb(0x70, ACBCTL2); |
||
271 | /* Polling mode */ |
||
272 | outb(0, ACBCTL1); |
||
273 | /* Disable slave address */ |
||
274 | outb(0, ACBADDR); |
||
275 | /* Enable the ACCESS.bus device */ |
||
276 | outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2); |
||
277 | /* Free STALL after START */ |
||
278 | outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1); |
||
279 | /* Send a STOP */ |
||
280 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); |
||
281 | /* Clear BER, NEGACK and STASTR bits */ |
||
282 | outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST); |
||
283 | /* Clear BB bit */ |
||
284 | outb(inb(ACBCST) | ACBCST_BB, ACBCST); |
||
285 | } |
||
286 | |||
287 | static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, |
||
288 | u16 address, unsigned short flags, |
||
289 | char rw, u8 command, int size, |
||
290 | union i2c_smbus_data *data) |
||
291 | { |
||
292 | struct scx200_acb_iface *iface = i2c_get_adapdata(adapter); |
||
293 | int len; |
||
294 | u8 *buffer; |
||
295 | u16 cur_word; |
||
296 | int rc; |
||
297 | |||
298 | switch (size) { |
||
299 | case I2C_SMBUS_QUICK: |
||
300 | len = 0; |
||
301 | buffer = NULL; |
||
302 | break; |
||
303 | case I2C_SMBUS_BYTE: |
||
304 | if (rw == I2C_SMBUS_READ) { |
||
305 | len = 1; |
||
306 | buffer = &data->byte; |
||
307 | } else { |
||
308 | len = 1; |
||
309 | buffer = &command; |
||
310 | } |
||
311 | break; |
||
312 | case I2C_SMBUS_BYTE_DATA: |
||
313 | len = 1; |
||
314 | buffer = &data->byte; |
||
315 | break; |
||
316 | case I2C_SMBUS_WORD_DATA: |
||
317 | len = 2; |
||
318 | cur_word = cpu_to_le16(data->word); |
||
319 | buffer = (u8 *)&cur_word; |
||
320 | break; |
||
321 | case I2C_SMBUS_BLOCK_DATA: |
||
322 | len = data->block[0]; |
||
323 | buffer = &data->block[1]; |
||
324 | break; |
||
325 | default: |
||
326 | return -EINVAL; |
||
327 | } |
||
328 | |||
329 | DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n", |
||
330 | size, address, command, len, rw == I2C_SMBUS_READ); |
||
331 | |||
332 | if (!len && rw == I2C_SMBUS_READ) { |
||
333 | dev_warn(&adapter->dev, "zero length read\n"); |
||
334 | return -EINVAL; |
||
335 | } |
||
336 | |||
337 | if (len && !buffer) { |
||
338 | dev_warn(&adapter->dev, "nonzero length but no buffer\n"); |
||
339 | return -EFAULT; |
||
340 | } |
||
341 | |||
342 | down(&iface->sem); |
||
343 | |||
344 | iface->address_byte = address<<1; |
||
345 | if (rw == I2C_SMBUS_READ) |
||
346 | iface->address_byte |= 1; |
||
347 | iface->command = command; |
||
348 | iface->ptr = buffer; |
||
349 | iface->len = len; |
||
350 | iface->result = -EINVAL; |
||
351 | iface->needs_reset = 0; |
||
352 | |||
353 | outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1); |
||
354 | |||
355 | if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) |
||
356 | iface->state = state_quick; |
||
357 | else |
||
358 | iface->state = state_address; |
||
359 | |||
360 | #ifdef POLLED_MODE |
||
361 | while (iface->state != state_idle) |
||
362 | scx200_acb_poll(iface); |
||
363 | #else /* POLLED_MODE */ |
||
364 | #error Interrupt driven mode not implemented |
||
365 | #endif /* POLLED_MODE */ |
||
366 | |||
367 | if (iface->needs_reset) |
||
368 | scx200_acb_reset(iface); |
||
369 | |||
370 | rc = iface->result; |
||
371 | |||
372 | up(&iface->sem); |
||
373 | |||
374 | if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ) |
||
375 | data->word = le16_to_cpu(cur_word); |
||
376 | |||
377 | #if DEBUG |
||
378 | printk(KERN_DEBUG NAME ": transfer done, result: %d", rc); |
||
379 | if (buffer) { |
||
380 | int i; |
||
381 | printk(" data:"); |
||
382 | for (i = 0; i < len; ++i) |
||
383 | printk(" %02x", buffer[i]); |
||
384 | } |
||
385 | printk("\n"); |
||
386 | #endif |
||
387 | |||
388 | return rc; |
||
389 | } |
||
390 | |||
391 | static u32 scx200_acb_func(struct i2c_adapter *adapter) |
||
392 | { |
||
393 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | |
||
394 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | |
||
395 | I2C_FUNC_SMBUS_BLOCK_DATA; |
||
396 | } |
||
397 | |||
398 | /* For now, we only handle combined mode (smbus) */ |
||
399 | static struct i2c_algorithm scx200_acb_algorithm = { |
||
400 | .name = "NatSemi SCx200 ACCESS.bus", |
||
401 | .id = I2C_ALGO_SMBUS, |
||
402 | .smbus_xfer = scx200_acb_smbus_xfer, |
||
403 | .functionality = scx200_acb_func, |
||
404 | }; |
||
405 | |||
406 | struct scx200_acb_iface *scx200_acb_list; |
||
407 | |||
408 | int scx200_acb_probe(struct scx200_acb_iface *iface) |
||
409 | { |
||
410 | u8 val; |
||
411 | |||
412 | /* Disable the ACCESS.bus device and Configure the SCL |
||
413 | frequency: 16 clock cycles */ |
||
414 | outb(0x70, ACBCTL2); |
||
415 | |||
416 | if (inb(ACBCTL2) != 0x70) { |
||
417 | DBG("ACBCTL2 readback failed\n"); |
||
418 | return -ENXIO; |
||
419 | } |
||
420 | |||
421 | outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1); |
||
422 | |||
423 | val = inb(ACBCTL1); |
||
424 | if (val) { |
||
425 | DBG("disabled, but ACBCTL1=0x%02x\n", val); |
||
426 | return -ENXIO; |
||
427 | } |
||
428 | |||
429 | outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2); |
||
430 | |||
431 | outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1); |
||
432 | |||
433 | val = inb(ACBCTL1); |
||
434 | if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) { |
||
435 | DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val); |
||
436 | return -ENXIO; |
||
437 | } |
||
438 | |||
439 | return 0; |
||
440 | } |
||
441 | |||
442 | static int __init scx200_acb_create(int base, int index) |
||
443 | { |
||
444 | struct scx200_acb_iface *iface; |
||
445 | struct i2c_adapter *adapter; |
||
446 | int rc = 0; |
||
447 | char description[64]; |
||
448 | |||
449 | iface = kmalloc(sizeof(*iface), GFP_KERNEL); |
||
450 | if (!iface) { |
||
451 | printk(KERN_ERR NAME ": can't allocate memory\n"); |
||
452 | rc = -ENOMEM; |
||
453 | goto errout; |
||
454 | } |
||
455 | |||
456 | memset(iface, 0, sizeof(*iface)); |
||
457 | adapter = &iface->adapter; |
||
458 | i2c_set_adapdata(adapter, iface); |
||
459 | snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index); |
||
460 | adapter->owner = THIS_MODULE; |
||
461 | adapter->id = I2C_ALGO_SMBUS; |
||
462 | adapter->algo = &scx200_acb_algorithm; |
||
463 | |||
464 | init_MUTEX(&iface->sem); |
||
465 | |||
466 | snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->name); |
||
467 | if (request_region(base, 8, description) == 0) { |
||
468 | dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n", |
||
469 | base, base + 8-1); |
||
470 | rc = -EBUSY; |
||
471 | goto errout; |
||
472 | } |
||
473 | iface->base = base; |
||
474 | |||
475 | rc = scx200_acb_probe(iface); |
||
476 | if (rc) { |
||
477 | dev_warn(&adapter->dev, "probe failed\n"); |
||
478 | goto errout; |
||
479 | } |
||
480 | |||
481 | scx200_acb_reset(iface); |
||
482 | |||
483 | if (i2c_add_adapter(adapter) < 0) { |
||
484 | dev_err(&adapter->dev, "failed to register\n"); |
||
485 | rc = -ENODEV; |
||
486 | goto errout; |
||
487 | } |
||
488 | |||
489 | lock_kernel(); |
||
490 | iface->next = scx200_acb_list; |
||
491 | scx200_acb_list = iface; |
||
492 | unlock_kernel(); |
||
493 | |||
494 | return 0; |
||
495 | |||
496 | errout: |
||
497 | if (iface) { |
||
498 | if (iface->base) |
||
499 | release_region(iface->base, 8); |
||
500 | kfree(iface); |
||
501 | } |
||
502 | return rc; |
||
503 | } |
||
504 | |||
505 | static int __init scx200_acb_init(void) |
||
506 | { |
||
507 | int i; |
||
508 | int rc; |
||
509 | |||
510 | printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); |
||
511 | |||
512 | /* Verify that this really is a SCx200 processor */ |
||
513 | if (pci_find_device(PCI_VENDOR_ID_NS, |
||
514 | PCI_DEVICE_ID_NS_SCx200_BRIDGE, |
||
515 | NULL) == NULL) |
||
516 | return -ENODEV; |
||
517 | |||
518 | rc = -ENXIO; |
||
519 | for (i = 0; i < MAX_DEVICES; ++i) { |
||
520 | if (base[i] > 0) |
||
521 | rc = scx200_acb_create(base[i], i); |
||
522 | } |
||
523 | if (scx200_acb_list) |
||
524 | return 0; |
||
525 | return rc; |
||
526 | } |
||
527 | |||
528 | static void __exit scx200_acb_cleanup(void) |
||
529 | { |
||
530 | struct scx200_acb_iface *iface; |
||
531 | lock_kernel(); |
||
532 | while ((iface = scx200_acb_list) != NULL) { |
||
533 | scx200_acb_list = iface->next; |
||
534 | unlock_kernel(); |
||
535 | |||
536 | i2c_del_adapter(&iface->adapter); |
||
537 | release_region(iface->base, 8); |
||
538 | kfree(iface); |
||
539 | lock_kernel(); |
||
540 | } |
||
541 | unlock_kernel(); |
||
542 | } |
||
543 | |||
544 | module_init(scx200_acb_init); |
||
545 | module_exit(scx200_acb_cleanup); |
||
546 | |||
547 | /* |
||
548 | Local variables: |
||
549 | compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules" |
||
550 | c-basic-offset: 8 |
||
551 | End: |
||
552 | */ |
||
553 |