Skip to content

Commit 21d9e60

Browse files
PatrickRudolphgroeck
authored andcommitted
hwmon: pmbus: Implement generic bus access delay
Some drivers, like the max15301 or zl6100, are intentionally delaying SMBus communications, to prevent transmission errors. As this is necessary on additional PMBus compatible devices, implement a generic delay mechanism in the pmbus core. Introduces two delay settings in the pmbus_driver_info struct, one applies to every SMBus transaction and the other is for write transaction only. Once set by the driver the SMBus traffic, using the generic pmbus access helpers, is automatically delayed when necessary. The two settings are: access_delay: - Unit in microseconds - Stores the accessed timestamp after every SMBus access - Delays when necessary before the next SMBus access write_delay: - Unit in microseconds - Stores the written timestamp after a write SMBus access - Delays when necessary before the next SMBus access This allows to drop the custom delay code from the drivers and easily introduce this feature in additional pmbus drivers. Signed-off-by: Patrick Rudolph <[email protected]> Message-ID: <[email protected]> Signed-off-by: Guenter Roeck <[email protected]>
1 parent 63fb21a commit 21d9e60

File tree

2 files changed

+96
-6
lines changed

2 files changed

+96
-6
lines changed

drivers/hwmon/pmbus/pmbus.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,16 @@ struct pmbus_driver_info {
466466

467467
/* custom attributes */
468468
const struct attribute_group **groups;
469+
470+
/*
471+
* Some chips need a little delay between SMBus communication. When
472+
* set, the generic PMBus helper functions will wait if necessary
473+
* to meet this requirement. The access delay is honored after
474+
* every SMBus operation. The write delay is only honored after
475+
* SMBus write operations.
476+
*/
477+
int access_delay; /* in microseconds */
478+
int write_delay; /* in microseconds */
469479
};
470480

471481
/* Regulator ops */

drivers/hwmon/pmbus/pmbus_core.c

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <linux/debugfs.h>
10+
#include <linux/delay.h>
1011
#include <linux/kernel.h>
1112
#include <linux/math64.h>
1213
#include <linux/module.h>
@@ -108,6 +109,8 @@ struct pmbus_data {
108109

109110
int vout_low[PMBUS_PAGES]; /* voltage low margin */
110111
int vout_high[PMBUS_PAGES]; /* voltage high margin */
112+
ktime_t write_time; /* Last SMBUS write timestamp */
113+
ktime_t access_time; /* Last SMBUS access timestamp */
111114
};
112115

113116
struct pmbus_debugfs_entry {
@@ -158,6 +161,39 @@ void pmbus_set_update(struct i2c_client *client, u8 reg, bool update)
158161
}
159162
EXPORT_SYMBOL_NS_GPL(pmbus_set_update, PMBUS);
160163

164+
/* Some chips need a delay between accesses. */
165+
static void pmbus_wait(struct i2c_client *client)
166+
{
167+
struct pmbus_data *data = i2c_get_clientdata(client);
168+
const struct pmbus_driver_info *info = data->info;
169+
s64 delta;
170+
171+
if (info->access_delay) {
172+
delta = ktime_us_delta(ktime_get(), data->access_time);
173+
174+
if (delta < info->access_delay)
175+
fsleep(info->access_delay - delta);
176+
} else if (info->write_delay) {
177+
delta = ktime_us_delta(ktime_get(), data->write_time);
178+
179+
if (delta < info->write_delay)
180+
fsleep(info->write_delay - delta);
181+
}
182+
}
183+
184+
/* Sets the last accessed timestamp for pmbus_wait */
185+
static void pmbus_update_ts(struct i2c_client *client, bool write_op)
186+
{
187+
struct pmbus_data *data = i2c_get_clientdata(client);
188+
const struct pmbus_driver_info *info = data->info;
189+
190+
if (info->access_delay) {
191+
data->access_time = ktime_get();
192+
} else if (info->write_delay && write_op) {
193+
data->write_time = ktime_get();
194+
}
195+
}
196+
161197
int pmbus_set_page(struct i2c_client *client, int page, int phase)
162198
{
163199
struct pmbus_data *data = i2c_get_clientdata(client);
@@ -168,11 +204,15 @@ int pmbus_set_page(struct i2c_client *client, int page, int phase)
168204

169205
if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) &&
170206
data->info->pages > 1 && page != data->currpage) {
207+
pmbus_wait(client);
171208
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
209+
pmbus_update_ts(client, true);
172210
if (rv < 0)
173211
return rv;
174212

213+
pmbus_wait(client);
175214
rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
215+
pmbus_update_ts(client, false);
176216
if (rv < 0)
177217
return rv;
178218

@@ -183,8 +223,10 @@ int pmbus_set_page(struct i2c_client *client, int page, int phase)
183223

184224
if (data->info->phases[page] && data->currphase != phase &&
185225
!(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) {
226+
pmbus_wait(client);
186227
rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE,
187228
phase);
229+
pmbus_update_ts(client, true);
188230
if (rv)
189231
return rv;
190232
}
@@ -202,7 +244,11 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
202244
if (rv < 0)
203245
return rv;
204246

205-
return i2c_smbus_write_byte(client, value);
247+
pmbus_wait(client);
248+
rv = i2c_smbus_write_byte(client, value);
249+
pmbus_update_ts(client, true);
250+
251+
return rv;
206252
}
207253
EXPORT_SYMBOL_NS_GPL(pmbus_write_byte, PMBUS);
208254

