All of lore.kernel.org
 help / color / mirror / Atom feed
* [lm-sensors] RFC patch to add eeprom write support
@ 2006-11-22 14:02 waltergoossens at home.nl
  2006-11-22 17:48 ` David Hubbard
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: waltergoossens at home.nl @ 2006-11-22 14:02 UTC (permalink / raw)
  To: lm-sensors

Hi list,

I created a patch to add write support to the i2c eeprom driver. This driver was originally developed for eeproms on DIMM modules (ones to which you do NOT want to write) so apart from the menu option to enable compile time write support you'll also need to "unlock" that functionality at runtime to protect people from accidentally destroying their chips.
This driver is tested with the Philips pcf8594C-2 but should also work with the 24c* microchip chips.


 
Add write support to the i2c eeproms. I protected write support by an
additional "lock" to make sure people don't accidentally overwrite 
data in an i2c eeprom that should be left alone.

Signed off by Walter Goossens <waltergoossens at home.nl>

diff -uarN -x '*.o' -x '*.ko' linux-2.6.17/drivers/i2c/chips/Kconfig linux-2.6.17-mpe04/drivers/i2c/chips/Kconfig
--- linux-2.6.17/drivers/i2c/chips/Kconfig	2006-11-22 15:33:39.000000000 +0000
+++ linux-2.6.17-mpe04/drivers/i2c/chips/Kconfig	2006-11-21 15:47:50.000000000 +0000
@@ -26,7 +26,7 @@
 	  will be called ds1374.
 
 config SENSORS_EEPROM
-	tristate "EEPROM reader"
+	tristate "EEPROM Chips"
 	depends on I2C && EXPERIMENTAL
 	help
 	  If you say yes here you get read-only access to the EEPROM data
@@ -35,7 +35,18 @@
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called eeprom.
-
+config SENSORS_EEPROM_WRITE
+  bool "EEPROM Write support (experimental)"
+  depends on I2C && SENSORS_EEPROM && EXPERIMENTAL
+  help
+    If you say yes here you get write access to the EEPROM data. Be 
+    VERY carefull when writing since this driver is designed to work
+    with chips on memory DIMMs which you will NOT want to destroy!
+    
+    Even when write support is enabled you will need to unlock it at
+    runtime to prevent errors. Write UNLOCK to the lock file in the 
+    sys/i2c/devices/<address>/ directory to gain write access. Any 
+    other value will lock write support.
 config SENSORS_PCF8574
 	tristate "Philips PCF8574 and PCF8574A"
 	depends on I2C && EXPERIMENTAL
diff -uarN -x '*.o' -x '*.ko' linux-2.6.17/drivers/i2c/chips/eeprom.c linux-2.6.17-mpe04/drivers/i2c/chips/eeprom.c
--- linux-2.6.17/drivers/i2c/chips/eeprom.c	2006-06-18 01:49:35.000000000 +0000
+++ linux-2.6.17-mpe04/drivers/i2c/chips/eeprom.c	2006-11-22 15:28:11.000000000 +0000
@@ -5,6 +5,10 @@
 			       Philip Edelbrock <phil at netroedge.com>
     Copyright (C) 2003 Greg Kroah-Hartman <greg at kroah.com>
     Copyright (C) 2003 IBM Corp.
+    Copyright (C) 2006 Walter Goossens <walter.goossens at axon.tv>
+    
+    2006-11-21 Walter Goossens <walter.goossens at axon.tv>
+    Added write support.
 
     2004-01-16  Jean Delvare <khali at linux-fr.org>
     Divide the eeprom in 32-byte (arbitrary) slices. This significantly
@@ -34,6 +38,7 @@
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
+#include <linux/delay.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
@@ -60,9 +65,11 @@
 	unsigned long last_updated[8];	/* In jiffies, 8 slices */
 	u8 data[EEPROM_SIZE];		/* Register values */
 	enum eeprom_nature nature;
+#ifdef CONFIG_SENSORS_EEPROM_WRITE
+	u8 write_lock;
+#endif
 };
 
-
 static int eeprom_attach_adapter(struct i2c_adapter *adapter);
 static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind);
 static int eeprom_detach_client(struct i2c_client *client);
@@ -140,14 +147,86 @@
 	return count;
 }
 
+#ifdef CONFIG_SENSORS_EEPROM_WRITE
+
+static ssize_t eeprom_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	int i = 0;
+	struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+	struct eeprom_data *data = i2c_get_clientdata(client);
+	char shadow[count];
+	
+	if(count>EEPROM_SIZE)
+		return 0;
+	/* Refuse to write Vaio Chips */
+	if(data->nature = VAIO)
+		return 0;
+	/* Only allow writes when we are unlocked! */
+	if(data->write_lock != 0)
+		return 0;
+	if(off + count > EEPROM_SIZE)
+		count = EEPROM_SIZE - off;
+	
+	memcpy(shadow,buf,count);
+	/* Prevent reading when we're writing */
+	mutex_lock(&data->update_lock);	
+	while(i < count) {
+		if((count - i) >= 8) {
+			/* Pagewrites (8 bytes) are the relatively fast */
+			i2c_smbus_write_i2c_block_data(client, (off + i), 8, shadow + i);
+			/* Wait for the chip to store everything. */
+			msleep(32);
+			i += 8;
+		} else {
+			i2c_smbus_write_i2c_block_data(client, (off + i), (count - i), shadow + i);
+			/* Wait for the chip to store everything. */
+			msleep(10 * (count - i));
+			i += (count - i);
+		}
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_lock(struct device *dev, struct device_attribute *attr, char *buf)
+{
+  struct eeprom_data *data = i2c_get_clientdata(to_i2c_client(dev));
+  return sprintf(buf, "%u\n", data->write_lock);
+}
+
+static ssize_t set_lock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+  struct i2c_client *client = to_i2c_client(dev);
+  struct eeprom_data *data = i2c_get_clientdata(client);
+  unsigned long val = simple_strtoul(buf, NULL, 10);
+  if (val = 0)
+  {
+  	data->write_lock = 0;
+  } else {
+  	data->write_lock = 1;
+  }
+  return count;
+}
+
+static DEVICE_ATTR(write_lock, S_IWUSR | S_IRUGO, show_lock, set_lock);
+
+#endif //CONFIG_SENSORS_EEPROM_WRITE
+
 static struct bin_attribute eeprom_attr = {
 	.attr = {
 		.name = "eeprom",
+#ifdef CONFIG_SENSORS_EEPROM_WRITE
+		.mode = S_IRUGO | S_IWUSR,
+#else
 		.mode = S_IRUGO,
+#endif
 		.owner = THIS_MODULE,
 	},
 	.size = EEPROM_SIZE,
 	.read = eeprom_read,
+#ifdef CONFIG_SENSORS_EEPROM_WRITE
+	.write = eeprom_write,
+#endif
 };
 
 static int eeprom_attach_adapter(struct i2c_adapter *adapter)
@@ -191,6 +270,11 @@
 	mutex_init(&data->update_lock);
 	data->nature = UNKNOWN;
 
+#ifdef CONFIG_SENSORS_EEPROM_WRITE
+	/* Disallow write by default */
+	data->write_lock = 1;
+#endif
+
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
 		goto exit_kfree;
@@ -210,6 +294,10 @@
 
 	/* create the sysfs eeprom file */
 	sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
+#ifdef CONFIG_SENSORS_EEPROM_WRITE
+	/* create the sysfs write lock file */
+	device_create_file(&new_client->dev, &dev_attr_write_lock);
+#endif
 
 	return 0;
 



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [lm-sensors] RFC patch to add eeprom write support
  2006-11-22 14:02 [lm-sensors] RFC patch to add eeprom write support waltergoossens at home.nl
@ 2006-11-22 17:48 ` David Hubbard
  2006-11-22 22:45 ` Walter Goossens
  2006-11-27 23:04 ` Walter Goossens
  2 siblings, 0 replies; 4+ messages in thread
