aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-14 20:31:54 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-14 20:31:54 -0400
commit6dc6472581f693b5fc95aebedf67b4960fb85cf0 (patch)
tree06a5a9a08519950575505273eabced331ed51405 /drivers/hwmon
parentee673eaa72d8d185012b1027a05e25aba18c267f (diff)
parent8acd3a60bcca17c6d89c73cee3ad6057eb83ba1e (diff)
Merge commit 'origin'
Manual fixup of conflicts on: arch/powerpc/include/asm/dcr-regs.h drivers/net/ibm_newemac/core.h
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig16
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/abituguru3.c3
-rw-r--r--drivers/hwmon/ad7414.c2
-rw-r--r--drivers/hwmon/atxp1.c18
-rw-r--r--drivers/hwmon/it87.c74
-rw-r--r--drivers/hwmon/max1111.c244
-rw-r--r--drivers/hwmon/ultra45_env.c320
8 files changed, 647 insertions, 32 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index d402e8d813ce..ebacc0af40fe 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -540,6 +540,15 @@ config SENSORS_LM93
540 This driver can also be built as a module. If so, the module 540 This driver can also be built as a module. If so, the module
541 will be called lm93. 541 will be called lm93.
542 542
543config SENSORS_MAX1111
544 tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
545 depends on SPI_MASTER
546 help
547 Say y here to support Maxim's MAX1111 ADC chips.
548
549 This driver can also be built as a module. If so, the module
550 will be called max1111.
551
543config SENSORS_MAX1619 552config SENSORS_MAX1619
544 tristate "Maxim MAX1619 sensor chip" 553 tristate "Maxim MAX1619 sensor chip"
545 depends on I2C 554 depends on I2C
@@ -791,6 +800,13 @@ config SENSORS_W83627EHF
791 This driver can also be built as a module. If so, the module 800 This driver can also be built as a module. If so, the module
792 will be called w83627ehf. 801 will be called w83627ehf.
793 802
803config SENSORS_ULTRA45
804 tristate "Sun Ultra45 PIC16F747"
805 depends on SPARC64
806 help
807 This driver provides support for the Ultra45 workstation environmental
808 sensors.
809
794config SENSORS_HDAPS 810config SENSORS_HDAPS
795 tristate "IBM Hard Drive Active Protection System (hdaps)" 811 tristate "IBM Hard Drive Active Protection System (hdaps)"
796 depends on INPUT && X86 812 depends on INPUT && X86
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 950134ab8426..042d5a78622e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
41obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o 41obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
42obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o 42obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
43obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o 43obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
44obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
44obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o 45obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
45obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o 46obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
46obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o 47obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
@@ -59,6 +60,7 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o
59obj-$(CONFIG_SENSORS_LM90) += lm90.o 60obj-$(CONFIG_SENSORS_LM90) += lm90.o
60obj-$(CONFIG_SENSORS_LM92) += lm92.o 61obj-$(CONFIG_SENSORS_LM92) += lm92.o
61obj-$(CONFIG_SENSORS_LM93) += lm93.o 62obj-$(CONFIG_SENSORS_LM93) += lm93.o
63obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
62obj-$(CONFIG_SENSORS_MAX1619) += max1619.o 64obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
63obj-$(CONFIG_SENSORS_MAX6650) += max6650.o 65obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
64obj-$(CONFIG_SENSORS_PC87360) += pc87360.o 66obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index d568c65c1370..d9e7a49d6cbf 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -279,7 +279,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
279 { "OTES1 Fan", 36, 2, 60, 1, 0 }, 279 { "OTES1 Fan", 36, 2, 60, 1, 0 },
280 { NULL, 0, 0, 0, 0, 0 } } 280 { NULL, 0, 0, 0, 0, 0 } }
281 }, 281 },
282 { 0x0011, NULL /* Abit AT8 32X, need DMI string */, { 282 { 0x0011, "AT8 32X(ATI RD580-ULI M1575)", {
283 { "CPU Core", 0, 0, 10, 1, 0 }, 283 { "CPU Core", 0, 0, 10, 1, 0 },
284 { "DDR", 1, 0, 20, 1, 0 }, 284 { "DDR", 1, 0, 20, 1, 0 },
285 { "DDR VTT", 2, 0, 10, 1, 0 }, 285 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -303,6 +303,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
303 { "SYS Fan", 34, 2, 60, 1, 0 }, 303 { "SYS Fan", 34, 2, 60, 1, 0 },
304 { "AUX1 Fan", 35, 2, 60, 1, 0 }, 304 { "AUX1 Fan", 35, 2, 60, 1, 0 },
305 { "AUX2 Fan", 36, 2, 60, 1, 0 }, 305 { "AUX2 Fan", 36, 2, 60, 1, 0 },
306 { "AUX3 Fan", 37, 2, 60, 1, 0 },
306 { NULL, 0, 0, 0, 0, 0 } } 307 { NULL, 0, 0, 0, 0, 0 } }
307 }, 308 },
308 { 0x0012, NULL /* Abit AN8 32X, need DMI string */, { 309 { 0x0012, NULL /* Abit AN8 32X, need DMI string */, {
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
index ce8d94fbfd7e..bfda8c80ef24 100644
--- a/drivers/hwmon/ad7414.c
+++ b/drivers/hwmon/ad7414.c
@@ -69,7 +69,7 @@ static inline int ad7414_write(struct i2c_client *client, u8 reg, u8 value)
69 return i2c_smbus_write_byte_data(client, reg, value); 69 return i2c_smbus_write_byte_data(client, reg, value);
70} 70}
71 71
72struct ad7414_data *ad7414_update_device(struct device *dev) 72static struct ad7414_data *ad7414_update_device(struct device *dev)
73{ 73{
74 struct i2c_client *client = to_i2c_client(dev); 74 struct i2c_client *client = to_i2c_client(dev);
75 struct ad7414_data *data = i2c_get_clientdata(client); 75 struct ad7414_data *data = i2c_get_clientdata(client);
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index d191118ba0cb..d6b490d3e36f 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -31,7 +31,7 @@
31 31
32MODULE_LICENSE("GPL"); 32MODULE_LICENSE("GPL");
33MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); 33MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
34MODULE_VERSION("0.6.2"); 34MODULE_VERSION("0.6.3");
35MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>"); 35MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
36 36
37#define ATXP1_VID 0x00 37#define ATXP1_VID 0x00
@@ -289,16 +289,16 @@ static int atxp1_detect(struct i2c_client *new_client, int kind,
289 if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && 289 if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
290 (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && 290 (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) &&
291 (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && 291 (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) &&
292 (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) { 292 (i2c_smbus_read_byte_data(new_client, 0xff) == 0)))
293 return -ENODEV;
293 294
294 /* No vendor ID, now checking if registers 0x10,0x11 (non-existent) 295 /* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
295 * showing the same as register 0x00 */ 296 * showing the same as register 0x00 */
296 temp = i2c_smbus_read_byte_data(new_client, 0x00); 297 temp = i2c_smbus_read_byte_data(new_client, 0x00);
297 298
298 if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && 299 if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
299 (i2c_smbus_read_byte_data(new_client, 0x11) == temp) )) 300 (i2c_smbus_read_byte_data(new_client, 0x11) == temp)))
300 return -ENODEV; 301 return -ENODEV;
301 }
302 302
303 /* Get VRM */ 303 /* Get VRM */
304 temp = vid_which_vrm(); 304 temp = vid_which_vrm();
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 30cdb0956779..d793cc011990 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -46,6 +46,8 @@
46#include <linux/err.h> 46#include <linux/err.h>
47#include <linux/mutex.h> 47#include <linux/mutex.h>
48#include <linux/sysfs.h> 48#include <linux/sysfs.h>
49#include <linux/string.h>
50#include <linux/dmi.h>
49#include <asm/io.h> 51#include <asm/io.h>
50 52
51#define DRVNAME "it87" 53#define DRVNAME "it87"
@@ -236,6 +238,8 @@ struct it87_sio_data {
236 /* Values read from Super-I/O config space */ 238 /* Values read from Super-I/O config space */
237 u8 revision; 239 u8 revision;
238 u8 vid_value; 240 u8 vid_value;
241 /* Values set based on DMI strings */
242 u8 skip_pwm;
239}; 243};
240 244
241/* For each registered chip, we need to keep some data in memory. 245/* For each registered chip, we need to keep some data in memory.
@@ -273,10 +277,10 @@ struct it87_data {
273static inline int has_16bit_fans(const struct it87_data *data) 277static inline int has_16bit_fans(const struct it87_data *data)
274{ 278{
275 /* IT8705F Datasheet 0.4.1, 3h == Version G. 279 /* IT8705F Datasheet 0.4.1, 3h == Version G.
276 IT8712F Datasheet 0.9.1, section 8.3.5 indicates 7h == Version I. 280 IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
277 These are the first revisions with 16bit tachometer support. */ 281 These are the first revisions with 16bit tachometer support. */
278 return (data->type == it87 && data->revision >= 0x03) 282 return (data->type == it87 && data->revision >= 0x03)
279 || (data->type == it8712 && data->revision >= 0x07) 283 || (data->type == it8712 && data->revision >= 0x08)
280 || data->type == it8716 284 || data->type == it8716
281 || data->type == it8718; 285 || data->type == it8718;
282} 286}
@@ -964,6 +968,7 @@ static int __init it87_find(unsigned short *address,
964{ 968{
965 int err = -ENODEV; 969 int err = -ENODEV;
966 u16 chip_type; 970 u16 chip_type;
971 const char *board_vendor, *board_name;
967 972
968 superio_enter(); 973 superio_enter();
969 chip_type = force_id ? force_id : superio_inw(DEVID); 974 chip_type = force_id ? force_id : superio_inw(DEVID);
@@ -1022,6 +1027,24 @@ static int __init it87_find(unsigned short *address,
1022 pr_info("it87: in7 is VCCH (+5V Stand-By)\n"); 1027 pr_info("it87: in7 is VCCH (+5V Stand-By)\n");
1023 } 1028 }
1024 1029
1030 /* Disable specific features based on DMI strings */
1031 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
1032 board_name = dmi_get_system_info(DMI_BOARD_NAME);
1033 if (board_vendor && board_name) {
1034 if (strcmp(board_vendor, "nVIDIA") == 0
1035 && strcmp(board_name, "FN68PT") == 0) {
1036 /* On the Shuttle SN68PT, FAN_CTL2 is apparently not
1037 connected to a fan, but to something else. One user
1038 has reported instant system power-off when changing
1039 the PWM2 duty cycle, so we disable it.
1040 I use the board name string as the trigger in case
1041 the same board is ever used in other systems. */
1042 pr_info("it87: Disabling pwm2 due to "
1043 "hardware constraints\n");
1044 sio_data->skip_pwm = (1 << 1);
1045 }
1046 }
1047
1025exit: 1048exit:
1026 superio_exit(); 1049 superio_exit();
1027 return err; 1050 return err;
@@ -1168,25 +1191,33 @@ static int __devinit it87_probe(struct platform_device *pdev)
1168 } 1191 }
1169 1192
1170 if (enable_pwm_interface) { 1193 if (enable_pwm_interface) {
1171 if ((err = device_create_file(dev, 1194 if (!(sio_data->skip_pwm & (1 << 0))) {
1172 &sensor_dev_attr_pwm1_enable.dev_attr)) 1195 if ((err = device_create_file(dev,
1173 || (err = device_create_file(dev, 1196 &sensor_dev_attr_pwm1_enable.dev_attr))
1174 &sensor_dev_attr_pwm2_enable.dev_attr)) 1197 || (err = device_create_file(dev,
1175 || (err = device_create_file(dev, 1198 &sensor_dev_attr_pwm1.dev_attr))
1176 &sensor_dev_attr_pwm3_enable.dev_attr)) 1199 || (err = device_create_file(dev,
1177 || (err = device_create_file(dev, 1200 &dev_attr_pwm1_freq)))
1178 &sensor_dev_attr_pwm1.dev_attr)) 1201 goto ERROR4;
1179 || (err = device_create_file(dev, 1202 }
1180 &sensor_dev_attr_pwm2.dev_attr)) 1203 if (!(sio_data->skip_pwm & (1 << 1))) {
1181 || (err = device_create_file(dev, 1204 if ((err = device_create_file(dev,
1182 &sensor_dev_attr_pwm3.dev_attr)) 1205 &sensor_dev_attr_pwm2_enable.dev_attr))
1183 || (err = device_create_file(dev, 1206 || (err = device_create_file(dev,
1184 &dev_attr_pwm1_freq)) 1207 &sensor_dev_attr_pwm2.dev_attr))
1185 || (err = device_create_file(dev, 1208 || (err = device_create_file(dev,
1186 &dev_attr_pwm2_freq)) 1209 &dev_attr_pwm2_freq)))
1187 || (err = device_create_file(dev, 1210 goto ERROR4;
1188 &dev_attr_pwm3_freq))) 1211 }
1189 goto ERROR4; 1212 if (!(sio_data->skip_pwm & (1 << 2))) {
1213 if ((err = device_create_file(dev,
1214 &sensor_dev_attr_pwm3_enable.dev_attr))
1215 || (err = device_create_file(dev,
1216 &sensor_dev_attr_pwm3.dev_attr))
1217 || (err = device_create_file(dev,
1218 &dev_attr_pwm3_freq)))
1219 goto ERROR4;
1220 }
1190 } 1221 }
1191 1222
1192 if (data->type == it8712 || data->type == it8716 1223 if (data->type == it8712 || data->type == it8716
@@ -1546,6 +1577,7 @@ static int __init sm_it87_init(void)
1546 unsigned short isa_address=0; 1577 unsigned short isa_address=0;
1547 struct it87_sio_data sio_data; 1578 struct it87_sio_data sio_data;
1548 1579
1580 memset(&sio_data, 0, sizeof(struct it87_sio_data));
1549 err = it87_find(&isa_address, &sio_data); 1581 err = it87_find(&isa_address, &sio_data);
1550 if (err) 1582 if (err)
1551 return err; 1583 return err;
diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c
new file mode 100644
index 000000000000..bfaa665ccf32
--- /dev/null
+++ b/drivers/hwmon/max1111.c
@@ -0,0 +1,244 @@
1/*
2 * max1111.c - +2.7V, Low-Power, Multichannel, Serial 8-bit ADCs
3 *
4 * Based on arch/arm/mach-pxa/corgi_ssp.c
5 *
6 * Copyright (C) 2004-2005 Richard Purdie
7 *
8 * Copyright (C) 2008 Marvell International Ltd.
9 * Eric Miao <eric.miao@marvell.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * publishhed by the Free Software Foundation.
14 */
15
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/err.h>
20#include <linux/hwmon.h>
21#include <linux/hwmon-sysfs.h>
22#include <linux/spi/spi.h>
23
24#define MAX1111_TX_BUF_SIZE 1
25#define MAX1111_RX_BUF_SIZE 2
26
27/* MAX1111 Commands */
28#define MAX1111_CTRL_PD0 (1u << 0)
29#define MAX1111_CTRL_PD1 (1u << 1)
30#define MAX1111_CTRL_SGL (1u << 2)
31#define MAX1111_CTRL_UNI (1u << 3)
32#define MAX1111_CTRL_SEL_SH (5) /* NOTE: bit 4 is ignored */
33#define MAX1111_CTRL_STR (1u << 7)
34
35struct max1111_data {
36 struct spi_device *spi;
37 struct device *hwmon_dev;
38 struct spi_message msg;
39 struct spi_transfer xfer[2];
40 uint8_t *tx_buf;
41 uint8_t *rx_buf;
42};
43
44static int max1111_read(struct device *dev, int channel)
45{
46 struct max1111_data *data = dev_get_drvdata(dev);
47 uint8_t v1, v2;
48 int err;
49
50 data->tx_buf[0] = (channel << MAX1111_CTRL_SEL_SH) |
51 MAX1111_CTRL_PD0 | MAX1111_CTRL_PD1 |
52 MAX1111_CTRL_SGL | MAX1111_CTRL_UNI | MAX1111_CTRL_STR;
53
54 err = spi_sync(data->spi, &data->msg);
55 if (err < 0) {
56 dev_err(dev, "spi_sync failed with %d\n", err);
57 return err;
58 }
59
60 v1 = data->rx_buf[0];
61 v2 = data->rx_buf[1];
62
63 if ((v1 & 0xc0) || (v2 & 0x3f))
64 return -EINVAL;
65
66 return (v1 << 2) | (v2 >> 6);
67}
68
69#ifdef CONFIG_SHARPSL_PM
70static struct max1111_data *the_max1111;
71
72int max1111_read_channel(int channel)
73{
74 return max1111_read(&the_max1111->spi->dev, channel);
75}
76EXPORT_SYMBOL(max1111_read_channel);
77#endif
78
79/*
80 * NOTE: SPI devices do not have a default 'name' attribute, which is
81 * likely to be used by hwmon applications to distinguish between
82 * different devices, explicitly add a name attribute here.
83 */
84static ssize_t show_name(struct device *dev,
85 struct device_attribute *attr, char *buf)
86{
87 return sprintf(buf, "max1111\n");
88}
89
90static ssize_t show_adc(struct device *dev,
91 struct device_attribute *attr, char *buf)
92{
93 int channel = to_sensor_dev_attr(attr)->index;
94 int ret;
95
96 ret = max1111_read(dev, channel);
97 if (ret < 0)
98 return ret;
99
100 return sprintf(buf, "%d\n", ret);
101}
102
103#define MAX1111_ADC_ATTR(_id) \
104 SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id)
105
106static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
107static MAX1111_ADC_ATTR(0);
108static MAX1111_ADC_ATTR(1);
109static MAX1111_ADC_ATTR(2);
110static MAX1111_ADC_ATTR(3);
111
112static struct attribute *max1111_attributes[] = {
113 &dev_attr_name.attr,
114 &sensor_dev_attr_adc0_in.dev_attr.attr,
115 &sensor_dev_attr_adc1_in.dev_attr.attr,
116 &sensor_dev_attr_adc2_in.dev_attr.attr,
117 &sensor_dev_attr_adc3_in.dev_attr.attr,
118 NULL,
119};
120
121static const struct attribute_group max1111_attr_group = {
122 .attrs = max1111_attributes,
123};
124
125static int setup_transfer(struct max1111_data *data)
126{
127 struct spi_message *m;
128 struct spi_transfer *x;
129
130 data->tx_buf = kmalloc(MAX1111_TX_BUF_SIZE, GFP_KERNEL);
131 if (!data->tx_buf)
132 return -ENOMEM;
133
134 data->rx_buf = kmalloc(MAX1111_RX_BUF_SIZE, GFP_KERNEL);
135 if (!data->rx_buf) {
136 kfree(data->tx_buf);
137 return -ENOMEM;
138 }
139
140 m = &data->msg;
141 x = &data->xfer[0];
142
143 spi_message_init(m);
144
145 x->tx_buf = &data->tx_buf[0];
146 x->len = 1;
147 spi_message_add_tail(x, m);
148
149 x++;
150 x->rx_buf = &data->rx_buf[0];
151 x->len = 2;
152 spi_message_add_tail(x, m);
153
154 return 0;
155}
156
157static int __devinit max1111_probe(struct spi_device *spi)
158{
159 struct max1111_data *data;
160 int err;
161
162 spi->bits_per_word = 8;
163 spi->mode = SPI_MODE_0;
164 err = spi_setup(spi);
165 if (err < 0)
166 return err;
167
168 data = kzalloc(sizeof(struct max1111_data), GFP_KERNEL);
169 if (data == NULL) {
170 dev_err(&spi->dev, "failed to allocate memory\n");
171 return -ENOMEM;
172 }
173
174 err = setup_transfer(data);
175 if (err)
176 goto err_free_data;
177
178 data->spi = spi;
179 spi_set_drvdata(spi, data);
180
181 err = sysfs_create_group(&spi->dev.kobj, &max1111_attr_group);
182 if (err) {
183 dev_err(&spi->dev, "failed to create attribute group\n");
184 goto err_free_all;
185 }
186
187 data->hwmon_dev = hwmon_device_register(&spi->dev);
188 if (IS_ERR(data->hwmon_dev)) {
189 dev_err(&spi->dev, "failed to create hwmon device\n");
190 err = PTR_ERR(data->hwmon_dev);
191 goto err_remove;
192 }
193
194#ifdef CONFIG_SHARPSL_PM
195 the_max1111 = data;
196#endif
197 return 0;
198
199err_remove:
200 sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
201err_free_all:
202 kfree(data->rx_buf);
203 kfree(data->tx_buf);
204err_free_data:
205 kfree(data);
206 return err;
207}
208
209static int __devexit max1111_remove(struct spi_device *spi)
210{
211 struct max1111_data *data = spi_get_drvdata(spi);
212
213 hwmon_device_unregister(data->hwmon_dev);
214 sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
215 kfree(data->rx_buf);
216 kfree(data->tx_buf);
217 kfree(data);
218 return 0;
219}
220
221static struct spi_driver max1111_driver = {
222 .driver = {
223 .name = "max1111",
224 .owner = THIS_MODULE,
225 },
226 .probe = max1111_probe,
227 .remove = __devexit_p(max1111_remove),
228};
229
230static int __init max1111_init(void)
231{
232 return spi_register_driver(&max1111_driver);
233}
234module_init(max1111_init);
235
236static void __exit max1111_exit(void)
237{
238 spi_unregister_driver(&max1111_driver);
239}
240module_exit(max1111_exit);
241
242MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
243MODULE_DESCRIPTION("MAX1111 ADC Driver");
244MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
new file mode 100644
index 000000000000..68e90abeba96
--- /dev/null
+++ b/drivers/hwmon/ultra45_env.c
@@ -0,0 +1,320 @@
1/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor.
2 *
3 * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
4 */
5
6#include <linux/kernel.h>
7#include <linux/types.h>
8#include <linux/slab.h>
9#include <linux/of_device.h>
10#include <linux/io.h>
11#include <linux/hwmon.h>
12#include <linux/hwmon-sysfs.h>
13
14#define DRV_MODULE_VERSION "0.1"
15
16MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
17MODULE_DESCRIPTION("Ultra45 environmental monitor driver");
18MODULE_LICENSE("GPL");
19MODULE_VERSION(DRV_MODULE_VERSION);
20
21/* PIC device registers */
22#define REG_CMD 0x00UL
23#define REG_CMD_RESET 0x80
24#define REG_CMD_ESTAR 0x01
25#define REG_STAT 0x01UL
26#define REG_STAT_FWVER 0xf0
27#define REG_STAT_TGOOD 0x08
28#define REG_STAT_STALE 0x04
29#define REG_STAT_BUSY 0x02
30#define REG_STAT_FAULT 0x01
31#define REG_DATA 0x40UL
32#define REG_ADDR 0x41UL
33#define REG_SIZE 0x42UL
34
35/* Registers accessed indirectly via REG_DATA/REG_ADDR */
36#define IREG_FAN0 0x00
37#define IREG_FAN1 0x01
38#define IREG_FAN2 0x02
39#define IREG_FAN3 0x03
40#define IREG_FAN4 0x04
41#define IREG_FAN5 0x05
42#define IREG_LCL_TEMP 0x06
43#define IREG_RMT1_TEMP 0x07
44#define IREG_RMT2_TEMP 0x08
45#define IREG_RMT3_TEMP 0x09
46#define IREG_LM95221_TEMP 0x0a
47#define IREG_FIRE_TEMP 0x0b
48#define IREG_LSI1064_TEMP 0x0c
49#define IREG_FRONT_TEMP 0x0d
50#define IREG_FAN_STAT 0x0e
51#define IREG_VCORE0 0x0f
52#define IREG_VCORE1 0x10
53#define IREG_VMEM0 0x11
54#define IREG_VMEM1 0x12
55#define IREG_PSU_TEMP 0x13
56
57struct env {
58 void __iomem *regs;
59 spinlock_t lock;
60
61 struct device *hwmon_dev;
62};
63
64static u8 env_read(struct env *p, u8 ireg)
65{
66 u8 ret;
67
68 spin_lock(&p->lock);
69 writeb(ireg, p->regs + REG_ADDR);
70 ret = readb(p->regs + REG_DATA);
71 spin_unlock(&p->lock);
72
73 return ret;
74}
75
76static void env_write(struct env *p, u8 ireg, u8 val)
77{
78 spin_lock(&p->lock);
79 writeb(ireg, p->regs + REG_ADDR);
80 writeb(val, p->regs + REG_DATA);
81 spin_unlock(&p->lock);
82}
83
84/* There seems to be a adr7462 providing these values, thus a lot
85 * of these calculations are borrowed from the adt7470 driver.
86 */
87#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x))
88#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM
89#define FAN_PERIOD_INVALID (0xff << 8)
90#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
91
92static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf)
93{
94 int fan_nr = to_sensor_dev_attr(attr)->index;
95 struct env *p = dev_get_drvdata(dev);
96 int rpm, period;
97 u8 val;
98
99 val = env_read(p, IREG_FAN0 + fan_nr);
100 period = (int) val << 8;
101 if (FAN_DATA_VALID(period))
102 rpm = FAN_PERIOD_TO_RPM(period);
103 else
104 rpm = 0;
105
106 return sprintf(buf, "%d\n", rpm);
107}
108
109static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr,
110 const char *buf, size_t count)
111{
112 int fan_nr = to_sensor_dev_attr(attr)->index;
113 int rpm = simple_strtol(buf, NULL, 10);
114 struct env *p = dev_get_drvdata(dev);
115 int period;
116 u8 val;
117
118 if (!rpm)
119 return -EINVAL;
120
121 period = FAN_RPM_TO_PERIOD(rpm);
122 val = period >> 8;
123 env_write(p, IREG_FAN0 + fan_nr, val);
124
125 return count;
126}
127
128static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, char *buf)
129{
130 int fan_nr = to_sensor_dev_attr(attr)->index;
131 struct env *p = dev_get_drvdata(dev);
132 u8 val = env_read(p, IREG_FAN_STAT);
133 return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0);
134}
135
136#define fan(index) \
137static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR, \
138 show_fan_speed, set_fan_speed, index); \
139static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, \
140 show_fan_fault, NULL, index)
141
142fan(0);
143fan(1);
144fan(2);
145fan(3);
146fan(4);
147
148static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6);
149
150static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
151{
152 int temp_nr = to_sensor_dev_attr(attr)->index;
153 struct env *p = dev_get_drvdata(dev);
154 s8 val;
155
156 val = env_read(p, IREG_LCL_TEMP + temp_nr);
157 return sprintf(buf, "%d\n", ((int) val) - 64);
158}
159
160static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0);
161static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1);
162static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2);
163static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3);
164static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4);
165static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5);
166static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6);
167static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7);
168static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13);
169
170static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, char *buf)
171{
172 int index = to_sensor_dev_attr(attr)->index;
173 struct env *p = dev_get_drvdata(dev);
174 u8 val;
175
176 val = readb(p->regs + REG_STAT);
177 return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0);
178}
179
180static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0);
181static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1);
182static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2);
183static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, 3);
184
185static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, char *buf)
186{
187 struct env *p = dev_get_drvdata(dev);
188 u8 val;
189
190 val = readb(p->regs + REG_STAT);
191 return sprintf(buf, "%d\n", val >> 4);
192}
193
194static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0);
195
196static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
197{
198 return sprintf(buf, "ultra45\n");
199}
200
201static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
202
203static struct attribute *env_attributes[] = {
204 &sensor_dev_attr_fan0_speed.dev_attr.attr,
205 &sensor_dev_attr_fan0_fault.dev_attr.attr,
206 &sensor_dev_attr_fan1_speed.dev_attr.attr,
207 &sensor_dev_attr_fan1_fault.dev_attr.attr,
208 &sensor_dev_attr_fan2_speed.dev_attr.attr,
209 &sensor_dev_attr_fan2_fault.dev_attr.attr,
210 &sensor_dev_attr_fan3_speed.dev_attr.attr,
211 &sensor_dev_attr_fan3_fault.dev_attr.attr,
212 &sensor_dev_attr_fan4_speed.dev_attr.attr,
213 &sensor_dev_attr_fan4_fault.dev_attr.attr,
214 &sensor_dev_attr_psu_fan_fault.dev_attr.attr,
215 &sensor_dev_attr_adt7462_local_temp.dev_attr.attr,
216 &sensor_dev_attr_cpu0_temp.dev_attr.attr,
217 &sensor_dev_attr_cpu1_temp.dev_attr.attr,
218 &sensor_dev_attr_motherboard_temp.dev_attr.attr,
219 &sensor_dev_attr_lm95221_local_temp.dev_attr.attr,
220 &sensor_dev_attr_fire_temp.dev_attr.attr,
221 &sensor_dev_attr_lsi1064_local_temp.dev_attr.attr,
222 &sensor_dev_attr_front_panel_temp.dev_attr.attr,
223 &sensor_dev_attr_psu_temp.dev_attr.attr,
224 &sensor_dev_attr_fan_failure.dev_attr.attr,
225 &sensor_dev_attr_env_bus_busy.dev_attr.attr,
226 &sensor_dev_attr_env_data_stale.dev_attr.attr,
227 &sensor_dev_attr_tpm_self_test_passed.dev_attr.attr,
228 &sensor_dev_attr_firmware_version.dev_attr.attr,
229 &sensor_dev_attr_name.dev_attr.attr,
230 NULL,
231};
232
233static const struct attribute_group env_group = {
234 .attrs = env_attributes,
235};
236
237static int __devinit env_probe(struct of_device *op,
238 const struct of_device_id *match)
239{
240 struct env *p = kzalloc(sizeof(*p), GFP_KERNEL);
241 int err = -ENOMEM;
242
243 if (!p)
244 goto out;
245
246 spin_lock_init(&p->lock);
247
248 p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747");
249 if (!p->regs)
250 goto out_free;
251
252 err = sysfs_create_group(&op->dev.kobj, &env_group);
253 if (err)
254 goto out_iounmap;
255
256 p->hwmon_dev = hwmon_device_register(&op->dev);
257 if (IS_ERR(p->hwmon_dev)) {
258 err = PTR_ERR(p->hwmon_dev);
259 goto out_sysfs_remove_group;
260 }
261
262 dev_set_drvdata(&op->dev, p);
263 err = 0;
264
265out:
266 return err;
267
268out_sysfs_remove_group:
269 sysfs_remove_group(&op->dev.kobj, &env_group);
270
271out_iounmap:
272 of_iounmap(&op->resource[0], p->regs, REG_SIZE);
273
274out_free:
275 kfree(p);
276 goto out;
277}
278
279static int __devexit env_remove(struct of_device *op)
280{
281 struct env *p = dev_get_drvdata(&op->dev);
282
283 if (p) {
284 sysfs_remove_group(&op->dev.kobj, &env_group);
285 hwmon_device_unregister(p->hwmon_dev);
286 of_iounmap(&op->resource[0], p->regs, REG_SIZE);
287 kfree(p);
288 }
289
290 return 0;
291}
292
293static const struct of_device_id env_match[] = {
294 {
295 .name = "env-monitor",
296 .compatible = "SUNW,ebus-pic16f747-env",
297 },
298 {},
299};
300MODULE_DEVICE_TABLE(of, env_match);
301
302static struct of_platform_driver env_driver = {
303 .name = "ultra45_env",
304 .match_table = env_match,
305 .probe = env_probe,
306 .remove = __devexit_p(env_remove),
307};
308
309static int __init env_init(void)
310{
311 return of_register_driver(&env_driver, &of_bus_type);
312}
313
314static void __exit env_exit(void)
315{
316 of_unregister_driver(&env_driver);
317}
318
319module_init(env_init);
320module_exit(env_exit);