| .. | .. |
|---|
| 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); |
|---|