From: David Hubbard @ 2006-11-22 17:48 UTC (permalink / raw)
  To: lm-sensors

Hi Walter,

I am not the lm-sensors maintainer, so if my comments are helpful in
any way, that's all I'm trying to accomplish.

> +config SENSORS_EEPROM_WRITE
> +  bool "EEPROM Write support (experimental)"
> +  depends on I2C && SENSORS_EEPROM && EXPERIMENTAL
> +  help
> +    If you say yes here you get write access to the EEPROM data. Be
> +    VERY carefull when writing since this driver is designed to work
> +    with chips on memory DIMMs which you will NOT want to destroy!
> +
> +    Even when write support is enabled you will need to unlock it at
> +    runtime to prevent errors. Write UNLOCK to the lock file in the
> +    sys/i2c/devices/<address>/ directory to gain write access. Any
> +    other value will lock write support.

This is confusing, I think. In the code below, the correct unlock
value is "0", not the string "UNLOCK."

> +static ssize_t set_lock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
> +{
> +  struct i2c_client *client = to_i2c_client(dev);
> +  struct eeprom_data *data = i2c_get_clientdata(client);
> +  unsigned long val = simple_strtoul(buf, NULL, 10);
> +  if (val = 0)
> +  {
> +       data->write_lock = 0;
> +  } else {
> +       data->write_lock = 1;
> +  }
> +  return count;
> +}
> +
> +static DEVICE_ATTR(write_lock, S_IWUSR | S_IRUGO, show_lock, set_lock);
> +
> +#endif //CONFIG_SENSORS_EEPROM_WRITE
> +

