1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators 4 * 5 * Copyright (c) 2017 Google Inc 6 * Copyright (c) 2020 Renesas Electronics America 7 * 8 */ 9 10 #include <linux/err.h> 11 #include <linux/hwmon-sysfs.h> 12 #include <linux/i2c.h> 13 #include <linux/init.h> 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/string.h> 17 #include <linux/sysfs.h> 18 19 #include "pmbus.h" 20 21 #define ISL68137_VOUT_AVS 0x30 22 #define RAA_DMPVR2_READ_VMON 0xc8 23 24 enum versions { 25 isl68137, 26 raa_dmpvr2_1rail, 27 raa_dmpvr2_2rail, 28 raa_dmpvr2_3rail, 29 raa_dmpvr2_hv, 30 }; 31 32 static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, 33 int page, 34 char *buf) 35 { 36 int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION); 37 38 return sprintf(buf, "%d\n", 39 (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0); 40 } 41 42 static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, 43 int page, 44 const char *buf, size_t count) 45 { 46 int rc, op_val; 47 bool result; 48 49 rc = kstrtobool(buf, &result); 50 if (rc) 51 return rc; 52 53 op_val = result ? ISL68137_VOUT_AVS : 0; 54 55 /* 56 * Writes to VOUT setpoint over AVSBus will persist after the VRM is 57 * switched to PMBus control. Switching back to AVSBus control 58 * restores this persisted setpoint rather than re-initializing to 59 * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before 60 * enabling AVS control is the workaround. 61 */ 62 if (op_val == ISL68137_VOUT_AVS) { 63 rc = pmbus_read_word_data(client, page, 0xff, 64 PMBUS_VOUT_COMMAND); 65 if (rc < 0) 66 return rc; 67 68 rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, 69 rc); 70 if (rc < 0) 71 return rc; 72 } 73 74 rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION, 75 ISL68137_VOUT_AVS, op_val); 76 77 return (rc < 0) ? rc : count; 78 } 79 80 static ssize_t isl68137_avs_enable_show(struct device *dev, 81 struct device_attribute *devattr, 82 char *buf) 83 { 84 struct i2c_client *client = to_i2c_client(dev->parent); 85 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 86 87 return isl68137_avs_enable_show_page(client, attr->index, buf); 88 } 89 90 static ssize_t isl68137_avs_enable_store(struct device *dev, 91 struct device_attribute *devattr, 92 const char *buf, size_t count) 93 { 94 struct i2c_client *client = to_i2c_client(dev->parent); 95 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 96 97 return isl68137_avs_enable_store_page(client, attr->index, buf, count); 98 } 99 100 static SENSOR_DEVICE_ATTR_RW(avs0_enable, isl68137_avs_enable, 0); 101 static SENSOR_DEVICE_ATTR_RW(avs1_enable, isl68137_avs_enable, 1); 102 103 static struct attribute *enable_attrs[] = { 104 &sensor_dev_attr_avs0_enable.dev_attr.attr, 105 &sensor_dev_attr_avs1_enable.dev_attr.attr, 106 NULL, 107 }; 108 109 static const struct attribute_group enable_group = { 110 .attrs = enable_attrs, 111 }; 112 113 static const struct attribute_group *isl68137_attribute_groups[] = { 114 &enable_group, 115 NULL, 116 }; 117 118 static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, 119 int phase, int reg) 120 { 121 int ret; 122 123 switch (reg) { 124 case PMBUS_VIRT_READ_VMON: 125 ret = pmbus_read_word_data(client, page, phase, 126 RAA_DMPVR2_READ_VMON); 127 break; 128 default: 129 ret = -ENODATA; 130 break; 131 } 132 133 return ret; 134 } 135 136 static struct pmbus_driver_info raa_dmpvr_info = { 137 .pages = 3, 138 .format[PSC_VOLTAGE_IN] = direct, 139 .format[PSC_VOLTAGE_OUT] = direct, 140 .format[PSC_CURRENT_IN] = direct, 141 .format[PSC_CURRENT_OUT] = direct, 142 .format[PSC_POWER] = direct, 143 .format[PSC_TEMPERATURE] = direct, 144 .m[PSC_VOLTAGE_IN] = 1, 145 .b[PSC_VOLTAGE_IN] = 0, 146 .R[PSC_VOLTAGE_IN] = 2, 147 .m[PSC_VOLTAGE_OUT] = 1, 148 .b[PSC_VOLTAGE_OUT] = 0, 149 .R[PSC_VOLTAGE_OUT] = 3, 150 .m[PSC_CURRENT_IN] = 1, 151 .b[PSC_CURRENT_IN] = 0, 152 .R[PSC_CURRENT_IN] = 2, 153 .m[PSC_CURRENT_OUT] = 1, 154 .b[PSC_CURRENT_OUT] = 0, 155 .R[PSC_CURRENT_OUT] = 1, 156 .m[PSC_POWER] = 1, 157 .b[PSC_POWER] = 0, 158 .R[PSC_POWER] = 0, 159 .m[PSC_TEMPERATURE] = 1, 160 .b[PSC_TEMPERATURE] = 0, 161 .R[PSC_TEMPERATURE] = 0, 162 .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN 163 | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 164 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP 165 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 166 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT 167 | PMBUS_HAVE_VMON, 168 .func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT 169 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP 170 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT 171 | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, 172 .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT 173 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP 174 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT 175 | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, 176 }; 177 178 static int isl68137_probe(struct i2c_client *client, 179 const struct i2c_device_id *id) 180 { 181 struct pmbus_driver_info *info; 182 183 info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); 184 if (!info) 185 return -ENOMEM; 186 memcpy(info, &raa_dmpvr_info, sizeof(*info)); 187 188 switch (id->driver_data) { 189 case isl68137: 190 info->pages = 2; 191 info->R[PSC_VOLTAGE_IN] = 3; 192 info->func[0] &= ~PMBUS_HAVE_VMON; 193 info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 194 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT 195 | PMBUS_HAVE_POUT; 196 info->groups = isl68137_attribute_groups; 197 break; 198 case raa_dmpvr2_1rail: 199 info->pages = 1; 200 info->read_word_data = raa_dmpvr2_read_word_data; 201 break; 202 case raa_dmpvr2_2rail: 203 info->pages = 2; 204 info->read_word_data = raa_dmpvr2_read_word_data; 205 break; 206 case raa_dmpvr2_3rail: 207 info->read_word_data = raa_dmpvr2_read_word_data; 208 break; 209 case raa_dmpvr2_hv: 210 info->pages = 1; 211 info->R[PSC_VOLTAGE_IN] = 1; 212 info->m[PSC_VOLTAGE_OUT] = 2; 213 info->R[PSC_VOLTAGE_OUT] = 2; 214 info->m[PSC_CURRENT_IN] = 2; 215 info->m[PSC_POWER] = 2; 216 info->R[PSC_POWER] = -1; 217 info->read_word_data = raa_dmpvr2_read_word_data; 218 break; 219 default: 220 return -ENODEV; 221 } 222 223 return pmbus_do_probe(client, id, info); 224 } 225 226 static const struct i2c_device_id raa_dmpvr_id[] = { 227 {"isl68137", isl68137}, 228 {"raa_dmpvr2_1rail", raa_dmpvr2_1rail}, 229 {"raa_dmpvr2_2rail", raa_dmpvr2_2rail}, 230 {"raa_dmpvr2_3rail", raa_dmpvr2_3rail}, 231 {"raa_dmpvr2_hv", raa_dmpvr2_hv}, 232 {} 233 }; 234 235 MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id); 236 237 /* This is the driver that will be inserted */ 238 static struct i2c_driver isl68137_driver = { 239 .driver = { 240 .name = "isl68137", 241 }, 242 .probe = isl68137_probe, 243 .remove = pmbus_do_remove, 244 .id_table = raa_dmpvr_id, 245 }; 246 247 module_i2c_driver(isl68137_driver); 248 249 MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>"); 250 MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators"); 251 MODULE_LICENSE("GPL"); 252