xref: /openbmc/linux/drivers/ata/pata_parport/friq.c (revision 5b77db9c)
172f2b0b2SOndrej Zary /*
272f2b0b2SOndrej Zary 	friq.c	(c) 1998    Grant R. Guenther <grant@torque.net>
372f2b0b2SOndrej Zary 		            Under the terms of the GNU General Public License
472f2b0b2SOndrej Zary 
572f2b0b2SOndrej Zary 	friq.c is a low-level protocol driver for the Freecom "IQ"
672f2b0b2SOndrej Zary 	parallel port IDE adapter.   Early versions of this adapter
772f2b0b2SOndrej Zary 	use the 'frpw' protocol.
872f2b0b2SOndrej Zary 
972f2b0b2SOndrej Zary 	Freecom uses this adapter in a battery powered external
1072f2b0b2SOndrej Zary 	CD-ROM drive.  It is also used in LS-120 drives by
1172f2b0b2SOndrej Zary 	Maxell and Panasonic, and other devices.
1272f2b0b2SOndrej Zary 
1372f2b0b2SOndrej Zary 	The battery powered drive requires software support to
1472f2b0b2SOndrej Zary 	control the power to the drive.  This module enables the
1572f2b0b2SOndrej Zary 	drive power when the high level driver (pcd) is loaded
1672f2b0b2SOndrej Zary 	and disables it when the module is unloaded.  Note, if
1772f2b0b2SOndrej Zary 	the friq module is built in to the kernel, the power
1872f2b0b2SOndrej Zary 	will never be switched off, so other means should be
1972f2b0b2SOndrej Zary 	used to conserve battery power.
2072f2b0b2SOndrej Zary 
2172f2b0b2SOndrej Zary */
2272f2b0b2SOndrej Zary 
2372f2b0b2SOndrej Zary /* Changes:
2472f2b0b2SOndrej Zary 
2572f2b0b2SOndrej Zary 	1.01	GRG 1998.12.20	 Added support for soft power switch
2672f2b0b2SOndrej Zary */
2772f2b0b2SOndrej Zary 
2872f2b0b2SOndrej Zary #define	FRIQ_VERSION	"1.01"
2972f2b0b2SOndrej Zary 
3072f2b0b2SOndrej Zary #include <linux/module.h>
3172f2b0b2SOndrej Zary #include <linux/init.h>
3272f2b0b2SOndrej Zary #include <linux/delay.h>
3372f2b0b2SOndrej Zary #include <linux/kernel.h>
3472f2b0b2SOndrej Zary #include <linux/types.h>
3572f2b0b2SOndrej Zary #include <linux/wait.h>
3672f2b0b2SOndrej Zary #include <asm/io.h>
3772f2b0b2SOndrej Zary 
3872f2b0b2SOndrej Zary #include <linux/pata_parport.h>
3972f2b0b2SOndrej Zary 
4072f2b0b2SOndrej Zary #define CMD(x)		w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\
4172f2b0b2SOndrej Zary 			w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x);
4272f2b0b2SOndrej Zary 
4372f2b0b2SOndrej Zary #define j44(l,h)	(((l>>4)&0x0f)|(h&0xf0))
4472f2b0b2SOndrej Zary 
4572f2b0b2SOndrej Zary /* cont = 0 - access the IDE register file
4672f2b0b2SOndrej Zary    cont = 1 - access the IDE command set
4772f2b0b2SOndrej Zary */
4872f2b0b2SOndrej Zary 
4972f2b0b2SOndrej Zary static int  cont_map[2] = { 0x08, 0x10 };
5072f2b0b2SOndrej Zary 
51882ff0caSOndrej Zary static int friq_read_regr(struct pi_adapter *pi, int cont, int regr)
5272f2b0b2SOndrej Zary 
5372f2b0b2SOndrej Zary {	int	h,l,r;
5472f2b0b2SOndrej Zary 
5572f2b0b2SOndrej Zary 	r = regr + cont_map[cont];
5672f2b0b2SOndrej Zary 
5772f2b0b2SOndrej Zary 	CMD(r);
5872f2b0b2SOndrej Zary 	w2(6); l = r1();
5972f2b0b2SOndrej Zary 	w2(4); h = r1();
6072f2b0b2SOndrej Zary 	w2(4);
6172f2b0b2SOndrej Zary 
6272f2b0b2SOndrej Zary 	return j44(l,h);
6372f2b0b2SOndrej Zary 
6472f2b0b2SOndrej Zary }
6572f2b0b2SOndrej Zary 
66882ff0caSOndrej Zary static void friq_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
6772f2b0b2SOndrej Zary 
6872f2b0b2SOndrej Zary {	int r;
6972f2b0b2SOndrej Zary 
7072f2b0b2SOndrej Zary         r = regr + cont_map[cont];
7172f2b0b2SOndrej Zary 
7272f2b0b2SOndrej Zary 	CMD(r);
7372f2b0b2SOndrej Zary 	w0(val);
7472f2b0b2SOndrej Zary 	w2(5);w2(7);w2(5);w2(4);
7572f2b0b2SOndrej Zary }
7672f2b0b2SOndrej Zary 
77882ff0caSOndrej Zary static void friq_read_block_int(struct pi_adapter *pi, char *buf, int count, int regr)
7872f2b0b2SOndrej Zary 
7972f2b0b2SOndrej Zary {       int     h, l, k, ph;
8072f2b0b2SOndrej Zary 
8172f2b0b2SOndrej Zary         switch(pi->mode) {
8272f2b0b2SOndrej Zary 
8372f2b0b2SOndrej Zary         case 0: CMD(regr);
8472f2b0b2SOndrej Zary                 for (k=0;k<count;k++) {
8572f2b0b2SOndrej Zary                         w2(6); l = r1();
8672f2b0b2SOndrej Zary                         w2(4); h = r1();
8772f2b0b2SOndrej Zary                         buf[k] = j44(l,h);
8872f2b0b2SOndrej Zary                 }
8972f2b0b2SOndrej Zary                 w2(4);
9072f2b0b2SOndrej Zary                 break;
9172f2b0b2SOndrej Zary 
9272f2b0b2SOndrej Zary         case 1: ph = 2;
9372f2b0b2SOndrej Zary                 CMD(regr+0xc0);
9472f2b0b2SOndrej Zary                 w0(0xff);
9572f2b0b2SOndrej Zary                 for (k=0;k<count;k++) {
9672f2b0b2SOndrej Zary                         w2(0xa4 + ph);
9772f2b0b2SOndrej Zary                         buf[k] = r0();
9872f2b0b2SOndrej Zary                         ph = 2 - ph;
9972f2b0b2SOndrej Zary                 }
10072f2b0b2SOndrej Zary                 w2(0xac); w2(0xa4); w2(4);
10172f2b0b2SOndrej Zary                 break;
10272f2b0b2SOndrej Zary 
10372f2b0b2SOndrej Zary 	case 2: CMD(regr+0x80);
10472f2b0b2SOndrej Zary 		for (k=0;k<count-2;k++) buf[k] = r4();
10572f2b0b2SOndrej Zary 		w2(0xac); w2(0xa4);
10672f2b0b2SOndrej Zary 		buf[count-2] = r4();
10772f2b0b2SOndrej Zary 		buf[count-1] = r4();
10872f2b0b2SOndrej Zary 		w2(4);
10972f2b0b2SOndrej Zary 		break;
11072f2b0b2SOndrej Zary 
11172f2b0b2SOndrej Zary 	case 3: CMD(regr+0x80);
11272f2b0b2SOndrej Zary                 for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
11372f2b0b2SOndrej Zary                 w2(0xac); w2(0xa4);
11472f2b0b2SOndrej Zary                 buf[count-2] = r4();
11572f2b0b2SOndrej Zary                 buf[count-1] = r4();
11672f2b0b2SOndrej Zary                 w2(4);
11772f2b0b2SOndrej Zary                 break;
11872f2b0b2SOndrej Zary 
11972f2b0b2SOndrej Zary 	case 4: CMD(regr+0x80);
12072f2b0b2SOndrej Zary                 for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
12172f2b0b2SOndrej Zary                 buf[count-4] = r4();
12272f2b0b2SOndrej Zary                 buf[count-3] = r4();
12372f2b0b2SOndrej Zary                 w2(0xac); w2(0xa4);
12472f2b0b2SOndrej Zary                 buf[count-2] = r4();
12572f2b0b2SOndrej Zary                 buf[count-1] = r4();
12672f2b0b2SOndrej Zary                 w2(4);
12772f2b0b2SOndrej Zary                 break;
12872f2b0b2SOndrej Zary 
12972f2b0b2SOndrej Zary         }
13072f2b0b2SOndrej Zary }
13172f2b0b2SOndrej Zary 
132882ff0caSOndrej Zary static void friq_read_block(struct pi_adapter *pi, char *buf, int count)
13372f2b0b2SOndrej Zary 
13472f2b0b2SOndrej Zary {	friq_read_block_int(pi,buf,count,0x08);
13572f2b0b2SOndrej Zary }
13672f2b0b2SOndrej Zary 
137882ff0caSOndrej Zary static void friq_write_block(struct pi_adapter *pi, char *buf, int count)
13872f2b0b2SOndrej Zary 
13972f2b0b2SOndrej Zary {	int	k;
14072f2b0b2SOndrej Zary 
14172f2b0b2SOndrej Zary 	switch(pi->mode) {
14272f2b0b2SOndrej Zary 
14372f2b0b2SOndrej Zary 	case 0:
14472f2b0b2SOndrej Zary 	case 1: CMD(8); w2(5);
14572f2b0b2SOndrej Zary         	for (k=0;k<count;k++) {
14672f2b0b2SOndrej Zary 			w0(buf[k]);
14772f2b0b2SOndrej Zary 			w2(7);w2(5);
14872f2b0b2SOndrej Zary 		}
14972f2b0b2SOndrej Zary 		w2(4);
15072f2b0b2SOndrej Zary 		break;
15172f2b0b2SOndrej Zary 
15272f2b0b2SOndrej Zary 	case 2: CMD(0xc8); w2(5);
15372f2b0b2SOndrej Zary 		for (k=0;k<count;k++) w4(buf[k]);
15472f2b0b2SOndrej Zary 		w2(4);
15572f2b0b2SOndrej Zary 		break;
15672f2b0b2SOndrej Zary 
15772f2b0b2SOndrej Zary         case 3: CMD(0xc8); w2(5);
15872f2b0b2SOndrej Zary                 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
15972f2b0b2SOndrej Zary                 w2(4);
16072f2b0b2SOndrej Zary                 break;
16172f2b0b2SOndrej Zary 
16272f2b0b2SOndrej Zary         case 4: CMD(0xc8); w2(5);
16372f2b0b2SOndrej Zary                 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
16472f2b0b2SOndrej Zary                 w2(4);
16572f2b0b2SOndrej Zary                 break;
16672f2b0b2SOndrej Zary 	}
16772f2b0b2SOndrej Zary }
16872f2b0b2SOndrej Zary 
169882ff0caSOndrej Zary static void friq_connect(struct pi_adapter *pi)
17072f2b0b2SOndrej Zary 
17172f2b0b2SOndrej Zary {       pi->saved_r0 = r0();
17272f2b0b2SOndrej Zary         pi->saved_r2 = r2();
17372f2b0b2SOndrej Zary 	w2(4);
17472f2b0b2SOndrej Zary }
17572f2b0b2SOndrej Zary 
176882ff0caSOndrej Zary static void friq_disconnect(struct pi_adapter *pi)
17772f2b0b2SOndrej Zary 
17872f2b0b2SOndrej Zary {       CMD(0x20);
17972f2b0b2SOndrej Zary 	w0(pi->saved_r0);
18072f2b0b2SOndrej Zary         w2(pi->saved_r2);
18172f2b0b2SOndrej Zary }
18272f2b0b2SOndrej Zary 
183882ff0caSOndrej Zary static int friq_test_proto(struct pi_adapter *pi, char *scratch, int verbose)
18472f2b0b2SOndrej Zary 
18572f2b0b2SOndrej Zary {       int     j, k, r;
18672f2b0b2SOndrej Zary 	int	e[2] = {0,0};
18772f2b0b2SOndrej Zary 
18872f2b0b2SOndrej Zary 	pi->saved_r0 = r0();
18972f2b0b2SOndrej Zary 	w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */
19072f2b0b2SOndrej Zary 	udelay(500);
19172f2b0b2SOndrej Zary 	w0(pi->saved_r0);
19272f2b0b2SOndrej Zary 
19372f2b0b2SOndrej Zary 	friq_connect(pi);
19472f2b0b2SOndrej Zary 	for (j=0;j<2;j++) {
19572f2b0b2SOndrej Zary                 friq_write_regr(pi,0,6,0xa0+j*0x10);
19672f2b0b2SOndrej Zary                 for (k=0;k<256;k++) {
19772f2b0b2SOndrej Zary                         friq_write_regr(pi,0,2,k^0xaa);
19872f2b0b2SOndrej Zary                         friq_write_regr(pi,0,3,k^0x55);
19972f2b0b2SOndrej Zary                         if (friq_read_regr(pi,0,2) != (k^0xaa)) e[j]++;
20072f2b0b2SOndrej Zary                         }
20172f2b0b2SOndrej Zary                 }
20272f2b0b2SOndrej Zary 	friq_disconnect(pi);
20372f2b0b2SOndrej Zary 
20472f2b0b2SOndrej Zary 	friq_connect(pi);
20572f2b0b2SOndrej Zary         friq_read_block_int(pi,scratch,512,0x10);
20672f2b0b2SOndrej Zary         r = 0;
20772f2b0b2SOndrej Zary         for (k=0;k<128;k++) if (scratch[k] != k) r++;
20872f2b0b2SOndrej Zary 	friq_disconnect(pi);
20972f2b0b2SOndrej Zary 
21072f2b0b2SOndrej Zary         if (verbose)  {
211a4f2ff92SOndrej Zary 		printk("friq: port 0x%x, mode %d, test=(%d,%d,%d)\n",
212a4f2ff92SOndrej Zary 		       pi->port, pi->mode, e[0], e[1], r);
21372f2b0b2SOndrej Zary         }
21472f2b0b2SOndrej Zary 
21572f2b0b2SOndrej Zary         return (r || (e[0] && e[1]));
21672f2b0b2SOndrej Zary }
21772f2b0b2SOndrej Zary 
21872f2b0b2SOndrej Zary 
219*5b77db9cSOndrej Zary static void friq_log_adapter(struct pi_adapter *pi)
22072f2b0b2SOndrej Zary 
22172f2b0b2SOndrej Zary {       char    *mode_string[6] = {"4-bit","8-bit",
22272f2b0b2SOndrej Zary 				   "EPP-8","EPP-16","EPP-32"};
22372f2b0b2SOndrej Zary 
224a4f2ff92SOndrej Zary 	printk("friq %s, Freecom IQ ASIC-2 adapter at 0x%x, ",
22572f2b0b2SOndrej Zary 		FRIQ_VERSION,pi->port);
22672f2b0b2SOndrej Zary         printk("mode %d (%s), delay %d\n",pi->mode,
22772f2b0b2SOndrej Zary 		mode_string[pi->mode],pi->delay);
22872f2b0b2SOndrej Zary 
22972f2b0b2SOndrej Zary 	pi->private = 1;
23072f2b0b2SOndrej Zary 	friq_connect(pi);
23172f2b0b2SOndrej Zary 	CMD(0x9e);  		/* disable sleep timer */
23272f2b0b2SOndrej Zary 	friq_disconnect(pi);
23372f2b0b2SOndrej Zary 
23472f2b0b2SOndrej Zary }
23572f2b0b2SOndrej Zary 
236882ff0caSOndrej Zary static void friq_release_proto(struct pi_adapter *pi)
23772f2b0b2SOndrej Zary {
23872f2b0b2SOndrej Zary 	if (pi->private) {		/* turn off the power */
23972f2b0b2SOndrej Zary 		friq_connect(pi);
24072f2b0b2SOndrej Zary 		CMD(0x1d); CMD(0x1e);
24172f2b0b2SOndrej Zary 		friq_disconnect(pi);
24272f2b0b2SOndrej Zary 		pi->private = 0;
24372f2b0b2SOndrej Zary 	}
24472f2b0b2SOndrej Zary }
24572f2b0b2SOndrej Zary 
24672f2b0b2SOndrej Zary static struct pi_protocol friq = {
24772f2b0b2SOndrej Zary 	.owner		= THIS_MODULE,
24872f2b0b2SOndrej Zary 	.name		= "friq",
24972f2b0b2SOndrej Zary 	.max_mode	= 5,
25072f2b0b2SOndrej Zary 	.epp_first	= 2,
25172f2b0b2SOndrej Zary 	.default_delay	= 1,
25272f2b0b2SOndrej Zary 	.max_units	= 1,
25372f2b0b2SOndrej Zary 	.write_regr	= friq_write_regr,
25472f2b0b2SOndrej Zary 	.read_regr	= friq_read_regr,
25572f2b0b2SOndrej Zary 	.write_block	= friq_write_block,
25672f2b0b2SOndrej Zary 	.read_block	= friq_read_block,
25772f2b0b2SOndrej Zary 	.connect	= friq_connect,
25872f2b0b2SOndrej Zary 	.disconnect	= friq_disconnect,
25972f2b0b2SOndrej Zary 	.test_proto	= friq_test_proto,
26072f2b0b2SOndrej Zary 	.log_adapter	= friq_log_adapter,
26172f2b0b2SOndrej Zary 	.release_proto	= friq_release_proto,
26272f2b0b2SOndrej Zary };
26372f2b0b2SOndrej Zary 
26472f2b0b2SOndrej Zary MODULE_LICENSE("GPL");
2652c08ec0fSOndrej Zary module_pata_parport_driver(friq);
266