David Hubbard


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [lm-sensors] RFC patch to add eeprom write support
  2006-11-22 14:02 [lm-sensors] RFC patch to add eeprom write support waltergoossens at home.nl
  2006-11-22 17:48 ` David Hubbard
@ 2006-11-22 22:45 ` Walter Goossens
  2006-11-27 23:04 ` Walter Goossens
  2 siblings, 0 replies; 4+ messages in thread
From: Walter Goossens @ 2006-11-22 22:45 UTC (permalink / raw)
  To: lm-sensors

Hi David
> Hi Walter,
>
> I am not the lm-sensors maintainer, so if my comments are helpful in
> any way, that's all I'm trying to accomplish.
>
All suggestions are welcome!! (espacially this one)
>> +config SENSORS_EEPROM_WRITE
>> +  bool "EEPROM Write support (experimental)"
>> +  depends on I2C && SENSORS_EEPROM && EXPERIMENTAL
>> +  help
>> +    If you say yes here you get write access to the EEPROM data. Be
>> +    VERY carefull when writing since this driver is designed to work
>> +    with chips on memory DIMMs which you will NOT want to destroy!
>> +
>> +    Even when write support is enabled you will need to unlock it at
>> +    runtime to prevent errors. Write UNLOCK to the lock file in the
>> +    sys/i2c/devices/<address>/ directory to gain write access. Any
>> +    other value will lock write support.
>
> This is confusing, I think. In the code below, the correct unlock
> value is "0", not the string "UNLOCK."
>
It's not confusing. It's wrong.
I was planning to use the UNLOCK word but looking at other drivers I 
concluded I'd better use a 1 or 0 to keep in line with them. Of cource I 
forgot to change the kconfig file when I changed my source...
I will fix this and resend the patch next week when I'm  back at my work.
>> +static ssize_t set_lock(struct device *dev, struct device_attribute 
>> *attr, const char *buf, size_t count)
>> +{
>> +  struct i2c_client *client = to_i2c_client(dev);
>> +  struct eeprom_data *data = i2c_get_clientdata(client);
>> +  unsigned long val = simple_strtoul(buf, NULL, 10);
>> +  if (val = 0)
>> +  {
>> +       data->write_lock = 0;
>> +  } else {
>> +       data->write_lock = 1;
>> +  }
>> +  return count;
>> +}
>> +
>> +static DEVICE_ATTR(write_lock, S_IWUSR | S_IRUGO, show_lock, set_lock);
>> +
>> +#endif //CONFIG_SENSORS_EEPROM_WRITE
>> +
>
> David Hubbard
>



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [lm-sensors] RFC patch to add eeprom write support
  2006-11-22 14:02 [lm-sensors] RFC patch to add eeprom write support waltergoossens at home.nl
  2006-11-22 17:48 ` David Hubbard
  2006-11-22 22:45 ` Walter Goossens
@ 2006-11-27 23:04 ` Walter Goossens
  2 siblings, 0 replies; 4+ messages in thread
From: Walter Goossens @ 2006-11-27 23:04 UTC (permalink / raw)
  To: lm-sensors

Fixed documentation thanks to David Hubbard

======

Added support for the MAX7311 i2c io port expanders. This driver is
based on the pcf8574 driver which supports the same kind of chip.

Signed off by Walter Goossens <waltergoossens at home.nl>

diff -uarN -x '*.o' -x '*.ko' linux-2.6.17/drivers/i2c/chips/Kconfig 
linux-2.6.17-mpe04/drivers/i2c/chips/Kconfig
--- linux-2.6.17/drivers/i2c/chips/Kconfig    2006-06-18 
01:49:35.000000000 +0000
+++ linux-2.6.17-mpe04/drivers/i2c/chips/Kconfig    2006-10-18 
11:00:05.000000000 +0000
@@ -117,4 +117,23 @@
       This driver can also be built as a module.  If so, the module
       will be called max6875.
 
