1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Hardware monitoring driver for MPS Single-phase Digital VR Controllers(MP9945) 4 */ 5 6 #include <linux/bitfield.h> 7 #include <linux/i2c.h> 8 #include <linux/module.h> 9 #include <linux/of_device.h> 10 #include "pmbus.h" 11 12 #define MFR_VR_MULTI_CONFIG_R1 0x08 13 #define MFR_SVID_CFG_R1 0xBD 14 15 /* VOUT_MODE register values */ 16 #define VOUT_MODE_LINEAR16 0x17 17 #define VOUT_MODE_VID 0x21 18 #define VOUT_MODE_DIRECT 0x40 19 20 #define MP9945_PAGE_NUM 1 21 22 #define MP9945_RAIL1_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | \ 23 PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | \ 24 PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \ 25 PMBUS_HAVE_TEMP | \ 26 PMBUS_HAVE_STATUS_VOUT | \ 27 PMBUS_HAVE_STATUS_IOUT | \ 28 PMBUS_HAVE_STATUS_TEMP | \ 29 PMBUS_HAVE_STATUS_INPUT) 30 31 enum mp9945_vout_mode { 32 MP9945_VOUT_MODE_VID, 33 MP9945_VOUT_MODE_DIRECT, 34 MP9945_VOUT_MODE_LINEAR16, 35 }; 36 37 struct mp9945_data { 38 struct pmbus_driver_info info; 39 enum mp9945_vout_mode vout_mode; 40 int vid_resolution; 41 int vid_offset; 42 }; 43 44 #define to_mp9945_data(x) container_of(x, struct mp9945_data, info) 45 46 static int mp9945_read_vout(struct i2c_client *client, struct mp9945_data *data) 47 { 48 int ret; 49 50 ret = i2c_smbus_read_word_data(client, PMBUS_READ_VOUT); 51 if (ret < 0) 52 return ret; 53 54 ret &= GENMASK(11, 0); 55 56 switch (data->vout_mode) { 57 case MP9945_VOUT_MODE_VID: 58 if (ret > 0) 59 ret = (ret + data->vid_offset) * data->vid_resolution; 60 break; 61 case MP9945_VOUT_MODE_DIRECT: 62 break; 63 case MP9945_VOUT_MODE_LINEAR16: 64 /* LSB: 1000 * 2^-9 (mV) */ 65 ret = DIV_ROUND_CLOSEST(ret * 125, 64); 66 break; 67 default: 68 return -ENODEV; 69 } 70 71 return ret; 72 } 73 74 static int mp9945_read_byte_data(struct i2c_client *client, int page, int reg) 75 { 76 int ret; 77 78 ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 79 if (ret < 0) 80 return ret; 81 82 switch (reg) { 83 case PMBUS_VOUT_MODE: 84 /* 85 * Override VOUT_MODE to DIRECT as the driver handles custom 86 * VOUT format conversions internally. 87 */ 88 return PB_VOUT_MODE_DIRECT; 89 default: 90 return -ENODATA; 91 } 92 } 93 94 static int mp9945_read_word_data(struct i2c_client *client, int page, int phase, 95 int reg) 96 { 97 const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 98 struct mp9945_data *data = to_mp9945_data(info); 99 int ret; 100 101 ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 102 if (ret < 0) 103 return ret; 104 105 switch (reg) { 106 case PMBUS_READ_VOUT: 107 ret = mp9945_read_vout(client, data); 108 break; 109 case PMBUS_VOUT_OV_FAULT_LIMIT: 110 case PMBUS_VOUT_UV_FAULT_LIMIT: 111 ret = i2c_smbus_read_word_data(client, reg); 112 if (ret < 0) 113 return ret; 114 115 /* LSB: 1.95 (mV) */ 116 ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * 39, 20); 117 break; 118 case PMBUS_VOUT_UV_WARN_LIMIT: 119 ret = i2c_smbus_read_word_data(client, reg); 120 if (ret < 0) 121 return ret; 122 123 ret &= GENMASK(9, 0); 124 if (ret > 0) 125 ret = (ret + data->vid_offset) * data->vid_resolution; 126 break; 127 default: 128 ret = -ENODATA; 129 break; 130 } 131 132 return ret; 133 } 134 135 static int mp9945_identify(struct i2c_client *client, 136 struct pmbus_driver_info *info) 137 { 138 struct mp9945_data *data = to_mp9945_data(info); 139 int ret; 140 141 ret = i2c_smbus_read_byte_data(client, PMBUS_VOUT_MODE); 142 if (ret < 0) 143 return ret; 144 145 switch (ret) { 146 case VOUT_MODE_LINEAR16: 147 data->vout_mode = MP9945_VOUT_MODE_LINEAR16; 148 break; 149 case VOUT_MODE_VID: 150 data->vout_mode = MP9945_VOUT_MODE_VID; 151 break; 152 case VOUT_MODE_DIRECT: 153 data->vout_mode = MP9945_VOUT_MODE_DIRECT; 154 break; 155 default: 156 return -ENODEV; 157 } 158 159 ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 3); 160 if (ret < 0) 161 return ret; 162 163 ret = i2c_smbus_read_word_data(client, MFR_VR_MULTI_CONFIG_R1); 164 if (ret < 0) 165 return ret; 166 167 data->vid_resolution = (FIELD_GET(BIT(2), ret)) ? 5 : 10; 168 169 ret = i2c_smbus_read_word_data(client, MFR_SVID_CFG_R1); 170 if (ret < 0) 171 return ret; 172 173 data->vid_offset = (FIELD_GET(BIT(15), ret)) ? 19 : 49; 174 175 return i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 176 } 177 178 static struct pmbus_driver_info mp9945_info = { 179 .pages = MP9945_PAGE_NUM, 180 .format[PSC_VOLTAGE_IN] = linear, 181 .format[PSC_VOLTAGE_OUT] = direct, 182 .format[PSC_CURRENT_IN] = linear, 183 .format[PSC_CURRENT_OUT] = linear, 184 .format[PSC_POWER] = linear, 185 .format[PSC_TEMPERATURE] = linear, 186 .m[PSC_VOLTAGE_OUT] = 1, 187 .R[PSC_VOLTAGE_OUT] = 3, 188 .b[PSC_VOLTAGE_OUT] = 0, 189 .func[0] = MP9945_RAIL1_FUNC, 190 .read_word_data = mp9945_read_word_data, 191 .read_byte_data = mp9945_read_byte_data, 192 .identify = mp9945_identify, 193 }; 194 195 static int mp9945_probe(struct i2c_client *client) 196 { 197 struct mp9945_data *data; 198 int ret; 199 200 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 201 if (!data) 202 return -ENOMEM; 203 204 memcpy(&data->info, &mp9945_info, sizeof(mp9945_info)); 205 206 /* 207 * Set page 0 before probe. The core reads paged registers which are 208 * only on page 0 for this device. 209 */ 210 ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 211 if (ret < 0) 212 return ret; 213 214 return pmbus_do_probe(client, &data->info); 215 } 216 217 static const struct i2c_device_id mp9945_id[] = { 218 {"mp9945"}, 219 {} 220 }; 221 MODULE_DEVICE_TABLE(i2c, mp9945_id); 222 223 static const struct of_device_id __maybe_unused mp9945_of_match[] = { 224 {.compatible = "mps,mp9945"}, 225 {} 226 }; 227 MODULE_DEVICE_TABLE(of, mp9945_of_match); 228 229 static struct i2c_driver mp9945_driver = { 230 .driver = { 231 .name = "mp9945", 232 .of_match_table = of_match_ptr(mp9945_of_match), 233 }, 234 .probe = mp9945_probe, 235 .id_table = mp9945_id, 236 }; 237 238 module_i2c_driver(mp9945_driver); 239 240 MODULE_AUTHOR("Cosmo Chou <chou.cosmo@gmail.com>"); 241 MODULE_DESCRIPTION("PMBus driver for MPS MP9945"); 242 MODULE_LICENSE("GPL"); 243 MODULE_IMPORT_NS("PMBUS"); 244