diff options
author | Rod Whitby <rod@whitby.id.au> | 2006-02-21 02:11:15 +0000 |
---|---|---|
committer | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2006-02-21 02:11:15 +0000 |
commit | f143febe3e368614fe975e26e879084ddcff36b6 (patch) | |
tree | c0e803cbc07e4e1b1bebd57ac85acaef58ed9c54 /packages | |
parent | 5cfbe5d6c94414f35d58c1007da1557e748a1e6f (diff) |
Added I2C support for the Loft
Diffstat (limited to 'packages')
3 files changed, 394 insertions, 1 deletions
diff --git a/packages/linux/ixp4xx-kernel/2.6.16/50-hwmon-ad741x.patch b/packages/linux/ixp4xx-kernel/2.6.16/50-hwmon-ad741x.patch new file mode 100644 index 0000000000..9d0a35b3fa --- /dev/null +++ b/packages/linux/ixp4xx-kernel/2.6.16/50-hwmon-ad741x.patch @@ -0,0 +1,378 @@ +--- + drivers/hwmon/Kconfig | 10 + + drivers/hwmon/Makefile | 1 + drivers/hwmon/ad741x.c | 340 +++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 351 insertions(+) + +--- linux-ixp4xx.orig/drivers/hwmon/Makefile 2006-02-19 17:45:45.000000000 +0100 ++++ linux-ixp4xx/drivers/hwmon/Makefile 2006-02-19 17:46:12.000000000 +0100 +@@ -44,6 +44,7 @@ obj-$(CONFIG_SENSORS_VIA686A) += via686a + obj-$(CONFIG_SENSORS_VT8231) += vt8231.o + obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o + obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o ++obj-$(CONFIG_SENSORS_AD741X) += ad741x.o + + ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) + EXTRA_CFLAGS += -DDEBUG +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-ixp4xx/drivers/hwmon/ad741x.c 2006-02-19 17:45:59.000000000 +0100 +@@ -0,0 +1,340 @@ ++/* ++ * An hwmon driver for the Analog Devices AD7417/18 ++ * Copyright 2006 Tower Technologies ++ * ++ * Author: Alessandro Zummo <a.zummo@towertech.it> ++ * ++ * Based on lm75.c ++ * Copyright 1998-99 Frodo Looijaard <frodol@dds.nl> ++ * ++ * 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. ++ */ ++ ++#include <linux/module.h> ++#include <linux/jiffies.h> ++#include <linux/i2c.h> ++#include <linux/hwmon.h> ++#include <linux/err.h> ++#include <linux/mutex.h> ++ ++#define DRV_VERSION "0.1" ++ ++/* straight from the datasheet */ ++#define AD741X_TEMP_MIN (-55000) ++#define AD741X_TEMP_MAX 125000 ++ ++/* Addresses to scan */ ++static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2A, 0x2B, 0x2C, ++ 0x2D, 0x2E, 0x2F, I2C_CLIENT_END }; ++ ++/* Insmod parameters */ ++I2C_CLIENT_INSMOD; ++ ++/* AD741X registers */ ++#define AD741X_REG_TEMP 0x00 ++#define AD741X_REG_CONF 0x01 ++#define AD741X_REG_TEMP_HYST 0x02 ++#define AD741X_REG_TEMP_OS 0x03 ++#define AD741X_REG_ADC 0x04 ++#define AD741X_REG_CONF2 0x05 ++ ++#define AD741X_REG_ADC_CH(x) (x << 5) ++ ++#define AD741X_CH_TEMP AD741X_REG_ADC_CH(0) ++#define AD741X_CH_AIN1 AD741X_REG_ADC_CH(1) ++#define AD741X_CH_AIN2 AD741X_REG_ADC_CH(2) ++#define AD741X_CH_AIN3 AD741X_REG_ADC_CH(3) ++#define AD741X_CH_AIN4 AD741X_REG_ADC_CH(4) ++ ++struct ad741x_data { ++ struct i2c_client client; ++ struct class_device *class_dev; ++ struct mutex lock; ++ char valid; /* !=0 if following fields are valid */ ++ unsigned long last_updated; /* In jiffies */ ++ u16 temp_input; /* Register values */ ++ u16 temp_max; ++ u16 temp_hyst; ++ u16 in1; ++ u16 in2; ++ u16 in3; ++ u16 in4; ++}; ++ ++static int ad741x_attach_adapter(struct i2c_adapter *adapter); ++static int ad741x_detect(struct i2c_adapter *adapter, int address, int kind); ++static int ad741x_detach_client(struct i2c_client *client); ++ ++static struct i2c_driver ad741x_driver = { ++ .driver = { ++ .name = "ad741x", ++ }, ++ .attach_adapter = ad741x_attach_adapter, ++ .detach_client = ad741x_detach_client, ++}; ++ ++/* TEMP: 0.001C/bit (-55C to +125C) ++ * REG: (0.5C/bit, two's complement) << 7 ++ */ ++static inline u16 AD741X_TEMP_TO_REG(int temp) ++{ ++ int ntemp = SENSORS_LIMIT(temp, AD741X_TEMP_MIN, AD741X_TEMP_MAX); ++ ntemp += (ntemp < 0 ? -250 : 250); ++ return (u16)((ntemp / 500) << 7); ++} ++ ++static inline int AD741X_TEMP_FROM_REG(u16 reg) ++{ ++ /* use integer division instead of equivalent right shift to ++ * guarantee arithmetic shift and preserve the sign ++ */ ++ return ((s16)reg / 128) * 500; ++} ++ ++/* All registers are word-sized, except for the configuration registers. ++ * AD741X uses a high-byte first convention, which is exactly opposite to ++ * the usual practice. ++ */ ++static int ad741x_read(struct i2c_client *client, u8 reg) ++{ ++ if (reg == AD741X_REG_CONF || reg == AD741X_REG_CONF2) ++ return i2c_smbus_read_byte_data(client, reg); ++ else ++ return swab16(i2c_smbus_read_word_data(client, reg)); ++} ++ ++static int ad741x_write(struct i2c_client *client, u8 reg, u16 value) ++{ ++ if (reg == AD741X_REG_CONF || reg == AD741X_REG_CONF2) ++ return i2c_smbus_write_byte_data(client, reg, value); ++ else ++ return i2c_smbus_write_word_data(client, reg, swab16(value)); ++} ++ ++static void ad741x_init_client(struct i2c_client *client) ++{ ++ /* Enable if in shutdown mode */ ++ int reg = ad741x_read(client, AD741X_REG_CONF); ++ if (reg >= 0 && (reg & 0x01)) ++ ad741x_write(client, AD741X_REG_CONF, reg & 0xfe); ++} ++ ++static struct ad741x_data *ad741x_update_device(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct ad741x_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->lock); ++ ++ if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ++ || !data->valid) { ++ u8 cfg; ++ dev_dbg(&client->dev, "starting ad741x update\n"); ++ ++ data->temp_input = ad741x_read(client, AD741X_REG_TEMP); ++ data->temp_max = ad741x_read(client, AD741X_REG_TEMP_OS); ++ data->temp_hyst = ad741x_read(client, AD741X_REG_TEMP_HYST); ++ ++ /* read config register and clear channel bits */ ++ cfg = ad741x_read(client, AD741X_REG_CONF); ++ cfg &= 0x1F; ++ ++ ad741x_write(client, AD741X_REG_CONF, cfg | AD741X_CH_AIN1); ++ data->in1 = ad741x_read(client, AD741X_REG_ADC); ++ ++ ad741x_write(client, AD741X_REG_CONF, cfg | AD741X_CH_AIN2); ++ data->in2 = ad741x_read(client, AD741X_REG_ADC); ++ ++ ad741x_write(client, AD741X_REG_CONF, cfg | AD741X_CH_AIN3); ++ data->in3 = ad741x_read(client, AD741X_REG_ADC); ++ ++ ad741x_write(client, AD741X_REG_CONF, cfg | AD741X_CH_AIN4); ++ data->in4 = ad741x_read(client, AD741X_REG_ADC); ++ ++ /* restore old configuration value */ ++ ad741x_write(client, AD741X_REG_CONF, cfg); ++ ++ data->last_updated = jiffies; ++ data->valid = 1; ++ } ++ ++ mutex_unlock(&data->lock); ++ ++ return data; ++} ++ ++#define show(value) \ ++static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ ++{ \ ++ struct ad741x_data *data = ad741x_update_device(dev); \ ++ return sprintf(buf, "%d\n", AD741X_TEMP_FROM_REG(data->value)); \ ++} ++show(temp_max); ++show(temp_hyst); ++show(temp_input); ++ ++#define show_adc(value) \ ++static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ ++{ \ ++ struct ad741x_data *data = ad741x_update_device(dev); \ ++ return sprintf(buf, "%d\n", data->value >> 6); \ ++} ++ ++show_adc(in1); ++show_adc(in2); ++show_adc(in3); ++show_adc(in4); ++ ++#define set(value, reg) \ ++static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ ++{ \ ++ struct i2c_client *client = to_i2c_client(dev); \ ++ struct ad741x_data *data = i2c_get_clientdata(client); \ ++ int temp = simple_strtoul(buf, NULL, 10); \ ++ \ ++ mutex_lock(&data->lock); \ ++ data->value = AD741X_TEMP_TO_REG(temp); \ ++ ad741x_write(client, reg, data->value); \ ++ mutex_unlock(&data->lock); \ ++ return count; \ ++} ++set(temp_max, AD741X_REG_TEMP_OS); ++set(temp_hyst, AD741X_REG_TEMP_HYST); ++ ++static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); ++static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); ++static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); ++ ++static DEVICE_ATTR(in1, S_IRUGO, show_in1, NULL); ++static DEVICE_ATTR(in2, S_IRUGO, show_in2, NULL); ++static DEVICE_ATTR(in3, S_IRUGO, show_in3, NULL); ++static DEVICE_ATTR(in4, S_IRUGO, show_in4, NULL); ++ ++static int ad741x_attach_adapter(struct i2c_adapter *adapter) ++{ ++ if (!(adapter->class & I2C_CLASS_HWMON)) ++ return 0; ++ return i2c_probe(adapter, &addr_data, ad741x_detect); ++} ++ ++static int ad741x_detect(struct i2c_adapter *adapter, int address, int kind) ++{ ++ struct i2c_client *client; ++ struct ad741x_data *data; ++ int err = 0; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_WORD_DATA)) ++ goto exit; ++ ++ if (!(data = kzalloc(sizeof(struct ad741x_data), GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ client = &data->client; ++ client->addr = address; ++ client->adapter = adapter; ++ client->driver = &ad741x_driver; ++ client->flags = 0; ++ ++ i2c_set_clientdata(client, data); ++ ++ mutex_init(&data->lock); ++ ++ /* AD7418 has a curious behaviour on registers 6 and 7. They ++ * both always read 0xC071 and are not documented on the datasheet. ++ * We use them to detect the chip. ++ */ ++ if (kind < 0) { ++ int reg; ++ ++ reg = i2c_smbus_read_word_data(client, 0x06); ++ if (reg != 0xC071) { ++ dev_dbg(&adapter->dev, "failed detection at %d: %x\n", 6, reg); ++ err = -ENODEV; ++ goto exit_free; ++ } ++ ++ reg = i2c_smbus_read_word_data(client, 0x07); ++ if (reg != 0xC071) { ++ dev_dbg(&adapter->dev, "failed detection at %d: %x\n", 7, reg); ++ err = -ENODEV; ++ goto exit_free; ++ } ++ ++ reg = i2c_smbus_read_byte_data(client, AD741X_REG_CONF2); ++ ++ /* bits 0-5 must be at 0 */ ++ if (reg & 0x3F) { ++ dev_dbg(&adapter->dev, "failed detection at %d: %x\n", ++ AD741X_REG_CONF2, reg); ++ err = -ENODEV; ++ goto exit_free; ++ } ++ } ++ ++ strlcpy(client->name, ad741x_driver.driver.name, I2C_NAME_SIZE); ++ ++ if ((err = i2c_attach_client(client))) ++ goto exit_free; ++ ++ dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); ++ ++ /* Initialize the AD741X chip */ ++ ad741x_init_client(client); ++ ++ /* Register sysfs hooks */ ++ data->class_dev = hwmon_device_register(&client->dev); ++ if (IS_ERR(data->class_dev)) { ++ err = PTR_ERR(data->class_dev); ++ goto exit_detach; ++ } ++ ++ device_create_file(&client->dev, &dev_attr_temp1_max); ++ device_create_file(&client->dev, &dev_attr_temp1_max_hyst); ++ device_create_file(&client->dev, &dev_attr_temp1_input); ++ device_create_file(&client->dev, &dev_attr_in1); ++ device_create_file(&client->dev, &dev_attr_in2); ++ device_create_file(&client->dev, &dev_attr_in3); ++ device_create_file(&client->dev, &dev_attr_in4); ++ ++ return 0; ++ ++exit_detach: ++ i2c_detach_client(client); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int ad741x_detach_client(struct i2c_client *client) ++{ ++ struct ad741x_data *data = i2c_get_clientdata(client); ++ hwmon_device_unregister(data->class_dev); ++ i2c_detach_client(client); ++ kfree(data); ++ return 0; ++} ++ ++static int __init ad741x_init(void) ++{ ++ return i2c_add_driver(&ad741x_driver); ++} ++ ++static void __exit ad741x_exit(void) ++{ ++ i2c_del_driver(&ad741x_driver); ++} ++ ++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); ++MODULE_DESCRIPTION("AD741X driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ ++module_init(ad741x_init); ++module_exit(ad741x_exit); +--- linux-ixp4xx.orig/drivers/hwmon/Kconfig 2006-02-19 17:45:45.000000000 +0100 ++++ linux-ixp4xx/drivers/hwmon/Kconfig 2006-02-19 17:47:07.000000000 +0100 +@@ -433,6 +433,16 @@ config SENSORS_W83627EHF + This driver can also be built as a module. If so, the module + will be called w83627ehf. + ++config SENSORS_AD741X ++ tristate "Analog Devices AD7417/18" ++ depends on HWMON && I2C && EXPERIMENTAL ++ help ++ If you say yes here you get support for the Analog Devices AD7417 ++ and AD7418 chips. ++ ++ This driver can also be built as a module. If so, the module ++ will be called ad741x. ++ + config SENSORS_HDAPS + tristate "IBM Hard Drive Active Protection System (hdaps)" + depends on HWMON && INPUT && X86 diff --git a/packages/linux/ixp4xx-kernel/2.6.16/50-i2c-bus-ixp4xx-hwmon.patch b/packages/linux/ixp4xx-kernel/2.6.16/50-i2c-bus-ixp4xx-hwmon.patch new file mode 100644 index 0000000000..d7fb8e55dc --- /dev/null +++ b/packages/linux/ixp4xx-kernel/2.6.16/50-i2c-bus-ixp4xx-hwmon.patch @@ -0,0 +1,14 @@ +--- + drivers/i2c/busses/i2c-ixp4xx.c | 1 + + 1 file changed, 1 insertion(+) + +--- linux-ixp4xx.orig/drivers/i2c/busses/i2c-ixp4xx.c 2006-02-11 15:18:29.000000000 +0100 ++++ linux-ixp4xx/drivers/i2c/busses/i2c-ixp4xx.c 2006-02-18 16:20:12.000000000 +0100 +@@ -126,6 +126,7 @@ static int ixp4xx_i2c_probe(struct platf + drv_data->algo_data.timeout = 100; + + drv_data->adapter.id = I2C_HW_B_IXP4XX; ++ drv_data->adapter.class = I2C_CLASS_HWMON; + strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, + I2C_NAME_SIZE); + drv_data->adapter.algo_data = &drv_data->algo_data; diff --git a/packages/linux/ixp4xx-kernel/2.6.16/defconfig b/packages/linux/ixp4xx-kernel/2.6.16/defconfig index 0862199528..472a692a32 100644 --- a/packages/linux/ixp4xx-kernel/2.6.16/defconfig +++ b/packages/linux/ixp4xx-kernel/2.6.16/defconfig @@ -1469,6 +1469,7 @@ CONFIG_RTC_INTF_DEV=y CONFIG_RTC_DRV_X1205=y CONFIG_RTC_DRV_DS1672=y CONFIG_RTC_DRV_PCF8563=y +CONFIG_RTC_DRV_RS5C372=y # CONFIG_RTC_DRV_TEST is not set # @@ -1596,7 +1597,7 @@ CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y # CONFIG_CIFS_EXPERIMENTAL is not set # CONFIG_NCP_FS is not set -CONFIG_CODA_FS=m +# CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set # CONFIG_9P_FS is not set |