MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / i2c / busses / i2c-elektor.c
blobf6bd38b060eb65d6ca421ae17f42dba2e514870b
1 /* ------------------------------------------------------------------------- */
2 /* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */
3 /* ------------------------------------------------------------------------- */
4 /* Copyright (C) 1995-97 Simon G. Vogl
5 1998-99 Hans Berglund
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* ------------------------------------------------------------------------- */
22 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
23 Frodo Looijaard <frodol@dds.nl> */
25 /* Partialy rewriten by Oleg I. Vdovikin for mmapped support of
26 for Alpha Processor Inc. UP-2000(+) boards */
28 #include <linux/config.h>
29 #include <linux/kernel.h>
30 #include <linux/ioport.h>
31 #include <linux/module.h>
32 #include <linux/delay.h>
33 #include <linux/slab.h>
34 #include <linux/init.h>
35 #include <linux/interrupt.h>
36 #include <linux/pci.h>
37 #include <linux/wait.h>
39 #include <linux/i2c.h>
40 #include <linux/i2c-algo-pcf.h>
42 #include <asm/io.h>
43 #include <asm/irq.h>
45 #include "../algos/i2c-algo-pcf.h"
47 #define DEFAULT_BASE 0x330
49 static int base;
50 static int irq;
51 static int clock = 0x1c;
52 static int own = 0x55;
53 static int mmapped;
55 /* vdovikin: removed static struct i2c_pcf_isa gpi; code -
56 this module in real supports only one device, due to missing arguments
57 in some functions, called from the algo-pcf module. Sometimes it's
58 need to be rewriten - but for now just remove this for simpler reading */
60 static wait_queue_head_t pcf_wait;
61 static int pcf_pending;
63 /* ----- local functions ---------------------------------------------- */
65 static void pcf_isa_setbyte(void *data, int ctl, int val)
67 int address = ctl ? (base + 1) : base;
69 /* enable irq if any specified for serial operation */
70 if (ctl && irq && (val & I2C_PCF_ESO)) {
71 val |= I2C_PCF_ENI;
74 pr_debug("i2c-elektor: Write 0x%X 0x%02X\n", address, val & 255);
76 switch (mmapped) {
77 case 0: /* regular I/O */
78 outb(val, address);
79 break;
80 case 2: /* double mapped I/O needed for UP2000 board,
81 I don't know why this... */
82 writeb(val, address);
83 /* fall */
84 case 1: /* memory mapped I/O */
85 writeb(val, address);
86 break;
90 static int pcf_isa_getbyte(void *data, int ctl)
92 int address = ctl ? (base + 1) : base;
93 int val = mmapped ? readb(address) : inb(address);
95 pr_debug("i2c-elektor: Read 0x%X 0x%02X\n", address, val);
97 return (val);
100 static int pcf_isa_getown(void *data)
102 return (own);
106 static int pcf_isa_getclock(void *data)
108 return (clock);
111 static void pcf_isa_waitforpin(void) {
113 int timeout = 2;
115 if (irq > 0) {
116 cli();
117 if (pcf_pending == 0) {
118 interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
119 } else
120 pcf_pending = 0;
121 sti();
122 } else {
123 udelay(100);
128 static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
129 pcf_pending = 1;
130 wake_up_interruptible(&pcf_wait);
131 return IRQ_HANDLED;
135 static int pcf_isa_init(void)
137 if (!mmapped) {
138 if (!request_region(base, 2, "i2c (isa bus adapter)")) {
139 printk(KERN_ERR
140 "i2c-elektor: requested I/O region (0x%X:2) "
141 "is in use.\n", base);
142 return -ENODEV;
145 if (irq > 0) {
146 if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", NULL) < 0) {
147 printk(KERN_ERR "i2c-elektor: Request irq%d failed\n", irq);
148 irq = 0;
149 } else
150 enable_irq(irq);
152 return 0;
155 /* ------------------------------------------------------------------------
156 * Encapsulate the above functions in the correct operations structure.
157 * This is only done when more than one hardware adapter is supported.
159 static struct i2c_algo_pcf_data pcf_isa_data = {
160 .setpcf = pcf_isa_setbyte,
161 .getpcf = pcf_isa_getbyte,
162 .getown = pcf_isa_getown,
163 .getclock = pcf_isa_getclock,
164 .waitforpin = pcf_isa_waitforpin,
165 .udelay = 10,
166 .mdelay = 10,
167 .timeout = 100,
170 static struct i2c_adapter pcf_isa_ops = {
171 .owner = THIS_MODULE,
172 .id = I2C_HW_P_ELEK,
173 .algo_data = &pcf_isa_data,
174 .name = "PCF8584 ISA adapter",
177 static int __init i2c_pcfisa_init(void)
179 #ifdef __alpha__
180 /* check to see we have memory mapped PCF8584 connected to the
181 Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
182 if (base == 0) {
184 struct pci_dev *cy693_dev =
185 pci_find_device(PCI_VENDOR_ID_CONTAQ,
186 PCI_DEVICE_ID_CONTAQ_82C693, NULL);
188 if (cy693_dev) {
189 char config;
190 /* yeap, we've found cypress, let's check config */
191 if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
193 pr_debug("i2c-elektor: found cy82c693, config register 0x47 = 0x%02x.\n", config);
195 /* UP2000 board has this register set to 0xe1,
196 but the most significant bit as seems can be
197 reset during the proper initialisation
198 sequence if guys from API decides to do that
199 (so, we can even enable Tsunami Pchip
200 window for the upper 1 Gb) */
202 /* so just check for ROMCS at 0xe0000,
203 ROMCS enabled for writes
204 and external XD Bus buffer in use. */
205 if ((config & 0x7f) == 0x61) {
206 /* seems to be UP2000 like board */
207 base = 0xe0000;
208 /* I don't know why we need to
209 write twice */
210 mmapped = 2;
211 /* UP2000 drives ISA with
212 8.25 MHz (PCI/4) clock
213 (this can be read from cypress) */
214 clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
215 printk(KERN_INFO "i2c-elektor: found API UP2000 like board, will probe PCF8584 later.\n");
220 #endif
222 /* sanity checks for mmapped I/O */
223 if (mmapped && base < 0xc8000) {
224 printk(KERN_ERR "i2c-elektor: incorrect base address (0x%0X) specified for mmapped I/O.\n", base);
225 return -ENODEV;
228 printk(KERN_INFO "i2c-elektor: i2c pcf8584-isa adapter driver\n");
230 if (base == 0) {
231 base = DEFAULT_BASE;
234 init_waitqueue_head(&pcf_wait);
235 if (pcf_isa_init())
236 return -ENODEV;
237 if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
238 goto fail;
240 printk(KERN_ERR "i2c-elektor: found device at %#x.\n", base);
242 return 0;
244 fail:
245 if (irq > 0) {
246 disable_irq(irq);
247 free_irq(irq, NULL);
250 if (!mmapped)
251 release_region(base , 2);
252 return -ENODEV;
255 static void i2c_pcfisa_exit(void)
257 i2c_pcf_del_bus(&pcf_isa_ops);
259 if (irq > 0) {
260 disable_irq(irq);
261 free_irq(irq, NULL);
264 if (!mmapped)
265 release_region(base , 2);
268 MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
269 MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
270 MODULE_LICENSE("GPL");
272 module_param(base, int, 0);
273 module_param(irq, int, 0);
274 module_param(clock, int, 0);
275 module_param(own, int, 0);
276 module_param(mmapped, int, 0);
278 module_init(i2c_pcfisa_init);
279 module_exit(i2c_pcfisa_exit);