Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.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 static spinlock_t lock;
63
64 /* ----- local functions ---------------------------------------------- */
65
66 static void pcf_isa_setbyte(void *data, int ctl, int val)
67 {
68         int address = ctl ? (base + 1) : base;
69
70         /* enable irq if any specified for serial operation */
71         if (ctl && irq && (val & I2C_PCF_ESO)) {
72                 val |= I2C_PCF_ENI;
73         }
74
75         pr_debug("i2c-elektor: Write 0x%X 0x%02X\n", address, val & 255);
76
77         switch (mmapped) {
78         case 0: /* regular I/O */
79                 outb(val, address);
80                 break;
81         case 2: /* double mapped I/O needed for UP2000 board,
82                    I don't know why this... */
83                 writeb(val, (void *)address);
84                 /* fall */
85         case 1: /* memory mapped I/O */
86                 writeb(val, (void *)address);
87                 break;
88         }
89 }
90
91 static int pcf_isa_getbyte(void *data, int ctl)
92 {
93         int address = ctl ? (base + 1) : base;
94         int val = mmapped ? readb((void *)address) : inb(address);
95
96         pr_debug("i2c-elektor: Read 0x%X 0x%02X\n", address, val);
97
98         return (val);
99 }
100
101 static int pcf_isa_getown(void *data)
102 {
103         return (own);
104 }
105
106
107 static int pcf_isa_getclock(void *data)
108 {
109         return (clock);
110 }
111
112 static void pcf_isa_waitforpin(void) {
113         DEFINE_WAIT(wait);
114         int timeout = 2;
115         unsigned long flags;
116
117         if (irq > 0) {
118                 spin_lock_irqsave(&lock, flags);
119                 if (pcf_pending == 0) {
120                         spin_unlock_irqrestore(&lock, flags);
121                         prepare_to_wait(&pcf_wait, &wait, TASK_INTERRUPTIBLE);
122                         if (schedule_timeout(timeout*HZ)) {
123                                 spin_lock_irqsave(&lock, flags);
124                                 if (pcf_pending == 1) {
125                                         pcf_pending = 0;
126                                 }
127                                 spin_unlock_irqrestore(&lock, flags);
128                         }
129                         finish_wait(&pcf_wait, &wait);
130                 } else {
131                         pcf_pending = 0;
132                         spin_unlock_irqrestore(&lock, flags);
133                 }
134         } else {
135                 udelay(100);
136         }
137 }
138
139
140 static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
141         spin_lock(&lock);
142         pcf_pending = 1;
143         spin_unlock(&lock);
144         wake_up_interruptible(&pcf_wait);
145         return IRQ_HANDLED;
146 }
147
148
149 static int pcf_isa_init(void)
150 {
151         spin_lock_init(&lock);
152         if (!mmapped) {
153                 if (!request_region(base, 2, "i2c (isa bus adapter)")) {
154                         printk(KERN_ERR
155                                "i2c-elektor: requested I/O region (0x%X:2) "
156                                "is in use.\n", base);
157                         return -ENODEV;
158                 }
159         }
160         if (irq > 0) {
161                 if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", NULL) < 0) {
162                         printk(KERN_ERR "i2c-elektor: Request irq%d failed\n", irq);
163                         irq = 0;
164                 } else
165                         enable_irq(irq);
166         }
167         return 0;
168 }
169
170 /* ------------------------------------------------------------------------
171  * Encapsulate the above functions in the correct operations structure.
172  * This is only done when more than one hardware adapter is supported.
173  */
174 static struct i2c_algo_pcf_data pcf_isa_data = {
175         .setpcf     = pcf_isa_setbyte,
176         .getpcf     = pcf_isa_getbyte,
177         .getown     = pcf_isa_getown,
178         .getclock   = pcf_isa_getclock,
179         .waitforpin = pcf_isa_waitforpin,
180         .udelay     = 10,
181         .mdelay     = 10,
182         .timeout    = 100,
183 };
184
185 static struct i2c_adapter pcf_isa_ops = {
186         .owner          = THIS_MODULE,
187         .class          = I2C_CLASS_HWMON,
188         .id             = I2C_HW_P_ELEK,
189         .algo_data      = &pcf_isa_data,
190         .name           = "PCF8584 ISA adapter",
191 };
192
193 static int __init i2c_pcfisa_init(void) 
194 {
195 #ifdef __alpha__
196         /* check to see we have memory mapped PCF8584 connected to the 
197         Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
198         if (base == 0) {
199                 struct pci_dev *cy693_dev;
200                 
201                 cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ, 
202                                            PCI_DEVICE_ID_CONTAQ_82C693, NULL);
203                 if (cy693_dev) {
204                         char config;
205                         /* yeap, we've found cypress, let's check config */
206                         if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
207                                 
208                                 pr_debug("i2c-elektor: found cy82c693, config register 0x47 = 0x%02x.\n", config);
209
210                                 /* UP2000 board has this register set to 0xe1,
211                                    but the most significant bit as seems can be 
212                                    reset during the proper initialisation
213                                    sequence if guys from API decides to do that
214                                    (so, we can even enable Tsunami Pchip
215                                    window for the upper 1 Gb) */
216
217                                 /* so just check for ROMCS at 0xe0000,
218                                    ROMCS enabled for writes
219                                    and external XD Bus buffer in use. */
220                                 if ((config & 0x7f) == 0x61) {
221                                         /* seems to be UP2000 like board */
222                                         base = 0xe0000;
223                                         /* I don't know why we need to
224                                            write twice */
225                                         mmapped = 2;
226                                         /* UP2000 drives ISA with
227                                            8.25 MHz (PCI/4) clock
228                                            (this can be read from cypress) */
229                                         clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
230                                         printk(KERN_INFO "i2c-elektor: found API UP2000 like board, will probe PCF8584 later.\n");
231                                 }
232                         }
233                         pci_dev_put(cy693_dev);
234                 }
235         }
236 #endif
237
238         /* sanity checks for mmapped I/O */
239         if (mmapped && base < 0xc8000) {
240                 printk(KERN_ERR "i2c-elektor: incorrect base address (0x%0X) specified for mmapped I/O.\n", base);
241                 return -ENODEV;
242         }
243
244         printk(KERN_INFO "i2c-elektor: i2c pcf8584-isa adapter driver\n");
245
246         if (base == 0) {
247                 base = DEFAULT_BASE;
248         }
249
250         init_waitqueue_head(&pcf_wait);
251         if (pcf_isa_init())
252                 return -ENODEV;
253         if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
254                 goto fail;
255         
256         printk(KERN_ERR "i2c-elektor: found device at %#x.\n", base);
257
258         return 0;
259
260  fail:
261         if (irq > 0) {
262                 disable_irq(irq);
263                 free_irq(irq, NULL);
264         }
265
266         if (!mmapped)
267                 release_region(base , 2);
268         return -ENODEV;
269 }
270
271 static void i2c_pcfisa_exit(void)
272 {
273         i2c_pcf_del_bus(&pcf_isa_ops);
274
275         if (irq > 0) {
276                 disable_irq(irq);
277                 free_irq(irq, NULL);
278         }
279
280         if (!mmapped)
281                 release_region(base , 2);
282 }
283
284 MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
285 MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
286 MODULE_LICENSE("GPL");
287
288 module_param(base, int, 0);
289 module_param(irq, int, 0);
290 module_param(clock, int, 0);
291 module_param(own, int, 0);
292 module_param(mmapped, int, 0);
293
294 module_init(i2c_pcfisa_init);
295 module_exit(i2c_pcfisa_exit);