+config SENSORS_MAX7311
+    tristate "Maxim MAX7311 16 port io expander"
+    depends on I2C
+    help
+      If you say yes here you will get support for the max7311 port
+      expander chip. This chip has 16 ioports each configurable for
+      input or output.
+     
+      This driver can also be built as a module. If so, the module
+      will be called max7311.
+config SENSORS_MAX7311_NUMCLIENTS
+    int "Maximum number of chips"
+    default "4"
+    depends on SENSORS_MAX7311
+config SENSORS_MAX7311_ADDRESSES
+    string "Addresses to scan"
+    default "0x20 0x24"
+    depends on SENSORS_MAX7311
+
 endmenu
diff -uarN -x '*.o' -x '*.ko' linux-2.6.17/drivers/i2c/chips/Makefile 
linux-2.6.17-mpe04/drivers/i2c/chips/Makefile
--- linux-2.6.17/drivers/i2c/chips/Makefile    2006-06-18 
01:49:35.000000000 +0000
+++ linux-2.6.17-mpe04/drivers/i2c/chips/Makefile    2006-10-18 
10:00:29.000000000 +0000
@@ -6,6 +6,7 @@
 obj-$(CONFIG_SENSORS_DS1374)    += ds1374.o
 obj-$(CONFIG_SENSORS_EEPROM)    += eeprom.o
 obj-$(CONFIG_SENSORS_MAX6875)    += max6875.o
+obj-$(CONFIG_SENSORS_MAX7311)    += max7311.o
 obj-$(CONFIG_SENSORS_M41T00)    += m41t00.o
 obj-$(CONFIG_SENSORS_PCA9539)    += pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)    += pcf8574.o
