.. | .. |
---|
7 | 7 | */ |
---|
8 | 8 | |
---|
9 | 9 | #include <linux/debugfs.h> |
---|
| 10 | +#include <linux/delay.h> |
---|
10 | 11 | #include <linux/kernel.h> |
---|
11 | 12 | #include <linux/module.h> |
---|
12 | 13 | #include <linux/of_device.h> |
---|
.. | .. |
---|
16 | 17 | #include <linux/i2c.h> |
---|
17 | 18 | #include <linux/pmbus.h> |
---|
18 | 19 | #include <linux/gpio/driver.h> |
---|
| 20 | +#include <linux/timekeeping.h> |
---|
19 | 21 | #include "pmbus.h" |
---|
20 | 22 | |
---|
21 | 23 | enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090, |
---|
.. | .. |
---|
65 | 67 | struct gpio_chip gpio; |
---|
66 | 68 | #endif |
---|
67 | 69 | struct dentry *debugfs; |
---|
| 70 | + ktime_t write_time; |
---|
68 | 71 | }; |
---|
69 | 72 | #define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) |
---|
70 | 73 | |
---|
.. | .. |
---|
72 | 75 | struct i2c_client *client; |
---|
73 | 76 | u8 index; |
---|
74 | 77 | }; |
---|
| 78 | + |
---|
| 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 | +} |
---|
75 | 145 | |
---|
76 | 146 | static int ucd9000_get_fan_config(struct i2c_client *client, int fan) |
---|
77 | 147 | { |
---|
.. | .. |
---|
598 | 668 | info->read_byte_data = ucd9000_read_byte_data; |
---|
599 | 669 | info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 |
---|
600 | 670 | | 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; |
---|
601 | 676 | } |
---|
602 | 677 | |
---|
603 | 678 | ucd9000_probe_gpio(client, mid, data); |
---|