I back-ported the AD7418 temp/voltage sensor driver from 2.6.22 to OpenWrt 7.07. Complete patch attached, and also copies of the various post-patched files for ease of reviewing.
I didn't totally understand what I was doing with the build file changes in openwrt so please excuse any blunders. I copied existing macros. Note that ad7418 depends on hwmon, however I do not explicitly declare that dependency in openwrt because there is no package for hwmon (there is a package for hwmon-vid, but that driver doesn't pertain to ixp4xx hardware and the kernel build doesn't make it even if you ask it to in that case so... I guess I'm depending on the kernel config enabling hwmon. It appears that it does so by default and that hwmon is always built-in). I used the newest code from 2.6.22, and not one of the older patches that I found around the 'net. This driver is useful to anyone with Gateworks Avila hardware, as it allows temperature and board power supply input voltage monitoring. If you have 7.07 installed on a Gateworks Avila or other board with this device, you should be able to apply my patches to a checked-out 7.07 tree, run make menuconfig and under kernel modules->other modules you should enable kmod-hwmon-ad7418 Then build which should produce this package: bin/packages/kmod-hwmon-ad7418_2.6.21.6-ixp4xx-1_armeb.ipk Install that package on the board then you should see this: [EMAIL PROTECTED]:~# ipkg install kmod-hwmon-ad7418_2.6.21.6-ixp4xx-1_armeb.ipk Installing kmod-hwmon-ad7418 (2.6.21.6-ixp4xx-1) to root... Configuring kmod-hwmon-ad7418 Done. [EMAIL PROTECTED]:~# lsmod Module Size Used by Tainted: P ad7418 3672 0 ... [EMAIL PROTECTED]:~# dmesg ... ad7418 0-0028: ad7418 chip found ad7418 0-0028: configuring for mode 1 And now you can read temp and voltage like this : [EMAIL PROTECTED]:~# cat /sys/bus/i2c/devices/0-0028/temp1_input 45500 [EMAIL PROTECTED]:~# cat /sys/bus/i2c/devices/0-0028/in1_input 669 45500 above means 45.5 degrees C (the chip has 0.25C resolution but the driver quantizes on 0.5C due to the use of a shared macro from lm_sensors). 669 above means (669/1024) * 2.5v read at the input to the chip. The Avila has a divider between the board input and the chip with a 23:1 ratio (actually on my board I measure it as 27:1). Any comments/complaints/feedback welcome. If this is acceptable I'd also like to figure out how to get it into svn. Thanks.
Index: target/linux/ixp4xx-2.6/config/default =================================================================== --- target/linux/ixp4xx-2.6/config/default (revision 8834) +++ target/linux/ixp4xx-2.6/config/default (working copy) @@ -407,6 +407,7 @@ # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1029 is not set # CONFIG_SENSORS_ADM1031 is not set +CONFIG_SENSORS_AD7418=m # CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set # CONFIG_SENSORS_ATXP1 is not set Index: target/linux/ixp4xx-2.6/patches/910-ad7418.patch =================================================================== --- target/linux/ixp4xx-2.6/patches/910-ad7418.patch (revision 0) +++ target/linux/ixp4xx-2.6/patches/910-ad7418.patch (revision 0) @@ -0,0 +1,408 @@ +diff -Naur linux-2.6.21.6/drivers/hwmon/ad7418.c linux-2.6.21.6_patched/drivers/hwmon/ad7418.c +--- linux-2.6.21.6/drivers/hwmon/ad7418.c 1969-12-31 17:00:00.000000000 -0700 ++++ linux-2.6.21.6_patched/drivers/hwmon/ad7418.c 2007-09-17 22:03:43.000000000 -0600 +@@ -0,0 +1,373 @@ ++/* ++ * An hwmon driver for the Analog Devices AD7416/17/18 ++ * Copyright (C) 2006-07 Tower Technologies ++ * ++ * Author: Alessandro Zummo <[EMAIL PROTECTED]> ++ * ++ * Based on lm75.c ++ * Copyright (C) 1998-99 Frodo Looijaard <[EMAIL PROTECTED]> ++ * ++ * 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 - version 2. ++ */ ++ ++#include <linux/module.h> ++#include <linux/jiffies.h> ++#include <linux/i2c.h> ++#include <linux/hwmon.h> ++#include <linux/hwmon-sysfs.h> ++#include <linux/err.h> ++#include <linux/mutex.h> ++#include <linux/delay.h> ++ ++#include "lm75.h" ++ ++#define DRV_VERSION "0.3" ++ ++/* Addresses to scan */ ++static unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END }; ++/* Insmod parameters */ ++I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418); ++ ++/* AD7418 registers */ ++#define AD7418_REG_TEMP_IN 0x00 ++#define AD7418_REG_CONF 0x01 ++#define AD7418_REG_TEMP_HYST 0x02 ++#define AD7418_REG_TEMP_OS 0x03 ++#define AD7418_REG_ADC 0x04 ++#define AD7418_REG_CONF2 0x05 ++ ++#define AD7418_REG_ADC_CH(x) ((x) << 5) ++#define AD7418_CH_TEMP AD7418_REG_ADC_CH(0) ++ ++static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN, ++ AD7418_REG_TEMP_HYST, ++ AD7418_REG_TEMP_OS }; ++ ++struct ad7418_data { ++ struct i2c_client client; ++ struct class_device *class_dev; ++ struct attribute_group attrs; ++ enum chips type; ++ struct mutex lock; ++ int adc_max; /* number of ADC channels */ ++ char valid; ++ unsigned long last_updated; /* In jiffies */ ++ s16 temp[3]; /* Register values */ ++ u16 in[4]; ++}; ++ ++static int ad7418_attach_adapter(struct i2c_adapter *adapter); ++static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind); ++static int ad7418_detach_client(struct i2c_client *client); ++ ++static struct i2c_driver ad7418_driver = { ++ .driver = { ++ .name = "ad7418", ++ }, ++ .attach_adapter = ad7418_attach_adapter, ++ .detach_client = ad7418_detach_client, ++}; ++ ++/* All registers are word-sized, except for the configuration registers. ++ * AD7418 uses a high-byte first convention. Do NOT use those functions to ++ * access the configuration registers CONF and CONF2, as they are byte-sized. ++ */ ++static inline int ad7418_read(struct i2c_client *client, u8 reg) ++{ ++ return swab16(i2c_smbus_read_word_data(client, reg)); ++} ++ ++static inline int ad7418_write(struct i2c_client *client, u8 reg, u16 value) ++{ ++ return i2c_smbus_write_word_data(client, reg, swab16(value)); ++} ++ ++static void ad7418_init_client(struct i2c_client *client) ++{ ++ struct ad7418_data *data = i2c_get_clientdata(client); ++ ++ int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF); ++ if (reg < 0) { ++ dev_err(&client->dev, "cannot read configuration register\n"); ++ } else { ++ dev_info(&client->dev, "configuring for mode 1\n"); ++ i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe); ++ ++ if (data->type == ad7417 || data->type == ad7418) ++ i2c_smbus_write_byte_data(client, ++ AD7418_REG_CONF2, 0x00); ++ } ++} ++ ++static struct ad7418_data *ad7418_update_device(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct ad7418_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->lock); ++ ++ if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ++ || !data->valid) { ++ u8 cfg; ++ int i, ch; ++ ++ /* read config register and clear channel bits */ ++ cfg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF); ++ cfg &= 0x1F; ++ ++ i2c_smbus_write_byte_data(client, AD7418_REG_CONF, ++ cfg | AD7418_CH_TEMP); ++ udelay(30); ++ ++ for (i = 0; i < 3; i++) { ++ data->temp[i] = ad7418_read(client, AD7418_REG_TEMP[i]); ++ } ++ ++ for (i = 0, ch = 4; i < data->adc_max; i++, ch--) { ++ i2c_smbus_write_byte_data(client, ++ AD7418_REG_CONF, ++ cfg | AD7418_REG_ADC_CH(ch)); ++ ++ udelay(15); ++ data->in[data->adc_max - 1 - i] = ++ ad7418_read(client, AD7418_REG_ADC); ++ } ++ ++ /* restore old configuration value */ ++ ad7418_write(client, AD7418_REG_CONF, cfg); ++ ++ data->last_updated = jiffies; ++ data->valid = 1; ++ } ++ ++ mutex_unlock(&data->lock); ++ ++ return data; ++} ++ ++static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct ad7418_data *data = ad7418_update_device(dev); ++ return sprintf(buf, "%d\n", ++ LM75_TEMP_FROM_REG(data->temp[attr->index])); ++} ++ ++static ssize_t show_adc(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct ad7418_data *data = ad7418_update_device(dev); ++ ++ return sprintf(buf, "%d\n", ++ ((data->in[attr->index] >> 6) * 2500 + 512) / 1024); ++} ++ ++static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct i2c_client *client = to_i2c_client(dev); ++ struct ad7418_data *data = i2c_get_clientdata(client); ++ int temp = simple_strtol(buf, NULL, 10); ++ ++ mutex_lock(&data->lock); ++ data->temp[attr->index] = LM75_TEMP_TO_REG(temp); ++ ad7418_write(client, AD7418_REG_TEMP[attr->index], data->temp[attr->index]); ++ mutex_unlock(&data->lock); ++ return count; ++} ++ ++static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); ++static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, ++ show_temp, set_temp, 1); ++static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, ++ show_temp, set_temp, 2); ++ ++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 0); ++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1); ++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2); ++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3); ++ ++static int ad7418_attach_adapter(struct i2c_adapter *adapter) ++{ ++ if (!(adapter->class & I2C_CLASS_HWMON)) ++ return 0; ++ return i2c_probe(adapter, &addr_data, ad7418_detect); ++} ++ ++static struct attribute *ad7416_attributes[] = { ++ &sensor_dev_attr_temp1_max.dev_attr.attr, ++ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ NULL ++}; ++ ++static struct attribute *ad7417_attributes[] = { ++ &sensor_dev_attr_temp1_max.dev_attr.attr, ++ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_in2_input.dev_attr.attr, ++ &sensor_dev_attr_in3_input.dev_attr.attr, ++ &sensor_dev_attr_in4_input.dev_attr.attr, ++ NULL ++}; ++ ++static struct attribute *ad7418_attributes[] = { ++ &sensor_dev_attr_temp1_max.dev_attr.attr, ++ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ NULL ++}; ++ ++static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind) ++{ ++ struct i2c_client *client; ++ struct ad7418_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 ad7418_data), GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ client = &data->client; ++ client->addr = address; ++ client->adapter = adapter; ++ client->driver = &ad7418_driver; ++ ++ 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, reg6, reg7; ++ ++ /* the AD7416 lies within this address range, but I have ++ * no means to check. ++ */ ++ if (address >= 0x48 && address <= 0x4f) { ++ /* XXX add tests for AD7416 here */ ++ /* data->type = ad7416; */ ++ } ++ /* here we might have AD7417 or AD7418 */ ++ else if (address >= 0x28 && address <= 0x2f) { ++ reg6 = i2c_smbus_read_word_data(client, 0x06); ++ reg7 = i2c_smbus_read_word_data(client, 0x07); ++ ++ if (address == 0x28 && reg6 == 0xC071 && reg7 == 0xC071) ++ data->type = ad7418; ++ ++ /* XXX add tests for AD7417 here */ ++ ++ ++ /* both AD7417 and AD7418 have bits 0-5 of ++ * the CONF2 register at 0 ++ */ ++ reg = i2c_smbus_read_byte_data(client, ++ AD7418_REG_CONF2); ++ if (reg & 0x3F) ++ data->type = any_chip; /* detection failed */ ++ } ++ } else { ++ dev_dbg(&adapter->dev, "detection forced\n"); ++ } ++ ++ if (kind > 0) ++ data->type = kind; ++ else if (kind < 0 && data->type == any_chip) { ++ err = -ENODEV; ++ goto exit_free; ++ } ++ ++ switch (data->type) { ++ case any_chip: ++ case ad7416: ++ data->adc_max = 0; ++ data->attrs.attrs = ad7416_attributes; ++ strlcpy(client->name, "ad7416", I2C_NAME_SIZE); ++ break; ++ ++ case ad7417: ++ data->adc_max = 4; ++ data->attrs.attrs = ad7417_attributes; ++ strlcpy(client->name, "ad7417", I2C_NAME_SIZE); ++ break; ++ ++ case ad7418: ++ data->adc_max = 1; ++ data->attrs.attrs = ad7418_attributes; ++ strlcpy(client->name, "ad7418", I2C_NAME_SIZE); ++ break; ++ } ++ ++ if ((err = i2c_attach_client(client))) ++ goto exit_free; ++ ++ dev_info(&client->dev, "%s chip found\n", client->name); ++ ++ /* Initialize the AD7418 chip */ ++ ad7418_init_client(client); ++ ++ /* Register sysfs hooks */ ++ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) ++ goto exit_detach; ++ ++ data->class_dev = hwmon_device_register(&client->dev); ++ if (IS_ERR(data->class_dev)) { ++ err = PTR_ERR(data->class_dev); ++ goto exit_remove; ++ } ++ ++ return 0; ++ ++exit_remove: ++ sysfs_remove_group(&client->dev.kobj, &data->attrs); ++exit_detach: ++ i2c_detach_client(client); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int ad7418_detach_client(struct i2c_client *client) ++{ ++ struct ad7418_data *data = i2c_get_clientdata(client); ++ hwmon_device_unregister(data->class_dev); ++ sysfs_remove_group(&client->dev.kobj, &data->attrs); ++ i2c_detach_client(client); ++ kfree(data); ++ return 0; ++} ++ ++static int __init ad7418_init(void) ++{ ++ return i2c_add_driver(&ad7418_driver); ++} ++ ++static void __exit ad7418_exit(void) ++{ ++ i2c_del_driver(&ad7418_driver); ++} ++ ++MODULE_AUTHOR("Alessandro Zummo <[EMAIL PROTECTED]>"); ++MODULE_DESCRIPTION("AD7416/17/18 driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ ++module_init(ad7418_init); ++module_exit(ad7418_exit); +diff -Naur linux-2.6.21.6/drivers/hwmon/Kconfig linux-2.6.21.6_patched/drivers/hwmon/Kconfig +--- linux-2.6.21.6/drivers/hwmon/Kconfig 2007-07-06 22:47:55.000000000 -0600 ++++ linux-2.6.21.6_patched/drivers/hwmon/Kconfig 2007-09-17 22:02:54.000000000 -0600 +@@ -575,6 +575,16 @@ + This driver can also be built as a module. If so, the module + will be called w83627ehf. + ++config SENSORS_AD7418 ++ tristate "Analog Devices AD7416/17/18" ++ depends on HWMON && I2C && EXPERIMENTAL ++ help ++ If you say yes here you get support for the Analog Devices ++ AD7416, AD7417 and AD7418 temperature monitoring chips. ++ ++ This driver can also be built as a module. If so, the module ++ will be called ad7418. ++ + config SENSORS_HDAPS + tristate "IBM Hard Drive Active Protection System (hdaps)" + depends on HWMON && INPUT && X86 +diff -Naur linux-2.6.21.6/drivers/hwmon/Makefile linux-2.6.21.6_patched/drivers/hwmon/Makefile +--- linux-2.6.21.6/drivers/hwmon/Makefile 2007-07-06 22:47:55.000000000 -0600 ++++ linux-2.6.21.6_patched/drivers/hwmon/Makefile 2007-09-17 22:02:54.000000000 -0600 +@@ -14,6 +14,7 @@ + obj-$(CONFIG_SENSORS_W83791D) += w83791d.o + + obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o ++obj-$(CONFIG_SENSORS_AD7418) += ad7418.o + obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o + obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o + obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o Index: package/kernel/modules/other.mk =================================================================== --- package/kernel/modules/other.mk (revision 8834) +++ package/kernel/modules/other.mk (working copy) @@ -370,6 +370,17 @@ endef $(eval $(call KernelPackage,hwmon-pc87360)) +define KernelPackage/hwmon-ad7418 + TITLE:=AD7418 monitoring support + DESCRIPTION:=Kernel modules for AD7416/7/8 chips + DEFAULT:=y if LINUX_2_6_IXP4XX_Avila + SUBMENU:=$(EMENU) + KCONFIG:=$(CONFIG_SENSORS_AD7418) + FILES:=$(LINUX_DIR)/drivers/hwmon/ad7418.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,50,ad7418) +endef +$(eval $(call KernelPackage,hwmon-ad7418)) + define KernelPackage/input-core TITLE:=Input device core DESCRIPTION:=Kernel modules for support of input device
# # Copyright (C) 2006 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # # $Id$ EMENU:=Other modules define KernelPackage/crypto TITLE:=CryptoAPI modules KCONFIG:= \ $(CONFIG_CRYPTO_HMAC) \ $(CONFIG_CRYPTO_NULL) \ $(CONFIG_CRYPTO_MD4) \ $(CONFIG_CRYPTO_MD5) \ $(CONFIG_CRYPTO_SHA1) \ $(CONFIG_CRYPTO_SHA256) \ $(CONFIG_CRYPTO_SHA512) \ $(CONFIG_CRYPTO_WP512) \ $(CONFIG_CRYPTO_TGR192) \ $(CONFIG_CRYPTO_DES) \ $(CONFIG_CRYPTO_BLOWFISH) \ $(CONFIG_CRYPTO_TWOFISH) \ $(CONFIG_CRYPTO_SERPENT) \ $(CONFIG_CRYPTO_AES) \ $(CONFIG_CRYPTO_CAST5) \ $(CONFIG_CRYPTO_CAST6) \ $(CONFIG_CRYPTO_TEA) \ $(CONFIG_CRYPTO_ARC4) \ $(CONFIG_CRYPTO_KHAZAD) \ $(CONFIG_CRYPTO_ANUBIS) \ $(CONFIG_CRYPTO_DEFLATE) \ $(CONFIG_CRYPTO_MICHAEL_MIC) \ $(CONFIG_CRYPTO_CRC32C) \ $(CONFIG_CRYPTO_ECB)) \ $(CONFIG_CRYPTO_BLKCIPHER) FILES:=$(LINUX_DIR)/crypto/*.$(LINUX_KMOD_SUFFIX) SUBMENU:=$(EMENU) endef $(eval $(call KernelPackage,crypto)) define KernelPackage/ide-core TITLE:=Kernel support for IDE DESCRIPTION:=\ Useful for usb mass storage devices (e.g. on WL-HDD)\\\ \\\ Includes: \\\ - ide-core \\\ - ide-detect \\\ - ide-disk KCONFIG:=$(CONFIG_IDE) FILES:=$(LINUX_DIR)/drivers/ide/*.$(LINUX_KMOD_SUFFIX) SUBMENU:=$(EMENU) AUTOLOAD:=$(call AutoLoad,20,ide-core) $(call AutoLoad,90,ide-generic ide-detect ide-disk) endef $(eval $(call KernelPackage,ide-core)) define KernelPackage/ide-pdc202xx TITLE:=PDC202xx IDE driver SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_BLK_DEV_PDC202XX_OLD) FILES:=$(LINUX_DIR)/drivers/ide/pci/pdc202xx_old.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,pdc202xx_old) endef $(eval $(call KernelPackage,ide-pdc202xx)) define KernelPackage/ide-aec62xx TITLE:=AEC62xx IDE driver SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_BLK_DEV_AEC62XX) FILES:=$(LINUX_DIR)/drivers/ide/pci/aec62xx.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,aec62xx) endef $(eval $(call KernelPackage,ide-aec62xx)) define KernelPackage/scsi-core TITLE:=Kernel support for SCSI SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_BLK_DEV_SD) FILES:= \ $(LINUX_DIR)/drivers/scsi/scsi_mod.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/scsi/sd_mod.$(LINUX_KMOD_SUFFIX) endef $(eval $(call KernelPackage,scsi-core)) define KernelPackage/lp TITLE:=Parallel port and line printer support KCONFIG:=$(CONFIG_PARPORT) FILES:= \ $(LINUX_DIR)/drivers/parport/parport.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/char/lp.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/char/ppdev.$(LINUX_KMOD_SUFFIX) SUBMENU:=$(EMENU) AUTOLOAD:=$(call AutoLoad,50, \ parport \ lp \ ) endef $(eval $(call KernelPackage,lp)) define KernelPackage/soundcore TITLE:=Sound support DESCRIPTION:=Kernel modules for sound support KCONFIG:=$(CONFIG_SOUND) SUBMENU:=$(EMENU) endef define KernelPackage/soundcore/2.4 FILES:=$(LINUX_DIR)/drivers/sound/soundcore.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,soundcore) endef define KernelPackage/soundcore/2.6 FILES:= \ $(LINUX_DIR)/sound/soundcore.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/sound/core/*.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/sound/core/oss/*.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,soundcore snd snd-page-alloc snd-hwdep snd-rawmidi snd-timer snd-pcm snd-mixer-oss snd-pcm-oss) endef define KernelPackage/soundcore/uml-2.6 FILES:= \ $(LINUX_DIR)/arch/um/drivers/hostaudio.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/sound/soundcore.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,soundcore hostaudio) endef $(eval $(call KernelPackage,soundcore)) define KernelPackage/loop TITLE:=Loopback device support DESCRIPTION:=Kernel module for loopback device support KCONFIG:=$(CONFIG_BLK_DEV_LOOP) SUBMENU:=$(EMENU) AUTOLOAD:=$(call AutoLoad,30,loop) FILES:=$(LINUX_DIR)/drivers/block/loop.$(LINUX_KMOD_SUFFIX) endef $(eval $(call KernelPackage,loop)) define KernelPackage/nbd TITLE:=Network block device support DESCRIPTION:=Kernel module for network block device support KCONFIG:=$(CONFIG_BLK_DEV_NBD) SUBMENU:=$(EMENU) AUTOLOAD:=$(call AutoLoad,30,nbd) FILES:=$(LINUX_DIR)/drivers/block/nbd.$(LINUX_KMOD_SUFFIX) endef $(eval $(call KernelPackage,nbd)) define KernelPackage/capi TITLE:=CAPI Support DESCRIPTION:=Kernel module for basic CAPI support KCONFIG:=$(CONFIG_ISDN) $(CONFIG_ISDN_CAPI) $(CONFIG_ISDN_CAPI_CAPI20) SUBMENU:=$(EMENU) AUTOLOAD:=$(call AutoLoad,30,kernelcapi capi) FILES:=$(LINUX_DIR)/drivers/isdn/capi/*capi.$(LINUX_KMOD_SUFFIX) endef $(eval $(call KernelPackage,capi)) define KernelPackage/pcmcia-core TITLE:=PCMCIA/CardBus support DESCRIPTION:=Kernel support for PCMCIA/CardBus controllers SUBMENU:=$(EMENU) endef define KernelPackage/pcmcia-core/2.4 KCONFIG:=$(CONFIG_PCMCIA) FILES:= \ $(LINUX_DIR)/drivers/pcmcia/pcmcia_core.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/pcmcia/yenta_socket.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/pcmcia/ds.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,40,pcmcia_core yenta_socket ds) endef define KernelPackage/pcmcia-core/2.6 KCONFIG:=$(CONFIG_PCCARD) FILES:= \ $(LINUX_DIR)/drivers/pcmcia/pcmcia_core.$(LINUX_KMOD_SUFFIX) \ $(if $(CONFIG_PCMCIA),$(LINUX_DIR)/drivers/pcmcia/pcmcia.$(LINUX_KMOD_SUFFIX)) \ $(LINUX_DIR)/drivers/pcmcia/yenta_socket.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/pcmcia/rsrc_nonstatic.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,40,pcmcia_core pcmcia rsrc_nonstatic yenta_socket) endef $(eval $(call KernelPackage,pcmcia-core)) define KernelPackage/pcmcia-serial TITLE:=Serial devices support DESCRIPTION:=Kernel support for PCMCIA/CardBus serial devices DEPENDS:=kmod-pcmcia-core SUBMENU:=$(EMENU) AUTOLOAD:=$(call AutoLoad,45,serial_cs) endef define KernelPackage/pcmcia-serial/2.4 KCONFIG:=$(CONFIG_PCMCIA_SERIAL_CS) FILES:=$(LINUX_DIR)/drivers/char/pcmcia/serial_cs.$(LINUX_KMOD_SUFFIX) endef define KernelPackage/pcmcia-serial/2.6 KCONFIG:=$(CONFIG_SERIAL_8250_CS) FILES:=$(LINUX_DIR)/drivers/serial/serial_cs.$(LINUX_KMOD_SUFFIX) endef $(eval $(call KernelPackage,pcmcia-serial)) define KernelPackage/bluetooth TITLE:=Bluetooth support DEPENDS:[EMAIL PROTECTED] DESCRIPTION:=Kernel support for Bluetooth devices SUBMENU:=$(EMENU) endef define KernelPackage/bluetooth/2.4 KCONFIG:=$(CONFIG_BLUEZ) FILES:= \ $(LINUX_DIR)/net/bluetooth/bluez.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/bluetooth/l2cap.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/bluetooth/sco.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/bluetooth/rfcomm/rfcomm.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/bluetooth/bnep/bnep.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/bluetooth/hci_uart.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/bluetooth/hci_usb.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,90,bluez l2cap sco rfcomm bnep hci_uart hci_usb) endef define KernelPackage/bluetooth/2.6 KCONFIG:=$(CONFIG_BT) FILES:= \ $(LINUX_DIR)/net/bluetooth/bluetooth.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/bluetooth/l2cap.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/bluetooth/sco.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/bluetooth/rfcomm/rfcomm.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/bluetooth/bnep/bnep.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/bluetooth/hci_uart.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/bluetooth/hci_usb.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,90,bluetooth l2cap sco rfcomm bnep hci_uart hci_usb) endef $(eval $(call KernelPackage,bluetooth)) define KernelPackage/mmc TITLE:=MMC/SD Card Support DEPENDS:[EMAIL PROTECTED] DESCRIPTION:=Kernel support for MMC/SD cards SUBMENU:=$(EMENU) endef define KernelPackage/mmc/2.6 KCONFIG:=$(CONFIG_MMC) FILES:= \ $(LINUX_DIR)/drivers/mmc/mmc_core.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/mmc/mmc_block.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/mmc/at91_mci.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,90,mmc_core mmc_block at91_mci) endef $(eval $(call KernelPackage,mmc)) define KernelPackage/softdog TITLE:=Software watchdog driver DESCRIPTION:=Software watchdog driver SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_SOFT_WATCHDOG) FILES:=$(LINUX_DIR)/drivers/char/softdog.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,softdog) endef define KernelPackage/softdog/2.4 FILES:=$(LINUX_DIR)/drivers/char/softdog.o endef define KernelPackage/softdog/2.6 FILES:=$(LINUX_DIR)/drivers/char/watchdog/softdog.ko endef $(eval $(call KernelPackage,softdog)) define KernelPackage/videodev TITLE=Video4Linux support DESCRIPTION:=Kernel modules for Video4Linux support DEPENDS:[EMAIL PROTECTED] SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_VIDEO_DEV) FILES:=$(LINUX_DIR)/drivers/media/video/*.$(LINUX_KMOD_SUFFIX) endef define KernelPackage/videodev/2.4 AUTOLOAD:=$(call AutoLoad,60,videodev) endef define KernelPackage/videodev/2.6 AUTOLOAD:=$(call AutoLoad,60,v4l2-common v4l1-compat compat_ioctl32 videodev) endef $(eval $(call KernelPackage,videodev)) define KernelPackage/leds-net48xx TITLE:=Soekris Net48xx LED support DESCRIPTION:=Kernel module for Soekris Net48xx LEDs DEFAULT:=y if LINUX_2_6_X86_Soekris DEPENDS:[EMAIL PROTECTED] SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_LEDS_NET48XX) FILES:=$(LINUX_DIR)/drivers/leds/leds-net48xx.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,leds-net48xx) endef $(eval $(call KernelPackage,leds-net48xx)) define KernelPackage/nsc-gpio TITLE:=Natsemi GPIO support DESCRIPTION:=Kernel module for Natsemi GPIO DEFAULT:=y if LINUX_2_6_X86_Soekris DEPENDS:[EMAIL PROTECTED] SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_NSC_GPIO) FILES:=$(LINUX_DIR)/drivers/char/nsc_gpio.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,40,nsc_gpio) endef $(eval $(call KernelPackage,nsc-gpio)) define KernelPackage/scx200-gpio TITLE:=Natsemi SCX200 GPIO support DESCRIPTION:=Kernel module for SCX200 GPIO DEFAULT:=y if LINUX_2_6_X86_Soekris DEPENDS:=kmod-nsc-gpio @LINUX_2_6_X86_Soekris SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_SCx200_GPIO) FILES:=$(LINUX_DIR)/drivers/char/scx200_gpio.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,scx200_gpio) endef $(eval $(call KernelPackage,scx200-gpio)) define KernelPackage/scx200-wdt TITLE:=Natsemi SCX200 Watchdog support DESCRIPTION:=Kernel module for SCX200 Watchdog DEFAULT:=y if LINUX_2_6_X86_Soekris DEPENDS:[EMAIL PROTECTED] SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_SC1200_WDT) FILES:=$(LINUX_DIR)/drivers/char/watchdog/scx200_wdt.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,scx200_wdt) endef $(eval $(call KernelPackage,scx200-wdt)) define KernelPackage/hwmon TITLE:=Hardware monitoring support DESCRIPTION:=Kernel modules for hardware monitoring DEFAULT:=y if LINUX_2_6_X86_Soekris SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_HWMON_VID) FILES:= \ $(LINUX_DIR)/drivers/hwmon/hwmon.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/drivers/hwmon/hwmon-vid.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,40,hwmon hwmon-vid) endef $(eval $(call KernelPackage,hwmon)) define KernelPackage/hwmon-pc87360 TITLE:=PC87360 monitoring support DESCRIPTION:=Kernel modules for PC87360 chips DEFAULT:=y if LINUX_2_6_X86_Soekris DEPENDS:=kmod-hwmon SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_SENSORS_PC87360) FILES:=$(LINUX_DIR)/drivers/hwmon/pc87360.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,pc87360) endef $(eval $(call KernelPackage,hwmon-pc87360)) define KernelPackage/hwmon-ad7418 TITLE:=AD7418 monitoring support DESCRIPTION:=Kernel modules for AD7416/7/8 chips DEFAULT:=y if LINUX_2_6_IXP4XX_Avila SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_SENSORS_AD7418) FILES:=$(LINUX_DIR)/drivers/hwmon/ad7418.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,ad7418) endef $(eval $(call KernelPackage,hwmon-ad7418)) define KernelPackage/input-core TITLE:=Input device core DESCRIPTION:=Kernel modules for support of input device SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_INPUT) FILES:=$(LINUX_DIR)/drivers/input/input-core.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,50,input-core) endef $(eval $(call KernelPackage,input-core)) define KernelPackage/input-evdev TITLE:=Input even device DESCRIPTION:=Kernel modules for support of input device events DEPENDS:=+kmod-input-core SUBMENU:=$(EMENU) KCONFIG:=$(CONFIG_INPUT_EVDEV) FILES:=$(LINUX_DIR)/drivers/input/evdev.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,60,evdev) endef $(eval $(call KernelPackage,input-evdev))
diff -Naur linux-2.6.21.6/drivers/hwmon/ad7418.c linux-2.6.21.6_patched/drivers/hwmon/ad7418.c --- linux-2.6.21.6/drivers/hwmon/ad7418.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.6.21.6_patched/drivers/hwmon/ad7418.c 2007-09-17 22:03:43.000000000 -0600 @@ -0,0 +1,373 @@ +/* + * An hwmon driver for the Analog Devices AD7416/17/18 + * Copyright (C) 2006-07 Tower Technologies + * + * Author: Alessandro Zummo <[EMAIL PROTECTED]> + * + * Based on lm75.c + * Copyright (C) 1998-99 Frodo Looijaard <[EMAIL PROTECTED]> + * + * 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 - version 2. + */ + +#include <linux/module.h> +#include <linux/jiffies.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/delay.h> + +#include "lm75.h" + +#define DRV_VERSION "0.3" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END }; +/* Insmod parameters */ +I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418); + +/* AD7418 registers */ +#define AD7418_REG_TEMP_IN 0x00 +#define AD7418_REG_CONF 0x01 +#define AD7418_REG_TEMP_HYST 0x02 +#define AD7418_REG_TEMP_OS 0x03 +#define AD7418_REG_ADC 0x04 +#define AD7418_REG_CONF2 0x05 + +#define AD7418_REG_ADC_CH(x) ((x) << 5) +#define AD7418_CH_TEMP AD7418_REG_ADC_CH(0) + +static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN, + AD7418_REG_TEMP_HYST, + AD7418_REG_TEMP_OS }; + +struct ad7418_data { + struct i2c_client client; + struct class_device *class_dev; + struct attribute_group attrs; + enum chips type; + struct mutex lock; + int adc_max; /* number of ADC channels */ + char valid; + unsigned long last_updated; /* In jiffies */ + s16 temp[3]; /* Register values */ + u16 in[4]; +}; + +static int ad7418_attach_adapter(struct i2c_adapter *adapter); +static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind); +static int ad7418_detach_client(struct i2c_client *client); + +static struct i2c_driver ad7418_driver = { + .driver = { + .name = "ad7418", + }, + .attach_adapter = ad7418_attach_adapter, + .detach_client = ad7418_detach_client, +}; + +/* All registers are word-sized, except for the configuration registers. + * AD7418 uses a high-byte first convention. Do NOT use those functions to + * access the configuration registers CONF and CONF2, as they are byte-sized. + */ +static inline int ad7418_read(struct i2c_client *client, u8 reg) +{ + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +static inline int ad7418_write(struct i2c_client *client, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void ad7418_init_client(struct i2c_client *client) +{ + struct ad7418_data *data = i2c_get_clientdata(client); + + int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF); + if (reg < 0) { + dev_err(&client->dev, "cannot read configuration register\n"); + } else { + dev_info(&client->dev, "configuring for mode 1\n"); + i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe); + + if (data->type == ad7417 || data->type == ad7418) + i2c_smbus_write_byte_data(client, + AD7418_REG_CONF2, 0x00); + } +} + +static struct ad7418_data *ad7418_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ad7418_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + u8 cfg; + int i, ch; + + /* read config register and clear channel bits */ + cfg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF); + cfg &= 0x1F; + + i2c_smbus_write_byte_data(client, AD7418_REG_CONF, + cfg | AD7418_CH_TEMP); + udelay(30); + + for (i = 0; i < 3; i++) { + data->temp[i] = ad7418_read(client, AD7418_REG_TEMP[i]); + } + + for (i = 0, ch = 4; i < data->adc_max; i++, ch--) { + i2c_smbus_write_byte_data(client, + AD7418_REG_CONF, + cfg | AD7418_REG_ADC_CH(ch)); + + udelay(15); + data->in[data->adc_max - 1 - i] = + ad7418_read(client, AD7418_REG_ADC); + } + + /* restore old configuration value */ + ad7418_write(client, AD7418_REG_CONF, cfg); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->lock); + + return data; +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct ad7418_data *data = ad7418_update_device(dev); + return sprintf(buf, "%d\n", + LM75_TEMP_FROM_REG(data->temp[attr->index])); +} + +static ssize_t show_adc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct ad7418_data *data = ad7418_update_device(dev); + + return sprintf(buf, "%d\n", + ((data->in[attr->index] >> 6) * 2500 + 512) / 1024); +} + +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct ad7418_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->lock); + data->temp[attr->index] = LM75_TEMP_TO_REG(temp); + ad7418_write(client, AD7418_REG_TEMP[attr->index], data->temp[attr->index]); + mutex_unlock(&data->lock); + return count; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_temp, set_temp, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp, set_temp, 2); + +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 0); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3); + +static int ad7418_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, ad7418_detect); +} + +static struct attribute *ad7416_attributes[] = { + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; + +static struct attribute *ad7417_attributes[] = { + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + NULL +}; + +static struct attribute *ad7418_attributes[] = { + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + NULL +}; + +static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct ad7418_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 ad7418_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + client->addr = address; + client->adapter = adapter; + client->driver = &ad7418_driver; + + 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, reg6, reg7; + + /* the AD7416 lies within this address range, but I have + * no means to check. + */ + if (address >= 0x48 && address <= 0x4f) { + /* XXX add tests for AD7416 here */ + /* data->type = ad7416; */ + } + /* here we might have AD7417 or AD7418 */ + else if (address >= 0x28 && address <= 0x2f) { + reg6 = i2c_smbus_read_word_data(client, 0x06); + reg7 = i2c_smbus_read_word_data(client, 0x07); + + if (address == 0x28 && reg6 == 0xC071 && reg7 == 0xC071) + data->type = ad7418; + + /* XXX add tests for AD7417 here */ + + + /* both AD7417 and AD7418 have bits 0-5 of + * the CONF2 register at 0 + */ + reg = i2c_smbus_read_byte_data(client, + AD7418_REG_CONF2); + if (reg & 0x3F) + data->type = any_chip; /* detection failed */ + } + } else { + dev_dbg(&adapter->dev, "detection forced\n"); + } + + if (kind > 0) + data->type = kind; + else if (kind < 0 && data->type == any_chip) { + err = -ENODEV; + goto exit_free; + } + + switch (data->type) { + case any_chip: + case ad7416: + data->adc_max = 0; + data->attrs.attrs = ad7416_attributes; + strlcpy(client->name, "ad7416", I2C_NAME_SIZE); + break; + + case ad7417: + data->adc_max = 4; + data->attrs.attrs = ad7417_attributes; + strlcpy(client->name, "ad7417", I2C_NAME_SIZE); + break; + + case ad7418: + data->adc_max = 1; + data->attrs.attrs = ad7418_attributes; + strlcpy(client->name, "ad7418", I2C_NAME_SIZE); + break; + } + + if ((err = i2c_attach_client(client))) + goto exit_free; + + dev_info(&client->dev, "%s chip found\n", client->name); + + /* Initialize the AD7418 chip */ + ad7418_init_client(client); + + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) + goto exit_detach; + + data->class_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->attrs); +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int ad7418_detach_client(struct i2c_client *client) +{ + struct ad7418_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &data->attrs); + i2c_detach_client(client); + kfree(data); + return 0; +} + +static int __init ad7418_init(void) +{ + return i2c_add_driver(&ad7418_driver); +} + +static void __exit ad7418_exit(void) +{ + i2c_del_driver(&ad7418_driver); +} + +MODULE_AUTHOR("Alessandro Zummo <[EMAIL PROTECTED]>"); +MODULE_DESCRIPTION("AD7416/17/18 driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(ad7418_init); +module_exit(ad7418_exit); diff -Naur linux-2.6.21.6/drivers/hwmon/Kconfig linux-2.6.21.6_patched/drivers/hwmon/Kconfig --- linux-2.6.21.6/drivers/hwmon/Kconfig 2007-07-06 22:47:55.000000000 -0600 +++ linux-2.6.21.6_patched/drivers/hwmon/Kconfig 2007-09-17 22:02:54.000000000 -0600 @@ -575,6 +575,16 @@ This driver can also be built as a module. If so, the module will be called w83627ehf. +config SENSORS_AD7418 + tristate "Analog Devices AD7416/17/18" + depends on HWMON && I2C && EXPERIMENTAL + help + If you say yes here you get support for the Analog Devices + AD7416, AD7417 and AD7418 temperature monitoring chips. + + This driver can also be built as a module. If so, the module + will be called ad7418. + config SENSORS_HDAPS tristate "IBM Hard Drive Active Protection System (hdaps)" depends on HWMON && INPUT && X86 diff -Naur linux-2.6.21.6/drivers/hwmon/Makefile linux-2.6.21.6_patched/drivers/hwmon/Makefile --- linux-2.6.21.6/drivers/hwmon/Makefile 2007-07-06 22:47:55.000000000 -0600 +++ linux-2.6.21.6_patched/drivers/hwmon/Makefile 2007-09-17 22:02:54.000000000 -0600 @@ -14,6 +14,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o +obj-$(CONFIG_SENSORS_AD7418) += ad7418.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
_______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org http://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel