Skip to content

Commit 634b330

Browse files
larsclausengregkh
authored andcommitted
hwmon: (ucd90320) Add minimum delay between bus accesses
[ Upstream commit 8d655e6 ] When probing the ucd90320 access to some of the registers randomly fails. Sometimes it NACKs a transfer, sometimes it returns just random data and the PEC check fails. Experimentation shows that this seems to be triggered by a register access directly back to back with a previous register write. Experimentation also shows that inserting a small delay after register writes makes the issue go away. Use a similar solution to what the max15301 driver does to solve the same problem. Create a custom set of bus read and write functions that make sure that the delay is added. Fixes: a470f11 ("hwmon: (pmbus/ucd9000) Add support for UCD90320 Power Sequencer") Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Link: https://lore.kernel.org/r/20230312160312.2227405-1-lars@metafoo.de Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 265656c commit 634b330

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

drivers/hwmon/pmbus/ucd9000.c

Lines changed: 75 additions & 0 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/module.h>
1213
#include <linux/of_device.h>
@@ -16,6 +17,7 @@
1617
#include <linux/i2c.h>
1718
#include <linux/pmbus.h>
1819
#include <linux/gpio/driver.h>
20+
#include <linux/timekeeping.h>
1921
#include "pmbus.h"
2022

2123
enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090,
@@ -65,6 +67,7 @@ struct ucd9000_data {
6567
struct gpio_chip gpio;
6668
#endif
6769
struct dentry *debugfs;
70+
ktime_t write_time;
6871
};
6972
#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info)
7073

@@ -73,6 +76,73 @@ struct ucd9000_debugfs_entry {
7376
u8 index;
7477
};
7578

79+
/*
80+
* It has been observed that the UCD90320 randomly fails register access when
81+
* doing another access right on the back of a register write. To mitigate this
82+
* make sure that there is a minimum delay between a write access and the
83+
* following access. The 250us is based on experimental data. At a delay of
84+
* 200us the issue seems to go away. Add a bit of extra margin to allow for
85+
* system to system differences.
86+
*/
87+
#define UCD90320_WAIT_DELAY_US 250
88+
89+
static inline void ucd90320_wait(const struct ucd9000_data *data)
90+
{
91+
s64 delta = ktime_us_delta(ktime_get(), data->write_time);
92+
93+
if (delta < UCD90320_WAIT_DELAY_US)
94+
udelay(UCD90320_WAIT_DELAY_US - delta);
95+
}
96+
97+
static int ucd90320_read_word_data(struct i2c_client *client, int page,
98+
int phase, int reg)
99+
{
100+
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
101+
struct ucd9000_data *data = to_ucd9000_data(info);
102+
103+
if (reg >= PMBUS_VIRT_BASE)
104+
return -ENXIO;
105+
106+
ucd90320_wait(data);
107+
return pmbus_read_word_data(client, page, phase, reg);
108+
}
109+
110+
static int ucd90320_read_byte_data(struct i2c_client *client, int page, int reg)
111+
{
112+
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
113+
struct ucd9000_data *data = to_ucd9000_data(info);
114+
115+
ucd90320_wait(data);
116+
return pmbus_read_byte_data(client, page, reg);
117+
}
118+
119+
static int ucd90320_write_word_data(struct i2c_client *client, int page,
120+
int reg, u16 word)
121+
{
122+
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
123+
struct ucd9000_data *data = to_ucd9000_data(info);
124+
int ret;
125+
126+
ucd90320_wait(data);
127+
ret = pmbus_write_word_data(client, page, reg, word);
128+
data->write_time = ktime_get();
129+
130+
return ret;
131+
}
132+
133+
static int ucd90320_write_byte(struct i2c_client *client, int page, u8 value)
134+
{
135+
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
136+
struct ucd9000_data *data = to_ucd9000_data(info);
137+
int ret;
138+
139+
ucd90320_wait(data);
140+
ret = pmbus_write_byte(client, page, value);
141+
data->write_time = ktime_get();
142+
143+
return ret;
144+
}
145+
76146
static int ucd9000_get_fan_config(struct i2c_client *client, int fan)
77147
{
78148
int fan_config = 0;
@@ -598,6 +668,11 @@ static int ucd9000_probe(struct i2c_client *client)
598668
info->read_byte_data = ucd9000_read_byte_data;
599669
info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12
600670
| PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34;
671+
} else if (mid->driver_data == ucd90320) {
672+
info->read_byte_data = ucd90320_read_byte_data;
673+
info->read_word_data = ucd90320_read_word_data;
674+
info->write_byte = ucd90320_write_byte;
675+
info->write_word_data = ucd90320_write_word_data;
601676
}
602677

603678
ucd9000_probe_gpio(client, mid, data);

0 commit comments

Comments
 (0)