aboutsummaryrefslogtreecommitdiff
path: root/drivers/hwmon/i5k_amb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/i5k_amb.c')
-rw-r--r--drivers/hwmon/i5k_amb.c113
1 files changed, 89 insertions, 24 deletions
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index 6ac5c6f5358..6c0080a3b90 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -3,7 +3,7 @@
* temperature sensors
* Copyright (C) 2007 IBM
*
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
*
* 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
@@ -21,15 +21,14 @@
*/
#include <linux/module.h>
-#include <linux/jiffies.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
#include <linux/log2.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#define DRVNAME "i5k_amb"
@@ -81,6 +80,8 @@ static unsigned long amb_reg_temp(unsigned int amb)
#define MAX_AMBS_PER_CHANNEL 16
#define MAX_AMBS (MAX_MEM_CHANNELS * \
MAX_AMBS_PER_CHANNEL)
+#define CHANNEL_SHIFT 4
+#define DIMM_MASK 0xF
/*
* Ugly hack: For some reason the highest bit is set if there
* are _any_ DIMMs in the channel. Attempting to read from
@@ -89,7 +90,7 @@ static unsigned long amb_reg_temp(unsigned int amb)
* might prevent us from seeing the 16th DIMM in the channel.
*/
#define REAL_MAX_AMBS_PER_CHANNEL 15
-#define KNOBS_PER_AMB 5
+#define KNOBS_PER_AMB 6
static unsigned long amb_num_from_reg(unsigned int byte_num, unsigned int bit)
{
@@ -156,8 +157,12 @@ static ssize_t store_amb_min(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i5k_amb_data *data = dev_get_drvdata(dev);
- unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+ unsigned long temp;
+ int ret = kstrtoul(buf, 10, &temp);
+ if (ret < 0)
+ return ret;
+ temp = temp / 500;
if (temp > 255)
temp = 255;
@@ -172,8 +177,12 @@ static ssize_t store_amb_mid(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i5k_amb_data *data = dev_get_drvdata(dev);
- unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+ unsigned long temp;
+ int ret = kstrtoul(buf, 10, &temp);
+ if (ret < 0)
+ return ret;
+ temp = temp / 500;
if (temp > 255)
temp = 255;
@@ -188,8 +197,12 @@ static ssize_t store_amb_max(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i5k_amb_data *data = dev_get_drvdata(dev);
- unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+ unsigned long temp;
+ int ret = kstrtoul(buf, 10, &temp);
+ if (ret < 0)
+ return ret;
+ temp = temp / 500;
if (temp > 255)
temp = 255;
@@ -237,7 +250,17 @@ static ssize_t show_amb_temp(struct device *dev,
500 * amb_read_byte(data, amb_reg_temp(attr->index)));
}
-static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ return sprintf(buf, "Ch. %d DIMM %d\n", attr->index >> CHANNEL_SHIFT,
+ attr->index & DIMM_MASK);
+}
+
+static int i5k_amb_hwmon_init(struct platform_device *pdev)
{
int i, j, k, d = 0;
u16 c;
@@ -267,6 +290,21 @@ static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
continue;
d++;
+ /* sysfs label */
+ iattr = data->attrs + data->num_attrs;
+ snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+ "temp%d_label", d);
+ iattr->s_attr.dev_attr.attr.name = iattr->name;
+ iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
+ iattr->s_attr.dev_attr.show = show_label;
+ iattr->s_attr.index = k;
+ sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
+ res = device_create_file(&pdev->dev,
+ &iattr->s_attr.dev_attr);
+ if (res)
+ goto exit_remove;
+ data->num_attrs++;
+
/* Temperature sysfs knob */
iattr = data->attrs + data->num_attrs;
snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
@@ -275,6 +313,7 @@ static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
iattr->s_attr.dev_attr.show = show_amb_temp;
iattr->s_attr.index = k;
+ sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
res = device_create_file(&pdev->dev,
&iattr->s_attr.dev_attr);
if (res)
@@ -290,6 +329,7 @@ static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
iattr->s_attr.dev_attr.show = show_amb_min;
iattr->s_attr.dev_attr.store = store_amb_min;
iattr->s_attr.index = k;
+ sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
res = device_create_file(&pdev->dev,
&iattr->s_attr.dev_attr);
if (res)
@@ -305,6 +345,7 @@ static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
iattr->s_attr.dev_attr.show = show_amb_mid;
iattr->s_attr.dev_attr.store = store_amb_mid;
iattr->s_attr.index = k;
+ sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
res = device_create_file(&pdev->dev,
&iattr->s_attr.dev_attr);
if (res)
@@ -320,6 +361,7 @@ static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
iattr->s_attr.dev_attr.show = show_amb_max;
iattr->s_attr.dev_attr.store = store_amb_max;
iattr->s_attr.index = k;
+ sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
res = device_create_file(&pdev->dev,
&iattr->s_attr.dev_attr);
if (res)
@@ -334,6 +376,7 @@ static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
iattr->s_attr.dev_attr.show = show_amb_alarm;
iattr->s_attr.index = k;
+ sysfs_attr_init(&iattr->s_attr.dev_attr.attr);
res = device_create_file(&pdev->dev,
&iattr->s_attr.dev_attr);
if (res)
@@ -363,7 +406,7 @@ exit_remove:
return res;
}
-static int __devinit i5k_amb_add(void)
+static int i5k_amb_add(void)
{
int res = -ENODEV;
@@ -382,7 +425,8 @@ err:
return res;
}
-static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data)
+static int i5k_find_amb_registers(struct i5k_amb_data *data,
+ unsigned long devid)
{
struct pci_dev *pcidev;
u32 val32;
@@ -390,7 +434,7 @@ static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data)
/* Find AMB register memory space */
pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_5000_ERR,
+ devid,
NULL);
if (!pcidev)
return -ENODEV;
@@ -415,7 +459,7 @@ out:
return res;
}
-static int __devinit i5k_channel_probe(u16 *amb_present, unsigned long dev_id)
+static int i5k_channel_probe(u16 *amb_present, unsigned long dev_id)
{
struct pci_dev *pcidev;
u16 val16;
@@ -441,30 +485,53 @@ out:
return res;
}
-static int __devinit i5k_amb_probe(struct platform_device *pdev)
+static struct {
+ unsigned long err;
+ unsigned long fbd0;
+} chipset_ids[] = {
+ { PCI_DEVICE_ID_INTEL_5000_ERR, PCI_DEVICE_ID_INTEL_5000_FBD0 },
+ { PCI_DEVICE_ID_INTEL_5400_ERR, PCI_DEVICE_ID_INTEL_5400_FBD0 },
+ { 0, 0 }
+};
+
+#ifdef MODULE
+static struct pci_device_id i5k_amb_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, i5k_amb_ids);
+#endif
+
+static int i5k_amb_probe(struct platform_device *pdev)
{
struct i5k_amb_data *data;
struct resource *reso;
- int res = -ENODEV;
+ int i, res;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
/* Figure out where the AMB registers live */
- res = i5k_find_amb_registers(data);
+ i = 0;
+ do {
+ res = i5k_find_amb_registers(data, chipset_ids[i].err);
+ if (res == 0)
+ break;
+ i++;
+ } while (chipset_ids[i].err);
+
if (res)
goto err;
/* Copy the DIMM presence map for the first two channels */
- res = i5k_channel_probe(&data->amb_present[0],
- PCI_DEVICE_ID_INTEL_5000_FBD0);
+ res = i5k_channel_probe(&data->amb_present[0], chipset_ids[i].fbd0);
if (res)
goto err;
/* Copy the DIMM presence map for the optional second two channels */
- i5k_channel_probe(&data->amb_present[2],
- PCI_DEVICE_ID_INTEL_5000_FBD1);
+ i5k_channel_probe(&data->amb_present[2], chipset_ids[i].fbd0 + 1);
/* Set up resource regions */
reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME);
@@ -489,7 +556,6 @@ static int __devinit i5k_amb_probe(struct platform_device *pdev)
err_init_failed:
iounmap(data->amb_mmio);
- platform_set_drvdata(pdev, NULL);
err_map_failed:
release_mem_region(data->amb_base, data->amb_len);
err:
@@ -497,7 +563,7 @@ err:
return res;
}
-static int __devexit i5k_amb_remove(struct platform_device *pdev)
+static int i5k_amb_remove(struct platform_device *pdev)
{
int i;
struct i5k_amb_data *data = platform_get_drvdata(pdev);
@@ -509,7 +575,6 @@ static int __devexit i5k_amb_remove(struct platform_device *pdev)
kfree(data->attrs);
iounmap(data->amb_mmio);
release_mem_region(data->amb_base, data->amb_len);
- platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
@@ -520,7 +585,7 @@ static struct platform_driver i5k_amb_driver = {
.name = DRVNAME,
},
.probe = i5k_amb_probe,
- .remove = __devexit_p(i5k_amb_remove),
+ .remove = i5k_amb_remove,
};
static int __init i5k_amb_init(void)
@@ -544,7 +609,7 @@ static void __exit i5k_amb_exit(void)
platform_driver_unregister(&i5k_amb_driver);
}
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
MODULE_DESCRIPTION("Intel 5000 chipset FB-DIMM AMB temperature sensor");
MODULE_LICENSE("GPL");