diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-25 14:10:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-25 14:10:34 -0700 |
commit | 750e06992d49666a7589aac555eb3bb68e4dbb88 (patch) | |
tree | 7ee3d85adf256491dae89e5b049bb28ef1a1680c | |
parent | d3ec4844d449cf7af9e749f73ba2052fb7b72fc2 (diff) | |
parent | 156e2d1adc03e17f18f98d297f7757fc6d93a589 (diff) |
Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
hwmon: (lm78) Become the maintainer
hwmon: (lm78) Make ISA interface depend on CONFIG_ISA
hwmon: (lm78) Avoid forward declarations
hwmon: (sht15) Correct a comment mistake
hwmon: (max1111) Avoid extra memory allocations
hwmon: (it87) Add chassis intrusion detection support
hwmon: (via-cputemp) Add VID reporting support
hwmon-vid: Add support for VIA family 6 model D CPU
hwmon: New driver sch5636
hwmon: (sch5627) Factor out some code shared with sch5636 driver
-rw-r--r-- | Documentation/hwmon/it87 | 3 | ||||
-rw-r--r-- | Documentation/hwmon/lm78 | 3 | ||||
-rw-r--r-- | Documentation/hwmon/sch5636 | 31 | ||||
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 21 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 2 | ||||
-rw-r--r-- | drivers/hwmon/hwmon-vid.c | 42 | ||||
-rw-r--r-- | drivers/hwmon/it87.c | 29 | ||||
-rw-r--r-- | drivers/hwmon/lm78.c | 305 | ||||
-rw-r--r-- | drivers/hwmon/max1111.c | 27 | ||||
-rw-r--r-- | drivers/hwmon/sch5627.c | 334 | ||||
-rw-r--r-- | drivers/hwmon/sch5636.c | 539 | ||||
-rw-r--r-- | drivers/hwmon/sch56xx-common.c | 340 | ||||
-rw-r--r-- | drivers/hwmon/sch56xx-common.h | 24 | ||||
-rw-r--r-- | drivers/hwmon/sht15.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/via-cputemp.c | 44 |
16 files changed, 1285 insertions, 468 deletions
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 38425f0f264..6f496a58673 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -76,7 +76,8 @@ IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they include an 'environment controller' with 3 temperature sensors, 3 fan -rotation speed sensors, 8 voltage sensors, and associated alarms. +rotation speed sensors, 8 voltage sensors, associated alarms, and chassis +intrusion detection. The IT8712F and IT8716F additionally feature VID inputs, used to report the Vcore voltage of the processor. The early IT8712F have 5 VID pins, diff --git a/Documentation/hwmon/lm78 b/Documentation/hwmon/lm78 index 60932e26aba..2bdc881a0c1 100644 --- a/Documentation/hwmon/lm78 +++ b/Documentation/hwmon/lm78 @@ -13,7 +13,8 @@ Supported chips: Datasheet: Publicly available at the National Semiconductor website http://www.national.com/ -Author: Frodo Looijaard <frodol@dds.nl> +Authors: Frodo Looijaard <frodol@dds.nl> + Jean Delvare <khali@linux-fr.org> Description ----------- diff --git a/Documentation/hwmon/sch5636 b/Documentation/hwmon/sch5636 new file mode 100644 index 00000000000..f83bd1c260f --- /dev/null +++ b/Documentation/hwmon/sch5636 @@ -0,0 +1,31 @@ +Kernel driver sch5636 +===================== + +Supported chips: + * SMSC SCH5636 + Prefix: 'sch5636' + Addresses scanned: none, address read from Super I/O config space + +Author: Hans de Goede <hdegoede@redhat.com> + + +Description +----------- + +SMSC SCH5636 Super I/O chips include an embedded microcontroller for +hardware monitoring solutions, allowing motherboard manufacturers to create +their own custom hwmon solution based upon the SCH5636. + +Currently the sch5636 driver only supports the Fujitsu Theseus SCH5636 based +hwmon solution. The sch5636 driver runs a sanity check on loading to ensure +it is dealing with a Fujitsu Theseus and not with another custom SCH5636 based +hwmon solution. + +The Fujitsu Theseus can monitor up to 5 voltages, 8 fans and 16 +temperatures. Note that the driver detects how many fan headers / +temperature sensors are actually implemented on the motherboard, so you will +likely see fewer temperature and fan inputs. + +An application note describing the Theseus' registers, as well as an +application note describing the protocol for communicating with the +microcontroller is available upon request. Please mail me if you want a copy. diff --git a/MAINTAINERS b/MAINTAINERS index efe0a4b0715..91e5cc7db8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3960,6 +3960,13 @@ L: lm-sensors@lm-sensors.org S: Maintained F: drivers/hwmon/lm73.c +LM78 HARDWARE MONITOR DRIVER +M: Jean Delvare <khali@linux-fr.org> +L: lm-sensors@lm-sensors.org +S: Maintained +F: Documentation/hwmon/lm78 +F: drivers/hwmon/lm78.c + LM83 HARDWARE MONITOR DRIVER M: Jean Delvare <khali@linux-fr.org> L: lm-sensors@lm-sensors.org diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 5f888f7e7dc..0598cd22edf 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1041,8 +1041,13 @@ config SENSORS_SMSC47B397 This driver can also be built as a module. If so, the module will be called smsc47b397. +config SENSORS_SCH56XX_COMMON + tristate + default n + config SENSORS_SCH5627 tristate "SMSC SCH5627" + select SENSORS_SCH56XX_COMMON help If you say yes here you get support for the hardware monitoring features of the SMSC SCH5627 Super-I/O chip. @@ -1050,6 +1055,21 @@ config SENSORS_SCH5627 This driver can also be built as a module. If so, the module will be called sch5627. +config SENSORS_SCH5636 + tristate "SMSC SCH5636" + select SENSORS_SCH56XX_COMMON + help + SMSC SCH5636 Super I/O chips include an embedded microcontroller for + hardware monitoring solutions, allowing motherboard manufacturers to + create their own custom hwmon solution based upon the SCH5636. + + Currently this driver only supports the Fujitsu Theseus SCH5636 based + hwmon solution. Say yes here if you want support for the Fujitsu + Theseus' hardware monitoring features. + + This driver can also be built as a module. If so, the module + will be called sch5636. + config SENSORS_ADS1015 tristate "Texas Instruments ADS1015" depends on I2C @@ -1142,6 +1162,7 @@ config SENSORS_TWL4030_MADC config SENSORS_VIA_CPUTEMP tristate "VIA CPU temperature sensor" depends on X86 + select HWMON_VID help If you say yes here you get support for the temperature sensor inside your CPU. Supported are all known variants of diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 28061cfa0cd..d7995a1d078 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -95,7 +95,9 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o +obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o +obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index c8195a077da..932da8a5aaf 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -140,7 +140,11 @@ int vid_from_reg(int val, u8 vrm) return(val & 0x10 ? 975 - (val & 0xF) * 25 : 1750 - val * 50); case 13: + case 131: val &= 0x3f; + /* Exception for Eden ULV 500 MHz */ + if (vrm == 131 && val == 0x3f) + val++; return(1708 - val * 16); case 14: /* Intel Core */ /* compute in uV, round to mV */ @@ -205,11 +209,45 @@ static struct vrm_model vrm_models[] = { {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nehemiah */ {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */ {X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */ - {X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */ + {X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7-M, C7, Eden (Esther) */ + {X86_VENDOR_CENTAUR, 0x6, 0xD, ANY, 134}, /* C7-D, C7-M, C7, Eden (Esther) */ {X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */ }; +/* + * Special case for VIA model D: there are two different possible + * VID tables, so we have to figure out first, which one must be + * used. This resolves temporary drm value 134 to 14 (Intel Core + * 7-bit VID), 13 (Pentium M 6-bit VID) or 131 (Pentium M 6-bit VID + * + quirk for Eden ULV 500 MHz). + * Note: something similar might be needed for model A, I'm not sure. + */ +static u8 get_via_model_d_vrm(void) +{ + unsigned int vid, brand, dummy; + static const char *brands[4] = { + "C7-M", "C7", "Eden", "C7-D" + }; + + rdmsr(0x198, dummy, vid); + vid &= 0xff; + + rdmsr(0x1154, brand, dummy); + brand = ((brand >> 4) ^ (brand >> 2)) & 0x03; + + if (vid > 0x3f) { + pr_info("Using %d-bit VID table for VIA %s CPU\n", + 7, brands[brand]); + return 14; + } else { + pr_info("Using %d-bit VID table for VIA %s CPU\n", + 6, brands[brand]); + /* Enable quirk for Eden */ + return brand == 2 ? 131 : 13; + } +} + static u8 find_vrm(u8 eff_family, u8 eff_model, u8 eff_stepping, u8 vendor) { int i = 0; @@ -247,6 +285,8 @@ u8 vid_which_vrm(void) eff_model += ((eax & 0x000F0000)>>16)<<4; } vrm_ret = find_vrm(eff_family, eff_model, eff_stepping, c->x86_vendor); + if (vrm_ret == 134) + vrm_ret = get_via_model_d_vrm(); if (vrm_ret == 0) pr_info("Unknown VRM version of your x86 CPU\n"); return vrm_ret; diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 5f524775043..d912649fac5 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -1172,6 +1172,32 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } + +static ssize_t clear_intrusion(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) +{ + struct it87_data *data = dev_get_drvdata(dev); + long val; + int config; + + if (strict_strtol(buf, 10, &val) < 0 || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + config = it87_read_value(data, IT87_REG_CONFIG); + if (config < 0) { + count = config; + } else { + config |= 1 << 5; + it87_write_value(data, IT87_REG_CONFIG, config); + /* Invalidate cache to force re-read */ + data->valid = 0; + } + mutex_unlock(&data->update_lock); + + return count; +} + static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9); static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10); @@ -1188,6 +1214,8 @@ static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 6); static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16); static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17); static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18); +static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, + show_alarm, clear_intrusion, 4); static ssize_t show_beep(struct device *dev, struct device_attribute *attr, char *buf) @@ -1350,6 +1378,7 @@ static struct attribute *it87_attributes[] = { &sensor_dev_attr_temp3_alarm.dev_attr.attr, &dev_attr_alarms.attr, + &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, &dev_attr_name.attr, NULL }; diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 4cb24eafe31..6df0b468171 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -2,7 +2,7 @@ lm78.c - Part of lm_sensors, Linux kernel modules for hardware monitoring Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> - Copyright (c) 2007 Jean Delvare <khali@linux-fr.org> + Copyright (c) 2007, 2011 Jean Delvare <khali@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 @@ -26,23 +26,21 @@ #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> -#include <linux/platform_device.h> -#include <linux/ioport.h> #include <linux/hwmon.h> #include <linux/hwmon-vid.h> #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> -#include <linux/io.h> -/* ISA device, if found */ -static struct platform_device *pdev; +#ifdef CONFIG_ISA +#include <linux/platform_device.h> +#include <linux/ioport.h> +#include <linux/io.h> +#endif /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; -static unsigned short isa_address = 0x290; - enum chips { lm78, lm79 }; /* Many LM78 constants specified below */ @@ -143,50 +141,12 @@ struct lm78_data { }; -static int lm78_i2c_detect(struct i2c_client *client, - struct i2c_board_info *info); -static int lm78_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm78_i2c_remove(struct i2c_client *client); - -static int __devinit lm78_isa_probe(struct platform_device *pdev); -static int __devexit lm78_isa_remove(struct platform_device *pdev); - static int lm78_read_value(struct lm78_data *data, u8 reg); static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value); static struct lm78_data *lm78_update_device(struct device *dev); static void lm78_init_device(struct lm78_data *data); -static const struct i2c_device_id lm78_i2c_id[] = { - { "lm78", lm78 }, - { "lm79", lm79 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm78_i2c_id); - -static struct i2c_driver lm78_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm78", - }, - .probe = lm78_i2c_probe, - .remove = lm78_i2c_remove, - .id_table = lm78_i2c_id, - .detect = lm78_i2c_detect, - .address_list = normal_i2c, -}; - -static struct platform_driver lm78_isa_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "lm78", - }, - .probe = lm78_isa_probe, - .remove = __devexit_p(lm78_isa_remove), -}; - - /* 7 Voltages */ static ssize_t show_in(struct device *dev, struct device_attribute *da, char *buf) @@ -514,6 +474,16 @@ static const struct attribute_group lm78_group = { .attrs = lm78_attributes, }; +/* + * ISA related code + */ +#ifdef CONFIG_ISA + +/* ISA device, if found */ +static struct platform_device *pdev; + +static unsigned short isa_address = 0x290; + /* I2C devices get this name attribute automatically, but for ISA devices we must create it by ourselves. */ static ssize_t show_name(struct device *dev, struct device_attribute @@ -525,6 +495,11 @@ static ssize_t show_name(struct device *dev, struct device_attribute } static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static struct lm78_data *lm78_data_if_isa(void) +{ + return pdev ? platform_get_drvdata(pdev) : NULL; +} + /* Returns 1 if the I2C chip appears to be an alias of the ISA chip */ static int lm78_alias_detect(struct i2c_client *client, u8 chipid) { @@ -558,12 +533,24 @@ static int lm78_alias_detect(struct i2c_client *client, u8 chipid) return 1; } +#else /* !CONFIG_ISA */ + +static int lm78_alias_detect(struct i2c_client *client, u8 chipid) +{ + return 0; +} + +static struct lm78_data *lm78_data_if_isa(void) +{ + return NULL; +} +#endif /* CONFIG_ISA */ static int lm78_i2c_detect(struct i2c_client *client, struct i2c_board_info *info) { int i; - struct lm78_data *isa = pdev ? platform_get_drvdata(pdev) : NULL; + struct lm78_data *isa = lm78_data_if_isa(); const char *client_name; struct i2c_adapter *adapter = client->adapter; int address = client->addr; @@ -663,76 +650,24 @@ static int lm78_i2c_remove(struct i2c_client *client) return 0; } -static int __devinit lm78_isa_probe(struct platform_device *pdev) -{ - int err; - struct lm78_data *data; - struct resource *res; - - /* Reserve the ISA region */ - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!request_region(res->start + LM78_ADDR_REG_OFFSET, 2, "lm78")) { - err = -EBUSY; - goto exit; - } - - if (!(data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit_release_region; - } - mutex_init(&data->lock); - data->isa_addr = res->start; - platform_set_drvdata(pdev, data); - - if (lm78_read_value(data, LM78_REG_CHIPID) & 0x80) { - data->type = lm79; - data->name = "lm79"; - } else { - data->type = lm78; - data->name = "lm78"; - } - - /* Initialize the LM78 chip */ - lm78_init_device(data); - - /* Register sysfs hooks */ - if ((err = sysfs_create_group(&pdev->dev.kobj, &lm78_group)) - || (err = device_create_file(&pdev->dev, &dev_attr_name))) - goto exit_remove_files; - - data->hwmon_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - - exit_remove_files: - sysfs_remove_group(&pdev->dev.kobj, &lm78_group); - device_remove_file(&pdev->dev, &dev_attr_name); - kfree(data); - exit_release_region: - release_region(res->start + LM78_ADDR_REG_OFFSET, 2); - exit: - return err; -} - -static int __devexit lm78_isa_remove(struct platform_device *pdev) -{ - struct lm78_data *data = platform_get_drvdata(pdev); - struct resource *res; - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&pdev->dev.kobj, &lm78_group); - device_remove_file(&pdev->dev, &dev_attr_name); - kfree(data); - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_region(res->start + LM78_ADDR_REG_OFFSET, 2); +static const struct i2c_device_id lm78_i2c_id[] = { + { "lm78", lm78 }, + { "lm79", lm79 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm78_i2c_id); - return 0; -} +static struct i2c_driver lm78_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm78", + }, + .probe = lm78_i2c_probe, + .remove = lm78_i2c_remove, + .id_table = lm78_i2c_id, + .detect = lm78_i2c_detect, + .address_list = normal_i2c, +}; /* The SMBus locks itself, but ISA access must be locked explicitly! We don't want to lock the whole ISA bus, so we lock each client @@ -743,6 +678,7 @@ static int lm78_read_value(struct lm78_data *data, u8 reg) { struct i2c_client *client = data->client; +#ifdef CONFIG_ISA if (!client) { /* ISA device */ int res; mutex_lock(&data->lock); @@ -751,6 +687,7 @@ static int lm78_read_value(struct lm78_data *data, u8 reg) mutex_unlock(&data->lock); return res; } else +#endif return i2c_smbus_read_byte_data(client, reg); } @@ -765,6 +702,7 @@ static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value) { struct i2c_client *client = data->client; +#ifdef CONFIG_ISA if (!client) { /* ISA device */ mutex_lock(&data->lock); outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); @@ -772,6 +710,7 @@ static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value) mutex_unlock(&data->lock); return 0; } else +#endif return i2c_smbus_write_byte_data(client, reg, value); } @@ -849,6 +788,88 @@ static struct lm78_data *lm78_update_device(struct device *dev) return data; } +#ifdef CONFIG_ISA +static int __devinit lm78_isa_probe(struct platform_device *pdev) +{ + int err; + struct lm78_data *data; + struct resource *res; + + /* Reserve the ISA region */ + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start + LM78_ADDR_REG_OFFSET, 2, "lm78")) { + err = -EBUSY; + goto exit; + } + + data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit_release_region; + } + mutex_init(&data->lock); + data->isa_addr = res->start; + platform_set_drvdata(pdev, data); + + if (lm78_read_value(data, LM78_REG_CHIPID) & 0x80) { + data->type = lm79; + data->name = "lm79"; + } else { + data->type = lm78; + data->name = "lm78"; + } + + /* Initialize the LM78 chip */ + lm78_init_device(data); + + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&pdev->dev.kobj, &lm78_group)) + || (err = device_create_file(&pdev->dev, &dev_attr_name))) + goto exit_remove_files; + + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove_files; + } + + return 0; + + exit_remove_files: + sysfs_remove_group(&pdev->dev.kobj, &lm78_group); + device_remove_file(&pdev->dev, &dev_attr_name); + kfree(data); + exit_release_region: + release_region(res->start + LM78_ADDR_REG_OFFSET, 2); + exit: + return err; +} + +static int __devexit lm78_isa_remove(struct platform_device *pdev) +{ + struct lm78_data *data = platform_get_drvdata(pdev); + struct resource *res; + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&pdev->dev.kobj, &lm78_group); + device_remove_file(&pdev->dev, &dev_attr_name); + kfree(data); + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start + LM78_ADDR_REG_OFFSET, 2); + + return 0; +} + +static struct platform_driver lm78_isa_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "lm78", + }, + .probe = lm78_isa_probe, + .remove = __devexit_p(lm78_isa_remove), +}; + /* return 1 if a supported chip is found, 0 otherwise */ static int __init lm78_isa_found(unsigned short address) { @@ -969,12 +990,10 @@ static int __init lm78_isa_device_add(unsigned short address) return err; } -static int __init sm_lm78_init(void) +static int __init lm78_isa_register(void) { int res; - /* We register the ISA device first, so that we can skip the - * registration of an I2C interface to the same device. */ if (lm78_isa_found(isa_address)) { res = platform_driver_register(&lm78_isa_driver); if (res) @@ -986,32 +1005,62 @@ static int __init sm_lm78_init(void) goto exit_unreg_isa_driver; } - res = i2c_add_driver(&lm78_driver); - if (res) - goto exit_unreg_isa_device; - return 0; - exit_unreg_isa_device: - platform_device_unregister(pdev); exit_unreg_isa_driver: platform_driver_unregister(&lm78_isa_driver); exit: return res; } -static void __exit sm_lm78_exit(void) +static void lm78_isa_unregister(void) { if (pdev) { platform_device_unregister(pdev); platform_driver_unregister(&lm78_isa_driver); } - i2c_del_driver(&lm78_driver); } +#else /* !CONFIG_ISA */ +static int __init lm78_isa_register(void) +{ + return 0; +} + +static void lm78_isa_unregister(void) +{ +} +#endif /* CONFIG_ISA */ +static int __init sm_lm78_init(void) +{ + int res; + + /* We register the ISA device first, so that we can skip the + * registration of an I2C interface to the same device. */ + res = lm78_isa_register(); + if (res) + goto exit; + + res = i2c_add_driver(&lm78_driver); + if (res) + goto exit_unreg_isa_device; + + return 0; + + exit_unreg_isa_device: + lm78_isa_unregister(); + exit: + return res; +} + +static void __exit sm_lm78_exit(void) +{ + lm78_isa_unregister(); + i2c_del_driver(&lm78_driver); +} -MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); +MODULE_AUTHOR("Frodo Looijaard, Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("LM78/LM79 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index 14335bbc9bd..c97b78ef911 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -38,8 +38,8 @@ struct max1111_data { struct device *hwmon_dev; struct spi_message msg; struct spi_transfer xfer[2]; - uint8_t *tx_buf; - uint8_t *rx_buf; + uint8_t tx_buf[MAX1111_TX_BUF_SIZE]; + uint8_t rx_buf[MAX1111_RX_BUF_SIZE]; struct mutex drvdata_lock; /* protect msg, xfer and buffers from multiple access */ }; @@ -131,33 +131,23 @@ static const struct attribute_group max1111_attr_group = { .attrs = max1111_attributes, }; -static int setup_transfer(struct max1111_data *data) +static int __devinit setup_transfer(struct max1111_data *data) { struct spi_message *m; struct spi_transfer *x; - data->tx_buf = kmalloc(MAX1111_TX_BUF_SIZE, GFP_KERNEL); - if (!data->tx_buf) - return -ENOMEM; - - data->rx_buf = kmalloc(MAX1111_RX_BUF_SIZE, GFP_KERNEL); - if (!data->rx_buf) { - kfree(data->tx_buf); - return -ENOMEM; - } - m = &data->msg; x = &data->xfer[0]; spi_message_init(m); x->tx_buf = &data->tx_buf[0]; - x->len = 1; + x->len = MAX1111_TX_BUF_SIZE; spi_message_add_tail(x, m); x++; x->rx_buf = &data->rx_buf[0]; - x->len = 2; + x->len = MAX1111_RX_BUF_SIZE; spi_message_add_tail(x, m); return 0; @@ -192,7 +182,7 @@ static int __devinit max1111_probe(struct spi_device *spi) err = sysfs_create_group(&spi->dev.kobj, &max1111_attr_group); if (err) { dev_err(&spi->dev, "failed to create attribute group\n"); - goto err_free_all; + goto err_free_data; } data->hwmon_dev = hwmon_device_register(&spi->dev); @@ -209,9 +199,6 @@ static int __devinit max1111_probe(struct spi_device *spi) err_remove: sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group); -err_free_all: - kfree(data->rx_buf); - kfree(data->tx_buf); err_free_data: kfree(data); return err; @@ -224,8 +211,6 @@ static int __devexit max1111_remove(struct spi_device *spi) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group); mutex_destroy(&data->drvdata_lock); - kfree(data->rx_buf); - kfree(data->tx_buf); kfree(data); return 0; } diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 3494a4cce41..e3b5c6039c2 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -28,33 +28,15 @@ #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> -#include <linux/io.h> -#include <linux/acpi.h> -#include <linux/delay.h> +#include "sch56xx-common.h" #define DRVNAME "sch5627" #define DEVNAME DRVNAME /* We only support one model */ -#define SIO_SCH5627_EM_LD 0x0C /* Embedded Microcontroller LD */ -#define SIO_UNLOCK_KEY 0x55 /* Key to enable Super-I/O */ -#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ - -#define SIO_REG_LDSEL 0x07 /* Logical device select */ -#define SIO_REG_DEVID 0x20 /* Device ID */ -#define SIO_REG_ENABLE 0x30 /* Logical device enable */ -#define SIO_REG_ADDR 0x66 /* Logical device address (2 bytes) */ - -#define SIO_SCH5627_ID 0xC6 /* Chipset ID */ - -#define REGION_LENGTH 9 - #define SCH5627_HWMON_ID 0xa5 #define SCH5627_COMPANY_ID 0x5c #define SCH5627_PRIMARY_ID 0xa0 -#define SCH5627_CMD_READ 0x02 -#define SCH5627_CMD_WRITE 0x03 - #define SCH5627_REG_BUILD_CODE 0x39 #define SCH5627_REG_BUILD_ID 0x3a #define SCH5627_REG_HWMON_ID 0x3c @@ -111,182 +93,6 @@ struct sch5627_data { u16 in[SCH5627_NO_IN]; }; -static struct platform_device *sch5627_pdev; - -/* Super I/O functions */ -static inline int superio_inb(int base, int reg) -{ - outb(reg, base); - return inb(base + 1); -} - -static inline int superio_enter(int base) -{ - /* Don't step on other drivers' I/O space by accident */ - if (!request_muxed_region(base, 2, DRVNAME)) { - pr_err("I/O address 0x%04x already in use\n", base); - return -EBUSY; - } - - outb(SIO_UNLOCK_KEY, base); - - return 0; -} - -static inline void superio_select(int base, int ld) -{ - outb(SIO_REG_LDSEL, base); - outb(ld, base + 1); -} - -static inline void superio_exit(int base) -{ - outb(SIO_LOCK_KEY, base); - release_region(base, 2); -} - -static int sch5627_send_cmd(struct sch5627_data *data, u8 cmd, u16 reg, u8 v) -{ - u8 val; - int i; - /* - * According to SMSC for the commands we use the maximum time for - * the EM to respond is 15 ms, but testing shows in practice it - * responds within 15-32 reads, so we first busy poll, and if - * that fails sleep a bit and try again until we are way past - * the 15 ms maximum response time. - */ - const int max_busy_polls = 64; - const int max_lazy_polls = 32; - - /* (Optional) Write-Clear the EC to Host Mailbox Register */ - val = inb(data->addr + 1); - outb(val, data->addr + 1); - - /* Set Mailbox Address Pointer to first location in Region 1 */ - outb(0x00, data->addr + 2); - outb(0x80, data->addr + 3); - - /* Write Request Packet Header */ - outb(cmd, data->addr + 4); /* VREG Access Type read:0x02 write:0x03 */ - outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */ - outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */ - - /* Write Value field */ - if (cmd == SCH5627_CMD_WRITE) - outb(v, data->addr + 4); - - /* Write Address field */ - outb(reg & 0xff, data->addr + 6); - outb(reg >> 8, data->addr + 7); - - /* Execute the Random Access Command */ - outb(0x01, data->addr); /* Write 01h to the Host-to-EC register */ - - /* EM Interface Polling "Algorithm" */ - for (i = 0; i < max_busy_polls + max_lazy_polls; i++) { - if (i >= max_busy_polls) - msleep(1); - /* Read Interrupt source Register */ - val = inb(data->addr + 8); - /* Write Clear the interrupt source bits */ - if (val) - outb(val, data->addr + 8); - /* Command Completed ? */ - if (val & 0x01) - break; - } - if (i == max_busy_polls + max_lazy_polls) { - pr_err("Max retries exceeded reading virtual " - "register 0x%04hx (%d)\n", reg, 1); - return -EIO; - } - - /* - * According to SMSC we may need to retry this, but sofar I've always - * seen this succeed in 1 try. - */ - for (i = 0; i < max_busy_polls; i++) { - /* Read EC-to-Host Register */ - val = inb(data->addr + 1); - /* Command Completed ? */ - if (val == 0x01) - break; - - if (i == 0) - pr_warn("EC reports: 0x%02x reading virtual register " - "0x%04hx\n", (unsigned int)val, reg); - } - if (i == max_busy_polls) { - pr_err("Max retries exceeded reading virtual " - "register 0x%04hx (%d)\n", reg, 2); - return -EIO; - } - - /* - * According to the SMSC app note we should now do: - * - * Set Mailbox Address Pointer to first location in Region 1 * - * outb(0x00, data->addr + 2); - * outb(0x80, data->addr + 3); - * - * But if we do that things don't work, so let's not. - */ - - /* Read Value field */ - if (cmd == SCH5627_CMD_READ) - return inb(data->addr + 4); - - return 0; -} - -static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg) -{ - return sch5627_send_cmd(data, SCH5627_CMD_READ, reg, 0); -} - |