diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/i2c/busses/scx200_acb.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/i2c/busses/scx200_acb.c')
-rw-r--r-- | drivers/i2c/busses/scx200_acb.c | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c new file mode 100644 index 000000000000..1c4159a93623 --- /dev/null +++ b/drivers/i2c/busses/scx200_acb.c | |||
@@ -0,0 +1,557 @@ | |||
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 <linux/delay.h> | ||
36 | #include <asm/io.h> | ||
37 | |||
38 | #include <linux/scx200.h> | ||
39 | |||
40 | #define NAME "scx200_acb" | ||
41 | |||
42 | MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); | ||
43 | MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver"); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | #define MAX_DEVICES 4 | ||
47 | static int base[MAX_DEVICES] = { 0x820, 0x840 }; | ||
48 | module_param_array(base, int, NULL, 0); | ||
49 | MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers"); | ||
50 | |||
51 | #ifdef DEBUG | ||
52 | #define DBG(x...) printk(KERN_DEBUG NAME ": " x) | ||
53 | #else | ||
54 | #define DBG(x...) | ||
55 | #endif | ||
56 | |||
57 | /* The hardware supports interrupt driven mode too, but I haven't | ||
58 | implemented that. */ | ||
59 | #define POLLED_MODE 1 | ||
60 | #define POLL_TIMEOUT (HZ) | ||
61 | |||
62 | enum scx200_acb_state { | ||
63 | state_idle, | ||
64 | state_address, | ||
65 | state_command, | ||
66 | state_repeat_start, | ||
67 | state_quick, | ||
68 | state_read, | ||
69 | state_write, | ||
70 | }; | ||
71 | |||
72 | static const char *scx200_acb_state_name[] = { | ||
73 | "idle", | ||
74 | "address", | ||
75 | "command", | ||
76 | "repeat_start", | ||
77 | "quick", | ||
78 | "read", | ||
79 | "write", | ||
80 | }; | ||
81 | |||
82 | /* Physical interface */ | ||
83 | struct scx200_acb_iface | ||
84 | { | ||
85 | struct scx200_acb_iface *next; | ||
86 | struct i2c_adapter adapter; | ||
87 | unsigned base; | ||
88 | struct semaphore sem; | ||
89 | |||
90 | /* State machine data */ | ||
91 | enum scx200_acb_state state; | ||
92 | int result; | ||
93 | u8 address_byte; | ||
94 | u8 command; | ||
95 | u8 *ptr; | ||
96 | char needs_reset; | ||
97 | unsigned len; | ||
98 | }; | ||
99 | |||
100 | /* Register Definitions */ | ||
101 | #define ACBSDA (iface->base + 0) | ||
102 | #define ACBST (iface->base + 1) | ||
103 | #define ACBST_SDAST 0x40 /* SDA Status */ | ||
104 | #define ACBST_BER 0x20 | ||
105 | #define ACBST_NEGACK 0x10 /* Negative Acknowledge */ | ||
106 | #define ACBST_STASTR 0x08 /* Stall After Start */ | ||
107 | #define ACBST_MASTER 0x02 | ||
108 | #define ACBCST (iface->base + 2) | ||
109 | #define ACBCST_BB 0x02 | ||
110 | #define ACBCTL1 (iface->base + 3) | ||
111 | #define ACBCTL1_STASTRE 0x80 | ||
112 | #define ACBCTL1_NMINTE 0x40 | ||
113 | #define ACBCTL1_ACK 0x10 | ||
114 | #define ACBCTL1_STOP 0x02 | ||
115 | #define ACBCTL1_START 0x01 | ||
116 | #define ACBADDR (iface->base + 4) | ||
117 | #define ACBCTL2 (iface->base + 5) | ||
118 | #define ACBCTL2_ENABLE 0x01 | ||
119 | |||
120 | /************************************************************************/ | ||
121 | |||
122 | static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) | ||
123 | { | ||
124 | const char *errmsg; | ||
125 | |||
126 | DBG("state %s, status = 0x%02x\n", | ||
127 | scx200_acb_state_name[iface->state], status); | ||
128 | |||
129 | if (status & ACBST_BER) { | ||
130 | errmsg = "bus error"; | ||
131 | goto error; | ||
132 | } | ||
133 | if (!(status & ACBST_MASTER)) { | ||
134 | errmsg = "not master"; | ||
135 | goto error; | ||
136 | } | ||
137 | if (status & ACBST_NEGACK) | ||
138 | goto negack; | ||
139 | |||
140 | switch (iface->state) { | ||
141 | case state_idle: | ||
142 | dev_warn(&iface->adapter.dev, "interrupt in idle state\n"); | ||
143 | break; | ||
144 | |||
145 | case state_address: | ||
146 | /* Do a pointer write first */ | ||
147 | outb(iface->address_byte & ~1, ACBSDA); | ||
148 | |||
149 | iface->state = state_command; | ||
150 | break; | ||
151 | |||
152 | case state_command: | ||
153 | outb(iface->command, ACBSDA); | ||
154 | |||
155 | if (iface->address_byte & 1) | ||
156 | iface->state = state_repeat_start; | ||
157 | else | ||
158 | iface->state = state_write; | ||
159 | break; | ||
160 | |||
161 | case state_repeat_start: | ||
162 | outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1); | ||
163 | /* fallthrough */ | ||
164 | |||
165 | case state_quick: | ||
166 | if (iface->address_byte & 1) { | ||
167 | if (iface->len == 1) | ||
168 | outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1); | ||
169 | else | ||
170 | outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1); | ||
171 | outb(iface->address_byte, ACBSDA); | ||
172 | |||
173 | iface->state = state_read; | ||
174 | } else { | ||
175 | outb(iface->address_byte, ACBSDA); | ||
176 | |||
177 | iface->state = state_write; | ||
178 | } | ||
179 | break; | ||
180 | |||
181 | case state_read: | ||
182 | /* Set ACK if receiving the last byte */ | ||
183 | if (iface->len == 1) | ||
184 | outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1); | ||
185 | else | ||
186 | outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1); | ||
187 | |||
188 | *iface->ptr++ = inb(ACBSDA); | ||
189 | --iface->len; | ||
190 | |||
191 | if (iface->len == 0) { | ||
192 | iface->result = 0; | ||
193 | iface->state = state_idle; | ||
194 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); | ||
195 | } | ||
196 | |||
197 | break; | ||
198 | |||
199 | case state_write: | ||
200 | if (iface->len == 0) { | ||
201 | iface->result = 0; | ||
202 | iface->state = state_idle; | ||
203 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); | ||
204 | break; | ||
205 | } | ||
206 | |||
207 | outb(*iface->ptr++, ACBSDA); | ||
208 | --iface->len; | ||
209 | |||
210 | break; | ||
211 | } | ||
212 | |||
213 | return; | ||
214 | |||
215 | negack: | ||
216 | DBG("negative acknowledge in state %s\n", | ||
217 | scx200_acb_state_name[iface->state]); | ||
218 | |||
219 | iface->state = state_idle; | ||
220 | iface->result = -ENXIO; | ||
221 | |||
222 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); | ||
223 | outb(ACBST_STASTR | ACBST_NEGACK, ACBST); | ||
224 | return; | ||
225 | |||
226 | error: | ||
227 | dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg, | ||
228 | scx200_acb_state_name[iface->state]); | ||
229 | |||
230 | iface->state = state_idle; | ||
231 | iface->result = -EIO; | ||
232 | iface->needs_reset = 1; | ||
233 | } | ||
234 | |||
235 | static void scx200_acb_timeout(struct scx200_acb_iface *iface) | ||
236 | { | ||
237 | dev_err(&iface->adapter.dev, "timeout in state %s\n", | ||
238 | scx200_acb_state_name[iface->state]); | ||
239 | |||
240 | iface->state = state_idle; | ||
241 | iface->result = -EIO; | ||
242 | iface->needs_reset = 1; | ||
243 | } | ||
244 | |||
245 | #ifdef POLLED_MODE | ||
246 | static void scx200_acb_poll(struct scx200_acb_iface *iface) | ||
247 | { | ||
248 | u8 status = 0; | ||
249 | unsigned long timeout; | ||
250 | |||
251 | timeout = jiffies + POLL_TIMEOUT; | ||
252 | while (time_before(jiffies, timeout)) { | ||
253 | status = inb(ACBST); | ||
254 | if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) { | ||
255 | scx200_acb_machine(iface, status); | ||
256 | return; | ||
257 | } | ||
258 | msleep(10); | ||
259 | } | ||
260 | |||
261 | scx200_acb_timeout(iface); | ||
262 | } | ||
263 | #endif /* POLLED_MODE */ | ||
264 | |||
265 | static void scx200_acb_reset(struct scx200_acb_iface *iface) | ||
266 | { | ||
267 | /* Disable the ACCESS.bus device and Configure the SCL | ||
268 | frequency: 16 clock cycles */ | ||
269 | outb(0x70, ACBCTL2); | ||
270 | /* Polling mode */ | ||
271 | outb(0, ACBCTL1); | ||
272 | /* Disable slave address */ | ||
273 | outb(0, ACBADDR); | ||
274 | /* Enable the ACCESS.bus device */ | ||
275 | outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2); | ||
276 | /* Free STALL after START */ | ||
277 | outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1); | ||
278 | /* Send a STOP */ | ||
279 | outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); | ||
280 | /* Clear BER, NEGACK and STASTR bits */ | ||
281 | outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST); | ||
282 | /* Clear BB bit */ | ||
283 | outb(inb(ACBCST) | ACBCST_BB, ACBCST); | ||
284 | } | ||
285 | |||
286 | static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, | ||
287 | u16 address, unsigned short flags, | ||
288 | char rw, u8 command, int size, | ||
289 | union i2c_smbus_data *data) | ||
290 | { | ||
291 | struct scx200_acb_iface *iface = i2c_get_adapdata(adapter); | ||
292 | int len; | ||
293 | u8 *buffer; | ||
294 | u16 cur_word; | ||
295 | int rc; | ||
296 | |||
297 | switch (size) { | ||
298 | case I2C_SMBUS_QUICK: | ||
299 | len = 0; | ||
300 | buffer = NULL; | ||
301 | break; | ||
302 | case I2C_SMBUS_BYTE: | ||
303 | if (rw == I2C_SMBUS_READ) { | ||
304 | len = 1; | ||
305 | buffer = &data->byte; | ||
306 | } else { | ||
307 | len = 1; | ||
308 | buffer = &command; | ||
309 | } | ||
310 | break; | ||
311 | case I2C_SMBUS_BYTE_DATA: | ||
312 | len = 1; | ||
313 | buffer = &data->byte; | ||
314 | break; | ||
315 | case I2C_SMBUS_WORD_DATA: | ||
316 | len = 2; | ||
317 | cur_word = cpu_to_le16(data->word); | ||
318 | buffer = (u8 *)&cur_word; | ||
319 | break; | ||
320 | case I2C_SMBUS_BLOCK_DATA: | ||
321 | len = data->block[0]; | ||
322 | buffer = &data->block[1]; | ||
323 | break; | ||
324 | default: | ||
325 | return -EINVAL; | ||
326 | } | ||
327 | |||
328 | DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n", | ||
329 | size, address, command, len, rw == I2C_SMBUS_READ); | ||
330 | |||
331 | if (!len && rw == I2C_SMBUS_READ) { | ||
332 | dev_warn(&adapter->dev, "zero length read\n"); | ||
333 | return -EINVAL; | ||
334 | } | ||
335 | |||
336 | if (len && !buffer) { | ||
337 | dev_warn(&adapter->dev, "nonzero length but no buffer\n"); | ||
338 | return -EFAULT; | ||
339 | } | ||
340 | |||
341 | down(&iface->sem); | ||
342 | |||
343 | iface->address_byte = address<<1; | ||
344 | if (rw == I2C_SMBUS_READ) | ||
345 | iface->address_byte |= 1; | ||
346 | iface->command = command; | ||
347 | iface->ptr = buffer; | ||
348 | iface->len = len; | ||
349 | iface->result = -EINVAL; | ||
350 | iface->needs_reset = 0; | ||
351 | |||
352 | outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1); | ||
353 | |||
354 | if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) | ||
355 | iface->state = state_quick; | ||
356 | else | ||
357 | iface->state = state_address; | ||
358 | |||
359 | #ifdef POLLED_MODE | ||
360 | while (iface->state != state_idle) | ||
361 | scx200_acb_poll(iface); | ||
362 | #else /* POLLED_MODE */ | ||
363 | #error Interrupt driven mode not implemented | ||
364 | #endif /* POLLED_MODE */ | ||
365 | |||
366 | if (iface->needs_reset) | ||
367 | scx200_acb_reset(iface); | ||
368 | |||
369 | rc = iface->result; | ||
370 | |||
371 | up(&iface->sem); | ||
372 | |||
373 | if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ) | ||
374 | data->word = le16_to_cpu(cur_word); | ||
375 | |||
376 | #ifdef DEBUG | ||
377 | DBG(": transfer done, result: %d", rc); | ||
378 | if (buffer) { | ||
379 | int i; | ||
380 | printk(" data:"); | ||
381 | for (i = 0; i < len; ++i) | ||
382 | printk(" %02x", buffer[i]); | ||
383 | } | ||
384 | printk("\n"); | ||
385 | #endif | ||
386 | |||
387 | return rc; | ||
388 | } | ||
389 | |||
390 | static u32 scx200_acb_func(struct i2c_adapter *adapter) | ||
391 | { | ||
392 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | | ||
393 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | | ||
394 | I2C_FUNC_SMBUS_BLOCK_DATA; | ||
395 | } | ||
396 | |||
397 | /* For now, we only handle combined mode (smbus) */ | ||
398 | static struct i2c_algorithm scx200_acb_algorithm = { | ||
399 | .name = "NatSemi SCx200 ACCESS.bus", | ||
400 | .id = I2C_ALGO_SMBUS, | ||
401 | .smbus_xfer = scx200_acb_smbus_xfer, | ||
402 | .functionality = scx200_acb_func, | ||
403 | }; | ||
404 | |||
405 | static struct scx200_acb_iface *scx200_acb_list; | ||
406 | |||
407 | static int scx200_acb_probe(struct scx200_acb_iface *iface) | ||
408 | { | ||
409 | u8 val; | ||
410 | |||
411 | /* Disable the ACCESS.bus device and Configure the SCL | ||
412 | frequency: 16 clock cycles */ | ||
413 | outb(0x70, ACBCTL2); | ||
414 | |||
415 | if (inb(ACBCTL2) != 0x70) { | ||
416 | DBG("ACBCTL2 readback failed\n"); | ||
417 | return -ENXIO; | ||
418 | } | ||
419 | |||
420 | outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1); | ||
421 | |||
422 | val = inb(ACBCTL1); | ||
423 | if (val) { | ||
424 | DBG("disabled, but ACBCTL1=0x%02x\n", val); | ||
425 | return -ENXIO; | ||
426 | } | ||
427 | |||
428 | outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2); | ||
429 | |||
430 | outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1); | ||
431 | |||
432 | val = inb(ACBCTL1); | ||
433 | if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) { | ||
434 | DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val); | ||
435 | return -ENXIO; | ||
436 | } | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int __init scx200_acb_create(int base, int index) | ||
442 | { | ||
443 | struct scx200_acb_iface *iface; | ||
444 | struct i2c_adapter *adapter; | ||
445 | int rc = 0; | ||
446 | char description[64]; | ||
447 | |||
448 | iface = kmalloc(sizeof(*iface), GFP_KERNEL); | ||
449 | if (!iface) { | ||
450 | printk(KERN_ERR NAME ": can't allocate memory\n"); | ||
451 | rc = -ENOMEM; | ||
452 | goto errout; | ||
453 | } | ||
454 | |||
455 | memset(iface, 0, sizeof(*iface)); | ||
456 | adapter = &iface->adapter; | ||
457 | i2c_set_adapdata(adapter, iface); | ||
458 | snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index); | ||
459 | adapter->owner = THIS_MODULE; | ||
460 | adapter->id = I2C_ALGO_SMBUS; | ||
461 | adapter->algo = &scx200_acb_algorithm; | ||
462 | adapter->class = I2C_CLASS_HWMON; | ||
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 struct pci_device_id scx200[] = { | ||
506 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, | ||
507 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, | ||
508 | { }, | ||
509 | }; | ||
510 | |||
511 | static int __init scx200_acb_init(void) | ||
512 | { | ||
513 | int i; | ||
514 | int rc; | ||
515 | |||
516 | pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); | ||
517 | |||
518 | /* Verify that this really is a SCx200 processor */ | ||
519 | if (pci_dev_present(scx200) == 0) | ||
520 | return -ENODEV; | ||
521 | |||
522 | rc = -ENXIO; | ||
523 | for (i = 0; i < MAX_DEVICES; ++i) { | ||
524 | if (base[i] > 0) | ||
525 | rc = scx200_acb_create(base[i], i); | ||
526 | } | ||
527 | if (scx200_acb_list) | ||
528 | return 0; | ||
529 | return rc; | ||
530 | } | ||
531 | |||
532 | static void __exit scx200_acb_cleanup(void) | ||
533 | { | ||
534 | struct scx200_acb_iface *iface; | ||
535 | lock_kernel(); | ||
536 | while ((iface = scx200_acb_list) != NULL) { | ||
537 | scx200_acb_list = iface->next; | ||
538 | unlock_kernel(); | ||
539 | |||
540 | i2c_del_adapter(&iface->adapter); | ||
541 | release_region(iface->base, 8); | ||
542 | kfree(iface); | ||
543 | lock_kernel(); | ||
544 | } | ||
545 | unlock_kernel(); | ||
546 | } | ||
547 | |||
548 | module_init(scx200_acb_init); | ||
549 | module_exit(scx200_acb_cleanup); | ||
550 | |||
551 | /* | ||
552 | Local variables: | ||
553 | compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules" | ||
554 | c-basic-offset: 8 | ||
555 | End: | ||
556 | */ | ||
557 | |||