zl6100.c revision 8b313ca7f1b98263ce22519b25a9c2a362eeb898
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, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 };
32
33struct zl6100_data {
34	int id;
35	ktime_t access;		/* chip access time */
36	int delay;		/* Delay between chip accesses in uS */
37	struct pmbus_driver_info info;
38};
39
40#define to_zl6100_data(x)  container_of(x, struct zl6100_data, info)
41
42#define ZL6100_MFR_CONFIG		0xd0
43#define ZL6100_DEVICE_ID		0xe4
44
45#define ZL6100_MFR_XTEMP_ENABLE		(1 << 7)
46
47#define ZL6100_WAIT_TIME		1000	/* uS	*/
48
49static ushort delay = ZL6100_WAIT_TIME;
50module_param(delay, ushort, 0644);
51MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
52
53/* Some chips need a delay between accesses */
54static inline void zl6100_wait(const struct zl6100_data *data)
55{
56	if (data->delay) {
57		s64 delta = ktime_us_delta(ktime_get(), data->access);
58		if (delta < data->delay)
59			udelay(data->delay - delta);
60	}
61}
62
63static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
64{
65	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
66	struct zl6100_data *data = to_zl6100_data(info);
67	int ret;
68
69	if (page || reg >= PMBUS_VIRT_BASE)
70		return -ENXIO;
71
72	if (data->id == zl2005) {
73		/*
74		 * Limit register detection is not reliable on ZL2005.
75		 * Make sure registers are not erroneously detected.
76		 */
77		switch (reg) {
78		case PMBUS_VOUT_OV_WARN_LIMIT:
79		case PMBUS_VOUT_UV_WARN_LIMIT:
80		case PMBUS_IOUT_OC_WARN_LIMIT:
81			return -ENXIO;
82		}
83	}
84
85	zl6100_wait(data);
86	ret = pmbus_read_word_data(client, page, reg);
87	data->access = ktime_get();
88
89	return ret;
90}
91
92static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
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 > 0)
99		return -ENXIO;
100
101	zl6100_wait(data);
102	ret = pmbus_read_byte_data(client, page, reg);
103	data->access = ktime_get();
104
105	return ret;
106}
107
108static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
109				  u16 word)
110{
111	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
112	struct zl6100_data *data = to_zl6100_data(info);
113	int ret;
114
115	if (page || reg >= PMBUS_VIRT_BASE)
116		return -ENXIO;
117
118	zl6100_wait(data);
119	ret = pmbus_write_word_data(client, page, reg, word);
120	data->access = ktime_get();
121
122	return ret;
123}
124
125static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
126{
127	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
128	struct zl6100_data *data = to_zl6100_data(info);
129	int ret;
130
131	if (page > 0)
132		return -ENXIO;
133
134	zl6100_wait(data);
135	ret = pmbus_write_byte(client, page, value);
136	data->access = ktime_get();
137
138	return ret;
139}
140
141static const struct i2c_device_id zl6100_id[] = {
142	{"bmr450", zl2005},
143	{"bmr451", zl2005},
144	{"bmr462", zl2008},
145	{"bmr463", zl2008},
146	{"bmr464", zl2008},
147	{"zl2004", zl2004},
148	{"zl2005", zl2005},
149	{"zl2006", zl2006},
150	{"zl2008", zl2008},
151	{"zl2105", zl2105},
152	{"zl2106", zl2106},
153	{"zl6100", zl6100},
154	{"zl6105", zl6105},
155	{ }
156};
157MODULE_DEVICE_TABLE(i2c, zl6100_id);
158
159static int zl6100_probe(struct i2c_client *client,
160			const struct i2c_device_id *id)
161{
162	int ret;
163	struct zl6100_data *data;
164	struct pmbus_driver_info *info;
165	u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
166	const struct i2c_device_id *mid;
167
168	if (!i2c_check_functionality(client->adapter,
169				     I2C_FUNC_SMBUS_READ_WORD_DATA
170				     | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
171		return -ENODEV;
172
173	ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID,
174					device_id);
175	if (ret < 0) {
176		dev_err(&client->dev, "Failed to read device ID\n");
177		return ret;
178	}
179	device_id[ret] = '\0';
180	dev_info(&client->dev, "Device ID %s\n", device_id);
181
182	mid = NULL;
183	for (mid = zl6100_id; mid->name[0]; mid++) {
184		if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
185			break;
186	}
187	if (!mid->name[0]) {
188		dev_err(&client->dev, "Unsupported device\n");
189		return -ENODEV;
190	}
191	if (id->driver_data != mid->driver_data)
192		dev_notice(&client->dev,
193			   "Device mismatch: Configured %s, detected %s\n",
194			   id->name, mid->name);
195
196	data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data),
197			    GFP_KERNEL);
198	if (!data)
199		return -ENOMEM;
200
201	data->id = mid->driver_data;
202
203	/*
204	 * According to information from the chip vendor, all currently
205	 * supported chips are known to require a wait time between I2C
206	 * accesses.
207	 */
208	data->delay = delay;
209
210	/*
211	 * Since there was a direct I2C device access above, wait before
212	 * accessing the chip again.
213	 */
214	data->access = ktime_get();
215	zl6100_wait(data);
216
217	info = &data->info;
218
219	info->pages = 1;
220	info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
221	  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
222	  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
223	  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
224
225	ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
226	if (ret < 0)
227		return ret;
228
229	if (ret & ZL6100_MFR_XTEMP_ENABLE)
230		info->func[0] |= PMBUS_HAVE_TEMP2;
231
232	data->access = ktime_get();
233	zl6100_wait(data);
234
235	info->read_word_data = zl6100_read_word_data;
236	info->read_byte_data = zl6100_read_byte_data;
237	info->write_word_data = zl6100_write_word_data;
238	info->write_byte = zl6100_write_byte;
239
240	return pmbus_do_probe(client, mid, info);
241}
242
243static int zl6100_remove(struct i2c_client *client)
244{
245	pmbus_do_remove(client);
246	return 0;
247}
248
249static struct i2c_driver zl6100_driver = {
250	.driver = {
251		   .name = "zl6100",
252		   },
253	.probe = zl6100_probe,
254	.remove = zl6100_remove,
255	.id_table = zl6100_id,
256};
257
258module_i2c_driver(zl6100_driver);
259
260MODULE_AUTHOR("Guenter Roeck");
261MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
262MODULE_LICENSE("GPL");
263