0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/err.h>
0009 #include <linux/i2c.h>
0010 #include <linux/init.h>
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/pmbus.h>
0014 #include <linux/slab.h>
0015 #include "pmbus.h"
0016
0017 enum chips { pim4006, pim4328, pim4820 };
0018
0019 struct pim4328_data {
0020 enum chips id;
0021 struct pmbus_driver_info info;
0022 };
0023
0024 #define to_pim4328_data(x) container_of(x, struct pim4328_data, info)
0025
0026
0027 #define PIM4328_MFR_READ_VINA 0xd3
0028 #define PIM4328_MFR_READ_VINB 0xd4
0029
0030
0031 #define PIM4328_MFR_READ_IINA 0xd6
0032 #define PIM4328_MFR_READ_IINB 0xd7
0033 #define PIM4328_MFR_FET_CHECKSTATUS 0xd9
0034
0035
0036 #define PIM4328_MFR_STATUS_BITS 0xd5
0037
0038
0039 #define PIM4328_MFR_READ_STATUS 0xd0
0040
0041 static const struct i2c_device_id pim4328_id[] = {
0042 {"bmr455", pim4328},
0043 {"pim4006", pim4006},
0044 {"pim4106", pim4006},
0045 {"pim4206", pim4006},
0046 {"pim4306", pim4006},
0047 {"pim4328", pim4328},
0048 {"pim4406", pim4006},
0049 {"pim4820", pim4820},
0050 {}
0051 };
0052 MODULE_DEVICE_TABLE(i2c, pim4328_id);
0053
0054 static int pim4328_read_word_data(struct i2c_client *client, int page,
0055 int phase, int reg)
0056 {
0057 int ret;
0058
0059 if (page > 0)
0060 return -ENXIO;
0061
0062 if (phase == 0xff)
0063 return -ENODATA;
0064
0065 switch (reg) {
0066 case PMBUS_READ_VIN:
0067 ret = pmbus_read_word_data(client, page, phase,
0068 phase == 0 ? PIM4328_MFR_READ_VINA
0069 : PIM4328_MFR_READ_VINB);
0070 break;
0071 case PMBUS_READ_IIN:
0072 ret = pmbus_read_word_data(client, page, phase,
0073 phase == 0 ? PIM4328_MFR_READ_IINA
0074 : PIM4328_MFR_READ_IINB);
0075 break;
0076 default:
0077 ret = -ENODATA;
0078 }
0079
0080 return ret;
0081 }
0082
0083 static int pim4328_read_byte_data(struct i2c_client *client, int page, int reg)
0084 {
0085 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
0086 struct pim4328_data *data = to_pim4328_data(info);
0087 int ret, status;
0088
0089 if (page > 0)
0090 return -ENXIO;
0091
0092 switch (reg) {
0093 case PMBUS_STATUS_BYTE:
0094 ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE);
0095 if (ret < 0)
0096 return ret;
0097 if (data->id == pim4006) {
0098 status = pmbus_read_word_data(client, page, 0xff,
0099 PIM4328_MFR_FET_CHECKSTATUS);
0100 if (status < 0)
0101 return status;
0102 if (status & 0x0630)
0103 ret |= PB_STATUS_VIN_UV;
0104 } else if (data->id == pim4328) {
0105 status = pmbus_read_byte_data(client, page,
0106 PIM4328_MFR_STATUS_BITS);
0107 if (status < 0)
0108 return status;
0109 if (status & 0x04)
0110 ret |= PB_STATUS_VIN_UV;
0111 if (status & 0x40)
0112 ret |= PB_STATUS_NONE_ABOVE;
0113 } else if (data->id == pim4820) {
0114 status = pmbus_read_byte_data(client, page,
0115 PIM4328_MFR_READ_STATUS);
0116 if (status < 0)
0117 return status;
0118 if (status & 0x05)
0119 ret |= PB_STATUS_NONE_ABOVE;
0120 if (status & 0x1a)
0121 ret |= PB_STATUS_VIN_UV;
0122 if (status & 0x40)
0123 ret |= PB_STATUS_TEMPERATURE;
0124 }
0125 break;
0126 default:
0127 ret = -ENODATA;
0128 }
0129
0130 return ret;
0131 }
0132
0133 static int pim4328_probe(struct i2c_client *client)
0134 {
0135 int status;
0136 u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
0137 const struct i2c_device_id *mid;
0138 struct pim4328_data *data;
0139 struct pmbus_driver_info *info;
0140 struct pmbus_platform_data *pdata;
0141 struct device *dev = &client->dev;
0142
0143 if (!i2c_check_functionality(client->adapter,
0144 I2C_FUNC_SMBUS_READ_BYTE_DATA
0145 | I2C_FUNC_SMBUS_BLOCK_DATA))
0146 return -ENODEV;
0147
0148 data = devm_kzalloc(&client->dev, sizeof(struct pim4328_data),
0149 GFP_KERNEL);
0150 if (!data)
0151 return -ENOMEM;
0152
0153 status = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, device_id);
0154 if (status < 0) {
0155 dev_err(&client->dev, "Failed to read Manufacturer Model\n");
0156 return status;
0157 }
0158 for (mid = pim4328_id; mid->name[0]; mid++) {
0159 if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
0160 break;
0161 }
0162 if (!mid->name[0]) {
0163 dev_err(&client->dev, "Unsupported device\n");
0164 return -ENODEV;
0165 }
0166
0167 if (strcmp(client->name, mid->name))
0168 dev_notice(&client->dev,
0169 "Device mismatch: Configured %s, detected %s\n",
0170 client->name, mid->name);
0171
0172 data->id = mid->driver_data;
0173 info = &data->info;
0174 info->pages = 1;
0175 info->read_byte_data = pim4328_read_byte_data;
0176 info->read_word_data = pim4328_read_word_data;
0177
0178 pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data),
0179 GFP_KERNEL);
0180 if (!pdata)
0181 return -ENOMEM;
0182 dev->platform_data = pdata;
0183 pdata->flags = PMBUS_NO_CAPABILITY | PMBUS_NO_WRITE_PROTECT;
0184
0185 switch (data->id) {
0186 case pim4006:
0187 info->phases[0] = 2;
0188 info->func[0] = PMBUS_PHASE_VIRTUAL | PMBUS_HAVE_VIN
0189 | PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT;
0190 info->pfunc[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN;
0191 info->pfunc[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN;
0192 break;
0193 case pim4328:
0194 info->phases[0] = 2;
0195 info->func[0] = PMBUS_PHASE_VIRTUAL
0196 | PMBUS_HAVE_VCAP | PMBUS_HAVE_VIN
0197 | PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT;
0198 info->pfunc[0] = PMBUS_HAVE_VIN;
0199 info->pfunc[1] = PMBUS_HAVE_VIN;
0200 info->format[PSC_VOLTAGE_IN] = direct;
0201 info->format[PSC_TEMPERATURE] = direct;
0202 info->format[PSC_CURRENT_OUT] = direct;
0203 pdata->flags |= PMBUS_USE_COEFFICIENTS_CMD;
0204 break;
0205 case pim4820:
0206 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_TEMP
0207 | PMBUS_HAVE_IIN;
0208 info->format[PSC_VOLTAGE_IN] = direct;
0209 info->format[PSC_TEMPERATURE] = direct;
0210 info->format[PSC_CURRENT_IN] = direct;
0211 pdata->flags |= PMBUS_USE_COEFFICIENTS_CMD;
0212 break;
0213 default:
0214 return -ENODEV;
0215 }
0216
0217 return pmbus_do_probe(client, info);
0218 }
0219
0220 static struct i2c_driver pim4328_driver = {
0221 .driver = {
0222 .name = "pim4328",
0223 },
0224 .probe_new = pim4328_probe,
0225 .id_table = pim4328_id,
0226 };
0227
0228 module_i2c_driver(pim4328_driver);
0229
0230 MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>");
0231 MODULE_DESCRIPTION("PMBus driver for PIM4006, PIM4328, PIM4820 power interface modules");
0232 MODULE_LICENSE("GPL");
0233 MODULE_IMPORT_NS(PMBUS);