19d2ecfb7SGuenter Roeck /* 29d2ecfb7SGuenter Roeck * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller 39d2ecfb7SGuenter Roeck * and Digital Power Monitor 49d2ecfb7SGuenter Roeck * 59d2ecfb7SGuenter Roeck * Copyright (c) 2011 Ericsson AB. 69d2ecfb7SGuenter Roeck * 79d2ecfb7SGuenter Roeck * This program is free software; you can redistribute it and/or modify 89d2ecfb7SGuenter Roeck * it under the terms of the GNU General Public License as published by 99d2ecfb7SGuenter Roeck * the Free Software Foundation; either version 2 of the License, or 109d2ecfb7SGuenter Roeck * (at your option) any later version. 119d2ecfb7SGuenter Roeck * 129d2ecfb7SGuenter Roeck * This program is distributed in the hope that it will be useful, 139d2ecfb7SGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 149d2ecfb7SGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 159d2ecfb7SGuenter Roeck * GNU General Public License for more details. 169d2ecfb7SGuenter Roeck */ 179d2ecfb7SGuenter Roeck 189d2ecfb7SGuenter Roeck #include <linux/kernel.h> 199d2ecfb7SGuenter Roeck #include <linux/module.h> 209d2ecfb7SGuenter Roeck #include <linux/init.h> 219d2ecfb7SGuenter Roeck #include <linux/err.h> 229d2ecfb7SGuenter Roeck #include <linux/slab.h> 239d2ecfb7SGuenter Roeck #include <linux/i2c.h> 2499b41608SGuenter Roeck #include <linux/bitops.h> 259d2ecfb7SGuenter Roeck #include "pmbus.h" 269d2ecfb7SGuenter Roeck 2792711269SGuenter Roeck enum chips { adm1075, adm1275, adm1276 }; 285cf231a3SGuenter Roeck 29c576e30cSGuenter Roeck #define ADM1275_PEAK_IOUT 0xd0 30c576e30cSGuenter Roeck #define ADM1275_PEAK_VIN 0xd1 31c576e30cSGuenter Roeck #define ADM1275_PEAK_VOUT 0xd2 329d2ecfb7SGuenter Roeck #define ADM1275_PMON_CONFIG 0xd4 339d2ecfb7SGuenter Roeck 3499b41608SGuenter Roeck #define ADM1275_VIN_VOUT_SELECT BIT(6) 3599b41608SGuenter Roeck #define ADM1275_VRANGE BIT(5) 3699b41608SGuenter Roeck #define ADM1075_IRANGE_50 BIT(4) 3799b41608SGuenter Roeck #define ADM1075_IRANGE_25 BIT(3) 3899b41608SGuenter Roeck #define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) 399d2ecfb7SGuenter Roeck 40c5e67636SGuenter Roeck #define ADM1275_IOUT_WARN2_LIMIT 0xd7 41c5e67636SGuenter Roeck #define ADM1275_DEVICE_CONFIG 0xd8 42c5e67636SGuenter Roeck 4399b41608SGuenter Roeck #define ADM1275_IOUT_WARN2_SELECT BIT(4) 44c5e67636SGuenter Roeck 455cf231a3SGuenter Roeck #define ADM1276_PEAK_PIN 0xda 465cf231a3SGuenter Roeck 4799b41608SGuenter Roeck #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) 48c5e67636SGuenter Roeck 4992711269SGuenter Roeck #define ADM1075_READ_VAUX 0xdd 5092711269SGuenter Roeck #define ADM1075_VAUX_OV_WARN_LIMIT 0xde 5192711269SGuenter Roeck #define ADM1075_VAUX_UV_WARN_LIMIT 0xdf 5292711269SGuenter Roeck #define ADM1075_VAUX_STATUS 0xf6 5392711269SGuenter Roeck 5499b41608SGuenter Roeck #define ADM1075_VAUX_OV_WARN BIT(7) 5599b41608SGuenter Roeck #define ADM1075_VAUX_UV_WARN BIT(6) 5692711269SGuenter Roeck 57c5e67636SGuenter Roeck struct adm1275_data { 585cf231a3SGuenter Roeck int id; 59c5e67636SGuenter Roeck bool have_oc_fault; 60*9048539bSGuenter Roeck bool have_uc_fault; 61*9048539bSGuenter Roeck bool have_vout; 62*9048539bSGuenter Roeck bool have_vaux_status; 63*9048539bSGuenter Roeck bool have_pin_max; 64c5e67636SGuenter Roeck struct pmbus_driver_info info; 65c5e67636SGuenter Roeck }; 66c5e67636SGuenter Roeck 67c5e67636SGuenter Roeck #define to_adm1275_data(x) container_of(x, struct adm1275_data, info) 68c5e67636SGuenter Roeck 69904b296fSGuenter Roeck struct coefficients { 70904b296fSGuenter Roeck s16 m; 71904b296fSGuenter Roeck s16 b; 72904b296fSGuenter Roeck s16 R; 73904b296fSGuenter Roeck }; 74904b296fSGuenter Roeck 75904b296fSGuenter Roeck static const struct coefficients adm1075_coefficients[] = { 76904b296fSGuenter Roeck [0] = { 27169, 0, -1 }, /* voltage */ 77904b296fSGuenter Roeck [1] = { 806, 20475, -1 }, /* current, irange25 */ 78904b296fSGuenter Roeck [2] = { 404, 20475, -1 }, /* current, irange50 */ 79904b296fSGuenter Roeck [3] = { 0, -1, 8549 }, /* power, irange25 */ 80904b296fSGuenter Roeck [4] = { 0, -1, 4279 }, /* power, irange50 */ 81904b296fSGuenter Roeck }; 82904b296fSGuenter Roeck 83904b296fSGuenter Roeck static const struct coefficients adm1275_coefficients[] = { 84904b296fSGuenter Roeck [0] = { 19199, 0, -2 }, /* voltage, vrange set */ 85904b296fSGuenter Roeck [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ 86904b296fSGuenter Roeck [2] = { 807, 20475, -1 }, /* current */ 87904b296fSGuenter Roeck }; 88904b296fSGuenter Roeck 89904b296fSGuenter Roeck static const struct coefficients adm1276_coefficients[] = { 90904b296fSGuenter Roeck [0] = { 19199, 0, -2 }, /* voltage, vrange set */ 91904b296fSGuenter Roeck [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ 92904b296fSGuenter Roeck [2] = { 807, 20475, -1 }, /* current */ 93904b296fSGuenter Roeck [3] = { 6043, 0, -2 }, /* power, vrange set */ 94904b296fSGuenter Roeck [4] = { 2115, 0, -1 }, /* power, vrange not set */ 95904b296fSGuenter Roeck }; 96904b296fSGuenter Roeck 97c576e30cSGuenter Roeck static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) 98c576e30cSGuenter Roeck { 99c5e67636SGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 100c5e67636SGuenter Roeck const struct adm1275_data *data = to_adm1275_data(info); 1015cf231a3SGuenter Roeck int ret = 0; 102c576e30cSGuenter Roeck 103c576e30cSGuenter Roeck if (page) 104c5e67636SGuenter Roeck return -ENXIO; 105c576e30cSGuenter Roeck 106c576e30cSGuenter Roeck switch (reg) { 107c5e67636SGuenter Roeck case PMBUS_IOUT_UC_FAULT_LIMIT: 108*9048539bSGuenter Roeck if (!data->have_uc_fault) 109*9048539bSGuenter Roeck return -ENXIO; 110c5e67636SGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); 111c5e67636SGuenter Roeck break; 112c5e67636SGuenter Roeck case PMBUS_IOUT_OC_FAULT_LIMIT: 113*9048539bSGuenter Roeck if (!data->have_oc_fault) 114*9048539bSGuenter Roeck return -ENXIO; 115c5e67636SGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); 116c5e67636SGuenter Roeck break; 11792711269SGuenter Roeck case PMBUS_VOUT_OV_WARN_LIMIT: 118*9048539bSGuenter Roeck if (data->have_vout) 119*9048539bSGuenter Roeck return -ENODATA; 12092711269SGuenter Roeck ret = pmbus_read_word_data(client, 0, 12192711269SGuenter Roeck ADM1075_VAUX_OV_WARN_LIMIT); 12292711269SGuenter Roeck break; 12392711269SGuenter Roeck case PMBUS_VOUT_UV_WARN_LIMIT: 124*9048539bSGuenter Roeck if (data->have_vout) 125*9048539bSGuenter Roeck return -ENODATA; 12692711269SGuenter Roeck ret = pmbus_read_word_data(client, 0, 12792711269SGuenter Roeck ADM1075_VAUX_UV_WARN_LIMIT); 12892711269SGuenter Roeck break; 12992711269SGuenter Roeck case PMBUS_READ_VOUT: 130*9048539bSGuenter Roeck if (data->have_vout) 131*9048539bSGuenter Roeck return -ENODATA; 13292711269SGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); 13392711269SGuenter Roeck break; 134c576e30cSGuenter Roeck case PMBUS_VIRT_READ_IOUT_MAX: 135c576e30cSGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); 136c576e30cSGuenter Roeck break; 137c576e30cSGuenter Roeck case PMBUS_VIRT_READ_VOUT_MAX: 138c576e30cSGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT); 139c576e30cSGuenter Roeck break; 140c576e30cSGuenter Roeck case PMBUS_VIRT_READ_VIN_MAX: 141c576e30cSGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); 142c576e30cSGuenter Roeck break; 1435cf231a3SGuenter Roeck case PMBUS_VIRT_READ_PIN_MAX: 144*9048539bSGuenter Roeck if (!data->have_pin_max) 145*9048539bSGuenter Roeck return -ENXIO; 1465cf231a3SGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN); 1475cf231a3SGuenter Roeck break; 148c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 149c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 150c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VIN_HISTORY: 1515cf231a3SGuenter Roeck break; 1525cf231a3SGuenter Roeck case PMBUS_VIRT_RESET_PIN_HISTORY: 153*9048539bSGuenter Roeck if (!data->have_pin_max) 154*9048539bSGuenter Roeck return -ENXIO; 155c576e30cSGuenter Roeck break; 156c576e30cSGuenter Roeck default: 157c576e30cSGuenter Roeck ret = -ENODATA; 158c576e30cSGuenter Roeck break; 159c576e30cSGuenter Roeck } 160c576e30cSGuenter Roeck return ret; 161c576e30cSGuenter Roeck } 162c576e30cSGuenter Roeck 163c576e30cSGuenter Roeck static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, 164c576e30cSGuenter Roeck u16 word) 165c576e30cSGuenter Roeck { 166c576e30cSGuenter Roeck int ret; 167c576e30cSGuenter Roeck 168c576e30cSGuenter Roeck if (page) 169c5e67636SGuenter Roeck return -ENXIO; 170c576e30cSGuenter Roeck 171c576e30cSGuenter Roeck switch (reg) { 172c5e67636SGuenter Roeck case PMBUS_IOUT_UC_FAULT_LIMIT: 173c5e67636SGuenter Roeck case PMBUS_IOUT_OC_FAULT_LIMIT: 174c5e67636SGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT, 175c5e67636SGuenter Roeck word); 176c5e67636SGuenter Roeck break; 177c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 178c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); 179c576e30cSGuenter Roeck break; 180c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 181c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0); 182c576e30cSGuenter Roeck break; 183c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VIN_HISTORY: 184c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0); 185c576e30cSGuenter Roeck break; 1865cf231a3SGuenter Roeck case PMBUS_VIRT_RESET_PIN_HISTORY: 1875cf231a3SGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); 1885cf231a3SGuenter Roeck break; 189c576e30cSGuenter Roeck default: 190c576e30cSGuenter Roeck ret = -ENODATA; 191c576e30cSGuenter Roeck break; 192c576e30cSGuenter Roeck } 193c576e30cSGuenter Roeck return ret; 194c576e30cSGuenter Roeck } 195c576e30cSGuenter Roeck 196c5e67636SGuenter Roeck static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) 197c5e67636SGuenter Roeck { 198c5e67636SGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 199c5e67636SGuenter Roeck const struct adm1275_data *data = to_adm1275_data(info); 200c5e67636SGuenter Roeck int mfr_status, ret; 201c5e67636SGuenter Roeck 202da8e48abSGuenter Roeck if (page > 0) 203c5e67636SGuenter Roeck return -ENXIO; 204c5e67636SGuenter Roeck 205c5e67636SGuenter Roeck switch (reg) { 206c5e67636SGuenter Roeck case PMBUS_STATUS_IOUT: 207c5e67636SGuenter Roeck ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT); 208c5e67636SGuenter Roeck if (ret < 0) 209c5e67636SGuenter Roeck break; 210*9048539bSGuenter Roeck if (!data->have_oc_fault && !data->have_uc_fault) 211*9048539bSGuenter Roeck break; 212c5e67636SGuenter Roeck mfr_status = pmbus_read_byte_data(client, page, 213c5e67636SGuenter Roeck PMBUS_STATUS_MFR_SPECIFIC); 214*9048539bSGuenter Roeck if (mfr_status < 0) 215*9048539bSGuenter Roeck return mfr_status; 216c5e67636SGuenter Roeck if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) { 217c5e67636SGuenter Roeck ret |= data->have_oc_fault ? 218c5e67636SGuenter Roeck PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; 219c5e67636SGuenter Roeck } 220c5e67636SGuenter Roeck break; 22192711269SGuenter Roeck case PMBUS_STATUS_VOUT: 222*9048539bSGuenter Roeck if (data->have_vout) 223*9048539bSGuenter Roeck return -ENODATA; 22492711269SGuenter Roeck ret = 0; 225*9048539bSGuenter Roeck if (data->have_vaux_status) { 22692711269SGuenter Roeck mfr_status = pmbus_read_byte_data(client, 0, 22792711269SGuenter Roeck ADM1075_VAUX_STATUS); 228*9048539bSGuenter Roeck if (mfr_status < 0) 229*9048539bSGuenter Roeck return mfr_status; 23092711269SGuenter Roeck if (mfr_status & ADM1075_VAUX_OV_WARN) 23192711269SGuenter Roeck ret |= PB_VOLTAGE_OV_WARNING; 23292711269SGuenter Roeck if (mfr_status & ADM1075_VAUX_UV_WARN) 23392711269SGuenter Roeck ret |= PB_VOLTAGE_UV_WARNING; 234*9048539bSGuenter Roeck } 23592711269SGuenter Roeck break; 236c5e67636SGuenter Roeck default: 237c5e67636SGuenter Roeck ret = -ENODATA; 238c5e67636SGuenter Roeck break; 239c5e67636SGuenter Roeck } 240c5e67636SGuenter Roeck return ret; 241c5e67636SGuenter Roeck } 242c5e67636SGuenter Roeck 24387102808SGuenter Roeck static const struct i2c_device_id adm1275_id[] = { 24492711269SGuenter Roeck { "adm1075", adm1075 }, 24587102808SGuenter Roeck { "adm1275", adm1275 }, 24687102808SGuenter Roeck { "adm1276", adm1276 }, 24787102808SGuenter Roeck { } 24887102808SGuenter Roeck }; 24987102808SGuenter Roeck MODULE_DEVICE_TABLE(i2c, adm1275_id); 25087102808SGuenter Roeck 2519d2ecfb7SGuenter Roeck static int adm1275_probe(struct i2c_client *client, 2529d2ecfb7SGuenter Roeck const struct i2c_device_id *id) 2539d2ecfb7SGuenter Roeck { 25487102808SGuenter Roeck u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; 255c5e67636SGuenter Roeck int config, device_config; 2569d2ecfb7SGuenter Roeck int ret; 2579d2ecfb7SGuenter Roeck struct pmbus_driver_info *info; 258c5e67636SGuenter Roeck struct adm1275_data *data; 25987102808SGuenter Roeck const struct i2c_device_id *mid; 260904b296fSGuenter Roeck const struct coefficients *coefficients; 261904b296fSGuenter Roeck int vindex = -1, cindex = -1, pindex = -1; 2629d2ecfb7SGuenter Roeck 2639d2ecfb7SGuenter Roeck if (!i2c_check_functionality(client->adapter, 26487102808SGuenter Roeck I2C_FUNC_SMBUS_READ_BYTE_DATA 26587102808SGuenter Roeck | I2C_FUNC_SMBUS_BLOCK_DATA)) 2669d2ecfb7SGuenter Roeck return -ENODEV; 2679d2ecfb7SGuenter Roeck 26887102808SGuenter Roeck ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); 26987102808SGuenter Roeck if (ret < 0) { 27087102808SGuenter Roeck dev_err(&client->dev, "Failed to read Manufacturer ID\n"); 27187102808SGuenter Roeck return ret; 27287102808SGuenter Roeck } 27387102808SGuenter Roeck if (ret != 3 || strncmp(block_buffer, "ADI", 3)) { 27487102808SGuenter Roeck dev_err(&client->dev, "Unsupported Manufacturer ID\n"); 27587102808SGuenter Roeck return -ENODEV; 27687102808SGuenter Roeck } 27787102808SGuenter Roeck 27887102808SGuenter Roeck ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); 27987102808SGuenter Roeck if (ret < 0) { 28087102808SGuenter Roeck dev_err(&client->dev, "Failed to read Manufacturer Model\n"); 28187102808SGuenter Roeck return ret; 28287102808SGuenter Roeck } 28387102808SGuenter Roeck for (mid = adm1275_id; mid->name[0]; mid++) { 28487102808SGuenter Roeck if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) 28587102808SGuenter Roeck break; 28687102808SGuenter Roeck } 28787102808SGuenter Roeck if (!mid->name[0]) { 28887102808SGuenter Roeck dev_err(&client->dev, "Unsupported device\n"); 28987102808SGuenter Roeck return -ENODEV; 29087102808SGuenter Roeck } 29187102808SGuenter Roeck 29287102808SGuenter Roeck if (id->driver_data != mid->driver_data) 29387102808SGuenter Roeck dev_notice(&client->dev, 29487102808SGuenter Roeck "Device mismatch: Configured %s, detected %s\n", 29587102808SGuenter Roeck id->name, mid->name); 29687102808SGuenter Roeck 29787102808SGuenter Roeck config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); 29887102808SGuenter Roeck if (config < 0) 29987102808SGuenter Roeck return config; 30087102808SGuenter Roeck 30187102808SGuenter Roeck device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG); 30287102808SGuenter Roeck if (device_config < 0) 30387102808SGuenter Roeck return device_config; 30487102808SGuenter Roeck 3058b313ca7SGuenter Roeck data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data), 3068b313ca7SGuenter Roeck GFP_KERNEL); 307c5e67636SGuenter Roeck if (!data) 3089d2ecfb7SGuenter Roeck return -ENOMEM; 3099d2ecfb7SGuenter Roeck 31087102808SGuenter Roeck data->id = mid->driver_data; 3119d2ecfb7SGuenter Roeck 312c5e67636SGuenter Roeck info = &data->info; 313c5e67636SGuenter Roeck 3149d2ecfb7SGuenter Roeck info->pages = 1; 3151061d851SGuenter Roeck info->format[PSC_VOLTAGE_IN] = direct; 3161061d851SGuenter Roeck info->format[PSC_VOLTAGE_OUT] = direct; 3171061d851SGuenter Roeck info->format[PSC_CURRENT_OUT] = direct; 318904b296fSGuenter Roeck info->format[PSC_POWER] = direct; 3199d2ecfb7SGuenter Roeck info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; 3209d2ecfb7SGuenter Roeck 321c576e30cSGuenter Roeck info->read_word_data = adm1275_read_word_data; 322c5e67636SGuenter Roeck info->read_byte_data = adm1275_read_byte_data; 323c576e30cSGuenter Roeck info->write_word_data = adm1275_write_word_data; 324c576e30cSGuenter Roeck 32587102808SGuenter Roeck switch (data->id) { 32692711269SGuenter Roeck case adm1075: 327*9048539bSGuenter Roeck if (device_config & ADM1275_IOUT_WARN2_SELECT) 328*9048539bSGuenter Roeck data->have_oc_fault = true; 329*9048539bSGuenter Roeck else 330*9048539bSGuenter Roeck data->have_uc_fault = true; 331*9048539bSGuenter Roeck data->have_pin_max = true; 332*9048539bSGuenter Roeck data->have_vaux_status = true; 333*9048539bSGuenter Roeck 334904b296fSGuenter Roeck coefficients = adm1075_coefficients; 335904b296fSGuenter Roeck vindex = 0; 33692711269SGuenter Roeck switch (config & ADM1075_IRANGE_MASK) { 33792711269SGuenter Roeck case ADM1075_IRANGE_25: 338904b296fSGuenter Roeck cindex = 1; 339904b296fSGuenter Roeck pindex = 3; 34092711269SGuenter Roeck break; 34192711269SGuenter Roeck case ADM1075_IRANGE_50: 342904b296fSGuenter Roeck cindex = 2; 343904b296fSGuenter Roeck pindex = 4; 34492711269SGuenter Roeck break; 34592711269SGuenter Roeck default: 34692711269SGuenter Roeck dev_err(&client->dev, "Invalid input current range"); 34792711269SGuenter Roeck break; 34892711269SGuenter Roeck } 349904b296fSGuenter Roeck 35092711269SGuenter Roeck info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN 35192711269SGuenter Roeck | PMBUS_HAVE_STATUS_INPUT; 35292711269SGuenter Roeck if (config & ADM1275_VIN_VOUT_SELECT) 35392711269SGuenter Roeck info->func[0] |= 35492711269SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 35592711269SGuenter Roeck break; 3565cf231a3SGuenter Roeck case adm1275: 357*9048539bSGuenter Roeck if (device_config & ADM1275_IOUT_WARN2_SELECT) 358*9048539bSGuenter Roeck data->have_oc_fault = true; 359*9048539bSGuenter Roeck else 360*9048539bSGuenter Roeck data->have_uc_fault = true; 361*9048539bSGuenter Roeck data->have_vout = true; 362*9048539bSGuenter Roeck 363904b296fSGuenter Roeck coefficients = adm1275_coefficients; 364904b296fSGuenter Roeck vindex = (config & ADM1275_VRANGE) ? 0 : 1; 365904b296fSGuenter Roeck cindex = 2; 366904b296fSGuenter Roeck 3679d2ecfb7SGuenter Roeck if (config & ADM1275_VIN_VOUT_SELECT) 3685cf231a3SGuenter Roeck info->func[0] |= 3695cf231a3SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 3709d2ecfb7SGuenter Roeck else 3715cf231a3SGuenter Roeck info->func[0] |= 3725cf231a3SGuenter Roeck PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; 3735cf231a3SGuenter Roeck break; 3745cf231a3SGuenter Roeck case adm1276: 375*9048539bSGuenter Roeck if (device_config & ADM1275_IOUT_WARN2_SELECT) 376*9048539bSGuenter Roeck data->have_oc_fault = true; 377*9048539bSGuenter Roeck else 378*9048539bSGuenter Roeck data->have_uc_fault = true; 379*9048539bSGuenter Roeck data->have_vout = true; 380*9048539bSGuenter Roeck data->have_pin_max = true; 381*9048539bSGuenter Roeck 382904b296fSGuenter Roeck coefficients = adm1276_coefficients; 383904b296fSGuenter Roeck vindex = (config & ADM1275_VRANGE) ? 0 : 1; 384904b296fSGuenter Roeck cindex = 2; 385904b296fSGuenter Roeck pindex = (config & ADM1275_VRANGE) ? 3 : 4; 386904b296fSGuenter Roeck 3875cf231a3SGuenter Roeck info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN 3885cf231a3SGuenter Roeck | PMBUS_HAVE_STATUS_INPUT; 3895cf231a3SGuenter Roeck if (config & ADM1275_VIN_VOUT_SELECT) 3905cf231a3SGuenter Roeck info->func[0] |= 3915cf231a3SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 3925cf231a3SGuenter Roeck break; 393904b296fSGuenter Roeck default: 394904b296fSGuenter Roeck dev_err(&client->dev, "Unsupported device\n"); 395904b296fSGuenter Roeck return -ENODEV; 396904b296fSGuenter Roeck } 397904b296fSGuenter Roeck if (vindex >= 0) { 398904b296fSGuenter Roeck info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m; 399904b296fSGuenter Roeck info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b; 400904b296fSGuenter Roeck info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R; 401904b296fSGuenter Roeck info->m[PSC_VOLTAGE_OUT] = coefficients[vindex].m; 402904b296fSGuenter Roeck info->b[PSC_VOLTAGE_OUT] = coefficients[vindex].b; 403904b296fSGuenter Roeck info->R[PSC_VOLTAGE_OUT] = coefficients[vindex].R; 404904b296fSGuenter Roeck } 405904b296fSGuenter Roeck if (cindex >= 0) { 406904b296fSGuenter Roeck info->m[PSC_CURRENT_OUT] = coefficients[cindex].m; 407904b296fSGuenter Roeck info->b[PSC_CURRENT_OUT] = coefficients[cindex].b; 408904b296fSGuenter Roeck info->R[PSC_CURRENT_OUT] = coefficients[cindex].R; 409904b296fSGuenter Roeck } 410904b296fSGuenter Roeck if (pindex >= 0) { 411904b296fSGuenter Roeck info->m[PSC_POWER] = coefficients[pindex].m; 412904b296fSGuenter Roeck info->b[PSC_POWER] = coefficients[pindex].b; 413904b296fSGuenter Roeck info->R[PSC_POWER] = coefficients[pindex].R; 4145cf231a3SGuenter Roeck } 4159d2ecfb7SGuenter Roeck 4168b313ca7SGuenter Roeck return pmbus_do_probe(client, id, info); 4179d2ecfb7SGuenter Roeck } 4189d2ecfb7SGuenter Roeck 4199d2ecfb7SGuenter Roeck static struct i2c_driver adm1275_driver = { 4209d2ecfb7SGuenter Roeck .driver = { 4219d2ecfb7SGuenter Roeck .name = "adm1275", 4229d2ecfb7SGuenter Roeck }, 4239d2ecfb7SGuenter Roeck .probe = adm1275_probe, 424dd285ad7SGuenter Roeck .remove = pmbus_do_remove, 4259d2ecfb7SGuenter Roeck .id_table = adm1275_id, 4269d2ecfb7SGuenter Roeck }; 4279d2ecfb7SGuenter Roeck 428f0967eeaSAxel Lin module_i2c_driver(adm1275_driver); 4299d2ecfb7SGuenter Roeck 4309d2ecfb7SGuenter Roeck MODULE_AUTHOR("Guenter Roeck"); 4315cf231a3SGuenter Roeck MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles"); 4329d2ecfb7SGuenter Roeck MODULE_LICENSE("GPL"); 433