patch-2.1.97 linux/drivers/sbus/char/envctrl.c

Next file: linux/drivers/sbus/char/flash.c
Previous file: linux/drivers/sbus/char/creator.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.96/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
@@ -0,0 +1,241 @@
+/* $Id: envctrl.c,v 1.3 1998/04/10 08:42:24 jj Exp $
+ * envctrl.c: Temperature and Fan monitoring on Machines providing it.
+ *
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+
+#include <asm/ebus.h>
+
+#define PCF8584_ADDRESS	0x55
+
+#define CONTROL_PIN	0x80
+#define CONTROL_ES0	0x40
+#define CONTROL_ES1	0x20
+#define CONTROL_ES2	0x10
+#define CONTROL_ENI	0x08
+#define CONTROL_STA	0x04
+#define CONTROL_STO	0x02
+#define CONTROL_ACK	0x01
+
+#define STATUS_PIN	0x80
+#define STATUS_STS	0x20
+#define STATUS_BER	0x10
+#define STATUS_LRB	0x08
+#define STATUS_AD0	0x08
+#define STATUS_AAB	0x04
+#define STATUS_LAB	0x02
+#define STATUS_BB	0x01
+
+/*
+ * CLK Mode Register.
+ */
+#define BUS_CLK_90	0x00
+#define BUS_CLK_45	0x01
+#define BUS_CLK_11	0x02
+#define BUS_CLK_1_5	0x03
+
+#define CLK_3		0x00
+#define CLK_4_43	0x10
+#define CLK_6		0x14
+#define CLK_8		0x18
+#define CLK_12		0x1c
+
+
+#define I2C_WRITE	0x00
+#define I2C_READ	0x01
+
+struct pcf8584_reg
+{
+	__volatile__ unsigned char data;
+	__volatile__ unsigned char csr;
+};
+
+static struct pcf8584_reg *i2c;
+
+
+struct i2c_addr_map {
+	unsigned char addr;
+	unsigned char mask;
+	char *name;
+};
+
+static struct i2c_addr_map devmap[] = {
+	{ 0x38, 0x78, "PCF8574A" },
+	{ 0x20, 0x78, "TDA8444" },
+	{ 0x48, 0x78, "PCF8591" },
+};
+#define NR_DEVMAP (sizeof(devmap) / sizeof(devmap[0]))
+
+static int
+envctrl_read(unsigned char dev, char *buffer, int len)
+{
+	unsigned char dummy;
+	unsigned char stat;
+	int error = -ENODEV;
+	int count = -1;
+
+	if (len == 0)
+		return 0;
+
+	i2c->data = (dev << 1) | I2C_READ;
+
+	while (!(i2c->csr & STATUS_BB))
+		udelay(1);
+
+	i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK;
+
+	do {
+		udelay(1);
+		while ((stat = i2c->csr) & STATUS_PIN)
+			udelay(1);
+
+		if (stat & STATUS_LRB)
+			goto stop;
+		error = 0;
+		if (count == (len - 2))
+			goto final;
+
+		if (++count > 0)
+			*buffer++ = i2c->data;
+		else
+			dummy = i2c->data;
+	} while (1);
+
+final:
+	i2c->csr = CONTROL_ES0;
+	if (++count > 0)
+		*buffer++ = i2c->data;
+	else
+		dummy = i2c->data;
+
+	udelay(1);
+	while ((stat = i2c->csr) & STATUS_PIN)
+		udelay(1);
+
+stop:
+	i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK;
+	if (++count > 0)
+		*buffer++ = i2c->data;
+	else
+		dummy = i2c->data;
+
+	if (error)
+		return error;
+	return count;
+}
+
+static int
+envctrl_write(unsigned char dev, char *buffer, int len)
+{
+	int error = -ENODEV;
+	int count = 0;
+
+	while (!(i2c->csr & STATUS_BB))
+		udelay(1);
+
+	i2c->data = (dev << 1) | I2C_WRITE;
+	i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK;
+
+	do {
+		unsigned char stat;
+
+		udelay(1);
+		while ((stat = i2c->csr) & STATUS_PIN)
+			udelay(1);
+
+		if (stat & STATUS_LRB)
+			goto stop;
+		error = count;
+		if (count == len)
+			goto stop;
+
+		i2c->data = *buffer++;
+		count++;
+	} while (1);
+
+stop:
+	i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK;
+	return error;
+}
+
+__initfunc(static int scan_bus(void))
+{
+	unsigned char dev;
+	int count = 0;
+	int i;
+
+	/* scan */
+	for (dev = 1; dev < 128; dev++)
+		if (envctrl_write(dev, 0, 0) == 0) {
+			for (i = 0; i < NR_DEVMAP; i++)
+				if ((dev & devmap[i].mask) == devmap[i].addr)
+					break;
+			printk("envctrl: i2c device at %02x: %s\n", dev,
+			       i < NR_DEVMAP ? devmap[i].name : "unknown");
+{
+			unsigned char buf[4];
+			if (envctrl_read(dev, buf, 4) == 4)
+				printk("envctrl: read %02x %02x %02x %02x\n",
+			               buf[0], buf[1], buf[2], buf[3]);
+}
+			count++;
+		}
+	return count ? 0 : -ENODEV;
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int envctrl_init(void))
+#endif
+{
+#ifdef CONFIG_PCI
+	struct linux_ebus *ebus;
+	struct linux_ebus_device *edev;
+
+	for_all_ebusdev(edev, ebus)
+		if (!strcmp(edev->prom_name, "SUNW,envctrl"))
+			break;
+
+	if (!edev)
+		return -ENODEV;
+
+	if (check_region(edev->base_address[0], sizeof(*i2c))) {
+		prom_printf("%s: Can't get region %lx, %d\n",
+			    __FUNCTION__, edev->base_address[0],
+			    sizeof(*i2c));
+		prom_halt();
+	}
+
+	request_region(edev->base_address[0],
+		       sizeof(*i2c), "i2c");
+
+	i2c = (struct pcf8584_reg *)edev->base_address[0];
+
+	i2c->csr = CONTROL_PIN;
+	i2c->data = PCF8584_ADDRESS;
+	i2c->csr = CONTROL_PIN | CONTROL_ES1;
+	i2c->data = CLK_4_43 | BUS_CLK_90;
+	i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK;
+	udelay(10000);
+
+	return scan_bus();
+#else
+	return -ENODEV;
+#endif
+}
+
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+}
+#endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov