336 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators4 *5 * Copyright (c) 2017 Google Inc6 * Copyright (c) 2020 Renesas Electronics America7 *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 0x3022#define RAA_DMPVR2_READ_VMON 0xc823 24enum chips {25 isl68137,26 isl68220,27 isl68221,28 isl68222,29 isl68223,30 isl68224,31 isl68225,32 isl68226,33 isl68227,34 isl68229,35 isl68233,36 isl68239,37 isl69222,38 isl69223,39 isl69224,40 isl69225,41 isl69227,42 isl69228,43 isl69234,44 isl69236,45 isl69239,46 isl69242,47 isl69243,48 isl69247,49 isl69248,50 isl69254,51 isl69255,52 isl69256,53 isl69259,54 isl69260,55 isl69268,56 isl69269,57 isl69298,58 raa228000,59 raa228004,60 raa228006,61 raa228228,62 raa229001,63 raa229004,64};65 66enum variants {67 raa_dmpvr1_2rail,68 raa_dmpvr2_1rail,69 raa_dmpvr2_2rail,70 raa_dmpvr2_2rail_nontc,71 raa_dmpvr2_3rail,72 raa_dmpvr2_hv,73};74 75static const struct i2c_device_id raa_dmpvr_id[];76 77static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client,78 int page,79 char *buf)80{81 int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION);82 83 return sprintf(buf, "%d\n",84 (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0);85}86 87static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,88 int page,89 const char *buf, size_t count)90{91 int rc, op_val;92 bool result;93 94 rc = kstrtobool(buf, &result);95 if (rc)96 return rc;97 98 op_val = result ? ISL68137_VOUT_AVS : 0;99 100 /*101 * Writes to VOUT setpoint over AVSBus will persist after the VRM is102 * switched to PMBus control. Switching back to AVSBus control103 * restores this persisted setpoint rather than re-initializing to104 * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before105 * enabling AVS control is the workaround.106 */107 if (op_val == ISL68137_VOUT_AVS) {108 rc = pmbus_read_word_data(client, page, 0xff,109 PMBUS_VOUT_COMMAND);110 if (rc < 0)111 return rc;112 113 rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND,114 rc);115 if (rc < 0)116 return rc;117 }118 119 rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION,120 ISL68137_VOUT_AVS, op_val);121 122 return (rc < 0) ? rc : count;123}124 125static ssize_t isl68137_avs_enable_show(struct device *dev,126 struct device_attribute *devattr,127 char *buf)128{129 struct i2c_client *client = to_i2c_client(dev->parent);130 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);131 132 return isl68137_avs_enable_show_page(client, attr->index, buf);133}134 135static ssize_t isl68137_avs_enable_store(struct device *dev,136 struct device_attribute *devattr,137 const char *buf, size_t count)138{139 struct i2c_client *client = to_i2c_client(dev->parent);140 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);141 142 return isl68137_avs_enable_store_page(client, attr->index, buf, count);143}144 145static SENSOR_DEVICE_ATTR_RW(avs0_enable, isl68137_avs_enable, 0);146static SENSOR_DEVICE_ATTR_RW(avs1_enable, isl68137_avs_enable, 1);147 148static struct attribute *enable_attrs[] = {149 &sensor_dev_attr_avs0_enable.dev_attr.attr,150 &sensor_dev_attr_avs1_enable.dev_attr.attr,151 NULL,152};153 154static const struct attribute_group enable_group = {155 .attrs = enable_attrs,156};157 158static const struct attribute_group *isl68137_attribute_groups[] = {159 &enable_group,160 NULL,161};162 163static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page,164 int phase, int reg)165{166 int ret;167 168 switch (reg) {169 case PMBUS_VIRT_READ_VMON:170 ret = pmbus_read_word_data(client, page, phase,171 RAA_DMPVR2_READ_VMON);172 break;173 default:174 ret = -ENODATA;175 break;176 }177 178 return ret;179}180 181static struct pmbus_driver_info raa_dmpvr_info = {182 .pages = 3,183 .format[PSC_VOLTAGE_IN] = direct,184 .format[PSC_VOLTAGE_OUT] = direct,185 .format[PSC_CURRENT_IN] = direct,186 .format[PSC_CURRENT_OUT] = direct,187 .format[PSC_POWER] = direct,188 .format[PSC_TEMPERATURE] = direct,189 .m[PSC_VOLTAGE_IN] = 1,190 .b[PSC_VOLTAGE_IN] = 0,191 .R[PSC_VOLTAGE_IN] = 2,192 .m[PSC_VOLTAGE_OUT] = 1,193 .b[PSC_VOLTAGE_OUT] = 0,194 .R[PSC_VOLTAGE_OUT] = 3,195 .m[PSC_CURRENT_IN] = 1,196 .b[PSC_CURRENT_IN] = 0,197 .R[PSC_CURRENT_IN] = 2,198 .m[PSC_CURRENT_OUT] = 1,199 .b[PSC_CURRENT_OUT] = 0,200 .R[PSC_CURRENT_OUT] = 1,201 .m[PSC_POWER] = 1,202 .b[PSC_POWER] = 0,203 .R[PSC_POWER] = 0,204 .m[PSC_TEMPERATURE] = 1,205 .b[PSC_TEMPERATURE] = 0,206 .R[PSC_TEMPERATURE] = 0,207 .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN208 | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2209 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP210 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT211 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT212 | PMBUS_HAVE_VMON,213 .func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT214 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP215 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT216 | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,217 .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT218 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP219 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT220 | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,221};222 223static int isl68137_probe(struct i2c_client *client)224{225 struct pmbus_driver_info *info;226 227 info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);228 if (!info)229 return -ENOMEM;230 memcpy(info, &raa_dmpvr_info, sizeof(*info));231 232 switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) {233 case raa_dmpvr1_2rail:234 info->pages = 2;235 info->R[PSC_VOLTAGE_IN] = 3;236 info->func[0] &= ~PMBUS_HAVE_VMON;237 info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT238 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT239 | PMBUS_HAVE_POUT;240 info->groups = isl68137_attribute_groups;241 break;242 case raa_dmpvr2_1rail:243 info->pages = 1;244 info->read_word_data = raa_dmpvr2_read_word_data;245 break;246 case raa_dmpvr2_2rail_nontc:247 info->func[0] &= ~PMBUS_HAVE_TEMP3;248 info->func[1] &= ~PMBUS_HAVE_TEMP3;249 fallthrough;250 case raa_dmpvr2_2rail:251 info->pages = 2;252 info->read_word_data = raa_dmpvr2_read_word_data;253 break;254 case raa_dmpvr2_3rail:255 info->read_word_data = raa_dmpvr2_read_word_data;256 break;257 case raa_dmpvr2_hv:258 info->pages = 1;259 info->R[PSC_VOLTAGE_IN] = 1;260 info->m[PSC_VOLTAGE_OUT] = 2;261 info->R[PSC_VOLTAGE_OUT] = 2;262 info->m[PSC_CURRENT_IN] = 2;263 info->m[PSC_POWER] = 2;264 info->R[PSC_POWER] = -1;265 info->read_word_data = raa_dmpvr2_read_word_data;266 break;267 default:268 return -ENODEV;269 }270 271 return pmbus_do_probe(client, info);272}273 274static const struct i2c_device_id raa_dmpvr_id[] = {275 {"isl68137", raa_dmpvr1_2rail},276 {"isl68220", raa_dmpvr2_2rail},277 {"isl68221", raa_dmpvr2_3rail},278 {"isl68222", raa_dmpvr2_2rail},279 {"isl68223", raa_dmpvr2_2rail},280 {"isl68224", raa_dmpvr2_3rail},281 {"isl68225", raa_dmpvr2_2rail},282 {"isl68226", raa_dmpvr2_3rail},283 {"isl68227", raa_dmpvr2_1rail},284 {"isl68229", raa_dmpvr2_3rail},285 {"isl68233", raa_dmpvr2_2rail},286 {"isl68239", raa_dmpvr2_3rail},287 288 {"isl69222", raa_dmpvr2_2rail},289 {"isl69223", raa_dmpvr2_3rail},290 {"isl69224", raa_dmpvr2_2rail},291 {"isl69225", raa_dmpvr2_2rail},292 {"isl69227", raa_dmpvr2_3rail},293 {"isl69228", raa_dmpvr2_3rail},294 {"isl69234", raa_dmpvr2_2rail},295 {"isl69236", raa_dmpvr2_2rail},296 {"isl69239", raa_dmpvr2_3rail},297 {"isl69242", raa_dmpvr2_2rail},298 {"isl69243", raa_dmpvr2_1rail},299 {"isl69247", raa_dmpvr2_2rail},300 {"isl69248", raa_dmpvr2_2rail},301 {"isl69254", raa_dmpvr2_2rail},302 {"isl69255", raa_dmpvr2_2rail},303 {"isl69256", raa_dmpvr2_2rail},304 {"isl69259", raa_dmpvr2_2rail},305 {"isl69260", raa_dmpvr2_2rail},306 {"isl69268", raa_dmpvr2_2rail},307 {"isl69269", raa_dmpvr2_3rail},308 {"isl69298", raa_dmpvr2_2rail},309 310 {"raa228000", raa_dmpvr2_hv},311 {"raa228004", raa_dmpvr2_hv},312 {"raa228006", raa_dmpvr2_hv},313 {"raa228228", raa_dmpvr2_2rail_nontc},314 {"raa229001", raa_dmpvr2_2rail},315 {"raa229004", raa_dmpvr2_2rail},316 {}317};318 319MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id);320 321/* This is the driver that will be inserted */322static struct i2c_driver isl68137_driver = {323 .driver = {324 .name = "isl68137",325 },326 .probe = isl68137_probe,327 .id_table = raa_dmpvr_id,328};329 330module_i2c_driver(isl68137_driver);331 332MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>");333MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators");334MODULE_LICENSE("GPL");335MODULE_IMPORT_NS(PMBUS);336