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

Next file: linux/drivers/sbus/char/rtc.c
Previous file: linux/drivers/sbus/audio/Config.in
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.9.2.1 2000/05/02 04:23:33 davem Exp $
+/* $Id: envctrl.c,v 1.9.2.2 2000/11/08 09:43:04 davem Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
@@ -11,6 +11,9 @@
  * 	http://www-eu2.semiconductors.com/pip/PCF8584P
  * 	http://www-eu2.semiconductors.com/pip/PCF8574AP
  * 	http://www-eu2.semiconductors.com/pip/PCF8591P
+ *
+ * 	EB - Added support for CP1500 Global Address and PS/Voltage monitoring.
+ * 	     Eric Brower <ebrower@usa.net>
  * 
  */
 
@@ -74,15 +77,16 @@
  * Firmware definitions.
  */
 #define PCF8584_MAX_CHANNELS            8
+#define PCF8584_GLOBALADDR_TYPE			6  /* global address monitor */
 #define PCF8584_FANSTAT_TYPE            3  /* fan status monitor */
 #define PCF8584_VOLTAGE_TYPE            2  /* voltage monitor    */
-#define PCF8584_TEMP_TYPE	        1  /* temperature monitor*/
+#define PCF8584_TEMP_TYPE	        	1  /* temperature monitor*/
 
 /* Monitor type of i2c child device.
  * Driver definitions.
  */
-#define ENVCTRL_NOMON			0
-#define ENVCTRL_CPUTEMP_MON		1    /* cpu temperature monitor */
+#define ENVCTRL_NOMON				0
+#define ENVCTRL_CPUTEMP_MON			1    /* cpu temperature monitor */
 #define ENVCTRL_CPUVOLTAGE_MON	  	2    /* voltage monitor         */
 #define ENVCTRL_FANSTAT_MON  		3    /* fan status monitor      */
 #define ENVCTRL_ETHERTEMP_MON		4    /* ethernet temperarture */
@@ -90,6 +94,7 @@
 #define ENVCTRL_VOLTAGESTAT_MON	  	5    /* voltage status monitor  */
 #define ENVCTRL_MTHRBDTEMP_MON		6    /* motherboard temperature */
 #define ENVCTRL_SCSITEMP_MON		7    /* scsi temperarture */
+#define ENVCTRL_GLOBALADDR_MON		8    /* global address */
 
 /* Child device type.
  * Driver definitions.
@@ -111,6 +116,15 @@
 #define ENVCTRL_MAX_CPU			4
 #define CHANNEL_DESC_SZ			256
 
+/* Mask values for combined GlobalAddress/PowerStatus node */
+#define ENVCTRL_GLOBALADDR_ADDR_MASK	0x1F
+#define ENVCTRL_GLOBALADDR_PSTAT_MASK	0x60
+
+/* Node 0x70 ignored on CompactPCI CP1400/1500 platforms
+ * (see envctrl_init_i2c_child)
+ */
+#define ENVCTRL_CPCI_IGNORED_NODE		0x70
+
 struct pcf8584_reg {
 	 unsigned char data;
 	 unsigned char csr;
@@ -198,7 +212,7 @@
 	int limit = 1000000;
 
 	while (--limit > 0) {
-		if(!(envctrl_readb(&i2c->csr) & STATUS_PIN)) 
+		if (!(envctrl_readb(&i2c->csr) & STATUS_PIN)) 
 			break;
 		udelay(1);
 	} 
@@ -472,6 +486,31 @@
 	return 1;
 }
 
+/* Function Description: Read global addressing line.
+ * Return : Always 1 byte. Status stored in bufdata.
+ */
+static int envctrl_i2c_globaladdr(struct i2c_child_t *pchild,
+				  unsigned char data,
+				  char *bufdata)
+{
+	/* Translatation table is not necessary, as global
+	 * addr is the integer value of the GA# bits.
+	 *
+	 * NOTE: MSB is documented as zero, but I see it as '1' always....
+	 *
+	 * -----------------------------------------------
+	 * | 0 | FAL | DEG | GA4 | GA3 | GA2 | GA1 | GA0 |
+	 * -----------------------------------------------
+	 * GA0 - GA4	integer value of Global Address (backplane slot#)
+	 * DEG			0 = cPCI Power supply output is starting to degrade
+	 * 				1 = cPCI Power supply output is OK
+	 * FAL			0 = cPCI Power supply has failed
+	 * 				1 = cPCI Power supply output is OK
+	 */
+	bufdata[0] = (data & ENVCTRL_GLOBALADDR_ADDR_MASK);
+	return 1;
+}
+
 /* Function Description: Read voltage and power supply status.
  * Return : Always 1 byte. Status stored in bufdata.
  */
@@ -598,9 +637,19 @@
 		copy_to_user((unsigned char*)buf, data, ret);
 		break;
 
