diff options
author | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-03-09 01:01:39 -0500 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-05-19 11:19:40 -0400 |
commit | 0c0a0615163e025eb978547969467012529e01d5 (patch) | |
tree | 5a30c5a7ba79426be50c8bb573fe3784badc1aa4 | |
parent | 84fc4585c152f34a1a90a03b7abb88a2e1218a42 (diff) |
hwmon: (pmbus) Support for TI UCD90xxx series Sequencer and System Health Controllers
Hardware monitoring support for TI UCD90120, UCD90124, UCD9090, and UCD90910
Sequencer and System Health Controllers.
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Reviewed-by: Tom Grennan <tom.grennan@ericsson.com>
-rw-r--r-- | Documentation/hwmon/ucd9000 | 110 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 14 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/ucd9000.c | 278 |
4 files changed, 402 insertions, 1 deletions
diff --git a/Documentation/hwmon/ucd9000 b/Documentation/hwmon/ucd9000 new file mode 100644 index 000000000000..40ca6db50c48 --- /dev/null +++ b/Documentation/hwmon/ucd9000 | |||
@@ -0,0 +1,110 @@ | |||
1 | Kernel driver ucd9000 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * TI UCD90120, UCD90124, UCD9090, and UCD90910 | ||
6 | Prefixes: 'ucd90120', 'ucd90124', 'ucd9090', 'ucd90910' | ||
7 | Addresses scanned: - | ||
8 | Datasheets: | ||
9 | http://focus.ti.com/lit/ds/symlink/ucd90120.pdf | ||
10 | http://focus.ti.com/lit/ds/symlink/ucd90124.pdf | ||
11 | http://focus.ti.com/lit/ds/symlink/ucd9090.pdf | ||
12 | http://focus.ti.com/lit/ds/symlink/ucd90910.pdf | ||
13 | |||
14 | Author: Guenter Roeck <guenter.roeck@ericsson.com> | ||
15 | |||
16 | |||
17 | Description | ||
18 | ----------- | ||
19 | |||
20 | From datasheets: | ||
21 | |||
22 | The UCD90120 Power Supply Sequencer and System Health Monitor monitors and | ||
23 | sequences up to 12 independent voltage rails. The device integrates a 12-bit | ||
24 | ADC with a 2.5V internal reference for monitoring up to 13 power supply voltage, | ||
25 | current, or temperature inputs. | ||
26 | |||
27 | The UCD90124 is a 12-rail PMBus/I2C addressable power-supply sequencer and | ||
28 | system-health monitor. The device integrates a 12-bit ADC for monitoring up to | ||
29 | 13 power-supply voltage, current, or temperature inputs. Twenty-six GPIO pins | ||
30 | can be used for power supply enables, power-on reset signals, external | ||
31 | interrupts, cascading, or other system functions. Twelve of these pins offer PWM | ||
32 | functionality. Using these pins, the UCD90124 offers support for fan control, | ||
33 | margining, and general-purpose PWM functions. | ||
34 | |||
35 | The UCD9090 is a 10-rail PMBus/I2C addressable power-supply sequencer and | ||
36 | monitor. The device integrates a 12-bit ADC for monitoring up to 10 power-supply | ||
37 | voltage inputs. Twenty-three GPIO pins can be used for power supply enables, | ||
38 | power-on reset signals, external interrupts, cascading, or other system | ||
39 | functions. Ten of these pins offer PWM functionality. Using these pins, the | ||
40 | UCD9090 offers support for margining, and general-purpose PWM functions. | ||
41 | |||
42 | The UCD90910 is a ten-rail I2C / PMBus addressable power-supply sequencer and | ||
43 | system-health monitor. The device integrates a 12-bit ADC for monitoring up to | ||
44 | 13 power-supply voltage, current, or temperature inputs. | ||
45 | |||
46 | This driver is a client driver to the core PMBus driver. Please see | ||
47 | Documentation/hwmon/pmbus for details on PMBus client drivers. | ||
48 | |||
49 | |||
50 | Usage Notes | ||
51 | ----------- | ||
52 | |||
53 | This driver does not auto-detect devices. You will have to instantiate the | ||
54 | devices explicitly. Please see Documentation/i2c/instantiating-devices for | ||
55 | details. | ||
56 | |||
57 | |||
58 | Platform data support | ||
59 | --------------------- | ||
60 | |||
61 | The driver supports standard PMBus driver platform data. Please see | ||
62 | Documentation/hwmon/pmbus for details. | ||
63 | |||
64 | |||
65 | Sysfs entries | ||
66 | ------------- | ||
67 | |||
68 | The following attributes are supported. Limits are read-write; all other | ||
69 | attributes are read-only. | ||
70 | |||
71 | in[1-12]_label "vout[1-12]". | ||
72 | in[1-12]_input Measured voltage. From READ_VOUT register. | ||
73 | in[1-12]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. | ||
74 | in[1-12]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. | ||
75 | in[1-12]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. | ||
76 | in[1-12]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. | ||
77 | in[1-12]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. | ||
78 | in[1-12]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. | ||
79 | in[1-12]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. | ||
80 | in[1-12]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. | ||
81 | |||
82 | curr[1-12]_label "iout[1-12]". | ||
83 | curr[1-12]_input Measured current. From READ_IOUT register. | ||
84 | curr[1-12]_max Maximum current. From IOUT_OC_WARN_LIMIT register. | ||
85 | curr[1-12]_lcrit Critical minumum output current. From IOUT_UC_FAULT_LIMIT | ||
86 | register. | ||
87 | curr[1-12]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. | ||
88 | curr[1-12]_max_alarm Current high alarm. From IOUT_OC_WARNING status. | ||
89 | curr[1-12]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status. | ||
90 | |||
91 | For each attribute index, either voltage or current is | ||
92 | reported, but not both. If voltage or current is | ||
93 | reported depends on the chip configuration. | ||
94 | |||
95 | temp[1-2]_input Measured temperatures. From READ_TEMPERATURE_1 and | ||
96 | READ_TEMPERATURE_2 registers. | ||
97 | temp[1-2]_max Maximum temperature. From OT_WARN_LIMIT register. | ||
98 | temp[1-2]_crit Critical high temperature. From OT_FAULT_LIMIT register. | ||
99 | temp[1-2]_max_alarm Temperature high alarm. | ||
100 | temp[1-2]_crit_alarm Temperature critical high alarm. | ||
101 | |||
102 | fan[1-4]_input Fan RPM. | ||
103 | fan[1-4]_alarm Fan alarm. | ||
104 | fan[1-4]_fault Fan fault. | ||
105 | |||
106 | Fan attributes are only available on chips supporting | ||
107 | fan control (UCD90124, UCD90910). Attribute files are | ||
108 | created only for enabled fans. | ||
109 | Note that even though UCD90910 supports up to 10 fans, | ||
110 | only up to four fans are currently supported. | ||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 07c4a860dffe..d00fd39f6ee3 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -857,12 +857,24 @@ config SENSORS_MAX8688 | |||
857 | This driver can also be built as a module. If so, the module will | 857 | This driver can also be built as a module. If so, the module will |
858 | be called max8688. | 858 | be called max8688. |
859 | 859 | ||
860 | config SENSORS_UCD9000 | ||
861 | tristate "TI UCD90120, UCD90124, UCD9090, UCD90910" | ||
862 | default n | ||
863 | help | ||
864 | If you say yes here you get hardware monitoring support for TI | ||
865 | UCD90120, UCD90124, UCD9090, UCD90910 Sequencer and System Health | ||
866 | Controllers. | ||
867 | |||
868 | This driver can also be built as a module. If so, the module will | ||
869 | be called ucd9000. | ||
870 | |||
860 | config SENSORS_UCD9200 | 871 | config SENSORS_UCD9200 |
861 | tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248" | 872 | tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248" |
862 | default n | 873 | default n |
863 | help | 874 | help |
864 | If you say yes here you get hardware monitoring support for TI | 875 | If you say yes here you get hardware monitoring support for TI |
865 | UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248. | 876 | UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248 |
877 | Digital PWM System Controllers. | ||
866 | 878 | ||
867 | This driver can also be built as a module. If so, the module will | 879 | This driver can also be built as a module. If so, the module will |
868 | be called ucd9200. | 880 | be called ucd9200. |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 1afe02961dec..c4a269b06925 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -123,6 +123,7 @@ obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o | |||
123 | obj-$(CONFIG_SENSORS_MAX16064) += max16064.o | 123 | obj-$(CONFIG_SENSORS_MAX16064) += max16064.o |
124 | obj-$(CONFIG_SENSORS_MAX34440) += max34440.o | 124 | obj-$(CONFIG_SENSORS_MAX34440) += max34440.o |
125 | obj-$(CONFIG_SENSORS_MAX8688) += max8688.o | 125 | obj-$(CONFIG_SENSORS_MAX8688) += max8688.o |
126 | obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o | ||
126 | obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o | 127 | obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o |
127 | 128 | ||
128 | ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG | 129 | ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG |
diff --git a/drivers/hwmon/ucd9000.c b/drivers/hwmon/ucd9000.c new file mode 100644 index 000000000000..ace1c7319734 --- /dev/null +++ b/drivers/hwmon/ucd9000.c | |||
@@ -0,0 +1,278 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for UCD90xxx Sequencer and System Health | ||
3 | * Controller series | ||
4 | * | ||
5 | * Copyright (C) 2011 Ericsson AB. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/i2c/pmbus.h> | ||
29 | #include "pmbus.h" | ||
30 | |||
31 | enum chips { ucd9000, ucd90120, ucd90124, ucd9090, ucd90910 }; | ||
32 | |||
33 | #define UCD9000_MONITOR_CONFIG 0xd5 | ||
34 | #define UCD9000_NUM_PAGES 0xd6 | ||
35 | #define UCD9000_FAN_CONFIG_INDEX 0xe7 | ||
36 | #define UCD9000_FAN_CONFIG 0xe8 | ||
37 | #define UCD9000_DEVICE_ID 0xfd | ||
38 | |||
39 | #define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) | ||
40 | #define UCD9000_MON_PAGE(x) ((x) & 0x0f) | ||
41 | |||
42 | #define UCD9000_MON_VOLTAGE 1 | ||
43 | #define UCD9000_MON_TEMPERATURE 2 | ||
44 | #define UCD9000_MON_CURRENT 3 | ||
45 | #define UCD9000_MON_VOLTAGE_HW 4 | ||
46 | |||
47 | #define UCD9000_NUM_FAN 4 | ||
48 | |||
49 | struct ucd9000_data { | ||
50 | u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; | ||
51 | struct pmbus_driver_info info; | ||
52 | }; | ||
53 | #define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) | ||
54 | |||
55 | static int ucd9000_get_fan_config(struct i2c_client *client, int fan) | ||
56 | { | ||
57 | int fan_config = 0; | ||
58 | struct ucd9000_data *data | ||
59 | = to_ucd9000_data(pmbus_get_driver_info(client)); | ||
60 | |||
61 | if (data->fan_data[fan][3] & 1) | ||
62 | fan_config |= PB_FAN_2_INSTALLED; /* Use lower bit position */ | ||
63 | |||
64 | /* Pulses/revolution */ | ||
65 | fan_config |= (data->fan_data[fan][3] & 0x06) >> 1; | ||
66 | |||
67 | return fan_config; | ||
68 | } | ||
69 | |||
70 | static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) | ||
71 | { | ||
72 | int ret = 0; | ||
73 | int fan_config; | ||
74 | |||
75 | switch (reg) { | ||
76 | case PMBUS_FAN_CONFIG_12: | ||
77 | if (page) | ||
78 | return -EINVAL; | ||
79 | |||
80 | ret = ucd9000_get_fan_config(client, 0); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | fan_config = ret << 4; | ||
84 | ret = ucd9000_get_fan_config(client, 1); | ||
85 | if (ret < 0) | ||
86 | return ret; | ||
87 | fan_config |= ret; | ||
88 | ret = fan_config; | ||
89 | break; | ||
90 | case PMBUS_FAN_CONFIG_34: | ||
91 | if (page) | ||
92 | return -EINVAL; | ||
93 | |||
94 | ret = ucd9000_get_fan_config(client, 2); | ||
95 | if (ret < 0) | ||
96 | return ret; | ||
97 | fan_config = ret << 4; | ||
98 | ret = ucd9000_get_fan_config(client, 3); | ||
99 | if (ret < 0) | ||
100 | return ret; | ||
101 | fan_config |= ret; | ||
102 | ret = fan_config; | ||
103 | break; | ||
104 | default: | ||
105 | ret = -ENODATA; | ||
106 | break; | ||
107 | } | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static const struct i2c_device_id ucd9000_id[] = { | ||
112 | {"ucd9000", ucd9000}, | ||
113 | {"ucd90120", ucd90120}, | ||
114 | {"ucd90124", ucd90124}, | ||
115 | {"ucd9090", ucd9090}, | ||
116 | {"ucd90910", ucd90910}, | ||
117 | {} | ||
118 | }; | ||
119 | MODULE_DEVICE_TABLE(i2c, ucd9000_id); | ||
120 | |||
121 | static int ucd9000_probe(struct i2c_client *client, | ||
122 | const struct i2c_device_id *id) | ||
123 | { | ||
124 | u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; | ||
125 | struct ucd9000_data *data; | ||
126 | struct pmbus_driver_info *info; | ||
127 | const struct i2c_device_id *mid; | ||
128 | int i, ret; | ||
129 | |||
130 | if (!i2c_check_functionality(client->adapter, | ||
131 | I2C_FUNC_SMBUS_BYTE_DATA | | ||
132 | I2C_FUNC_SMBUS_BLOCK_DATA)) | ||
133 | return -ENODEV; | ||
134 | |||
135 | ret = i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID, | ||
136 | block_buffer); | ||
137 | if (ret < 0) { | ||
138 | dev_err(&client->dev, "Failed to read device ID\n"); | ||
139 | return ret; | ||
140 | } | ||
141 | block_buffer[ret] = '\0'; | ||
142 | dev_info(&client->dev, "Device ID %s\n", block_buffer); | ||
143 | |||
144 | mid = NULL; | ||
145 | for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) { | ||
146 | mid = &ucd9000_id[i]; | ||
147 | if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) | ||
148 | break; | ||
149 | } | ||
150 | if (!mid || !strlen(mid->name)) { | ||
151 | dev_err(&client->dev, "Unsupported device\n"); | ||
152 | return -ENODEV; | ||
153 | } | ||
154 | |||
155 | if (id->driver_data != ucd9000 && id->driver_data != mid->driver_data) | ||
156 | dev_notice(&client->dev, | ||
157 | "Device mismatch: Configured %s, detected %s\n", | ||
158 | id->name, mid->name); | ||
159 | |||
160 | data = kzalloc(sizeof(struct ucd9000_data), GFP_KERNEL); | ||
161 | if (!data) | ||
162 | return -ENOMEM; | ||
163 | info = &data->info; | ||
164 | |||
165 | ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES); | ||
166 | if (ret < 0) { | ||
167 | dev_err(&client->dev, | ||
168 | "Failed to read number of active pages\n"); | ||
169 | goto out; | ||
170 | } | ||
171 | info->pages = ret; | ||
172 | if (!info->pages) { | ||
173 | dev_err(&client->dev, "No pages configured\n"); | ||
174 | ret = -ENODEV; | ||
175 | goto out; | ||
176 | } | ||
177 | |||
178 | /* The internal temperature sensor is always active */ | ||
179 | info->func[0] = PMBUS_HAVE_TEMP; | ||
180 | |||
181 | /* Everything else is configurable */ | ||
182 | ret = i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG, | ||
183 | block_buffer); | ||
184 | if (ret <= 0) { | ||
185 | dev_err(&client->dev, "Failed to read configuration data\n"); | ||
186 | ret = -ENODEV; | ||
187 | goto out; | ||
188 | } | ||
189 | for (i = 0; i < ret; i++) { | ||
190 | int page = UCD9000_MON_PAGE(block_buffer[i]); | ||
191 | |||
192 | if (page >= info->pages) | ||
193 | continue; | ||
194 | |||
195 | switch (UCD9000_MON_TYPE(block_buffer[i])) { | ||
196 | case UCD9000_MON_VOLTAGE: | ||
197 | case UCD9000_MON_VOLTAGE_HW: | ||
198 | info->func[page] |= PMBUS_HAVE_VOUT | ||
199 | | PMBUS_HAVE_STATUS_VOUT; | ||
200 | break; | ||
201 | case UCD9000_MON_TEMPERATURE: | ||
202 | info->func[page] |= PMBUS_HAVE_TEMP2 | ||
203 | | PMBUS_HAVE_STATUS_TEMP; | ||
204 | break; | ||
205 | case UCD9000_MON_CURRENT: | ||
206 | info->func[page] |= PMBUS_HAVE_IOUT | ||
207 | | PMBUS_HAVE_STATUS_IOUT; | ||
208 | break; | ||
209 | default: | ||
210 | break; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | /* Fan configuration */ | ||
215 | if (mid->driver_data == ucd90124) { | ||
216 | for (i = 0; i < UCD9000_NUM_FAN; i++) { | ||
217 | i2c_smbus_write_byte_data(client, | ||
218 | UCD9000_FAN_CONFIG_INDEX, i); | ||
219 | ret = i2c_smbus_read_block_data(client, | ||
220 | UCD9000_FAN_CONFIG, | ||
221 | data->fan_data[i]); | ||
222 | if (ret < 0) | ||
223 | goto out; | ||
224 | } | ||
225 | i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0); | ||
226 | |||
227 | info->read_byte_data = ucd9000_read_byte_data; | ||
228 | info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | ||
229 | | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; | ||
230 | } | ||
231 | |||
232 | ret = pmbus_do_probe(client, mid, info); | ||
233 | if (ret < 0) | ||
234 | goto out; | ||
235 | return 0; | ||
236 | |||
237 | out: | ||
238 | kfree(data); | ||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | static int ucd9000_remove(struct i2c_client *client) | ||
243 | { | ||
244 | int ret; | ||
245 | struct ucd9000_data *data; | ||
246 | |||
247 | data = to_ucd9000_data(pmbus_get_driver_info(client)); | ||
248 | ret = pmbus_do_remove(client); | ||
249 | kfree(data); | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | |||
254 | /* This is the driver that will be inserted */ | ||
255 | static struct i2c_driver ucd9000_driver = { | ||
256 | .driver = { | ||
257 | .name = "ucd9000", | ||
258 | }, | ||
259 | .probe = ucd9000_probe, | ||
260 | .remove = ucd9000_remove, | ||
261 | .id_table = ucd9000_id, | ||
262 | }; | ||
263 | |||
264 | static int __init ucd9000_init(void) | ||
265 | { | ||
266 | return i2c_add_driver(&ucd9000_driver); | ||
267 | } | ||
268 | |||
269 | static void __exit ucd9000_exit(void) | ||
270 | { | ||
271 | i2c_del_driver(&ucd9000_driver); | ||
272 | } | ||
273 | |||
274 | MODULE_AUTHOR("Guenter Roeck"); | ||
275 | MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); | ||
276 | MODULE_LICENSE("GPL"); | ||
277 | module_init(ucd9000_init); | ||
278 | module_exit(ucd9000_exit); | ||