0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/err.h>
0010 #include <linux/i2c.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include "pmbus.h"
0015
0016 #define PXE1610_NUM_PAGES 3
0017
0018
0019 static int pxe1610_identify(struct i2c_client *client,
0020 struct pmbus_driver_info *info)
0021 {
0022 int i;
0023
0024 for (i = 0; i < PXE1610_NUM_PAGES; i++) {
0025 if (pmbus_check_byte_register(client, i, PMBUS_VOUT_MODE)) {
0026 u8 vout_mode;
0027 int ret;
0028
0029
0030 ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
0031 if (ret < 0)
0032 return ret;
0033
0034 vout_mode = ret & GENMASK(4, 0);
0035
0036 switch (vout_mode) {
0037 case 1:
0038 info->vrm_version[i] = vr12;
0039 break;
0040 case 2:
0041 info->vrm_version[i] = vr13;
0042 break;
0043 default:
0044
0045
0046
0047
0048 if (i != 0) {
0049 info->pages = i;
0050 return 0;
0051 }
0052
0053 return -ENODEV;
0054 }
0055 }
0056 }
0057
0058 return 0;
0059 }
0060
0061 static struct pmbus_driver_info pxe1610_info = {
0062 .pages = PXE1610_NUM_PAGES,
0063 .format[PSC_VOLTAGE_IN] = linear,
0064 .format[PSC_VOLTAGE_OUT] = vid,
0065 .format[PSC_CURRENT_IN] = linear,
0066 .format[PSC_CURRENT_OUT] = linear,
0067 .format[PSC_TEMPERATURE] = linear,
0068 .format[PSC_POWER] = linear,
0069 .func[0] = PMBUS_HAVE_VIN
0070 | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
0071 | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
0072 | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
0073 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
0074 | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
0075 .func[1] = PMBUS_HAVE_VIN
0076 | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
0077 | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
0078 | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
0079 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
0080 | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
0081 .func[2] = PMBUS_HAVE_VIN
0082 | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
0083 | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
0084 | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
0085 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
0086 | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
0087 .identify = pxe1610_identify,
0088 };
0089
0090 static int pxe1610_probe(struct i2c_client *client)
0091 {
0092 struct pmbus_driver_info *info;
0093 u8 buf[I2C_SMBUS_BLOCK_MAX];
0094 int ret;
0095
0096 if (!i2c_check_functionality(
0097 client->adapter,
0098 I2C_FUNC_SMBUS_READ_BYTE_DATA
0099 | I2C_FUNC_SMBUS_READ_WORD_DATA
0100 | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
0101 return -ENODEV;
0102
0103
0104
0105
0106
0107 i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
0108
0109
0110 ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
0111 if (ret < 0) {
0112 dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
0113 return ret;
0114 }
0115 if (ret != 2 || strncmp(buf, "XP", 2)) {
0116 dev_err(&client->dev, "MFR_ID unrecognized\n");
0117 return -ENODEV;
0118 }
0119
0120 info = devm_kmemdup(&client->dev, &pxe1610_info,
0121 sizeof(struct pmbus_driver_info),
0122 GFP_KERNEL);
0123 if (!info)
0124 return -ENOMEM;
0125
0126 return pmbus_do_probe(client, info);
0127 }
0128
0129 static const struct i2c_device_id pxe1610_id[] = {
0130 {"pxe1610", 0},
0131 {"pxe1110", 0},
0132 {"pxm1310", 0},
0133 {}
0134 };
0135
0136 MODULE_DEVICE_TABLE(i2c, pxe1610_id);
0137
0138 static struct i2c_driver pxe1610_driver = {
0139 .driver = {
0140 .name = "pxe1610",
0141 },
0142 .probe_new = pxe1610_probe,
0143 .id_table = pxe1610_id,
0144 };
0145
0146 module_i2c_driver(pxe1610_driver);
0147
0148 MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>");
0149 MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310");
0150 MODULE_LICENSE("GPL");
0151 MODULE_IMPORT_NS(PMBUS);