aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <guenter.roeck@ericsson.com>2011-07-30 01:21:53 -0400
committerGuenter Roeck <guenter.roeck@ericsson.com>2011-10-24 14:09:40 -0400
commit200855e52db1b1834121ba57fbd89c5b4911e02c (patch)
treefa0c572e5c40b8558ae2e8fc5069a41c2c503668
parentda8e48ab483e1f54c1099bed91bfd2c302bc7ddf (diff)
hwmon: (pmbus) Add support for Intersil power management chips
Add support for Intersil / Zilker Labs ZL2004, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105. Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Reviewed-by: Robert Coulson <robert.coulson@ericsson.com>
-rw-r--r--Documentation/hwmon/zl6100125
-rw-r--r--drivers/hwmon/pmbus/Kconfig11
-rw-r--r--drivers/hwmon/pmbus/Makefile1
-rw-r--r--drivers/hwmon/pmbus/zl6100.c256
4 files changed, 393 insertions, 0 deletions
diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100
new file mode 100644
index 000000000000..7617798b5c97
--- /dev/null
+++ b/Documentation/hwmon/zl6100
@@ -0,0 +1,125 @@
1Kernel driver zl6100
2====================
3
4Supported chips:
5 * Intersil / Zilker Labs ZL2004
6 Prefix: 'zl2004'
7 Addresses scanned: -
8 Datasheet: http://www.intersil.com/data/fn/fn6847.pdf
9 * Intersil / Zilker Labs ZL2006
10 Prefix: 'zl2006'
11 Addresses scanned: -
12 Datasheet: http://www.intersil.com/data/fn/fn6850.pdf
13 * Intersil / Zilker Labs ZL2008
14 Prefix: 'zl2008'
15 Addresses scanned: -
16 Datasheet: http://www.intersil.com/data/fn/fn6859.pdf
17 * Intersil / Zilker Labs ZL2105
18 Prefix: 'zl2105'
19 Addresses scanned: -
20 Datasheet: http://www.intersil.com/data/fn/fn6851.pdf
21 * Intersil / Zilker Labs ZL2106
22 Prefix: 'zl2106'
23 Addresses scanned: -
24 Datasheet: http://www.intersil.com/data/fn/fn6852.pdf
25 * Intersil / Zilker Labs ZL6100
26 Prefix: 'zl6100'
27 Addresses scanned: -
28 Datasheet: http://www.intersil.com/data/fn/fn6876.pdf
29 * Intersil / Zilker Labs ZL6105
30 Prefix: 'zl6105'
31 Addresses scanned: -
32 Datasheet: http://www.intersil.com/data/fn/fn6906.pdf
33
34Author: Guenter Roeck <guenter.roeck@ericsson.com>
35
36
37Description
38-----------
39
40This driver supports hardware montoring for Intersil / Zilker Labs ZL6100 and
41compatible digital DC-DC controllers.
42
43The driver is a client driver to the core PMBus driver. Please see
44Documentation/hwmon/pmbus and Documentation.hwmon/pmbus-core for details
45on PMBus client drivers.
46
47
48Usage Notes
49-----------
50
51This driver does not auto-detect devices. You will have to instantiate the
52devices explicitly. Please see Documentation/i2c/instantiating-devices for
53details.
54
55WARNING: Do not access chip registers using the i2cdump command, and do not use
56any of the i2ctools commands on a command register used to save and restore
57configuration data (0x11, 0x12, 0x15, 0x16, and 0xf4). The chips supported by
58this driver interpret any access to those command registers (including read
59commands) as request to execute the command in question. Unless write accesses
60to those registers are protected, this may result in power loss, board resets,
61and/or Flash corruption. Worst case, your board may turn into a brick.
62
63
64Platform data support
65---------------------
66
67The driver supports standard PMBus driver platform data.
68
69
70Module parameters
71-----------------
72
73delay
74-----
75
76Some Intersil/Zilker Labs DC-DC controllers require a minimum interval between
77I2C bus accesses. According to Intersil, the minimum interval is 2 ms, though
781 ms appears to be sufficient and has not caused any problems in testing.
79The problem is known to affect ZL6100, ZL2105, and ZL2008. It is known not to
80affect ZL2004 and ZL6105. The driver automatically sets the interval to 1 ms
81except for ZL2004 and ZL6105. To enable manual override, the driver provides a
82writeable module parameter, 'delay', which can be used to set the interval to
83a value between 0 and 65,535 microseconds.
84
85
86Sysfs entries
87-------------
88
89The following attributes are supported. Limits are read-write; all other
90attributes are read-only.
91
92in1_label "vin"
93in1_input Measured input voltage.
94in1_min Minimum input voltage.
95in1_max Maximum input voltage.
96in1_lcrit Critical minumum input voltage.
97in1_crit Critical maximum input voltage.
98in1_min_alarm Input voltage low alarm.
99in1_max_alarm Input voltage high alarm.
100in1_lcrit_alarm Input voltage critical low alarm.
101in1_crit_alarm Input voltage critical high alarm.
102
103in2_label "vout1"
104in2_input Measured output voltage.
105in2_lcrit Critical minumum output Voltage.
106in2_crit Critical maximum output voltage.
107in2_lcrit_alarm Critical output voltage critical low alarm.
108in2_crit_alarm Critical output voltage critical high alarm.
109
110curr1_label "iout1"
111curr1_input Measured output current.
112curr1_lcrit Critical minimum output current.
113curr1_crit Critical maximum output current.
114curr1_lcrit_alarm Output current critical low alarm.
115curr1_crit_alarm Output current critical high alarm.
116
117temp[12]_input Measured temperature.
118temp[12]_min Minimum temperature.
119temp[12]_max Maximum temperature.
120temp[12]_lcrit Critical low temperature.
121temp[12]_crit Critical high temperature.
122temp[12]_min_alarm Chip temperature low alarm.
123temp[12]_max_alarm Chip temperature high alarm.
124temp[12]_lcrit_alarm Chip temperature critical low alarm.
125temp[12]_crit_alarm Chip temperature critical high alarm.
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 37575582e51a..efaf340651a0 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -98,4 +98,15 @@ config SENSORS_UCD9200
98 This driver can also be built as a module. If so, the module will 98 This driver can also be built as a module. If so, the module will
99 be called ucd9200. 99 be called ucd9200.
100 100
101config SENSORS_ZL6100
102 tristate "Intersil ZL6100 and compatibles"
103 default n
104 help
105 If you say yes here you get hardware monitoring support for Intersil
106 ZL2004, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105 Digital
107 DC/DC Controllers.
108
109 This driver can also be built as a module. If so, the module will
110 be called zl6100.
111
101endif # PMBUS 112endif # PMBUS
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index 623eedb1ed9a..b9e4fb421f6c 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
11obj-$(CONFIG_SENSORS_MAX8688) += max8688.o 11obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
12obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o 12obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
13obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o 13obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
14obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
new file mode 100644
index 000000000000..2bc980006f83
--- /dev/null
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -0,0 +1,256 @@
1/*
2 * Hardware monitoring driver for ZL6100 and compatibles
3 *
4 * Copyright (c) 2011 Ericsson AB.
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 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/err.h>
25#include <linux/slab.h>
26#include <linux/i2c.h>
27#include <linux/ktime.h>
28#include <linux/delay.h>
29#include "pmbus.h"
30
31enum chips { zl2004, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 };
32
33struct zl6100_data {
34 int id;
35 ktime_t access; /* chip access time */
36 struct pmbus_driver_info info;
37};
38
39#define to_zl6100_data(x) container_of(x, struct zl6100_data, info)
40
41#define ZL6100_DEVICE_ID 0xe4
42
43#define ZL6100_WAIT_TIME 1000 /* uS */
44
45static ushort delay = ZL6100_WAIT_TIME;
46module_param(delay, ushort, 0644);
47MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
48
49/* Some chips need a delay between accesses */
50static inline void zl6100_wait(const struct zl6100_data *data)
51{
52 if (delay) {
53 s64 delta = ktime_us_delta(ktime_get(), data->access);
54 if (delta < delay)
55 udelay(delay - delta);
56 }
57}
58
59static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
60{
61 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
62 struct zl6100_data *data = to_zl6100_data(info);
63 int ret;
64
65 if (page || reg >= PMBUS_VIRT_BASE)
66 return -ENXIO;
67
68 zl6100_wait(data);
69 ret = pmbus_read_word_data(client, page, reg);
70 data->access = ktime_get();
71
72 return ret;
73}
74
75static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
76{
77 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
78 struct zl6100_data *data = to_zl6100_data(info);
79 int ret;
80
81 if (page > 0)
82 return -ENXIO;
83
84 zl6100_wait(data);
85 ret = pmbus_read_byte_data(client, page, reg);
86 data->access = ktime_get();
87
88 return ret;
89}
90
91static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
92 u16 word)
93{
94 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
95 struct zl6100_data *data = to_zl6100_data(info);
96 int ret;
97
98 if (page || reg >= PMBUS_VIRT_BASE)
99 return -ENXIO;
100
101 zl6100_wait(data);
102 ret = pmbus_write_word_data(client, page, reg, word);
103 data->access = ktime_get();
104
105 return ret;
106}
107
108static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
109{
110 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
111 struct zl6100_data *data = to_zl6100_data(info);
112 int ret;
113
114 if (page > 0)
115 return -ENXIO;
116
117 zl6100_wait(data);
118 ret = pmbus_write_byte(client, page, value);
119 data->access = ktime_get();
120
121 return ret;
122}
123
124static const struct i2c_device_id zl6100_id[] = {
125 {"zl2004", zl2004},
126 {"zl2006", zl2006},
127 {"zl2008", zl2008},
128 {"zl2105", zl2105},
129 {"zl2106", zl2106},
130 {"zl6100", zl6100},
131 {"zl6105", zl6105},
132 { }
133};
134MODULE_DEVICE_TABLE(i2c, zl6100_id);
135
136static int zl6100_probe(struct i2c_client *client,
137 const struct i2c_device_id *id)
138{
139 int ret;
140 struct zl6100_data *data;
141 struct pmbus_driver_info *info;
142 u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
143 const struct i2c_device_id *mid;
144
145 if (!i2c_check_functionality(client->adapter,
146 I2C_FUNC_SMBUS_READ_BYTE_DATA
147 | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
148 return -ENODEV;
149
150 ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID,
151 device_id);
152 if (ret < 0) {
153 dev_err(&client->dev, "Failed to read device ID\n");
154 return ret;
155 }
156 device_id[ret] = '\0';
157 dev_info(&client->dev, "Device ID %s\n", device_id);
158
159 mid = NULL;
160 for (mid = zl6100_id; mid->name[0]; mid++) {
161 if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
162 break;
163 }
164 if (!mid->name[0]) {
165 dev_err(&client->dev, "Unsupported device\n");
166 return -ENODEV;
167 }
168 if (id->driver_data != mid->driver_data)
169 dev_notice(&client->dev,
170 "Device mismatch: Configured %s, detected %s\n",
171 id->name, mid->name);
172
173 data = kzalloc(sizeof(struct zl6100_data), GFP_KERNEL);
174 if (!data)
175 return -ENOMEM;
176
177 data->id = mid->driver_data;
178
179 /*
180 * ZL2008, ZL2105, and ZL6100 are known to require a wait time
181 * between I2C accesses. ZL2004 and ZL6105 are known to be safe.
182 *
183 * Only clear the wait time for chips known to be safe. The wait time
184 * can be cleared later for additional chips if tests show that it
185 * is not needed (in other words, better be safe than sorry).
186 */
187 if (data->id == zl2004 || data->id == zl6105)
188 delay = 0;
189
190 /*
191 * Since there was a direct I2C device access above, wait before
192 * accessing the chip again.
193 * Set the timestamp, wait, then set it again. This should provide
194 * enough buffer time to be safe.
195 */
196 data->access = ktime_get();
197 zl6100_wait(data);
198 data->access = ktime_get();
199
200 info = &data->info;
201
202 info->pages = 1;
203 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
204 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
205 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
206 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
207
208 info->read_word_data = zl6100_read_word_data;
209 info->read_byte_data = zl6100_read_byte_data;
210 info->write_word_data = zl6100_write_word_data;
211 info->write_byte = zl6100_write_byte;
212
213 ret = pmbus_do_probe(client, mid, info);
214 if (ret)
215 goto err_mem;
216 return 0;
217
218err_mem:
219 kfree(data);
220 return ret;
221}
222
223static int zl6100_remove(struct i2c_client *client)
224{
225 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
226 const struct zl6100_data *data = to_zl6100_data(info);
227
228 pmbus_do_remove(client);
229 kfree(data);
230 return 0;
231}
232
233static struct i2c_driver zl6100_driver = {
234 .driver = {
235 .name = "zl6100",
236 },
237 .probe = zl6100_probe,
238 .remove = zl6100_remove,
239 .id_table = zl6100_id,
240};
241
242static int __init zl6100_init(void)
243{
244 return i2c_add_driver(&zl6100_driver);
245}
246
247static void __exit zl6100_exit(void)
248{
249 i2c_del_driver(&zl6100_driver);
250}
251
252MODULE_AUTHOR("Guenter Roeck");
253MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
254MODULE_LICENSE("GPL");
255module_init(zl6100_init);
256module_exit(zl6100_exit);