1 /* ------------------------------------------------------------------------- */
2 /* i2c-elv.c i2c-hw access for philips style parallel port adapters	     */
3 /* ------------------------------------------------------------------------- */
4 /*   Copyright (C) 1995-2000 Simon G. Vogl
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
19 /* ------------------------------------------------------------------------- */
20 
21 /* With some changes from Ky�sti M�lkki <kmalkki@cc.hut.fi> and even
22    Frodo Looijaard <frodol@dds.nl> */
23 
24 /* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */
25 
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/delay.h>
29 #include <linux/slab.h>
30 #include <linux/init.h>
31 #include <linux/ioport.h>
32 #include <linux/errno.h>
33 #include <linux/i2c.h>
34 #include <linux/i2c-algo-bit.h>
35 #include <asm/io.h>
36 
37 #define DEFAULT_BASE 0x378
38 static int base=0;
39 static unsigned char PortData = 0;
40 
41 /* ----- global defines -----------------------------------------------	*/
42 #define DEB(x)		/* should be reasonable open, close &c. 	*/
43 #define DEB2(x) 	/* low level debugging - very slow 		*/
44 #define DEBE(x)	x	/* error messages 				*/
45 #define DEBINIT(x) x	/* detection status messages			*/
46 
47 /* --- Convenience defines for the parallel port:			*/
48 #define BASE	(unsigned int)(data)
49 #define DATA	BASE			/* Centronics data port		*/
50 #define STAT	(BASE+1)		/* Centronics status port	*/
51 #define CTRL	(BASE+2)		/* Centronics control port	*/
52 
53 
54 /* ----- local functions ----------------------------------------------	*/
55 
56 
bit_elv_setscl(void * data,int state)57 static void bit_elv_setscl(void *data, int state)
58 {
59 	if (state) {
60 		PortData &= 0xfe;
61 	} else {
62 		PortData |=1;
63 	}
64 	outb(PortData, DATA);
65 }
66 
bit_elv_setsda(void * data,int state)67 static void bit_elv_setsda(void *data, int state)
68 {
69 	if (state) {
70 		PortData &=0xfd;
71 	} else {
72 		PortData |=2;
73 	}
74 	outb(PortData, DATA);
75 }
76 
bit_elv_getscl(void * data)77 static int bit_elv_getscl(void *data)
78 {
79 	return ( 0 == ( (inb_p(STAT)) & 0x08 ) );
80 }
81 
bit_elv_getsda(void * data)82 static int bit_elv_getsda(void *data)
83 {
84 	return ( 0 == ( (inb_p(STAT)) & 0x40 ) );
85 }
86 
bit_elv_init(void)87 static int bit_elv_init(void)
88 {
89 	if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
90 		return -ENODEV;
91 	} else {
92 						/* test for ELV adap. 	*/
93 		if (inb(base+1) & 0x80) {	/* BUSY should be high	*/
94 			DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n"));
95 			return -ENODEV;
96 		} else {
97 			outb(0x0c,base+2);	/* SLCT auf low		*/
98 			udelay(400);
99 			if ( !(inb(base+1) & 0x10) ) {
100 				outb(0x04,base+2);
101 				DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n"));
102 				return -ENODEV;
103 			}
104 		}
105 		request_region(base,(base == 0x3bc)? 3 : 8,
106 			"i2c (ELV adapter)");
107 		PortData = 0;
108 		bit_elv_setsda((void*)base,1);
109 		bit_elv_setscl((void*)base,1);
110 	}
111 	return 0;
112 }
113 
bit_elv_exit(void)114 static void __exit bit_elv_exit(void)
115 {
116 	release_region( base , (base == 0x3bc)? 3 : 8 );
117 }
118 
bit_elv_reg(struct i2c_client * client)119 static int bit_elv_reg(struct i2c_client *client)
120 {
121 	return 0;
122 }
123 
bit_elv_unreg(struct i2c_client * client)124 static int bit_elv_unreg(struct i2c_client *client)
125 {
126 	return 0;
127 }
128 
bit_elv_inc_use(struct i2c_adapter * adap)129 static void bit_elv_inc_use(struct i2c_adapter *adap)
130 {
131 #ifdef MODULE
132 	MOD_INC_USE_COUNT;
133 #endif
134 }
135 
bit_elv_dec_use(struct i2c_adapter * adap)136 static void bit_elv_dec_use(struct i2c_adapter *adap)
137 {
138 #ifdef MODULE
139 	MOD_DEC_USE_COUNT;
140 #endif
141 }
142 
143 /* ------------------------------------------------------------------------
144  * Encapsulate the above functions in the correct operations structure.
145  * This is only done when more than one hardware adapter is supported.
146  */
147 static struct i2c_algo_bit_data bit_elv_data = {
148 	.setsda		= bit_elv_setsda,
149 	.setscl		= bit_elv_setscl,
150 	.getsda		= bit_elv_getsda,
151 	.getscl		= bit_elv_getscl,
152 	.udelay		= 80,
153 	.mdelay		= 80,
154 	.timeout	= HZ
155 };
156 
157 static struct i2c_adapter bit_elv_ops = {
158 	.name		= "ELV Parallel port adaptor",
159 	.id		= I2C_HW_B_ELV,
160 	.algo_data	= &bit_elv_data,
161 	.inc_use	= bit_elv_inc_use,
162 	.dec_use	= bit_elv_dec_use,
163 	.client_register = bit_elv_reg,
164 	.client_unregister = bit_elv_unreg,
165 };
166 
i2c_bitelv_init(void)167 int __init i2c_bitelv_init(void)
168 {
169 	printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
170 	if (base==0) {
171 		/* probe some values */
172 		base=DEFAULT_BASE;
173 		bit_elv_data.data=(void*)DEFAULT_BASE;
174 		if (bit_elv_init()==0) {
175 			if(i2c_bit_add_bus(&bit_elv_ops) < 0)
176 				return -ENODEV;
177 		} else {
178 			return -ENODEV;
179 		}
180 	} else {
181 		bit_elv_ops.data=(void*)base;
182 		if (bit_elv_init()==0) {
183 			if(i2c_bit_add_bus(&bit_elv_ops) < 0)
184 				return -ENODEV;
185 		} else {
186 			return -ENODEV;
187 		}
188 	}
189 	printk(KERN_DEBUG "i2c-elv.o: found device at %#x.\n",base);
190 	return 0;
191 }
192 
193 
194 EXPORT_NO_SYMBOLS;
195 
196 #ifdef MODULE
197 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
198 MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter");
199 MODULE_LICENSE("GPL");
200 
201 MODULE_PARM(base, "i");
202 
init_module(void)203 int init_module(void)
204 {
205 	return i2c_bitelv_init();
206 }
207 
cleanup_module(void)208 void cleanup_module(void)
209 {
210 	i2c_bit_del_bus(&bit_elv_ops);
211 	bit_elv_exit();
212 }
213 
214 #endif
215