diff -uarN -x '*.o' -x '*.ko' linux-2.6.17/drivers/i2c/chips/max7311.c 
linux-2.6.17-mpe04/drivers/i2c/chips/max7311.c
--- linux-2.6.17/drivers/i2c/chips/max7311.c    1970-01-01 
00:00:00.000000000 +0000
+++ linux-2.6.17-mpe04/drivers/i2c/chips/max7311.c    2006-10-18 
11:27:59.000000000 +0000
@@ -0,0 +1,352 @@
+/*
+    max7311.c
+    Copyright (c) 2006  Walter Goossens <walter.goossens at axon.tv>
+   
+    Based on:
+   
+    pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware
+             monitoring
+    Copyright (c) 2000  Frodo Looijaard <frodol at dds.nl>,
+                        Philip Edelbrock <phil at netroedge.com>,
+                        Dan Eaton <dan.eaton at rocketlogix.com>
+    Ported to Linux 2.6 by Aurelien Jarno <aurel32 at debian.org> with
+    the help of Jean Delvare <khali at linux-fr.org>
+
+    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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/list.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[CONFIG_SENSORS_MAX7311_NUMCLIENTS];
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* Initial values */
+#define MAX7311_INIT 0xFFFF  /* All ports in input */
+/* Chip registers */
+#define REG_INPUT       0x00
+#define REG_OUTPUT      0x02
+#define REG_POLARITY    0x04
+#define REG_CONFIG      0x06
+#define REG_TIMEOUT     0x08
+
+/* Keep a list of all registered clients */
+static LIST_HEAD(max7311_clients);
+
+/* Each client has this additional data */
+struct max7311_data {
+  struct i2c_client client;
+
+  uint16_t output;
+  uint16_t config;
+  uint16_t polarity;
+  struct list_head list;
+};
+
+
+static int max7311_attach_adapter(struct i2c_adapter *adapter);
+static int max7311_detect(struct i2c_adapter *adapter, int address, int 
kind);
+static int max7311_detach_client(struct i2c_client *client);
+static void max7311_init_client(struct i2c_client *client);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max7311_driver = {
+  .driver = {
+    .name = "max7311",
+  },
+  .id   = I2C_DRIVERID_MAX7311,
+  .attach_adapter = max7311_attach_adapter,
+  .detach_client  = max7311_detach_client,
+};
+
+/* following are the sysfs callback functions */
+static ssize_t show_read(struct device *dev, struct device_attribute 
*attr, char *buf)
+{
+  struct i2c_client *client = to_i2c_client(dev);
+  return sprintf(buf, "%u\n", i2c_smbus_read_word_data(client,REG_INPUT));
+}
+
+static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
+
+static ssize_t show_write(struct device *dev, struct device_attribute 
*attr, char *buf)
+{
+  struct max7311_data *data = i2c_get_clientdata(to_i2c_client(dev));
+  return sprintf(buf, "%u\n", data->output);
+}
+
+static ssize_t set_write(struct device *dev, struct device_attribute 
*attr, const char *buf, size_t count)
+{
+  struct i2c_client *client = to_i2c_client(dev);
+  struct max7311_data *data = i2c_get_clientdata(client);
+  unsigned long val = simple_strtoul(buf, NULL, 10);
+
+  if (val > 0xFFFF)
+  {
+    return -EINVAL;
+  }
+  data->output = val;
+  i2c_smbus_write_word_data(client, REG_OUTPUT,data->output);
+  return count;
+}
+
+static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
+
+static ssize_t show_config(struct device *dev, struct device_attribute 
*attr, char *buf)
+{
+  struct max7311_data *data = i2c_get_clientdata(to_i2c_client(dev));
+  return sprintf(buf, "%u\n", data->config);
+}
+
+static ssize_t set_config(struct device *dev, struct device_attribute 
*attr, const char *buf, size_t count)
+{
+  struct i2c_client *client = to_i2c_client(dev);
+  struct max7311_data *data = i2c_get_clientdata(client);
+  unsigned long val = simple_strtoul(buf, NULL, 10);
+
+  if (val > 0xFFFF)
+  {
+    return -EINVAL;
+  }
+  data->config = val;
+  i2c_smbus_write_word_data(client, REG_CONFIG,data->config);
+  return count;
+}
+
+static DEVICE_ATTR(config, S_IWUSR | S_IRUGO, show_config, set_config);
+
+static ssize_t show_polarity(struct device *dev, struct 
device_attribute *attr, char *buf)
+{
+  struct max7311_data *data = i2c_get_clientdata(to_i2c_client(dev));
+  return sprintf(buf, "%u\n", data->polarity);
+}
+
+static ssize_t set_polarity(struct device *dev, struct device_attribute 
*attr, const char *buf, size_t count)
+{
+  struct i2c_client *client = to_i2c_client(dev);
+  struct max7311_data *data = i2c_get_clientdata(client);
+  unsigned long val = simple_strtoul(buf, NULL, 10);
+
+  if (val > 0xFFFF)
+  {
+    return -EINVAL;
+  }
+  data->polarity = val;
+  i2c_smbus_write_word_data(client, REG_CONFIG,data->polarity);
+  return count;
+}
+
+static DEVICE_ATTR(polarity, S_IWUSR | S_IRUGO, show_polarity, 
set_polarity);
+
+/*
+ * Real code
+ */
+
+static int max7311_attach_adapter(struct i2c_adapter *adapter)
+{
+  return i2c_probe(adapter, &addr_data, max7311_detect);
+}
+
+/* This function is called by i2c_probe */
+static int max7311_detect(struct i2c_adapter *adapter, int address, int 
kind)
+{
+  struct i2c_client *new_client;
+  struct max7311_data *data;
+  int err = 0;
+  /* Can out adapter suply everything we need ? */
+  if (!i2c_check_functionality(adapter, 
I2C_FUNC_SMBUS_BYTE|I2C_FUNC_SMBUS_BYTE_DATA))
+  {
+    return -1;
+  }
+
+  /* OK. For now, we presume we have a valid client. We now create the
+  client structure, even though we cannot fill it completely yet. */
+  if (!(data = kzalloc(sizeof(struct max7311_data), GFP_KERNEL))) {
+    err = -ENOMEM;
+    return err;
+  }
+
+  new_client = &data->client;
+  i2c_set_clientdata(new_client, data);
+  new_client->addr = address;
+  new_client->adapter = adapter;
+  new_client->driver = &max7311_driver;
+  new_client->flags = 0;
+
+  /* Fill in the remaining client fields and put it into the global list */
+  strlcpy(new_client->name, "max7311", I2C_NAME_SIZE);
+
+  /* Tell the I2C layer a new client has arrived */
+  if ((err = i2c_attach_client(new_client)))
+  {
+    kfree(data);
+    return err;
+  }
+  /* Initialize the PCF8574 chip */
+  max7311_init_client(new_client);
+
+  /* Register sysfs hooks */
+  device_create_file(&new_client->dev, &dev_attr_read);
+  device_create_file(&new_client->dev, &dev_attr_write);
+  device_create_file(&new_client->dev, &dev_attr_config);
+  device_create_file(&new_client->dev, &dev_attr_polarity);
+  return 0;
+}
+
+static int max7311_detach_client(struct i2c_client *client)
+{
+  int err;
+  struct max7311_data *data = i2c_get_clientdata(client);
+ 
+  if ((err = i2c_detach_client(client)))
+  {
+    return err;
+  }
+  list_del(&data->list);
+  kfree(data);
+  return 0;
+}
+
+/* Called when we have found a new MAX7311. */
+static void max7311_init_client(struct i2c_client *client)
+{
+  struct max7311_data *data = i2c_get_clientdata(client);
+  //Default all ports to inputs!
+  data->config = i2c_smbus_read_word_data(client,REG_CONFIG);
+  data->output = i2c_smbus_read_word_data(client,REG_OUTPUT);
+  data->polarity = i2c_smbus_read_word_data(client,REG_POLARITY);
+  //Enable bus timeout
+  i2c_smbus_write_byte_data(client,REG_TIMEOUT,0x01);
+  //Register with our list
+  INIT_LIST_HEAD(&data->list);
+  list_add_tail(&data->list, &max7311_clients);
+}
+
+struct max7311_data * get_max7311_client(int bus, int address)
+{
+  struct list_head *walk;
+  struct list_head *tmp;
+  struct max7311_data *data;
+
+  list_for_each_safe(walk, tmp, &max7311_clients) {
+    data = list_entry(walk, struct max7311_data, list);
+    if ((data->client.adapter->nr = bus)&&(data->client.addr=address))
+      return data;
+  }
+  return NULL;
+}
+
+static int do_max7311_write(int bus, int address, int chipReg, int newData)
+{
+  struct max7311_data *data;
+  if((data=get_max7311_client(bus,address)))
+  {
+    switch(chipReg) {
+      case REG_OUTPUT:
+      {
+        data->output = newData;
+        return i2c_smbus_write_word_data(&data->client,REG_OUTPUT,newData);
+      } break;
+      case REG_POLARITY:
+      {
+        data->polarity = newData;
+        return 
i2c_smbus_write_word_data(&data->client,REG_POLARITY,newData);
+      } break;
+      case REG_CONFIG:
+      {
+        data->config = newData;
+        return i2c_smbus_write_word_data(&data->client,REG_CONFIG,newData);
+      }
+      default:
+      {
+        return -1;
+      }
+    }
+  } else {
+    return -ENODEV;
+  }
+}
+static int do_max7311_read(int bus, int address, int chipReg)
+{
+  struct max7311_data *data;
+  if((data=get_max7311_client(bus,address)))
+  {
+    switch(chipReg) {
+      case REG_INPUT:
+      {
+        return i2c_smbus_read_word_data(&data->client,REG_INPUT);
+      } break;
+      case REG_OUTPUT:
+      {
+        return data->output;
+      } break;
+      case REG_POLARITY:
+      {
+        return data->polarity;
+      } break;
+      case REG_CONFIG:
+      {
+        return data->config;
+      }
+      default:
+      {
+        return -1;
+      }
+    }
+  } else {
+    return -ENODEV;
+  }
+}
+
+static int __init max7311_init(void)
+{
+  int i;
+  unsigned short addr;
+  char *all_addr = CONFIG_SENSORS_MAX7311_ADDRESSES;
+  for(i=0; i<CONFIG_SENSORS_MAX7311_NUMCLIENTS; i++) {
+    addr = simple_strtoul(all_addr,&all_addr,16);
+    if(all_addr[0]!='\0') {
+      all_addr++;
+    }
+    if(addr)
+    {
+      normal_i2c[i] = addr;
+    } else {
+      normal_i2c[i] = I2C_CLIENT_END;
+    }
+  }
+  return i2c_add_driver(&max7311_driver);
+}
+
+static void __exit max7311_exit(void)
+{
+  i2c_del_driver(&max7311_driver);
+}
+
+
+MODULE_AUTHOR("Walter Goossens <walter.goossens at axon.tv>");
+MODULE_DESCRIPTION("MAX7311 driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(do_max7311_read);
+EXPORT_SYMBOL(do_max7311_write);
+
+module_init(max7311_init);
+module_exit(max7311_exit);



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-11-27 23:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-22 14:02 [lm-sensors] RFC patch to add eeprom write support waltergoossens at home.nl
2006-11-22 17:48 ` David Hubbard
2006-11-22 22:45 ` Walter Goossens
2006-11-27 23:04 ` Walter Goossens

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.