+	case ENVCTRL_RD_GLOBALADDRESS:
+		if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+			return 0;
+		data[0] = envctrl_i2c_read_8574(pchild->addr);
+		ret = envctrl_i2c_globaladdr(pchild, data[0], data);
+		copy_to_user((unsigned char*)buf, data, ret);
+		break;
+
 	case ENVCTRL_RD_VOLTAGE_STATUS:
 		if (!(pchild = envctrl_get_i2c_child(ENVCTRL_VOLTAGESTAT_MON)))
-			return 0;
+			/* If voltage monitor not present, check for CPCI equivalent */
+			if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+				return 0;
 		data[0] = envctrl_i2c_read_8574(pchild->addr);
 		ret = envctrl_i2c_voltage_status(pchild, data[0], data);
 		copy_to_user((unsigned char*)buf, data, ret);
@@ -631,6 +680,7 @@
 	case ENVCTRL_RD_VOLTAGE_STATUS:
 	case ENVCTRL_RD_ETHERNET_TEMPERATURE:
 	case ENVCTRL_RD_SCSI_TEMPERATURE:
+	case ENVCTRL_RD_GLOBALADDRESS:
 		file->private_data = (void *)(long)cmd;
 		break;
 
@@ -729,9 +779,6 @@
 
 	if (!(strcmp(chnl_desc,"temp,ethernet")))
 		pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
-
-	if (!(strcmp(chnl_desc,"temp,ethernet")))
-		pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
 }
 
 /* Function Description: Initialize monitor channel with channel desc,
@@ -785,6 +832,39 @@
 	pchild->mon_type[0] = ENVCTRL_FANSTAT_MON;
 }
 
+/* Function Description: Initialize child device for global addressing line.
+ * Return: None.
+ */
+static void envctrl_init_globaladdr(struct i2c_child_t *pchild)
+{
+	int i;
+
+	/* Voltage/PowerSupply monitoring is piggybacked 
+	 * with Global Address on CompactPCI.  See comments
+	 * within envctrl_i2c_globaladdr for bit assignments.
+	 *
+	 * The mask is created here by assigning mask bits to each
+	 * bit position that represents PCF8584_VOLTAGE_TYPE data.
+	 * Channel numbers are not consecutive within the globaladdr
+	 * node (why?), so we use the actual counter value as chnls_mask
+	 * index instead of the chnl_array[x].chnl_no value.
+	 *
+	 * NOTE: This loop could be replaced with a constant representing
+	 * a mask of bits 5&6 (ENVCTRL_GLOBALADDR_PSTAT_MASK).
+	 */
+	for (i = 0; i < pchild->total_chnls; i++) {
+		if (PCF8584_VOLTAGE_TYPE == pchild->chnl_array[i].type) {
+			pchild->voltage_mask |= chnls_mask[i];
+		}
+	}
+
+	/* We only need to know if this child has global addressing 
+	 * line monitored.  We dont care which channels since we know 
+	 * the mask already (ENVCTRL_GLOBALADDR_ADDR_MASK).
+	 */
+	pchild->mon_type[0] = ENVCTRL_GLOBALADDR_MON;
+}
+
 /* Initialize child device monitoring voltage status. */
 static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
 {
@@ -832,6 +912,26 @@
 		}
 	}
 
+	/* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
+	 * sections 2.5, 3.5, 4.5 state node 0x70 for CP1400/1500 is
+	 * "For Factory Use Only."
+	 *
+	 * We ignore the node on these platforms by assigning the
+	 * 'NULL' monitor type.
+	 */
+	if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
+		int len;
+		char prop[56];
+
+		len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
+		if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len))) {
+			for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
+				pchild->mon_type[len] = ENVCTRL_NOMON;
+			}
+			return;
+		}
+	}
+
 	/* Get the monitor channels. */
 	len = prom_getproperty(node, "channels-in-use", (char *)pchild->chnl_array,
 			       PCF8584_MAX_CHANNELS*sizeof(struct pcf8584_channel));
@@ -843,6 +943,11 @@
 			envctrl_init_adc(pchild, node);
 			break;
 
+		case PCF8584_GLOBALADDR_TYPE:
+			envctrl_init_globaladdr(pchild);
+			i = pchild->total_chnls;
+			break;
+
 		case PCF8584_FANSTAT_TYPE:
 			envctrl_init_fanstat(pchild);
 			i = pchild->total_chnls;
@@ -940,6 +1045,18 @@
 	if (misc_register(&envctrl_dev)) {
 		printk("envctrl: Unable to get misc minor %d\n",
 		       envctrl_dev.minor);
+	}
+
+	/* Note above traversal routine post-incremented 'i' to accomodate 
+	 * a next child device, so we decrement before reverse-traversal of
+	 * child devices.
+	 */
+	printk("envctrl: initialized ");
+	for (--i; i >= 0; --i) {
+		printk("[%s 0x%lx]%s", 
+			(I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : 
+			((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), 
+			i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
 	}
 
 	return 0;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)