1*0c459759SDelphine CC Chiu // SPDX-License-Identifier: GPL-2.0-or-later 2*0c459759SDelphine CC Chiu 3*0c459759SDelphine CC Chiu #include <linux/err.h> 4*0c459759SDelphine CC Chiu #include <linux/i2c.h> 5*0c459759SDelphine CC Chiu #include <linux/init.h> 6*0c459759SDelphine CC Chiu #include <linux/kernel.h> 7*0c459759SDelphine CC Chiu #include <linux/module.h> 8*0c459759SDelphine CC Chiu #include <linux/pmbus.h> 9*0c459759SDelphine CC Chiu #include "pmbus.h" 10*0c459759SDelphine CC Chiu 11*0c459759SDelphine CC Chiu /* LTC4286 register */ 12*0c459759SDelphine CC Chiu #define LTC4286_MFR_CONFIG1 0xF2 13*0c459759SDelphine CC Chiu 14*0c459759SDelphine CC Chiu /* LTC4286 configuration */ 15*0c459759SDelphine CC Chiu #define VRANGE_SELECT_BIT BIT(1) 16*0c459759SDelphine CC Chiu 17*0c459759SDelphine CC Chiu #define LTC4286_MFR_ID_SIZE 3 18*0c459759SDelphine CC Chiu 19*0c459759SDelphine CC Chiu /* 20*0c459759SDelphine CC Chiu * Initialize the MBR as default settings which is referred to LTC4286 datasheet 21*0c459759SDelphine CC Chiu * (March 22, 2022 version) table 3 page 16 22*0c459759SDelphine CC Chiu */ 23*0c459759SDelphine CC Chiu static struct pmbus_driver_info ltc4286_info = { 24*0c459759SDelphine CC Chiu .pages = 1, 25*0c459759SDelphine CC Chiu .format[PSC_VOLTAGE_IN] = direct, 26*0c459759SDelphine CC Chiu .format[PSC_VOLTAGE_OUT] = direct, 27*0c459759SDelphine CC Chiu .format[PSC_CURRENT_OUT] = direct, 28*0c459759SDelphine CC Chiu .format[PSC_POWER] = direct, 29*0c459759SDelphine CC Chiu .format[PSC_TEMPERATURE] = direct, 30*0c459759SDelphine CC Chiu .m[PSC_VOLTAGE_IN] = 32, 31*0c459759SDelphine CC Chiu .b[PSC_VOLTAGE_IN] = 0, 32*0c459759SDelphine CC Chiu .R[PSC_VOLTAGE_IN] = 1, 33*0c459759SDelphine CC Chiu .m[PSC_VOLTAGE_OUT] = 32, 34*0c459759SDelphine CC Chiu .b[PSC_VOLTAGE_OUT] = 0, 35*0c459759SDelphine CC Chiu .R[PSC_VOLTAGE_OUT] = 1, 36*0c459759SDelphine CC Chiu .m[PSC_CURRENT_OUT] = 1024, 37*0c459759SDelphine CC Chiu .b[PSC_CURRENT_OUT] = 0, 38*0c459759SDelphine CC Chiu /* 39*0c459759SDelphine CC Chiu * The rsense value used in MBR formula in LTC4286 datasheet should be ohm unit. 40*0c459759SDelphine CC Chiu * However, the rsense value that user input is micro ohm. 41*0c459759SDelphine CC Chiu * Thus, the MBR setting which involves rsense should be shifted by 6 digits. 42*0c459759SDelphine CC Chiu */ 43*0c459759SDelphine CC Chiu .R[PSC_CURRENT_OUT] = 3 - 6, 44*0c459759SDelphine CC Chiu .m[PSC_POWER] = 1, 45*0c459759SDelphine CC Chiu .b[PSC_POWER] = 0, 46*0c459759SDelphine CC Chiu /* 47*0c459759SDelphine CC Chiu * The rsense value used in MBR formula in LTC4286 datasheet should be ohm unit. 48*0c459759SDelphine CC Chiu * However, the rsense value that user input is micro ohm. 49*0c459759SDelphine CC Chiu * Thus, the MBR setting which involves rsense should be shifted by 6 digits. 50*0c459759SDelphine CC Chiu */ 51*0c459759SDelphine CC Chiu .R[PSC_POWER] = 4 - 6, 52*0c459759SDelphine CC Chiu .m[PSC_TEMPERATURE] = 1, 53*0c459759SDelphine CC Chiu .b[PSC_TEMPERATURE] = 273, 54*0c459759SDelphine CC Chiu .R[PSC_TEMPERATURE] = 0, 55*0c459759SDelphine CC Chiu .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | 56*0c459759SDelphine CC Chiu PMBUS_HAVE_PIN | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_VOUT | 57*0c459759SDelphine CC Chiu PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_TEMP, 58*0c459759SDelphine CC Chiu }; 59*0c459759SDelphine CC Chiu 60*0c459759SDelphine CC Chiu static const struct i2c_device_id ltc4286_id[] = { 61*0c459759SDelphine CC Chiu { "ltc4286", 0 }, 62*0c459759SDelphine CC Chiu { "ltc4287", 1 }, 63*0c459759SDelphine CC Chiu {} 64*0c459759SDelphine CC Chiu }; 65*0c459759SDelphine CC Chiu MODULE_DEVICE_TABLE(i2c, ltc4286_id); 66*0c459759SDelphine CC Chiu 67*0c459759SDelphine CC Chiu static int ltc4286_probe(struct i2c_client *client) 68*0c459759SDelphine CC Chiu { 69*0c459759SDelphine CC Chiu int ret; 70*0c459759SDelphine CC Chiu const struct i2c_device_id *mid; 71*0c459759SDelphine CC Chiu u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; 72*0c459759SDelphine CC Chiu struct pmbus_driver_info *info; 73*0c459759SDelphine CC Chiu u32 rsense; 74*0c459759SDelphine CC Chiu int vrange_nval, vrange_oval; 75*0c459759SDelphine CC Chiu 76*0c459759SDelphine CC Chiu ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); 77*0c459759SDelphine CC Chiu if (ret < 0) { 78*0c459759SDelphine CC Chiu return dev_err_probe(&client->dev, ret, 79*0c459759SDelphine CC Chiu "Failed to read manufacturer id\n"); 80*0c459759SDelphine CC Chiu } 81*0c459759SDelphine CC Chiu 82*0c459759SDelphine CC Chiu /* 83*0c459759SDelphine CC Chiu * Refer to ltc4286 datasheet page 20 84*0c459759SDelphine CC Chiu * the manufacturer id is LTC 85*0c459759SDelphine CC Chiu */ 86*0c459759SDelphine CC Chiu if (ret != LTC4286_MFR_ID_SIZE || 87*0c459759SDelphine CC Chiu strncmp(block_buffer, "LTC", LTC4286_MFR_ID_SIZE)) { 88*0c459759SDelphine CC Chiu return dev_err_probe(&client->dev, -ENODEV, 89*0c459759SDelphine CC Chiu "Manufacturer id mismatch\n"); 90*0c459759SDelphine CC Chiu } 91*0c459759SDelphine CC Chiu 92*0c459759SDelphine CC Chiu ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); 93*0c459759SDelphine CC Chiu if (ret < 0) { 94*0c459759SDelphine CC Chiu return dev_err_probe(&client->dev, ret, 95*0c459759SDelphine CC Chiu "Failed to read manufacturer model\n"); 96*0c459759SDelphine CC Chiu } 97*0c459759SDelphine CC Chiu 98*0c459759SDelphine CC Chiu for (mid = ltc4286_id; mid->name[0]; mid++) { 99*0c459759SDelphine CC Chiu if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) 100*0c459759SDelphine CC Chiu break; 101*0c459759SDelphine CC Chiu } 102*0c459759SDelphine CC Chiu if (!mid->name[0]) 103*0c459759SDelphine CC Chiu return dev_err_probe(&client->dev, -ENODEV, 104*0c459759SDelphine CC Chiu "Unsupported device\n"); 105*0c459759SDelphine CC Chiu 106*0c459759SDelphine CC Chiu if (of_property_read_u32(client->dev.of_node, 107*0c459759SDelphine CC Chiu "shunt-resistor-micro-ohms", &rsense)) 108*0c459759SDelphine CC Chiu rsense = 300; /* 0.3 mOhm if not set via DT */ 109*0c459759SDelphine CC Chiu 110*0c459759SDelphine CC Chiu if (rsense == 0) 111*0c459759SDelphine CC Chiu return -EINVAL; 112*0c459759SDelphine CC Chiu 113*0c459759SDelphine CC Chiu /* Check for the latter MBR value won't overflow */ 114*0c459759SDelphine CC Chiu if (rsense > (INT_MAX / 1024)) 115*0c459759SDelphine CC Chiu return -EINVAL; 116*0c459759SDelphine CC Chiu 117*0c459759SDelphine CC Chiu info = devm_kmemdup(&client->dev, <c4286_info, sizeof(*info), 118*0c459759SDelphine CC Chiu GFP_KERNEL); 119*0c459759SDelphine CC Chiu if (!info) 120*0c459759SDelphine CC Chiu return -ENOMEM; 121*0c459759SDelphine CC Chiu 122*0c459759SDelphine CC Chiu /* Check MFR1 CONFIG register bit 1 VRANGE_SELECT before driver loading */ 123*0c459759SDelphine CC Chiu vrange_oval = i2c_smbus_read_word_data(client, LTC4286_MFR_CONFIG1); 124*0c459759SDelphine CC Chiu if (vrange_oval < 0) 125*0c459759SDelphine CC Chiu return dev_err_probe(&client->dev, vrange_oval, 126*0c459759SDelphine CC Chiu "Failed to read manufacturer configuration one\n"); 127*0c459759SDelphine CC Chiu vrange_nval = vrange_oval; 128*0c459759SDelphine CC Chiu 129*0c459759SDelphine CC Chiu if (device_property_read_bool(&client->dev, "adi,vrange-low-enable")) { 130*0c459759SDelphine CC Chiu vrange_nval &= 131*0c459759SDelphine CC Chiu ~VRANGE_SELECT_BIT; /* VRANGE_SELECT = 0, 25.6 volts */ 132*0c459759SDelphine CC Chiu 133*0c459759SDelphine CC Chiu info->m[PSC_VOLTAGE_IN] = 128; 134*0c459759SDelphine CC Chiu info->m[PSC_VOLTAGE_OUT] = 128; 135*0c459759SDelphine CC Chiu info->m[PSC_POWER] = 4 * rsense; 136*0c459759SDelphine CC Chiu } else { 137*0c459759SDelphine CC Chiu vrange_nval |= 138*0c459759SDelphine CC Chiu VRANGE_SELECT_BIT; /* VRANGE_SELECT = 1, 102.4 volts */ 139*0c459759SDelphine CC Chiu 140*0c459759SDelphine CC Chiu info->m[PSC_POWER] = rsense; 141*0c459759SDelphine CC Chiu } 142*0c459759SDelphine CC Chiu if (vrange_nval != vrange_oval) { 143*0c459759SDelphine CC Chiu /* Set MFR1 CONFIG register bit 1 VRANGE_SELECT */ 144*0c459759SDelphine CC Chiu ret = i2c_smbus_write_word_data(client, LTC4286_MFR_CONFIG1, 145*0c459759SDelphine CC Chiu vrange_nval); 146*0c459759SDelphine CC Chiu if (ret < 0) 147*0c459759SDelphine CC Chiu return dev_err_probe(&client->dev, ret, 148*0c459759SDelphine CC Chiu "Failed to set vrange\n"); 149*0c459759SDelphine CC Chiu } 150*0c459759SDelphine CC Chiu 151*0c459759SDelphine CC Chiu info->m[PSC_CURRENT_OUT] = 1024 * rsense; 152*0c459759SDelphine CC Chiu 153*0c459759SDelphine CC Chiu return pmbus_do_probe(client, info); 154*0c459759SDelphine CC Chiu } 155*0c459759SDelphine CC Chiu 156*0c459759SDelphine CC Chiu static const struct of_device_id ltc4286_of_match[] = { 157*0c459759SDelphine CC Chiu { .compatible = "lltc,ltc4286" }, 158*0c459759SDelphine CC Chiu { .compatible = "lltc,ltc4287" }, 159*0c459759SDelphine CC Chiu {} 160*0c459759SDelphine CC Chiu }; 161*0c459759SDelphine CC Chiu 162*0c459759SDelphine CC Chiu static struct i2c_driver ltc4286_driver = { 163*0c459759SDelphine CC Chiu .driver = { 164*0c459759SDelphine CC Chiu .name = "ltc4286", 165*0c459759SDelphine CC Chiu .of_match_table = ltc4286_of_match, 166*0c459759SDelphine CC Chiu }, 167*0c459759SDelphine CC Chiu .probe = ltc4286_probe, 168*0c459759SDelphine CC Chiu .id_table = ltc4286_id, 169*0c459759SDelphine CC Chiu }; 170*0c459759SDelphine CC Chiu 171*0c459759SDelphine CC Chiu module_i2c_driver(ltc4286_driver); 172*0c459759SDelphine CC Chiu 173*0c459759SDelphine CC Chiu MODULE_AUTHOR("Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>"); 174*0c459759SDelphine CC Chiu MODULE_DESCRIPTION("PMBUS driver for LTC4286 and compatibles"); 175*0c459759SDelphine CC Chiu MODULE_LICENSE("GPL"); 176