xref: /openbmc/linux/drivers/i2c/busses/i2c-elektor.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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);
296