Files
lm-sensors/i2c/old-code/pcf-lp.c
T
Frodo Looijaard 11e88380d5 The basic directory structure for lmsensors2.
README.directories contains a description of the directories I created;
  read it if you have questions about them.
doc/design is the design document I sent before through email.
doc/useful_addresses.html contains links to I2C, SMBus and sensors
  information.

Note that we may have to change minor i2c things, like Makefiles; this
is why I put it in the archive too (we should, of course, send important
changes to Simon Vogl).


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@3 7894878c-1315-0410-8ee3-d5d059ff63e0
1998-11-02 20:29:28 +00:00

229 lines
6.6 KiB
C

/* ------------------------------------------------------------------------- */
/* pcf-lp.c i2c-hw access for PCF 8584 on bidir. parallel ports */
/* ------------------------------------------------------------------------- */
/*
-----.-.---....------..-.-.---.... Oh bugger! Hope it works this time......
Copyright (C) 1995-97 Simon G. Vogl
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
static char rcsid[] = "$Id: pcf-lp.c,v 1.1 1998/09/05 18:20:09 i2c Exp $";
/*
* $Log: pcf-lp.c,v $
* Revision 1.1 1998/09/05 18:20:09 i2c
* Initial revision
*
* Revision 1.4 1998/01/20 10:01:29 i2c
* *** empty log message ***
*
* Revision 1.3 1997/06/15 14:21:37 i2c
* removed debugging messages
*
* Revision 1.2 1997/06/03 06:00:10 i2c
* first version that works
*
* Revision 1.2 1996/11/20 20:20:46 i2c
* first version for ISA bus.
*
* Revision 1.1 1996/11/17 11:00:03 i2c
* Initial revision
*
*
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/errno.h>
#include "i2c.h"
#include "i2c-priv.h"
/* ----- global defines ----------------------------------------------- */
#define DEB(x) /* should be reasonable open, close &c. */
#define DEB2(x) /* low level debugging - very slow */
#define DEBE(x) x /* error messages */
#define DEBHW(x) x /* lowest level hardware debug -- log changes of*/
/* the bit lines... */
#define lpPort(port) (i2c_table[minor].base+(port))
/* ----- local variables ---------------------------------------------- */
static unsigned char ctrl; /* remember line states */
/* (re)set line states */
#define Strobe(arg) if (!arg) ctrl|= 0x01; else ctrl &=!0x01;\
outb_p(ctrl,lpPort(2)) /* Strobe -- pin 1 */
#define AutoLF(arg) if (!arg) ctrl|= 0x02; else ctrl &=!0x02;\
outb_p(ctrl,lpPort(2)) /* AutoLF -- pin 14 */
#define Init(arg) if ( arg) ctrl|= 0x04; else ctrl &=!0x04;\
outb(ctrl,lpPort(2)) /* Init -- pin 16 */
#define Select(arg) if (!arg) ctrl|= 0x08; else ctrl &=!0x08;\
outb_p(ctrl,lpPort(2)) /* Sel. in - pin 17 */
/* 0x10 -- Int Enable */
#define ReadBit(arg) if(arg) ctrl|= 0x20; else ctrl &=!0x20;\
outb_p(ctrl,lpPort(2)) /* direction bit */
#define inStr() (! (0x01 & inb(lpPort(2)) ) ) /* Strobe -- pin 1 */
#define inALF() (! (0x02 & inb(lpPort(2)) ) ) /* AutoLF -- pin 14 */
#define inIni() ( (0x04 & inb(lpPort(2)) ) ) /* Init -- pin 16 */
#define inSel() (! (0x08 & inb(lpPort(2)) ) ) /* Sel. in - pin 17 */
/* 0x10 -- Int Enable */
/*
#define Argl() printk("(wr-%d cs-%d a0-%d (%#2x, %#2x))\n", \
inStr(),inALF(),inIni(),inb(lpPort(0)),inb(lpPort(1)) )
*/
#define Argl() /**/
#define wr(arg) Strobe(arg); Argl() /* write line */
#define cs(arg) AutoLF(arg); Argl() /* chip select */
#define a0(arg) Init (arg); Argl() /* address line */
/* ----- local functions ---------------------------------------------- */
/*
#if (PCFADAPS) > 1
# define Local static
#else
# define Local inline
#endif
*/
#define Local /**/
/* --------- okay, I borrowed it. Stays here for debugging.
* check the epp status. After a EPP transfer, it should be true that
* 1) the TIMEOUT bit (SPP_STR.0) is clear
* 2) the READY bit (SPP_STR.7) is set
* returns 1 if okay
*/
static int ex_ppa_check_epp_status(int minor)
{
char r;
inb(STAT);
r = inb(STAT);
if (r & 1) {
outb(r, STAT);
outb(r&0xfe, STAT);
printk("timed out on port 0x%04x\n", BASE);
return 0;
}
if (!(r & 0x80)) {
return 0;
}
return 1;
}
Local int pcf_read (int minor, int adr)
{
int ret;
a0(adr);
ex_ppa_check_epp_status(minor);
ret = inb(lpPort(4));
return ret;
}
Local void pcf_write (int minor, int adr,char data)
{
a0(adr);
ex_ppa_check_epp_status(minor);
outb(data,lpPort(4));
}
Local int pcf_init (int minor)
{
char ctrl,ecr; /* parallel port registers */
if (check_region(i2c_table[minor].base, 8) < 0 ) {
return -ENODEV;
} else {
request_region(i2c_table[minor].base, 8, "i2c (pcf-lp)");
}
/* This is the standard detection algorithm for ECP ports */
/* now detect, what kind of parallel port we have: */
ecr = inb(i2c_table[minor].base+0x402);
ctrl= inb(i2c_table[minor].base+0x002);
if (ecr!=ctrl) { /* Okay, we seem to have an extended port :) */
if (check_region(i2c_table[minor].base + 0x400, 8) < 0 ) {
DEBE(printk( "i2c_init, port %#x: ext. ports already in use "
"using only standard driver.\n",
i2c_table[minor].base));
return -ENODEV;
} else {
if ( (ecr & 0x03) != 0x01 ) { /* FIFO empty? */
printk("FIFO not empty\n");
return -ENODEV;
}
outb(0x34,i2c_table[minor].base+0x402);
if (inb(i2c_table[minor].base+0x402) != 0x35 ){ /* bits 0,1 readonly */
printk("bits 0,1 not rd/only");
return -ENODEV;
}
/* Okay, now we should have an ECP-capable printer port */
printk("i2c%d: ECP parallel port.\n",minor);
request_region(i2c_table[minor].base+0x0400, 3 ,
"i2c (Extended Parallel port adapter)");
outb(0x94 ,lpPort(0x402)); /* EPP mode */
ctrl = inb(CTRL);
if (i2c_table[minor].irq > 0){ /* enable int. */
outb(inb(lpPort(0x402)|0x10), lpPort(0x402));
outb(ctrl|0x10,CTRL);
}
ex_ppa_check_epp_status(minor);
printk("status reads %2x\n",pcf_read(minor,1));
ex_ppa_check_epp_status(minor);
printk("data reads %2x\n",pcf_read(minor,0));
}
} else {
printk("i2c%d: Need EPP port. Sorry.\n",minor);
return -ENODEV;
}
/* Okay, now it's time to init my data structures */
return 0;
}
Local void pcf_exit (int minor)
{
release_region( i2c_table[minor].base, 8 );
release_region( i2c_table[minor].base + 0x0400, 3 );
}
/* ------------------------------------------------------------------------
* Encapsulate the above functions in the correct operations structure.
* This is only done when more than one hardware adapter is supported.
*/
#if (PCFADAPS) > 1
struct i2c_pcf_ops pcf_lp_ops = {
pcf_read,
pcf_write,
pcf_init,
pcf_exit
};
#endif