diff options
Diffstat (limited to 'drivers/i2c/busses/scx200_acb.c')
-rw-r--r-- | drivers/i2c/busses/scx200_acb.c | 90 |
1 files changed, 43 insertions, 47 deletions
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index d3478e084522..f45779b76908 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c | |||
@@ -1,27 +1,25 @@ | |||
1 | /* linux/drivers/i2c/scx200_acb.c | 1 | /* |
2 | |||
3 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> | 2 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> |
4 | 3 | ||
5 | National Semiconductor SCx200 ACCESS.bus support | 4 | National Semiconductor SCx200 ACCESS.bus support |
6 | 5 | ||
7 | Based on i2c-keywest.c which is: | 6 | Based on i2c-keywest.c which is: |
8 | Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org> | 7 | Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org> |
9 | Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> | 8 | Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> |
10 | 9 | ||
11 | This program is free software; you can redistribute it and/or | 10 | This program is free software; you can redistribute it and/or |
12 | modify it under the terms of the GNU General Public License as | 11 | modify it under the terms of the GNU General Public License as |
13 | published by the Free Software Foundation; either version 2 of the | 12 | published by the Free Software Foundation; either version 2 of the |
14 | License, or (at your option) any later version. | 13 | License, or (at your option) any later version. |
15 | 14 | ||
16 | This program is distributed in the hope that it will be useful, | 15 | This program is distributed in the hope that it will be useful, |
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 | General Public License for more details. | 18 | General Public License for more details. |
20 | 19 | ||
21 | You should have received a copy of the GNU General Public License | 20 | You should have received a copy of the GNU General Public License |
22 | along with this program; if not, write to the Free Software | 21 | along with this program; if not, write to the Free Software |
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | |||
25 | */ | 23 | */ |
26 | 24 | ||
27 | #include <linux/module.h> | 25 | #include <linux/module.h> |
@@ -79,8 +77,7 @@ static const char *scx200_acb_state_name[] = { | |||
79 | }; | 77 | }; |
80 | 78 | ||
81 | /* Physical interface */ | 79 | /* Physical interface */ |
82 | struct scx200_acb_iface | 80 | struct scx200_acb_iface { |
83 | { | ||
84 | struct scx200_acb_iface *next; | 81 | struct scx200_acb_iface *next; |
85 | struct i2c_adapter adapter; | 82 | struct i2c_adapter adapter; |
86 | unsigned base; | 83 | unsigned base; |
@@ -100,7 +97,7 @@ struct scx200_acb_iface | |||
100 | #define ACBSDA (iface->base + 0) | 97 | #define ACBSDA (iface->base + 0) |
101 | #define ACBST (iface->base + 1) | 98 | #define ACBST (iface->base + 1) |
102 | #define ACBST_SDAST 0x40 /* SDA Status */ | 99 | #define ACBST_SDAST 0x40 /* SDA Status */ |
103 | #define ACBST_BER 0x20 | 100 | #define ACBST_BER 0x20 |
104 | #define ACBST_NEGACK 0x10 /* Negative Acknowledge */ | 101 | #define ACBST_NEGACK 0x10 /* Negative Acknowledge */ |
105 | #define ACBST_STASTR 0x08 /* Stall After Start */ | 102 | #define ACBST_STASTR 0x08 /* Stall After Start */ |
106 | #define ACBST_MASTER 0x02 | 103 | #define ACBST_MASTER 0x02 |
@@ -109,9 +106,9 @@ struct scx200_acb_iface | |||
109 | #define ACBCTL1 (iface->base + 3) | 106 | #define ACBCTL1 (iface->base + 3) |
110 | #define ACBCTL1_STASTRE 0x80 | 107 | #define ACBCTL1_STASTRE 0x80 |
111 | #define ACBCTL1_NMINTE 0x40 | 108 | #define ACBCTL1_NMINTE 0x40 |
112 | #define ACBCTL1_ACK 0x10 | 109 | #define ACBCTL1_ACK 0x10 |
113 | #define ACBCTL1_STOP 0x02 | 110 | #define ACBCTL1_STOP 0x02 |
114 | #define ACBCTL1_START 0x01 | 111 | #define ACBCTL1_START 0x01 |
115 | #define ACBADDR (iface->base + 4) | 112 | #define ACBADDR (iface->base + 4) |
116 | #define ACBCTL2 (iface->base + 5) | 113 | #define ACBCTL2 (iface->base + 5) |
117 | #define ACBCTL2_ENABLE 0x01 | 114 | #define ACBCTL2_ENABLE 0x01 |
@@ -122,7 +119,7 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) | |||
122 | { | 119 | { |
123 | const char *errmsg; | 120 | const char *errmsg; |
124 | 121 | ||
125 | DBG("state %s, status = 0x%02x\n", | 122 | DBG("state %s, status = 0x%02x\n", |
126 | scx200_acb_state_name[iface->state], status); | 123 | scx200_acb_state_name[iface->state], status); |
127 | 124 | ||
128 | if (status & ACBST_BER) { | 125 | if (status & ACBST_BER) { |
@@ -160,10 +157,10 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) | |||
160 | case state_repeat_start: | 157 | case state_repeat_start: |
161 | outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1); | 158 | outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1); |
162 | /* fallthrough */ | 159 | /* fallthrough */ |
163 | 160 | ||
164 | case state_quick: | 161 | case state_quick: |
165 | if (iface->address_byte & 1) { | 162 | if (iface->address_byte & 1) { |
166 | if (iface->len == 1) | 163 | if (iface->len == 1) |
167 | outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1); | 164 | outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1); |
168 | else | 165 | else |
169 | outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1); | 166 | outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1); |
@@ -202,17 +199,17 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) | |||
202 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); | 199 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); |
203 | break; | 200 | break; |
204 | } | 201 | } |
205 | 202 | ||
206 | outb(*iface->ptr++, ACBSDA); | 203 | outb(*iface->ptr++, ACBSDA); |
207 | --iface->len; | 204 | --iface->len; |
208 | 205 | ||
209 | break; | 206 | break; |
210 | } | 207 | } |
211 | 208 | ||
212 | return; | 209 | return; |
213 | 210 | ||
214 | negack: | 211 | negack: |
215 | DBG("negative acknowledge in state %s\n", | 212 | DBG("negative acknowledge in state %s\n", |
216 | scx200_acb_state_name[iface->state]); | 213 | scx200_acb_state_name[iface->state]); |
217 | 214 | ||
218 | iface->state = state_idle; | 215 | iface->state = state_idle; |
@@ -231,7 +228,7 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) | |||
231 | iface->needs_reset = 1; | 228 | iface->needs_reset = 1; |
232 | } | 229 | } |
233 | 230 | ||
234 | static void scx200_acb_timeout(struct scx200_acb_iface *iface) | 231 | static void scx200_acb_timeout(struct scx200_acb_iface *iface) |
235 | { | 232 | { |
236 | dev_err(&iface->adapter.dev, "timeout in state %s\n", | 233 | dev_err(&iface->adapter.dev, "timeout in state %s\n", |
237 | scx200_acb_state_name[iface->state]); | 234 | scx200_acb_state_name[iface->state]); |
@@ -264,7 +261,7 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface) | |||
264 | static void scx200_acb_reset(struct scx200_acb_iface *iface) | 261 | static void scx200_acb_reset(struct scx200_acb_iface *iface) |
265 | { | 262 | { |
266 | /* Disable the ACCESS.bus device and Configure the SCL | 263 | /* Disable the ACCESS.bus device and Configure the SCL |
267 | frequency: 16 clock cycles */ | 264 | frequency: 16 clock cycles */ |
268 | outb(0x70, ACBCTL2); | 265 | outb(0x70, ACBCTL2); |
269 | /* Polling mode */ | 266 | /* Polling mode */ |
270 | outb(0, ACBCTL1); | 267 | outb(0, ACBCTL1); |
@@ -283,9 +280,9 @@ static void scx200_acb_reset(struct scx200_acb_iface *iface) | |||
283 | } | 280 | } |
284 | 281 | ||
285 | static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, | 282 | static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, |
286 | u16 address, unsigned short flags, | 283 | u16 address, unsigned short flags, |
287 | char rw, u8 command, int size, | 284 | char rw, u8 command, int size, |
288 | union i2c_smbus_data *data) | 285 | union i2c_smbus_data *data) |
289 | { | 286 | { |
290 | struct scx200_acb_iface *iface = i2c_get_adapdata(adapter); | 287 | struct scx200_acb_iface *iface = i2c_get_adapdata(adapter); |
291 | int len; | 288 | int len; |
@@ -295,9 +292,10 @@ static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, | |||
295 | 292 | ||
296 | switch (size) { | 293 | switch (size) { |
297 | case I2C_SMBUS_QUICK: | 294 | case I2C_SMBUS_QUICK: |
298 | len = 0; | 295 | len = 0; |
299 | buffer = NULL; | 296 | buffer = NULL; |
300 | break; | 297 | break; |
298 | |||
301 | case I2C_SMBUS_BYTE: | 299 | case I2C_SMBUS_BYTE: |
302 | if (rw == I2C_SMBUS_READ) { | 300 | if (rw == I2C_SMBUS_READ) { |
303 | len = 1; | 301 | len = 1; |
@@ -306,22 +304,26 @@ static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, | |||
306 | len = 1; | 304 | len = 1; |
307 | buffer = &command; | 305 | buffer = &command; |
308 | } | 306 | } |
309 | break; | 307 | break; |
308 | |||
310 | case I2C_SMBUS_BYTE_DATA: | 309 | case I2C_SMBUS_BYTE_DATA: |
311 | len = 1; | 310 | len = 1; |
312 | buffer = &data->byte; | 311 | buffer = &data->byte; |
313 | break; | 312 | break; |
313 | |||
314 | case I2C_SMBUS_WORD_DATA: | 314 | case I2C_SMBUS_WORD_DATA: |
315 | len = 2; | 315 | len = 2; |
316 | cur_word = cpu_to_le16(data->word); | 316 | cur_word = cpu_to_le16(data->word); |
317 | buffer = (u8 *)&cur_word; | 317 | buffer = (u8 *)&cur_word; |
318 | break; | 318 | break; |
319 | |||
319 | case I2C_SMBUS_BLOCK_DATA: | 320 | case I2C_SMBUS_BLOCK_DATA: |
320 | len = data->block[0]; | 321 | len = data->block[0]; |
321 | buffer = &data->block[1]; | 322 | buffer = &data->block[1]; |
322 | break; | 323 | break; |
324 | |||
323 | default: | 325 | default: |
324 | return -EINVAL; | 326 | return -EINVAL; |
325 | } | 327 | } |
326 | 328 | ||
327 | DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n", | 329 | DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n", |
@@ -370,7 +372,7 @@ static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, | |||
370 | up(&iface->sem); | 372 | up(&iface->sem); |
371 | 373 | ||
372 | if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ) | 374 | if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ) |
373 | data->word = le16_to_cpu(cur_word); | 375 | data->word = le16_to_cpu(cur_word); |
374 | 376 | ||
375 | #ifdef DEBUG | 377 | #ifdef DEBUG |
376 | DBG(": transfer done, result: %d", rc); | 378 | DBG(": transfer done, result: %d", rc); |
@@ -406,7 +408,7 @@ static int scx200_acb_probe(struct scx200_acb_iface *iface) | |||
406 | u8 val; | 408 | u8 val; |
407 | 409 | ||
408 | /* Disable the ACCESS.bus device and Configure the SCL | 410 | /* Disable the ACCESS.bus device and Configure the SCL |
409 | frequency: 16 clock cycles */ | 411 | frequency: 16 clock cycles */ |
410 | outb(0x70, ACBCTL2); | 412 | outb(0x70, ACBCTL2); |
411 | 413 | ||
412 | if (inb(ACBCTL2) != 0x70) { | 414 | if (inb(ACBCTL2) != 0x70) { |
@@ -459,7 +461,8 @@ static int __init scx200_acb_create(int base, int index) | |||
459 | 461 | ||
460 | init_MUTEX(&iface->sem); | 462 | init_MUTEX(&iface->sem); |
461 | 463 | ||
462 | snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->name); | 464 | snprintf(description, sizeof(description), |
465 | "NatSemi SCx200 ACCESS.bus [%s]", adapter->name); | ||
463 | if (request_region(base, 8, description) == 0) { | 466 | if (request_region(base, 8, description) == 0) { |
464 | dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n", | 467 | dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n", |
465 | base, base + 8-1); | 468 | base, base + 8-1); |
@@ -528,6 +531,7 @@ static int __init scx200_acb_init(void) | |||
528 | static void __exit scx200_acb_cleanup(void) | 531 | static void __exit scx200_acb_cleanup(void) |
529 | { | 532 | { |
530 | struct scx200_acb_iface *iface; | 533 | struct scx200_acb_iface *iface; |
534 | |||
531 | lock_kernel(); | 535 | lock_kernel(); |
532 | while ((iface = scx200_acb_list) != NULL) { | 536 | while ((iface = scx200_acb_list) != NULL) { |
533 | scx200_acb_list = iface->next; | 537 | scx200_acb_list = iface->next; |
@@ -543,11 +547,3 @@ static void __exit scx200_acb_cleanup(void) | |||
543 | 547 | ||
544 | module_init(scx200_acb_init); | 548 | module_init(scx200_acb_init); |
545 | module_exit(scx200_acb_cleanup); | 549 | 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 | |||