All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg KH <greg@kroah.com>
To: linux-kernel@vger.kernel.org, sensors@stimpy.netroedge.com
Subject: Re: [PATCH] I2C update for 2.6.8-rc1
Date: Wed, 14 Jul 2004 17:07:11 -0700	[thread overview]
Message-ID: <10898500311477@kroah.com> (raw)
In-Reply-To: <10898500302358@kroah.com>

ChangeSet 1.1784.13.9, 2004/07/09 14:47:50-07:00, khali@linux-fr.org

[PATCH] I2C: adm1025 driver ported to 2.6

This is my port of the adm1025 driver to 2.6. It has been tested by a
few users and reported to work OK.

Signed-off-by: Jean Delvare <khali at linux-fr dot org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>


 drivers/i2c/chips/Kconfig   |   10 
 drivers/i2c/chips/Makefile  |    1 
 drivers/i2c/chips/adm1025.c |  570 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 581 insertions(+)


diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
--- a/drivers/i2c/chips/Kconfig	2004-07-14 16:59:39 -07:00
+++ b/drivers/i2c/chips/Kconfig	2004-07-14 16:59:39 -07:00
@@ -22,6 +22,16 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called adm1021.
 
+config SENSORS_ADM1025
+	tristate "Analog Devices ADM1025 and compatibles"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for Analog Devices ADM1025
+	  and Philips NE1619 sensor chips.
+	  This driver can also be built as a module.  If so, the module
+	  will be called adm1025.
+
 config SENSORS_ADM1031
 	tristate "Analog Devices ADM1031 and compatibles"
 	depends on I2C && EXPERIMENTAL
diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
--- a/drivers/i2c/chips/Makefile	2004-07-14 16:59:39 -07:00
+++ b/drivers/i2c/chips/Makefile	2004-07-14 16:59:39 -07:00
@@ -8,6 +8,7 @@
 obj-$(CONFIG_SENSORS_W83781D)	+= w83781d.o
 
 obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021.o
+obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
 obj-$(CONFIG_SENSORS_ADM1031)	+= adm1031.o
 obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
 obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
