New driver for MAX663x temperature sensor.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Patch against 2.4 kernel.
Simple temperature sensor chip.
Implemented read temperature and write low/high values.
Tested on UP ppc32.

Please review and commit.

-- 
	Evgeniy Polaykov ( s0mbre )

Crash is better than data corruption. -- Art Grabowski
-------------- next part --------------
===== drivers/i2c/max663x.c 1.0 vs 1.2 =====
--- /dev/null	Thu Jan 30 13:24:37 2003
+++ 1.2/drivers/i2c/max663x.c	Mon Apr 12 17:00:33 2004
@@ -0,0 +1,274 @@
+/*
+ * 	max663x.c
+ * 
+ * 2003-2004 Copyright (c) Evgeniy Polyakov <johnpol at 2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * The GNU GPL is contained in /usr/doc/copyright/GPL on a Debian
+ * system and in the file COPYING in the Linux kernel source.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-proc.h>
+
+#define MAX663x_TEMP		0x00
+#define MAX663x_CONTROL		0x01
+#define MAX663x_HYST		0x02
+#define MAX663x_MAX 		0x03
+#define MAX663x_LOW 		0x04
+#define MAX663x_HIGH		0x05
+
+static int max663x_attach_adapter(struct i2c_adapter *);
+static int max663x_detect(struct i2c_adapter *, int, unsigned short, int);
+static int max663x_detach_client(struct i2c_client *);
+static void __max663x_temp(unsigned long);
+void max663x_temp(struct i2c_client *, int, int, int *, long *);
+
+
+static ctl_table max663x_ctl_table[] = 
+{
+	{0x1000, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &max663x_temp},
+	{0}
+};
+
+static unsigned short normal_i2c[] 		= { SENSORS_I2C_END };
+static unsigned short normal_i2c_range[] 	= { 0x48, 0x4f, SENSORS_I2C_END };
+static unsigned int normal_isa[]		= { SENSORS_ISA_END };
+static unsigned int normal_isa_range[] 		= { SENSORS_ISA_END };
+
+SENSORS_INSMOD_1(max663x);
+
+struct max663x_data {
+	struct semaphore update_lock;
+	char valid;
+	unsigned long last_updated;
+	u16 temp;
+	u16 temp_max, temp_low, temp_high, temp_hyst;
+	u8 control;
+	u16 address;
+};
+
+static struct i2c_driver max663x_driver = {
+	.name		= "max663x",
+	.flags		= I2C_DF_NOTIFY,
+	.id		= 1234,
+	.attach_adapter	= max663x_attach_adapter,
+	.detach_client	= max663x_detach_client,
+};
+
+static int max663x_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_detect(adapter, &addr_data, max663x_detect);
+}
+
+static int max663x_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind)
+{
+	struct i2c_client *new_client = NULL;
+	struct max663x_data *data = NULL;
+	int err = 0;
+	char type_name[32];
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+	{
+		printk(KERN_ERR "Adapter doesn't support functionality.\n");
+		goto error1;
+	}
+
+	new_client = kmalloc(sizeof(*new_client), GFP_KERNEL);
+	if (!new_client) 
+	{
+		printk(KERN_ERR "Failed to create new max663x I2C client.\n");
+		err = -ENOMEM;
+		goto error1;
+	}
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+	{
+		printk(KERN_ERR "Failed to create new private data for max663x sensor.\n");
+		err = -ENOMEM;
+		goto error2;
+	}
+			
+	memset(new_client, 0, sizeof(*new_client));
+	memset(data, 0, sizeof(*data));
+
+	data->address 		= address;
+
+	new_client->data 	= data;
+	new_client->addr 	= address;
+	new_client->adapter 	= adapter;
+	new_client->driver 	= &max663x_driver;
+	new_client->flags 	= 0;
+	new_client->id		= 123;
+
+	strncpy(new_client->name, "max663x", sizeof(new_client->name));
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	err = i2c_attach_client(new_client);
+	if (err)
+	{
+		printk(KERN_ERR "Failed to attach max663x I2C client to I2C bus, err=%d.\n", err);
+		goto error3;
+	}
+
+	snprintf(type_name, sizeof(type_name), "max663x");
+	err = i2c_register_entry(new_client, type_name, max663x_ctl_table, THIS_MODULE);
+	if (err < 0)
+	{
+		printk(KERN_ERR "Failed to register new entry for max663x sensor. err=%d\n", err);
+		goto error4;
+	}
+
+	__max663x_temp((unsigned long)new_client);
+
+	printk("Found max663x I2C temperature sensor.\n");
+
+	return 0;
+
+error4:
+	i2c_detach_client(new_client);
+error3:
+	kfree(new_client);
+error2:
+	kfree(data);
+error1:
+	return err;
+}
+
+static int max663x_detach_client(struct i2c_client *client)
+{
+	struct max663x_data *data = client->data;
+	int err;
+
+	err = i2c_detach_client(client);
+	if (err) 
+	{
+		printk(KERN_ERR "Client deregistration failed, client not detached.\n");
+		return err;
+	}
+
+	kfree(client);
+	kfree(data);
+	return 0;
+}
+
+static inline int reg2temp(uint16_t temp)
+{
+	if (temp & 0x8000)
+	{
+		return (255 - (temp >> 7));
+	}
+	else
+	{
+		return (temp >> 7);
+	}
+}
+
+static inline uint16_t temp2reg(int temp)
+{
+	uint16_t reg;
+	
+	if (temp > 255)
+		temp = 255;
+	if (temp < -255)
+		temp = -255;
+	
+	if (temp < 0)
+	{
+		reg = temp + 255;
+		reg <<= 7;
+		reg |= 0x8000;
+	}
+	else
+	{
+		reg = (temp << 7);
+	}
+
+	return reg;
+}
+
+static u16 swap_bytes(u16 val)
+{
+	return (val >> 8) | (val << 8);
+}
+
+void __max663x_temp(unsigned long __data)
+{
+	struct i2c_client *client = (struct i2c_client *)__data;
+	struct max663x_data *data = client->data;
+
+	data->temp 	= swap_bytes(i2c_smbus_read_word_data(client, MAX663x_TEMP));
+	data->control 	= i2c_smbus_read_byte_data(client, MAX663x_CONTROL);
+	data->temp_low 	= swap_bytes(i2c_smbus_read_word_data(client, MAX663x_LOW));
+	data->temp_high	= swap_bytes(i2c_smbus_read_word_data(client, MAX663x_HIGH));
+	data->temp_hyst	= swap_bytes(i2c_smbus_read_word_data(client, MAX663x_HYST));
+	data->temp_max	= swap_bytes(i2c_smbus_read_word_data(client, MAX663x_MAX));
+}
+
+void max663x_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results)
+{
+	struct max663x_data *data = client->data;
+
+	if (operation == SENSORS_PROC_REAL_INFO)
+		*nrels_mag = 1;
+	else if (operation == SENSORS_PROC_REAL_READ) 
+	{
+		__max663x_temp((unsigned long)client);
+
+		results[0] = reg2temp(data->temp_max);
+		results[1] = reg2temp(data->temp_hyst);
+		results[2] = reg2temp(data->temp);
+		*nrels_mag = 3;
+	} 
+	else if (operation == SENSORS_PROC_REAL_WRITE) 
+	{
+		if (*nrels_mag >= 1) 
+		{
+			data->temp_max = temp2reg(results[0]);
+			i2c_smbus_write_word_data(client, MAX663x_HIGH, swap_bytes(data->temp_high));
+		}
+		if (*nrels_mag >= 2) 
+		{
+			data->temp_max = temp2reg(results[1]);
+			i2c_smbus_write_word_data(client, MAX663x_LOW, swap_bytes(data->temp_low));
+		}
+	}
+}
+
+static int __init max663x_init(void)
+{
+	return i2c_add_driver(&max663x_driver);
+}
+
+static void __exit max663x_fini(void)
+{
+	i2c_del_driver(&max663x_driver);
+}
+
+
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol at 2ka.mipt.ru>");
+MODULE_DESCRIPTION("MAX663x temerature sensor");
+MODULE_LICENSE("GPL");
+
+module_init(max663x_init);
+module_exit(max663x_fini);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://lists.lm-sensors.org/pipermail/lm-sensors/attachments/20040412/483e9ac1/attachment.bin 


[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux