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