@@ -233,7 +279,11 @@ int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg,
233279
if (rv < 0)
234280
return rv;
235281

236-
return i2c_smbus_write_word_data(client, reg, word);
282+
pmbus_wait(client);
283+
rv = i2c_smbus_write_word_data(client, reg, word);
284+
pmbus_update_ts(client, true);
285+
286+
return rv;
237287
}
238288
EXPORT_SYMBOL_NS_GPL(pmbus_write_word_data, PMBUS);
239289

@@ -351,7 +401,11 @@ int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg)
351401
if (rv < 0)
352402
return rv;
353403

354-
return i2c_smbus_read_word_data(client, reg);
404+
pmbus_wait(client);
405+
rv = i2c_smbus_read_word_data(client, reg);
406+
pmbus_update_ts(client, false);
407+
408+
return rv;
355409
}
356410
EXPORT_SYMBOL_NS_GPL(pmbus_read_word_data, PMBUS);
357411

@@ -410,7 +464,11 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
410464
if (rv < 0)
411465
return rv;
412466

413-
return i2c_smbus_read_byte_data(client, reg);
467+
pmbus_wait(client);
468+
rv = i2c_smbus_read_byte_data(client, reg);
469+
pmbus_update_ts(client, false);
470+
471+
return rv;
414472
}
415473
EXPORT_SYMBOL_NS_GPL(pmbus_read_byte_data, PMBUS);
416474

@@ -422,7 +480,11 @@ int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value)
422480
if (rv < 0)
423481
return rv;
424482

425-
return i2c_smbus_write_byte_data(client, reg, value);
483+
pmbus_wait(client);
484+
rv = i2c_smbus_write_byte_data(client, reg, value);
485+
pmbus_update_ts(client, true);
486+
487+
return rv;
426488
}
427489
EXPORT_SYMBOL_NS_GPL(pmbus_write_byte_data, PMBUS);
428490

@@ -454,7 +516,11 @@ static int pmbus_read_block_data(struct i2c_client *client, int page, u8 reg,
454516
if (rv < 0)
455517
return rv;
456518

457-
return i2c_smbus_read_block_data(client, reg, data_buf);
519+
pmbus_wait(client);
520+
rv = i2c_smbus_read_block_data(client, reg, data_buf);
521+
pmbus_update_ts(client, false);
522+
523+
return rv;
458524
}
459525

460526
static struct pmbus_sensor *pmbus_find_sensor(struct pmbus_data *data, int page,
@@ -2450,9 +2516,11 @@ static int pmbus_read_coefficients(struct i2c_client *client,
24502516
data.block[1] = attr->reg;
24512517
data.block[2] = 0x01;
24522518

2519+
pmbus_wait(client);
24532520
rv = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
24542521
I2C_SMBUS_WRITE, PMBUS_COEFFICIENTS,
24552522
I2C_SMBUS_BLOCK_PROC_CALL, &data);
2523+
pmbus_update_ts(client, true);
24562524

24572525
if (rv < 0)
24582526
return rv;
@@ -2604,7 +2672,10 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
26042672

26052673
/* Enable PEC if the controller and bus supports it */
26062674
if (!(data->flags & PMBUS_NO_CAPABILITY)) {
2675+
pmbus_wait(client);
26072676
ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY);
2677+
pmbus_update_ts(client, false);
2678+
26082679
if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) {
26092680
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC))
26102681
client->flags |= I2C_CLIENT_PEC;
@@ -2617,10 +2688,16 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
26172688
* Bail out if both registers are not supported.
26182689
*/
26192690
data->read_status = pmbus_read_status_word;
2691+
pmbus_wait(client);
26202692
ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD);
2693+
pmbus_update_ts(client, false);
2694+
26212695
if (ret < 0 || ret == 0xffff) {
26222696
data->read_status = pmbus_read_status_byte;
2697+
pmbus_wait(client);
26232698
ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE);
2699+
pmbus_update_ts(client, false);
2700+
26242701
if (ret < 0 || ret == 0xff) {
26252702
dev_err(dev, "PMBus status register not found\n");
26262703
return -ENODEV;
@@ -2635,7 +2712,10 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
26352712
* limit registers need to be disabled.
26362713
*/
26372714
if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) {
2715+
pmbus_wait(client);
26382716
ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT);
2717+
pmbus_update_ts(client, false);
2718+
26392719
if (ret > 0 && (ret & PB_WP_ANY))
26402720
data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
26412721
}

0 commit comments

Comments
 (0)