Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

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