vserver 1.9.3
[linux-2.6.git] / drivers / i2c / busses / i2c-elektor.c
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
6
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.                */
20 /* ------------------------------------------------------------------------- */
21
22 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
23    Frodo Looijaard <frodol@dds.nl> */
24
25 /* Partialy rewriten by Oleg I. Vdovikin for mmapped support of 
26    for Alpha Processor Inc. UP-2000(+) boards */
27
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>
38
39 #include <linux/i2c.h>
40 #include <linux/i2c-algo-pcf.h>
41
42 #include <asm/io.h>
43 #include <asm/irq.h>
44
45 #include "../algos/i2c-algo-pcf.h"
46
47 #define DEFAULT_BASE 0x330
48
49 static int base;
50 static int irq;
51 static int clock  = 0x1c;
52 static int own    = 0x55;
53 static int mmapped;
54
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 */
59
60 static wait_queue_head_t pcf_wait;
61 static int pcf_pending;
62
63 /* ----- local functions ---------------------------------------------- */
64
65 static void pcf_isa_setbyte(void *data, int ctl, int val)
66 {
67         int address = ctl ? (base + 1) : base;
68
69         /* enable irq if any specified for serial operation */
70         if (ctl && irq && (val & I2C_PCF_ESO)) {
71                 val |= I2C_PCF_ENI;
72         }
73
74         pr_debug("i2c-elektor: Write 0x%X 0x%02X\n", address, val & 255);
75
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;
87         }
88 }
89
90 static int pcf_isa_getbyte(void *data, int ctl)
91 {
92         int address = ctl ? (base + 1) : base;
93         int val = mmapped ? readb(address) : inb(address);
94
95         pr_debug("i2c-elektor: Read 0x%X 0x%02X\n", address, val);
96
97         return (val);
98 }
99
100 static int pcf_isa_getown(void *data)
101 {
102         return (own);
103 }
104
105
106 static int pcf_isa_getclock(void *data)
107 {
108         return (clock);
109 }
110
111 static void pcf_isa_waitforpin(void) {
112
113         int timeout = 2;
114
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);
124         }
125 }
126
127
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;
132 }
133
134
135 static int pcf_isa_init(void)
136 {
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;
143                 }
144         }
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);
151         }
152         return 0;
153 }
154
155 /* ------------------------------------------------------------------------
156  * Encapsulate the above functions in the correct operations structure.
157  * This is only done when more than one hardware adapter is supported.
158  */
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,
168 };
169
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",
175 };
176
177 static int __init i2c_pcfisa_init(void) 
178 {
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) {
183                 
184                 struct pci_dev *cy693_dev =
185                     pci_find_device(PCI_VENDOR_ID_CONTAQ, 
186                                     PCI_DEVICE_ID_CONTAQ_82C693, NULL);
187
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)) {
192                                 
193                                 pr_debug("i2c-elektor: found cy82c693, config register 0x47 = 0x%02x.\n", config);
194
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) */
201
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");
216                                 }
217                         }
218                 }
219         }
220 #endif
221
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;
226         }
227
228         printk(KERN_INFO "i2c-elektor: i2c pcf8584-isa adapter driver\n");
229
230         if (base == 0) {
231                 base = DEFAULT_BASE;
232         }
233
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;
239         
240         printk(KERN_ERR "i2c-elektor: found device at %#x.\n", base);
241
242         return 0;
243
244  fail:
245         if (irq > 0) {
246                 disable_irq(irq);
247                 free_irq(irq, NULL);
248         }
249
250         if (!mmapped)
251                 release_region(base , 2);
252         return -ENODEV;
253 }
254
255 static void i2c_pcfisa_exit(void)
256 {
257         i2c_pcf_del_bus(&pcf_isa_ops);
258
259         if (irq > 0) {
260                 disable_irq(irq);
261                 free_irq(irq, NULL);
262         }
263
264         if (!mmapped)
265                 release_region(base , 2);
266 }
267
268 MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
269 MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
270 MODULE_LICENSE("GPL");
271
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);
277
278 module_init(i2c_pcfisa_init);
279 module_exit(i2c_pcfisa_exit);