1*8991ebd9SSamuel Mendoza-Jonas /* 2*8991ebd9SSamuel Mendoza-Jonas * Hardware monitoring driver for IR35221 3*8991ebd9SSamuel Mendoza-Jonas * 4*8991ebd9SSamuel Mendoza-Jonas * Copyright (C) IBM Corporation 2017. 5*8991ebd9SSamuel Mendoza-Jonas * 6*8991ebd9SSamuel Mendoza-Jonas * This program is free software; you can redistribute it and/or 7*8991ebd9SSamuel Mendoza-Jonas * modify it under the terms of the GNU General Public License 8*8991ebd9SSamuel Mendoza-Jonas * as published by the Free Software Foundation; either version 9*8991ebd9SSamuel Mendoza-Jonas * 2 of the License, or (at your option) any later version. 10*8991ebd9SSamuel Mendoza-Jonas */ 11*8991ebd9SSamuel Mendoza-Jonas 12*8991ebd9SSamuel Mendoza-Jonas #include <linux/err.h> 13*8991ebd9SSamuel Mendoza-Jonas #include <linux/i2c.h> 14*8991ebd9SSamuel Mendoza-Jonas #include <linux/init.h> 15*8991ebd9SSamuel Mendoza-Jonas #include <linux/kernel.h> 16*8991ebd9SSamuel Mendoza-Jonas #include <linux/module.h> 17*8991ebd9SSamuel Mendoza-Jonas #include "pmbus.h" 18*8991ebd9SSamuel Mendoza-Jonas 19*8991ebd9SSamuel Mendoza-Jonas #define IR35221_MFR_VIN_PEAK 0xc5 20*8991ebd9SSamuel Mendoza-Jonas #define IR35221_MFR_VOUT_PEAK 0xc6 21*8991ebd9SSamuel Mendoza-Jonas #define IR35221_MFR_IOUT_PEAK 0xc7 22*8991ebd9SSamuel Mendoza-Jonas #define IR35221_MFR_TEMP_PEAK 0xc8 23*8991ebd9SSamuel Mendoza-Jonas #define IR35221_MFR_VIN_VALLEY 0xc9 24*8991ebd9SSamuel Mendoza-Jonas #define IR35221_MFR_VOUT_VALLEY 0xca 25*8991ebd9SSamuel Mendoza-Jonas #define IR35221_MFR_IOUT_VALLEY 0xcb 26*8991ebd9SSamuel Mendoza-Jonas #define IR35221_MFR_TEMP_VALLEY 0xcc 27*8991ebd9SSamuel Mendoza-Jonas 28*8991ebd9SSamuel Mendoza-Jonas static long ir35221_reg2data(int data, enum pmbus_sensor_classes class) 29*8991ebd9SSamuel Mendoza-Jonas { 30*8991ebd9SSamuel Mendoza-Jonas s16 exponent; 31*8991ebd9SSamuel Mendoza-Jonas s32 mantissa; 32*8991ebd9SSamuel Mendoza-Jonas long val; 33*8991ebd9SSamuel Mendoza-Jonas 34*8991ebd9SSamuel Mendoza-Jonas /* We only modify LINEAR11 formats */ 35*8991ebd9SSamuel Mendoza-Jonas exponent = ((s16)data) >> 11; 36*8991ebd9SSamuel Mendoza-Jonas mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; 37*8991ebd9SSamuel Mendoza-Jonas 38*8991ebd9SSamuel Mendoza-Jonas val = mantissa * 1000L; 39*8991ebd9SSamuel Mendoza-Jonas 40*8991ebd9SSamuel Mendoza-Jonas /* scale result to micro-units for power sensors */ 41*8991ebd9SSamuel Mendoza-Jonas if (class == PSC_POWER) 42*8991ebd9SSamuel Mendoza-Jonas val = val * 1000L; 43*8991ebd9SSamuel Mendoza-Jonas 44*8991ebd9SSamuel Mendoza-Jonas if (exponent >= 0) 45*8991ebd9SSamuel Mendoza-Jonas val <<= exponent; 46*8991ebd9SSamuel Mendoza-Jonas else 47*8991ebd9SSamuel Mendoza-Jonas val >>= -exponent; 48*8991ebd9SSamuel Mendoza-Jonas 49*8991ebd9SSamuel Mendoza-Jonas return val; 50*8991ebd9SSamuel Mendoza-Jonas } 51*8991ebd9SSamuel Mendoza-Jonas 52*8991ebd9SSamuel Mendoza-Jonas #define MAX_MANTISSA (1023 * 1000) 53*8991ebd9SSamuel Mendoza-Jonas #define MIN_MANTISSA (511 * 1000) 54*8991ebd9SSamuel Mendoza-Jonas 55*8991ebd9SSamuel Mendoza-Jonas static u16 ir35221_data2reg(long val, enum pmbus_sensor_classes class) 56*8991ebd9SSamuel Mendoza-Jonas { 57*8991ebd9SSamuel Mendoza-Jonas s16 exponent = 0, mantissa; 58*8991ebd9SSamuel Mendoza-Jonas bool negative = false; 59*8991ebd9SSamuel Mendoza-Jonas 60*8991ebd9SSamuel Mendoza-Jonas if (val == 0) 61*8991ebd9SSamuel Mendoza-Jonas return 0; 62*8991ebd9SSamuel Mendoza-Jonas 63*8991ebd9SSamuel Mendoza-Jonas if (val < 0) { 64*8991ebd9SSamuel Mendoza-Jonas negative = true; 65*8991ebd9SSamuel Mendoza-Jonas val = -val; 66*8991ebd9SSamuel Mendoza-Jonas } 67*8991ebd9SSamuel Mendoza-Jonas 68*8991ebd9SSamuel Mendoza-Jonas /* Power is in uW. Convert to mW before converting. */ 69*8991ebd9SSamuel Mendoza-Jonas if (class == PSC_POWER) 70*8991ebd9SSamuel Mendoza-Jonas val = DIV_ROUND_CLOSEST(val, 1000L); 71*8991ebd9SSamuel Mendoza-Jonas 72*8991ebd9SSamuel Mendoza-Jonas /* Reduce large mantissa until it fits into 10 bit */ 73*8991ebd9SSamuel Mendoza-Jonas while (val >= MAX_MANTISSA && exponent < 15) { 74*8991ebd9SSamuel Mendoza-Jonas exponent++; 75*8991ebd9SSamuel Mendoza-Jonas val >>= 1; 76*8991ebd9SSamuel Mendoza-Jonas } 77*8991ebd9SSamuel Mendoza-Jonas /* Increase small mantissa to improve precision */ 78*8991ebd9SSamuel Mendoza-Jonas while (val < MIN_MANTISSA && exponent > -15) { 79*8991ebd9SSamuel Mendoza-Jonas exponent--; 80*8991ebd9SSamuel Mendoza-Jonas val <<= 1; 81*8991ebd9SSamuel Mendoza-Jonas } 82*8991ebd9SSamuel Mendoza-Jonas 83*8991ebd9SSamuel Mendoza-Jonas /* Convert mantissa from milli-units to units */ 84*8991ebd9SSamuel Mendoza-Jonas mantissa = DIV_ROUND_CLOSEST(val, 1000); 85*8991ebd9SSamuel Mendoza-Jonas 86*8991ebd9SSamuel Mendoza-Jonas /* Ensure that resulting number is within range */ 87*8991ebd9SSamuel Mendoza-Jonas if (mantissa > 0x3ff) 88*8991ebd9SSamuel Mendoza-Jonas mantissa = 0x3ff; 89*8991ebd9SSamuel Mendoza-Jonas 90*8991ebd9SSamuel Mendoza-Jonas /* restore sign */ 91*8991ebd9SSamuel Mendoza-Jonas if (negative) 92*8991ebd9SSamuel Mendoza-Jonas mantissa = -mantissa; 93*8991ebd9SSamuel Mendoza-Jonas 94*8991ebd9SSamuel Mendoza-Jonas /* Convert to 5 bit exponent, 11 bit mantissa */ 95*8991ebd9SSamuel Mendoza-Jonas return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); 96*8991ebd9SSamuel Mendoza-Jonas } 97*8991ebd9SSamuel Mendoza-Jonas 98*8991ebd9SSamuel Mendoza-Jonas static u16 ir35221_scale_result(s16 data, int shift, 99*8991ebd9SSamuel Mendoza-Jonas enum pmbus_sensor_classes class) 100*8991ebd9SSamuel Mendoza-Jonas { 101*8991ebd9SSamuel Mendoza-Jonas long val; 102*8991ebd9SSamuel Mendoza-Jonas 103*8991ebd9SSamuel Mendoza-Jonas val = ir35221_reg2data(data, class); 104*8991ebd9SSamuel Mendoza-Jonas 105*8991ebd9SSamuel Mendoza-Jonas if (shift < 0) 106*8991ebd9SSamuel Mendoza-Jonas val >>= -shift; 107*8991ebd9SSamuel Mendoza-Jonas else 108*8991ebd9SSamuel Mendoza-Jonas val <<= shift; 109*8991ebd9SSamuel Mendoza-Jonas 110*8991ebd9SSamuel Mendoza-Jonas return ir35221_data2reg(val, class); 111*8991ebd9SSamuel Mendoza-Jonas } 112*8991ebd9SSamuel Mendoza-Jonas 113*8991ebd9SSamuel Mendoza-Jonas static int ir35221_read_word_data(struct i2c_client *client, int page, int reg) 114*8991ebd9SSamuel Mendoza-Jonas { 115*8991ebd9SSamuel Mendoza-Jonas int ret; 116*8991ebd9SSamuel Mendoza-Jonas 117*8991ebd9SSamuel Mendoza-Jonas switch (reg) { 118*8991ebd9SSamuel Mendoza-Jonas case PMBUS_IOUT_OC_FAULT_LIMIT: 119*8991ebd9SSamuel Mendoza-Jonas case PMBUS_IOUT_OC_WARN_LIMIT: 120*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, reg); 121*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 122*8991ebd9SSamuel Mendoza-Jonas break; 123*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, 1, PSC_CURRENT_OUT); 124*8991ebd9SSamuel Mendoza-Jonas break; 125*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIN_OV_FAULT_LIMIT: 126*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIN_OV_WARN_LIMIT: 127*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIN_UV_WARN_LIMIT: 128*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, reg); 129*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -4, PSC_VOLTAGE_IN); 130*8991ebd9SSamuel Mendoza-Jonas break; 131*8991ebd9SSamuel Mendoza-Jonas case PMBUS_IIN_OC_WARN_LIMIT: 132*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, reg); 133*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 134*8991ebd9SSamuel Mendoza-Jonas break; 135*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN); 136*8991ebd9SSamuel Mendoza-Jonas break; 137*8991ebd9SSamuel Mendoza-Jonas case PMBUS_READ_VIN: 138*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, PMBUS_READ_VIN); 139*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 140*8991ebd9SSamuel Mendoza-Jonas break; 141*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN); 142*8991ebd9SSamuel Mendoza-Jonas break; 143*8991ebd9SSamuel Mendoza-Jonas case PMBUS_READ_IIN: 144*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, PMBUS_READ_IIN); 145*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 146*8991ebd9SSamuel Mendoza-Jonas break; 147*8991ebd9SSamuel Mendoza-Jonas if (page == 0) 148*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -4, PSC_CURRENT_IN); 149*8991ebd9SSamuel Mendoza-Jonas else 150*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -5, PSC_CURRENT_IN); 151*8991ebd9SSamuel Mendoza-Jonas break; 152*8991ebd9SSamuel Mendoza-Jonas case PMBUS_READ_POUT: 153*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, PMBUS_READ_POUT); 154*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 155*8991ebd9SSamuel Mendoza-Jonas break; 156*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -1, PSC_POWER); 157*8991ebd9SSamuel Mendoza-Jonas break; 158*8991ebd9SSamuel Mendoza-Jonas case PMBUS_READ_PIN: 159*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, PMBUS_READ_PIN); 160*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 161*8991ebd9SSamuel Mendoza-Jonas break; 162*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -1, PSC_POWER); 163*8991ebd9SSamuel Mendoza-Jonas break; 164*8991ebd9SSamuel Mendoza-Jonas case PMBUS_READ_IOUT: 165*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, PMBUS_READ_IOUT); 166*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 167*8991ebd9SSamuel Mendoza-Jonas break; 168*8991ebd9SSamuel Mendoza-Jonas if (page == 0) 169*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -1, PSC_CURRENT_OUT); 170*8991ebd9SSamuel Mendoza-Jonas else 171*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -2, PSC_CURRENT_OUT); 172*8991ebd9SSamuel Mendoza-Jonas break; 173*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIRT_READ_VIN_MAX: 174*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, IR35221_MFR_VIN_PEAK); 175*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 176*8991ebd9SSamuel Mendoza-Jonas break; 177*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN); 178*8991ebd9SSamuel Mendoza-Jonas break; 179*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIRT_READ_VOUT_MAX: 180*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, IR35221_MFR_VOUT_PEAK); 181*8991ebd9SSamuel Mendoza-Jonas break; 182*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIRT_READ_IOUT_MAX: 183*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, IR35221_MFR_IOUT_PEAK); 184*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 185*8991ebd9SSamuel Mendoza-Jonas break; 186*8991ebd9SSamuel Mendoza-Jonas if (page == 0) 187*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN); 188*8991ebd9SSamuel Mendoza-Jonas else 189*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -2, PSC_CURRENT_IN); 190*8991ebd9SSamuel Mendoza-Jonas break; 191*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIRT_READ_TEMP_MAX: 192*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, IR35221_MFR_TEMP_PEAK); 193*8991ebd9SSamuel Mendoza-Jonas break; 194*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIRT_READ_VIN_MIN: 195*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, 196*8991ebd9SSamuel Mendoza-Jonas IR35221_MFR_VIN_VALLEY); 197*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 198*8991ebd9SSamuel Mendoza-Jonas break; 199*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN); 200*8991ebd9SSamuel Mendoza-Jonas break; 201*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIRT_READ_VOUT_MIN: 202*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, 203*8991ebd9SSamuel Mendoza-Jonas IR35221_MFR_VOUT_VALLEY); 204*8991ebd9SSamuel Mendoza-Jonas break; 205*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIRT_READ_IOUT_MIN: 206*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, 207*8991ebd9SSamuel Mendoza-Jonas IR35221_MFR_IOUT_VALLEY); 208*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) 209*8991ebd9SSamuel Mendoza-Jonas break; 210*8991ebd9SSamuel Mendoza-Jonas if (page == 0) 211*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN); 212*8991ebd9SSamuel Mendoza-Jonas else 213*8991ebd9SSamuel Mendoza-Jonas ret = ir35221_scale_result(ret, -2, PSC_CURRENT_IN); 214*8991ebd9SSamuel Mendoza-Jonas break; 215*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIRT_READ_TEMP_MIN: 216*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_read_word_data(client, page, 217*8991ebd9SSamuel Mendoza-Jonas IR35221_MFR_TEMP_VALLEY); 218*8991ebd9SSamuel Mendoza-Jonas break; 219*8991ebd9SSamuel Mendoza-Jonas default: 220*8991ebd9SSamuel Mendoza-Jonas ret = -ENODATA; 221*8991ebd9SSamuel Mendoza-Jonas break; 222*8991ebd9SSamuel Mendoza-Jonas } 223*8991ebd9SSamuel Mendoza-Jonas 224*8991ebd9SSamuel Mendoza-Jonas return ret; 225*8991ebd9SSamuel Mendoza-Jonas } 226*8991ebd9SSamuel Mendoza-Jonas 227*8991ebd9SSamuel Mendoza-Jonas static int ir35221_write_word_data(struct i2c_client *client, int page, int reg, 228*8991ebd9SSamuel Mendoza-Jonas u16 word) 229*8991ebd9SSamuel Mendoza-Jonas { 230*8991ebd9SSamuel Mendoza-Jonas int ret; 231*8991ebd9SSamuel Mendoza-Jonas u16 val; 232*8991ebd9SSamuel Mendoza-Jonas 233*8991ebd9SSamuel Mendoza-Jonas switch (reg) { 234*8991ebd9SSamuel Mendoza-Jonas case PMBUS_IOUT_OC_FAULT_LIMIT: 235*8991ebd9SSamuel Mendoza-Jonas case PMBUS_IOUT_OC_WARN_LIMIT: 236*8991ebd9SSamuel Mendoza-Jonas val = ir35221_scale_result(word, -1, PSC_CURRENT_OUT); 237*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_write_word_data(client, page, reg, val); 238*8991ebd9SSamuel Mendoza-Jonas break; 239*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIN_OV_FAULT_LIMIT: 240*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIN_OV_WARN_LIMIT: 241*8991ebd9SSamuel Mendoza-Jonas case PMBUS_VIN_UV_WARN_LIMIT: 242*8991ebd9SSamuel Mendoza-Jonas val = ir35221_scale_result(word, 4, PSC_VOLTAGE_IN); 243*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_write_word_data(client, page, reg, val); 244*8991ebd9SSamuel Mendoza-Jonas break; 245*8991ebd9SSamuel Mendoza-Jonas case PMBUS_IIN_OC_WARN_LIMIT: 246*8991ebd9SSamuel Mendoza-Jonas val = ir35221_scale_result(word, 1, PSC_CURRENT_IN); 247*8991ebd9SSamuel Mendoza-Jonas ret = pmbus_write_word_data(client, page, reg, val); 248*8991ebd9SSamuel Mendoza-Jonas break; 249*8991ebd9SSamuel Mendoza-Jonas default: 250*8991ebd9SSamuel Mendoza-Jonas ret = -ENODATA; 251*8991ebd9SSamuel Mendoza-Jonas break; 252*8991ebd9SSamuel Mendoza-Jonas } 253*8991ebd9SSamuel Mendoza-Jonas 254*8991ebd9SSamuel Mendoza-Jonas return ret; 255*8991ebd9SSamuel Mendoza-Jonas } 256*8991ebd9SSamuel Mendoza-Jonas 257*8991ebd9SSamuel Mendoza-Jonas static int ir35221_probe(struct i2c_client *client, 258*8991ebd9SSamuel Mendoza-Jonas const struct i2c_device_id *id) 259*8991ebd9SSamuel Mendoza-Jonas { 260*8991ebd9SSamuel Mendoza-Jonas struct pmbus_driver_info *info; 261*8991ebd9SSamuel Mendoza-Jonas u8 buf[I2C_SMBUS_BLOCK_MAX]; 262*8991ebd9SSamuel Mendoza-Jonas int ret; 263*8991ebd9SSamuel Mendoza-Jonas 264*8991ebd9SSamuel Mendoza-Jonas if (!i2c_check_functionality(client->adapter, 265*8991ebd9SSamuel Mendoza-Jonas I2C_FUNC_SMBUS_READ_BYTE_DATA 266*8991ebd9SSamuel Mendoza-Jonas | I2C_FUNC_SMBUS_READ_WORD_DATA 267*8991ebd9SSamuel Mendoza-Jonas | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) 268*8991ebd9SSamuel Mendoza-Jonas return -ENODEV; 269*8991ebd9SSamuel Mendoza-Jonas 270*8991ebd9SSamuel Mendoza-Jonas ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); 271*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) { 272*8991ebd9SSamuel Mendoza-Jonas dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n"); 273*8991ebd9SSamuel Mendoza-Jonas return ret; 274*8991ebd9SSamuel Mendoza-Jonas } 275*8991ebd9SSamuel Mendoza-Jonas if (ret != 2 || strncmp(buf, "RI", strlen("RI"))) { 276*8991ebd9SSamuel Mendoza-Jonas dev_err(&client->dev, "MFR_ID unrecognised\n"); 277*8991ebd9SSamuel Mendoza-Jonas return -ENODEV; 278*8991ebd9SSamuel Mendoza-Jonas } 279*8991ebd9SSamuel Mendoza-Jonas 280*8991ebd9SSamuel Mendoza-Jonas ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); 281*8991ebd9SSamuel Mendoza-Jonas if (ret < 0) { 282*8991ebd9SSamuel Mendoza-Jonas dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n"); 283*8991ebd9SSamuel Mendoza-Jonas return ret; 284*8991ebd9SSamuel Mendoza-Jonas } 285*8991ebd9SSamuel Mendoza-Jonas if (ret != 2 || !(buf[0] == 0x6c && buf[1] == 0x00)) { 286*8991ebd9SSamuel Mendoza-Jonas dev_err(&client->dev, "MFR_MODEL unrecognised\n"); 287*8991ebd9SSamuel Mendoza-Jonas return -ENODEV; 288*8991ebd9SSamuel Mendoza-Jonas } 289*8991ebd9SSamuel Mendoza-Jonas 290*8991ebd9SSamuel Mendoza-Jonas info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info), 291*8991ebd9SSamuel Mendoza-Jonas GFP_KERNEL); 292*8991ebd9SSamuel Mendoza-Jonas if (!info) 293*8991ebd9SSamuel Mendoza-Jonas return -ENOMEM; 294*8991ebd9SSamuel Mendoza-Jonas 295*8991ebd9SSamuel Mendoza-Jonas info->write_word_data = ir35221_write_word_data; 296*8991ebd9SSamuel Mendoza-Jonas info->read_word_data = ir35221_read_word_data; 297*8991ebd9SSamuel Mendoza-Jonas 298*8991ebd9SSamuel Mendoza-Jonas info->pages = 2; 299*8991ebd9SSamuel Mendoza-Jonas info->format[PSC_VOLTAGE_IN] = linear; 300*8991ebd9SSamuel Mendoza-Jonas info->format[PSC_VOLTAGE_OUT] = linear; 301*8991ebd9SSamuel Mendoza-Jonas info->format[PSC_CURRENT_IN] = linear; 302*8991ebd9SSamuel Mendoza-Jonas info->format[PSC_CURRENT_OUT] = linear; 303*8991ebd9SSamuel Mendoza-Jonas info->format[PSC_POWER] = linear; 304*8991ebd9SSamuel Mendoza-Jonas info->format[PSC_TEMPERATURE] = linear; 305*8991ebd9SSamuel Mendoza-Jonas 306*8991ebd9SSamuel Mendoza-Jonas info->func[0] = PMBUS_HAVE_VIN 307*8991ebd9SSamuel Mendoza-Jonas | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN 308*8991ebd9SSamuel Mendoza-Jonas | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN 309*8991ebd9SSamuel Mendoza-Jonas | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP 310*8991ebd9SSamuel Mendoza-Jonas | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT 311*8991ebd9SSamuel Mendoza-Jonas | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP; 312*8991ebd9SSamuel Mendoza-Jonas info->func[1] = info->func[0]; 313*8991ebd9SSamuel Mendoza-Jonas 314*8991ebd9SSamuel Mendoza-Jonas return pmbus_do_probe(client, id, info); 315*8991ebd9SSamuel Mendoza-Jonas } 316*8991ebd9SSamuel Mendoza-Jonas 317*8991ebd9SSamuel Mendoza-Jonas static const struct i2c_device_id ir35221_id[] = { 318*8991ebd9SSamuel Mendoza-Jonas {"ir35221", 0}, 319*8991ebd9SSamuel Mendoza-Jonas {} 320*8991ebd9SSamuel Mendoza-Jonas }; 321*8991ebd9SSamuel Mendoza-Jonas 322*8991ebd9SSamuel Mendoza-Jonas MODULE_DEVICE_TABLE(i2c, ir35221_id); 323*8991ebd9SSamuel Mendoza-Jonas 324*8991ebd9SSamuel Mendoza-Jonas static struct i2c_driver ir35221_driver = { 325*8991ebd9SSamuel Mendoza-Jonas .driver = { 326*8991ebd9SSamuel Mendoza-Jonas .name = "ir35221", 327*8991ebd9SSamuel Mendoza-Jonas }, 328*8991ebd9SSamuel Mendoza-Jonas .probe = ir35221_probe, 329*8991ebd9SSamuel Mendoza-Jonas .remove = pmbus_do_remove, 330*8991ebd9SSamuel Mendoza-Jonas .id_table = ir35221_id, 331*8991ebd9SSamuel Mendoza-Jonas }; 332*8991ebd9SSamuel Mendoza-Jonas 333*8991ebd9SSamuel Mendoza-Jonas module_i2c_driver(ir35221_driver); 334*8991ebd9SSamuel Mendoza-Jonas 335*8991ebd9SSamuel Mendoza-Jonas MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com"); 336*8991ebd9SSamuel Mendoza-Jonas MODULE_DESCRIPTION("PMBus driver for IR35221"); 337*8991ebd9SSamuel Mendoza-Jonas MODULE_LICENSE("GPL"); 338