aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJean Delvare <jdelvare@suse.de>2015-01-24 08:16:21 -0500
committerJean Delvare <jdelvare@suse.de>2015-01-24 08:16:21 -0500
commitada072816be1f284cda273f1d980a429b007566a (patch)
tree7007dbd66a5ddea351f195acbf523338a8fc3fd4 /drivers
parentec6f34e5b552fb0a52e6aae1a5afbbb1605cc6cc (diff)
hwmon: (i5500_temp) New driver for the Intel 5500/5520/X58 chipsets
The Intel 5500, 5520 and X58 chipsets embed a digital thermal sensor. This new driver supports it. Note that on many boards the sensor seems to be disabled and reports the minimum value (36.5 degrees Celsius) all the time. Signed-off-by: Jean Delvare <jdelvare@suse.de> Tested-by: Romain Dolbeau <romain@dolbeau.org> Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/i5500_temp.c201
3 files changed, 212 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6529c09c46f0..a7de26d1ac80 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -574,6 +574,16 @@ config SENSORS_IIO_HWMON
574 for those channels specified in the map. This map can be provided 574 for those channels specified in the map. This map can be provided
575 either via platform data or the device tree bindings. 575 either via platform data or the device tree bindings.
576 576
577config SENSORS_I5500
578 tristate "Intel 5500/5520/X58 temperature sensor"
579 depends on X86 && PCI
580 help
581 If you say yes here you get support for the temperature
582 sensor inside the Intel 5500, 5520 and X58 chipsets.
583
584 This driver can also be built as a module. If so, the module
585 will be called i5500_temp.
586
577config SENSORS_CORETEMP 587config SENSORS_CORETEMP
578 tristate "Intel Core/Core2/Atom temperature sensor" 588 tristate "Intel Core/Core2/Atom temperature sensor"
579 depends on X86 589 depends on X86
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 67280643bcf0..6c941472e707 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
68obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o 68obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
69obj-$(CONFIG_SENSORS_HTU21) += htu21.o 69obj-$(CONFIG_SENSORS_HTU21) += htu21.o
70obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o 70obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
71obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o
71obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o 72obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
72obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o 73obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
73obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o 74obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c
new file mode 100644
index 000000000000..cbc822dec942
--- /dev/null
+++ b/drivers/hwmon/i5500_temp.c
@@ -0,0 +1,201 @@
1/*
2 * i5500_temp - Driver for Intel 5500/5520/X58 chipset thermal sensor
3 *
4 * Copyright (C) 2012, 2014 Jean Delvare <jdelvare@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/jiffies.h>
21#include <linux/pci.h>
22#include <linux/hwmon.h>
23#include <linux/hwmon-sysfs.h>
24#include <linux/err.h>
25#include <linux/mutex.h>
26
27/* Register definitions from datasheet */
28#define REG_TSTHRCATA 0xE2
29#define REG_TSCTRL 0xE8
30#define REG_TSTHRRPEX 0xEB
31#define REG_TSTHRLO 0xEC
32#define REG_TSTHRHI 0xEE
33#define REG_CTHINT 0xF0
34#define REG_TSFSC 0xF3
35#define REG_CTSTS 0xF4
36#define REG_TSTHRRQPI 0xF5
37#define REG_CTCTRL 0xF7
38#define REG_TSTIMER 0xF8
39
40struct i5500_temp_data {
41 struct device *hwmon_dev;
42 const char *name;
43};
44
45/*
46 * Sysfs stuff
47 */
48
49/* Sensor resolution : 0.5 degree C */
50static ssize_t show_temp(struct device *dev,
51 struct device_attribute *devattr, char *buf)
52{
53 struct pci_dev *pdev = to_pci_dev(dev);
54 long temp;
55 u16 tsthrhi;
56 s8 tsfsc;
57
58 pci_read_config_word(pdev, REG_TSTHRHI, &tsthrhi);
59 pci_read_config_byte(pdev, REG_TSFSC, &tsfsc);
60 temp = ((long)tsthrhi - tsfsc) * 500;
61
62 return sprintf(buf, "%ld\n", temp);
63}
64
65static ssize_t show_thresh(struct device *dev,
66 struct device_attribute *devattr, char *buf)
67{
68 struct pci_dev *pdev = to_pci_dev(dev);
69 int reg = to_sensor_dev_attr(devattr)->index;
70 long temp;
71 u16 tsthr;
72
73 pci_read_config_word(pdev, reg, &tsthr);
74 temp = tsthr * 500;
75
76 return sprintf(buf, "%ld\n", temp);
77}
78
79static ssize_t show_alarm(struct device *dev,
80 struct device_attribute *devattr, char *buf)
81{
82 struct pci_dev *pdev = to_pci_dev(dev);
83 int nr = to_sensor_dev_attr(devattr)->index;
84 u8 ctsts;
85
86 pci_read_config_byte(pdev, REG_CTSTS, &ctsts);
87 return sprintf(buf, "%u\n", (unsigned int)ctsts & (1 << nr));
88}
89
90static ssize_t show_name(struct device *dev, struct device_attribute
91 *devattr, char *buf)
92{
93 struct i5500_temp_data *data = dev_get_drvdata(dev);
94
95 return sprintf(buf, "%s\n", data->name);
96}
97
98static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
99static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_thresh, NULL, 0xE2);
100static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_thresh, NULL, 0xEC);
101static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_thresh, NULL, 0xEE);
102static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
103static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
104static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
105
106static struct attribute *i5500_temp_attributes[] = {
107 &dev_attr_temp1_input.attr,
108 &sensor_dev_attr_temp1_crit.dev_attr.attr,
109 &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
110 &sensor_dev_attr_temp1_max.dev_attr.attr,
111 &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
112 &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
113 &dev_attr_name.attr,
114 NULL
115};
116
117static const struct attribute_group i5500_temp_group = {
118 .attrs = i5500_temp_attributes,
119};
120
121static const struct pci_device_id i5500_temp_ids[] = {
122 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3438) },
123 { 0 },
124};
125
126MODULE_DEVICE_TABLE(pci, i5500_temp_ids);
127
128static int i5500_temp_probe(struct pci_dev *pdev,
129 const struct pci_device_id *id)
130{
131 int err;
132 struct i5500_temp_data *data;
133
134 data = kzalloc(sizeof(struct i5500_temp_data), GFP_KERNEL);
135 if (!data) {
136 err = -ENOMEM;
137 goto exit;
138 }
139
140 data->name = "intel5500";
141 dev_set_drvdata(&pdev->dev, data);
142
143 err = pci_enable_device(pdev);
144 if (err) {
145 dev_err(&pdev->dev, "Failed to enable device\n");
146 goto exit_free;
147 }
148
149 /* Register sysfs hooks */
150 err = sysfs_create_group(&pdev->dev.kobj, &i5500_temp_group);
151 if (err)
152 goto exit_free;
153
154 data->hwmon_dev = hwmon_device_register(&pdev->dev);
155 if (IS_ERR(data->hwmon_dev)) {
156 err = PTR_ERR(data->hwmon_dev);
157 goto exit_remove;
158 }
159
160 return 0;
161
162 exit_remove:
163 sysfs_remove_group(&pdev->dev.kobj, &i5500_temp_group);
164 exit_free:
165 kfree(data);
166 exit:
167 return err;
168}
169
170static void i5500_temp_remove(struct pci_dev *pdev)
171{
172 struct i5500_temp_data *data = dev_get_drvdata(&pdev->dev);
173
174 hwmon_device_unregister(data->hwmon_dev);
175 sysfs_remove_group(&pdev->dev.kobj, &i5500_temp_group);
176 kfree(data);
177}
178
179static struct pci_driver i5500_temp_driver = {
180 .name = "i5500_temp",
181 .id_table = i5500_temp_ids,
182 .probe = i5500_temp_probe,
183 .remove = i5500_temp_remove,
184};
185
186static int __init i5500_temp_init(void)
187{
188 return pci_register_driver(&i5500_temp_driver);
189}
190
191static void __exit i5500_temp_exit(void)
192{
193 pci_unregister_driver(&i5500_temp_driver);
194}
195
196MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
197MODULE_DESCRIPTION("Intel 5500/5520/X58 chipset thermal sensor driver");
198MODULE_LICENSE("GPL");
199
200module_init(i5500_temp_init)
201module_exit(i5500_temp_exit)