diff -Nru a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/i2c/chips/adm1025.c	2004-07-14 16:59:39 -07:00
@@ -0,0 +1,570 @@
+/*
+ * adm1025.c
+ *
+ * Copyright (C) 2000       Chen-Yuan Wu <gwu@esoft.com>
+ * Copyright (C) 2003-2004  Jean Delvare <khali@linux-fr.org>
+ *
+ * The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6
+ * voltages (including its own power source) and up to two temperatures
+ * (its own plus up to one external one). Voltages are scaled internally
+ * (which is not the common way) with ratios such that the nominal value
+ * of each voltage correspond to a register value of 192 (which means a
+ * resolution of about 0.5% of the nominal value). Temperature values are
+ * reported with a 1 deg resolution and a 3 deg accuracy. Complete
+ * datasheet can be obtained from Analog's website at:
+ *   http://www.analog.com/Analog_Root/productPage/productHome/0,2121,ADM1025,00.html
+ *
+ * This driver also supports the ADM1025A, which differs from the ADM1025
+ * only in that it has "open-drain VID inputs while the ADM1025 has
+ * on-chip 100k pull-ups on the VID inputs". It doesn't make any
+ * difference for us.
+ *
+ * This driver also supports the NE1619, a sensor chip made by Philips.
+ * That chip is similar to the ADM1025A, with a few differences. The only
+ * difference that matters to us is that the NE1619 has only two possible
+ * addresses while the ADM1025A has a third one. Complete datasheet can be
+ * obtained from Philips's website at:
+ *   http://www.semiconductors.philips.com/pip/NE1619DS.html
+ *
+ * Since the ADM1025 was the first chipset supported by this driver, most
+ * comments will refer to this chipset, but are actually general and
+ * concern all supported chipsets, unless mentioned otherwise.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/i2c-vid.h>
+
+/*
+ * Addresses to scan
+ * ADM1025 and ADM1025A have three possible addresses: 0x2c, 0x2d and 0x2e.
+ * NE1619 has two possible addresses: 0x2c and 0x2d.
+ */
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
+
+/*
+ * Insmod parameters
+ */
+
+SENSORS_INSMOD_2(adm1025, ne1619);
+
+/*
+ * The ADM1025 registers
+ */
+
+#define ADM1025_REG_MAN_ID		0x3E
+#define ADM1025_REG_CHIP_ID 		0x3F
+#define ADM1025_REG_CONFIG		0x40
+#define ADM1025_REG_STATUS1		0x41
+#define ADM1025_REG_STATUS2		0x42
+#define ADM1025_REG_IN(nr)		(0x20 + (nr))
+#define ADM1025_REG_IN_MAX(nr)		(0x2B + (nr) * 2)
+#define ADM1025_REG_IN_MIN(nr)		(0x2C + (nr) * 2)
+#define ADM1025_REG_TEMP(nr)		(0x26 + (nr))
+#define ADM1025_REG_TEMP_HIGH(nr)	(0x37 + (nr) * 2)
+#define ADM1025_REG_TEMP_LOW(nr)	(0x38 + (nr) * 2)
+#define ADM1025_REG_VID			0x47
+#define ADM1025_REG_VID4		0x49
+
+/*
+ * Conversions and various macros
+ * The ADM1025 uses signed 8-bit values for temperatures.
+ */
+
+static int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 };
+
+#define IN_FROM_REG(reg,scale)	(((reg) * (scale) + 96) / 192)
+#define IN_TO_REG(val,scale)	((val) <= 0 ? 0 : \
+				 (val) * 192 >= (scale) * 255 ? 255 : \
+				 ((val) * 192 + (scale)/2) / (scale))
+
+#define TEMP_FROM_REG(reg)	((reg) * 1000)
+#define TEMP_TO_REG(val)	((val) <= -127500 ? -128 : \
+				 (val) >= 126500 ? 127 : \
+				 (((val) < 0 ? (val)-500 : (val)+500) / 1000))
+
+/*
+ * Functions declaration
+ */
+
+static int adm1025_attach_adapter(struct i2c_adapter *adapter);
+static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind);
+static void adm1025_init_client(struct i2c_client *client);
+static int adm1025_detach_client(struct i2c_client *client);
+static struct adm1025_data *adm1025_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver adm1025_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "adm1025",
+	.id		= I2C_DRIVERID_ADM1025,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= adm1025_attach_adapter,
+	.detach_client	= adm1025_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct adm1025_data {
+	struct i2c_client client;
+	struct semaphore update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	u8 in[6];		/* register value */
+	u8 in_max[6];		/* register value */
+	u8 in_min[6];		/* register value */
+	s8 temp[2];		/* register value */
+	s8 temp_min[2];		/* register value */
+	s8 temp_max[2];		/* register value */
+	u16 alarms;		/* register values, combined */
+	u8 vid;			/* register values, combined */
+	u8 vrm;
+};
+
+/*
+ * Internal variables
+ */
+
+static int adm1025_id = 0;
+
+/*
+ * Sysfs stuff
+ */
+
+#define show_in(offset) \
+static ssize_t show_in##offset(struct device *dev, char *buf) \
+{ \
+	struct adm1025_data *data = adm1025_update_device(dev); \
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
+		       in_scale[offset])); \
+} \
+static ssize_t show_in##offset##_min(struct device *dev, char *buf) \
+{ \
+	struct adm1025_data *data = adm1025_update_device(dev); \
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
+		       in_scale[offset])); \
+} \
+static ssize_t show_in##offset##_max(struct device *dev, char *buf) \
+{ \
+	struct adm1025_data *data = adm1025_update_device(dev); \
+	return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
+		       in_scale[offset])); \
+} \
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);
+show_in(0);
+show_in(1);
+show_in(2);
+show_in(3);
+show_in(4);
+show_in(5);
+
+#define show_temp(offset) \
+static ssize_t show_temp##offset(struct device *dev, char *buf) \
+{ \
+	struct adm1025_data *data = adm1025_update_device(dev); \
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
+} \
+static ssize_t show_temp##offset##_min(struct device *dev, char *buf) \
+{ \
+	struct adm1025_data *data = adm1025_update_device(dev); \
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \
+} \
+static ssize_t show_temp##offset##_max(struct device *dev, char *buf) \
+{ \
+	struct adm1025_data *data = adm1025_update_device(dev); \
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \
+}\
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp##offset, NULL);
+show_temp(1);
+show_temp(2);
+
+#define set_in(offset) \
+static ssize_t set_in##offset##_min(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct adm1025_data *data = i2c_get_clientdata(client); \
+	data->in_min[offset] = IN_TO_REG(simple_strtol(buf, NULL, 10), \
+			       in_scale[offset]); \
+	i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \
+				  data->in_min[offset]); \
+	return count; \
+} \
+static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct adm1025_data *data = i2c_get_clientdata(client); \
+	data->in_max[offset] = IN_TO_REG(simple_strtol(buf, NULL, 10), \
+			       in_scale[offset]); \
+	i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \
+				  data->in_max[offset]); \
+	return count; \
+} \
+static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
+	show_in##offset##_min, set_in##offset##_min); \
+static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
+	show_in##offset##_max, set_in##offset##_max);
+set_in(0);
+set_in(1);
+set_in(2);
+set_in(3);
+set_in(4);
+set_in(5);
+
+#define set_temp(offset) \
+static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct adm1025_data *data = i2c_get_clientdata(client); \
+	data->temp_min[offset-1] = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
+	i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \
+				  data->temp_min[offset-1]); \
+	return count; \
+} \
+static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct adm1025_data *data = i2c_get_clientdata(client); \
+	data->temp_max[offset-1] = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
+	i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \
+				  data->temp_max[offset-1]); \
+	return count; \
+} \
+static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+	show_temp##offset##_min, set_temp##offset##_min); \
+static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+	show_temp##offset##_max, set_temp##offset##_max);
+set_temp(1);
+set_temp(2);
+
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_vid(struct device *dev, char *buf)
+{
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, char *buf)
+{
+	struct adm1025_data *data = adm1025_update_device(dev);
+	return sprintf(buf, "%u\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adm1025_data *data = i2c_get_clientdata(client);
+	data->vrm = simple_strtoul(buf, NULL, 10);
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+/*
+ * Real code
+ */
+
+static int adm1025_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_detect(adapter, &addr_data, adm1025_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *new_client;
+	struct adm1025_data *data;
+	int err = 0;
+	const char *name = "";
+	u8 config;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		goto exit;
+
+	if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(data, 0, sizeof(struct adm1025_data));
+
+	/* The common I2C client data is placed right before the
+	   ADM1025-specific data. */
+	new_client = &data->client;
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &adm1025_driver;
+	new_client->flags = 0;
+
+	/*
+	 * Now we do the remaining detection. A negative kind means that
+	 * the driver was loaded with no force parameter (default), so we
+	 * must both detect and identify the chip. A zero kind means that
+	 * the driver was loaded with the force parameter, the detection
+	 * step shall be skipped. A positive kind means that the driver
+	 * was loaded with the force parameter and a given kind of chip is
+	 * requested, so both the detection and the identification steps
+	 * are skipped.
+	 */
+	config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG);
+	if (kind < 0) { /* detection */
+		if ((config & 0x80) != 0x00
+		 || (i2c_smbus_read_byte_data(new_client,
+		     ADM1025_REG_STATUS1) & 0xC0) != 0x00
+		 || (i2c_smbus_read_byte_data(new_client,
+		     ADM1025_REG_STATUS2) & 0xBC) != 0x00) {
+			dev_dbg(&adapter->dev,
+				"ADM1025 detection failed at 0x%02x.\n",
+				address);
+			goto exit_free;
+		}
+	}
+
+	if (kind <= 0) { /* identification */
+		u8 man_id, chip_id;
+
+		man_id = i2c_smbus_read_byte_data(new_client,
+			 ADM1025_REG_MAN_ID);
+		chip_id = i2c_smbus_read_byte_data(new_client,
+			  ADM1025_REG_CHIP_ID);
+		
+		if (man_id == 0x41) { /* Analog Devices */
+			if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */
+				kind = adm1025;
+			}
+		} else
+		if (man_id == 0xA1) { /* Philips */
+			if (address != 0x2E
+			 && (chip_id & 0xF0) == 0x20) { /* NE1619 */
+				kind = ne1619;
+			}
+		}
+
+		if (kind <= 0) { /* identification failed */
+			dev_info(&adapter->dev,
+			    "Unsupported chip (man_id=0x%02X, "
+			    "chip_id=0x%02X).\n", man_id, chip_id);
+			goto exit_free;
+		}
+	}
+
+	if (kind == adm1025) {
+		name = "adm1025";
+	} else if (kind == ne1619) {
+		name = "ne1619";
+	}
+
+	/* We can fill in the remaining client fields */
+	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+	new_client->id = adm1025_id++;
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+
+	/* Initialize the ADM1025 chip */
+	adm1025_init_client(new_client);
+
+	/* Register sysfs hooks */
+	device_create_file(&new_client->dev, &dev_attr_in0_input);
+	device_create_file(&new_client->dev, &dev_attr_in1_input);
+	device_create_file(&new_client->dev, &dev_attr_in2_input);
+	device_create_file(&new_client->dev, &dev_attr_in3_input);
+	device_create_file(&new_client->dev, &dev_attr_in5_input);
+	device_create_file(&new_client->dev, &dev_attr_in0_min);
+	device_create_file(&new_client->dev, &dev_attr_in1_min);
+	device_create_file(&new_client->dev, &dev_attr_in2_min);
+	device_create_file(&new_client->dev, &dev_attr_in3_min);
+	device_create_file(&new_client->dev, &dev_attr_in5_min);
+	device_create_file(&new_client->dev, &dev_attr_in0_max);
+	device_create_file(&new_client->dev, &dev_attr_in1_max);
+	device_create_file(&new_client->dev, &dev_attr_in2_max);
+	device_create_file(&new_client->dev, &dev_attr_in3_max);
+	device_create_file(&new_client->dev, &dev_attr_in5_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp2_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min);
+	device_create_file(&new_client->dev, &dev_attr_temp2_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp2_max);
+	device_create_file(&new_client->dev, &dev_attr_alarms);
+	device_create_file(&new_client->dev, &dev_attr_in1_ref);
+	device_create_file(&new_client->dev, &dev_attr_vrm);
+
+	/* Pin 11 is either in4 (+12V) or VID4 */
+	if (!(config & 0x20)) {
+		device_create_file(&new_client->dev, &dev_attr_in4_input);
+		device_create_file(&new_client->dev, &dev_attr_in4_min);
+		device_create_file(&new_client->dev, &dev_attr_in4_max);
+	}
+
+	return 0;
+
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static void adm1025_init_client(struct i2c_client *client)
+{
+	u8 reg;
+	struct adm1025_data *data = i2c_get_clientdata(client);
+	int i;
+
+	data->vrm = 82;
+
+	/*
+	 * Set high limits
+	 * Usually we avoid setting limits on driver init, but it happens
+	 * that the ADM1025 comes with stupid default limits (all registers
+	 * set to 0). In case the chip has not gone through any limit
+	 * setting yet, we better set the high limits to the max so that
+	 * no alarm triggers.
+	 */
+	for (i=0; i<6; i++) {
+		reg = i2c_smbus_read_byte_data(client,
+					       ADM1025_REG_IN_MAX(i));
+		if (reg == 0)
+			i2c_smbus_write_byte_data(client,
+						  ADM1025_REG_IN_MAX(i),
+						  0xFF);
+	}
+	for (i=0; i<2; i++) {
+		reg = i2c_smbus_read_byte_data(client,
+					       ADM1025_REG_TEMP_HIGH(i));
+		if (reg == 0)
+			i2c_smbus_write_byte_data(client,
+						  ADM1025_REG_TEMP_HIGH(i),
+						  0x7F);
+	}
+
+	/*
+	 * Start the conversions
+	 */
+	reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
+	if (!(reg & 0x01))
+		i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG,
+					  (reg&0x7E)|0x01);
+}
+
+static int adm1025_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, "
+			"client not detached.\n");
+		return err;
+	}
+
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static struct adm1025_data *adm1025_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adm1025_data *data = i2c_get_clientdata(client);
+
+	down(&data->update_lock);
+
+	if ((jiffies - data->last_updated > HZ * 2) ||
+	    (jiffies < data->last_updated) ||
+	    !data->valid) {
+		int i;
+
+		dev_dbg(&client->dev, "Updating data.\n");
+		for (i=0; i<6; i++) {
+			data->in[i] = i2c_smbus_read_byte_data(client,
+				      ADM1025_REG_IN(i));
+			data->in_min[i] = i2c_smbus_read_byte_data(client,
+					  ADM1025_REG_IN_MIN(i));
+			data->in_max[i] = i2c_smbus_read_byte_data(client,
+					  ADM1025_REG_IN_MAX(i));
+		}
+		for (i=0; i<2; i++) {
+			data->temp[i] = i2c_smbus_read_byte_data(client,
+					ADM1025_REG_TEMP(i));
+			data->temp_min[i] = i2c_smbus_read_byte_data(client,
+					    ADM1025_REG_TEMP_LOW(i));
+			data->temp_max[i] = i2c_smbus_read_byte_data(client,
+					    ADM1025_REG_TEMP_HIGH(i));
+		}
+		data->alarms = i2c_smbus_read_byte_data(client,
+			       ADM1025_REG_STATUS1)
+			     | (i2c_smbus_read_byte_data(client,
+				ADM1025_REG_STATUS2) << 8);
+		data->vid = (i2c_smbus_read_byte_data(client,
+			     ADM1025_REG_VID) & 0x0f)
+			  | ((i2c_smbus_read_byte_data(client,
+			      ADM1025_REG_VID4) & 0x01) << 4);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+
+	return data;
+}
+
+static int __init sensors_adm1025_init(void)
+{
+	return i2c_add_driver(&adm1025_driver);
+}
+
+static void __exit sensors_adm1025_exit(void)
+{
+	i2c_del_driver(&adm1025_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("ADM1025 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_adm1025_init);
+module_exit(sensors_adm1025_exit);


  reply	other threads:[~2004-07-15  0:21 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-07-15  0:05 [BK PATCH] I2C update for 2.6.8-rc1 Greg KH
2005-05-19  6:25 ` Greg KH
2004-07-15  0:07 ` [PATCH] " Greg KH
2004-07-15  0:07   ` Greg KH
2005-05-19  6:25     ` Greg KH
2004-07-15  0:07     ` Greg KH
2005-05-19  6:25       ` Greg KH
2004-07-15  0:07       ` Greg KH
2005-05-19  6:25         ` Greg KH
2004-07-15  0:07         ` Greg KH
2005-05-19  6:25           ` Greg KH
2004-07-15  0:07           ` Greg KH
2005-05-19  6:25             ` Greg KH
2004-07-15  0:07             ` Greg KH
2004-07-15  0:07               ` Greg KH
2005-05-19  6:25                 ` Greg KH
2004-07-15  0:07                 ` Greg KH [this message]
2004-07-15  0:07                   ` Greg KH
2005-05-19  6:25                     ` Greg KH
2004-07-15  0:07                     ` Greg KH
2005-05-19  6:25                       ` Greg KH
2004-07-15  0:07                       ` Greg KH
2004-07-15  0:07                         ` Greg KH
2005-05-19  6:25                           ` Greg KH
2004-07-15  0:07                           ` Greg KH
2005-05-19  6:25                             ` Greg KH
2004-07-15  0:07                             ` Greg KH
2005-05-19  6:25                               ` Greg KH
2004-07-16 17:07                         ` Pavel Machek
2005-05-19  6:25                           ` Pavel Machek
2004-07-16 17:17                           ` Greg KH
2005-05-19  6:25                             ` Greg KH
2004-07-16 17:39                             ` Bob Riegelmann
2005-05-19  6:25                               ` Bob Riegelmann
2004-07-16 18:19                             ` Adam Kropelin
2005-05-19  6:25                               ` Adam Kropelin
2005-05-19  6:25     ` Jean Delvare
2005-05-19  6:25     ` Philip Pokorny
2005-05-19  6:25     ` Greg KH
2005-05-19  6:25     ` Greg KH
2004-07-17 14:30 ` Greg (or anyone else) one small i2c question Reinder
2004-07-30  5:40   ` --- " Reinder
2004-07-30  6:30     ` Denis Vlasenko
2004-08-25  6:44   ` Greg " Greg KH
2004-08-24 21:58 ` [BK PATCH] I2C update for 2.6.8-rc1 Alex Williamson
2005-05-19  6:25   ` Alex Williamson
2004-08-24 22:04   ` Greg KH
2005-05-19  6:25     ` Greg KH
2004-08-25  0:37     ` Linus Torvalds
2005-05-19  6:25       ` Linus Torvalds
2004-08-25  1:38       ` Alex Williamson
2005-05-19  6:25         ` Alex Williamson
2004-08-25  1:42         ` Alex Williamson
2005-05-19  6:25           ` Alex Williamson
2004-08-25  2:02         ` Linus Torvalds
2005-05-19  6:25           ` Linus Torvalds
2004-08-25  6:14           ` Greg KH
2005-05-19  6:25             ` Greg KH
2004-08-25  6:36             ` Greg KH
2005-05-19  6:25               ` Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=10898500311477@kroah.com \
    --to=greg@kroah.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sensors@stimpy.netroedge.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.