Skip to content

Commit 41730b7

Browse files
committed
zl6100: Add support for VMON on chips supporting it
Signed-off-by: Guenter Roeck <[email protected]>
1 parent b168f71 commit 41730b7

File tree

1 file changed

+134
-23
lines changed

1 file changed

+134
-23
lines changed

zl6100.c

Lines changed: 134 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@
2929
#include "pmbus.h"
3030

3131
enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105,
32-
zl9101m, zl9117m };
32+
zl9101, zl9117 };
3333

3434
struct zl6100_data {
3535
int id;
3636
ktime_t access; /* chip access time */
37+
int delay; /* Delay between chip accesses in uS */
3738
struct pmbus_driver_info info;
3839
};
3940

@@ -44,29 +45,64 @@ struct zl6100_data {
4445

4546
#define ZL6100_MFR_XTEMP_ENABLE (1 << 7)
4647

48+
#define MFR_VMON_OV_FAULT_LIMIT 0xf5
49+
#define MFR_VMON_UV_FAULT_LIMIT 0xf6
50+
#define MFR_READ_VMON 0xf7
51+
52+
#define VMON_UV_WARNING (1 << 5)
53+
#define VMON_OV_WARNING (1 << 4)
54+
#define VMON_UV_FAULT (1 << 1)
55+
#define VMON_OV_FAULT (1 << 0)
56+
4757
#define ZL6100_WAIT_TIME 1000 /* uS */
4858

59+
#define ZL6100_VOUT_EXPONENT -13
60+
4961
static ushort delay = ZL6100_WAIT_TIME;
5062
module_param(delay, ushort, 0644);
5163
MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
5264

5365
/* Some chips need a delay between accesses */
5466
static inline void zl6100_wait(const struct zl6100_data *data)
5567
{
56-
if (delay) {
68+
if (data->delay) {
5769
s64 delta = ktime_us_delta(ktime_get(), data->access);
58-
if (delta < delay)
59-
udelay(delay - delta);
70+
if (delta < data->delay)
71+
udelay(data->delay - delta);
6072
}
6173
}
6274

75+
static int zl6100_lin11_to_lin16(int reg)
76+
{
77+
int mantissa = ((s16)((reg & 0x7ff) << 5)) >> 5;
78+
int shift = ZL6100_VOUT_EXPONENT - (((s16)reg) >> 11);
79+
80+
if (shift < 0)
81+
mantissa <<= -shift;
82+
else if (shift)
83+
mantissa >>= shift;
84+
85+
return mantissa & 0xffff;
86+
}
87+
88+
static u16 zl6100_lin16_to_lin11(u16 reg)
89+
{
90+
int exp = ZL6100_VOUT_EXPONENT;
91+
92+
while (reg > 0x3ff) {
93+
exp++;
94+
reg >>= 1;
95+
}
96+
return reg | (exp << 11);
97+
}
98+
6399
static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
64100
{
65101
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
66102
struct zl6100_data *data = to_zl6100_data(info);
67103
int ret;
68104

69-
if (page || reg >= PMBUS_VIRT_BASE)
105+
if (page > info->pages || reg >= PMBUS_VIRT_BASE)
70106
return -ENXIO;
71107

72108
if (data->id == zl2005) {
@@ -83,25 +119,71 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
83119
}
84120

85121
zl6100_wait(data);
86-
ret = pmbus_read_word_data(client, page, reg);
87-
data->access = ktime_get();
88122

123+
if (page == 1) {
124+
page = 0;
125+
switch (reg) {
126+
case PMBUS_READ_VOUT:
127+
reg = MFR_READ_VMON;
128+
break;
129+
case PMBUS_VOUT_OV_FAULT_LIMIT:
130+
reg = MFR_VMON_OV_FAULT_LIMIT;
131+
break;
132+
case PMBUS_VOUT_UV_FAULT_LIMIT:
133+
reg = MFR_VMON_UV_FAULT_LIMIT;
134+
break;
135+
default:
136+
/* No other valid registers on page 1 */
137+
return -ENXIO;
138+
}
139+
ret = pmbus_read_word_data(client, page, reg);
140+
if (ret > 0)
141+
ret = zl6100_lin11_to_lin16(ret);
142+
} else {
143+
ret = pmbus_read_word_data(client, page, reg);
144+
}
145+
data->access = ktime_get();
89146
return ret;
90147
}
91148

92149
static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
93150
{
94151
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
95152
struct zl6100_data *data = to_zl6100_data(info);
96-
int ret;
153+
int ret, status;
97154

98-
if (page > 0)
155+
if (page > info->pages)
99156
return -ENXIO;
100157

101158
zl6100_wait(data);
102-
ret = pmbus_read_byte_data(client, page, reg);
103-
data->access = ktime_get();
104159

160+
if (page == 1) {
161+
switch (reg) {
162+
case PMBUS_STATUS_VOUT:
163+
ret = pmbus_read_byte_data(client, 0,
164+
PMBUS_STATUS_MFR_SPECIFIC);
165+
if (ret < 0)
166+
break;
167+
168+
status = 0;
169+
if (ret & VMON_UV_WARNING)
170+
status |= PB_VOLTAGE_UV_WARNING;
171+
if (ret & VMON_OV_WARNING)
172+
status |= PB_VOLTAGE_OV_WARNING;
173+
if (ret & VMON_UV_FAULT)
174+
status |= PB_VOLTAGE_UV_FAULT;
175+
if (ret & VMON_OV_FAULT)
176+
status |= PB_VOLTAGE_OV_FAULT;
177+
ret = status;
178+
break;
179+
default:
180+
/* No other valid registers on page 1 */
181+
return -ENXIO;
182+
}
183+
} else {
184+
ret = pmbus_read_byte_data(client, page, reg);
185+
}
186+
data->access = ktime_get();
105187
return ret;
106188
}
107189

@@ -112,9 +194,25 @@ static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
112194
struct zl6100_data *data = to_zl6100_data(info);
113195
int ret;
114196

115-
if (page || reg >= PMBUS_VIRT_BASE)
197+
if (page > info->pages || reg >= PMBUS_VIRT_BASE)
116198
return -ENXIO;
117199

200+
if (page == 1) {
201+
page = 0;
202+
switch (reg) {
203+
case PMBUS_VOUT_OV_FAULT_LIMIT:
204+
reg = MFR_VMON_OV_FAULT_LIMIT;
205+
break;
206+
case PMBUS_VOUT_UV_FAULT_LIMIT:
207+
reg = MFR_VMON_UV_FAULT_LIMIT;
208+
break;
209+
default:
210+
/* No other valid registers on page 1 */
211+
return -ENXIO;
212+
}
213+
word = zl6100_lin16_to_lin11(word);
214+
}
215+
118216
zl6100_wait(data);
119217
ret = pmbus_write_word_data(client, page, reg, word);
120218
data->access = ktime_get();
@@ -126,14 +224,16 @@ static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
126224
{
127225
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
128226
struct zl6100_data *data = to_zl6100_data(info);
129-
int ret;
227+
int ret = 0;
130228

131-
if (page > 0)
229+
if (page > info->pages)
132230
return -ENXIO;
133231

134-
zl6100_wait(data);
135-
ret = pmbus_write_byte(client, page, value);
136-
data->access = ktime_get();
232+
if (page <= 0) {
233+
zl6100_wait(data);
234+
ret = pmbus_write_byte(client, page, value);
235+
data->access = ktime_get();
236+
}
137237

138238
return ret;
139239
}
@@ -152,8 +252,8 @@ static const struct i2c_device_id zl6100_id[] = {
152252
{"zl2106", zl2106},
153253
{"zl6100", zl6100},
154254
{"zl6105", zl6105},
155-
{"zl9101m", zl9101m},
156-
{"zl9117m", zl9117m},
255+
{"zl9101", zl9101},
256+
{"zl9117", zl9117},
157257
{ }
158258
};
159259
MODULE_DEVICE_TABLE(i2c, zl6100_id);
@@ -203,16 +303,17 @@ static int zl6100_probe(struct i2c_client *client,
203303
data->id = mid->driver_data;
204304

205305
/*
206-
* ZL2005, ZL2008, ZL2105, and ZL6100 are known to require a wait time
207-
* between I2C accesses. ZL2004 and ZL6105 are known to be safe.
208-
* Other chips have not yet been tested.
306+
* ZL2005, ZL2008, ZL2105, ZL6100, ZL9101M, and ZL9117M are known to
307+
* require a wait time between I2C accesses. ZL2004 and ZL6105 are known
308+
* to be safe. Other chips have not yet been tested.
209309
*
210310
* Only clear the wait time for chips known to be safe. The wait time
211311
* can be cleared later for additional chips if tests show that it
212312
* is not needed (in other words, better be safe than sorry).
213313
*/
314+
data->delay = delay;
214315
if (data->id == zl2004 || data->id == zl6105)
215-
delay = 0;
316+
data->delay = 0;
216317

217318
/*
218319
* Since there was a direct I2C device access above, wait before
@@ -229,6 +330,16 @@ static int zl6100_probe(struct i2c_client *client,
229330
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
230331
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
231332

333+
/*
334+
* ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
335+
* (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as output
336+
* voltage on the second page (vout2).
337+
*/
338+
if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117) {
339+
info->pages = 2;
340+
info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
341+
}
342+
232343
ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
233344
if (ret < 0)
234345
return ret;

0 commit comments

Comments
 (0)