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> 249d2ecfb7SGuenter Roeck #include "pmbus.h" 259d2ecfb7SGuenter Roeck 265cf231a3SGuenter Roeck enum chips { adm1275, adm1276 }; 275cf231a3SGuenter Roeck 28c576e30cSGuenter Roeck #define ADM1275_PEAK_IOUT 0xd0 29c576e30cSGuenter Roeck #define ADM1275_PEAK_VIN 0xd1 30c576e30cSGuenter Roeck #define ADM1275_PEAK_VOUT 0xd2 319d2ecfb7SGuenter Roeck #define ADM1275_PMON_CONFIG 0xd4 329d2ecfb7SGuenter Roeck 339d2ecfb7SGuenter Roeck #define ADM1275_VIN_VOUT_SELECT (1 << 6) 349d2ecfb7SGuenter Roeck #define ADM1275_VRANGE (1 << 5) 359d2ecfb7SGuenter Roeck 36c5e67636SGuenter Roeck #define ADM1275_IOUT_WARN2_LIMIT 0xd7 37c5e67636SGuenter Roeck #define ADM1275_DEVICE_CONFIG 0xd8 38c5e67636SGuenter Roeck 39c5e67636SGuenter Roeck #define ADM1275_IOUT_WARN2_SELECT (1 << 4) 40c5e67636SGuenter Roeck 415cf231a3SGuenter Roeck #define ADM1276_PEAK_PIN 0xda 425cf231a3SGuenter Roeck 43c5e67636SGuenter Roeck #define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0) 44c5e67636SGuenter Roeck 45c5e67636SGuenter Roeck struct adm1275_data { 465cf231a3SGuenter Roeck int id; 47c5e67636SGuenter Roeck bool have_oc_fault; 48c5e67636SGuenter Roeck struct pmbus_driver_info info; 49c5e67636SGuenter Roeck }; 50c5e67636SGuenter Roeck 51c5e67636SGuenter Roeck #define to_adm1275_data(x) container_of(x, struct adm1275_data, info) 52c5e67636SGuenter Roeck 53c576e30cSGuenter Roeck static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) 54c576e30cSGuenter Roeck { 55c5e67636SGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 56c5e67636SGuenter Roeck const struct adm1275_data *data = to_adm1275_data(info); 575cf231a3SGuenter Roeck int ret = 0; 58c576e30cSGuenter Roeck 59c576e30cSGuenter Roeck if (page) 60c5e67636SGuenter Roeck return -ENXIO; 61c576e30cSGuenter Roeck 62c576e30cSGuenter Roeck switch (reg) { 63c5e67636SGuenter Roeck case PMBUS_IOUT_UC_FAULT_LIMIT: 64c5e67636SGuenter Roeck if (data->have_oc_fault) { 65c5e67636SGuenter Roeck ret = -ENXIO; 66c5e67636SGuenter Roeck break; 67c5e67636SGuenter Roeck } 68c5e67636SGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); 69c5e67636SGuenter Roeck break; 70c5e67636SGuenter Roeck case PMBUS_IOUT_OC_FAULT_LIMIT: 71c5e67636SGuenter Roeck if (!data->have_oc_fault) { 72c5e67636SGuenter Roeck ret = -ENXIO; 73c5e67636SGuenter Roeck break; 74c5e67636SGuenter Roeck } 75c5e67636SGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); 76c5e67636SGuenter Roeck break; 77c576e30cSGuenter Roeck case PMBUS_VIRT_READ_IOUT_MAX: 78c576e30cSGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); 79c576e30cSGuenter Roeck break; 80c576e30cSGuenter Roeck case PMBUS_VIRT_READ_VOUT_MAX: 81c576e30cSGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT); 82c576e30cSGuenter Roeck break; 83c576e30cSGuenter Roeck case PMBUS_VIRT_READ_VIN_MAX: 84c576e30cSGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); 85c576e30cSGuenter Roeck break; 865cf231a3SGuenter Roeck case PMBUS_VIRT_READ_PIN_MAX: 875cf231a3SGuenter Roeck if (data->id != adm1276) { 885cf231a3SGuenter Roeck ret = -ENXIO; 895cf231a3SGuenter Roeck break; 905cf231a3SGuenter Roeck } 915cf231a3SGuenter Roeck ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN); 925cf231a3SGuenter Roeck break; 93c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 94c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 95c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VIN_HISTORY: 965cf231a3SGuenter Roeck break; 975cf231a3SGuenter Roeck case PMBUS_VIRT_RESET_PIN_HISTORY: 985cf231a3SGuenter Roeck if (data->id != adm1276) 995cf231a3SGuenter Roeck ret = -ENXIO; 100c576e30cSGuenter Roeck break; 101c576e30cSGuenter Roeck default: 102c576e30cSGuenter Roeck ret = -ENODATA; 103c576e30cSGuenter Roeck break; 104c576e30cSGuenter Roeck } 105c576e30cSGuenter Roeck return ret; 106c576e30cSGuenter Roeck } 107c576e30cSGuenter Roeck 108c576e30cSGuenter Roeck static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, 109c576e30cSGuenter Roeck u16 word) 110c576e30cSGuenter Roeck { 111c576e30cSGuenter Roeck int ret; 112c576e30cSGuenter Roeck 113c576e30cSGuenter Roeck if (page) 114c5e67636SGuenter Roeck return -ENXIO; 115c576e30cSGuenter Roeck 116c576e30cSGuenter Roeck switch (reg) { 117c5e67636SGuenter Roeck case PMBUS_IOUT_UC_FAULT_LIMIT: 118c5e67636SGuenter Roeck case PMBUS_IOUT_OC_FAULT_LIMIT: 119c5e67636SGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT, 120c5e67636SGuenter Roeck word); 121c5e67636SGuenter Roeck break; 122c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 123c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); 124c576e30cSGuenter Roeck break; 125c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 126c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0); 127c576e30cSGuenter Roeck break; 128c576e30cSGuenter Roeck case PMBUS_VIRT_RESET_VIN_HISTORY: 129c576e30cSGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0); 130c576e30cSGuenter Roeck break; 1315cf231a3SGuenter Roeck case PMBUS_VIRT_RESET_PIN_HISTORY: 1325cf231a3SGuenter Roeck ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); 1335cf231a3SGuenter Roeck break; 134c576e30cSGuenter Roeck default: 135c576e30cSGuenter Roeck ret = -ENODATA; 136c576e30cSGuenter Roeck break; 137c576e30cSGuenter Roeck } 138c576e30cSGuenter Roeck return ret; 139c576e30cSGuenter Roeck } 140c576e30cSGuenter Roeck 141c5e67636SGuenter Roeck static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) 142c5e67636SGuenter Roeck { 143c5e67636SGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 144c5e67636SGuenter Roeck const struct adm1275_data *data = to_adm1275_data(info); 145c5e67636SGuenter Roeck int mfr_status, ret; 146c5e67636SGuenter Roeck 147da8e48abSGuenter Roeck if (page > 0) 148c5e67636SGuenter Roeck return -ENXIO; 149c5e67636SGuenter Roeck 150c5e67636SGuenter Roeck switch (reg) { 151c5e67636SGuenter Roeck case PMBUS_STATUS_IOUT: 152c5e67636SGuenter Roeck ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT); 153c5e67636SGuenter Roeck if (ret < 0) 154c5e67636SGuenter Roeck break; 155c5e67636SGuenter Roeck mfr_status = pmbus_read_byte_data(client, page, 156c5e67636SGuenter Roeck PMBUS_STATUS_MFR_SPECIFIC); 157c5e67636SGuenter Roeck if (mfr_status < 0) { 158c5e67636SGuenter Roeck ret = mfr_status; 159c5e67636SGuenter Roeck break; 160c5e67636SGuenter Roeck } 161c5e67636SGuenter Roeck if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) { 162c5e67636SGuenter Roeck ret |= data->have_oc_fault ? 163c5e67636SGuenter Roeck PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; 164c5e67636SGuenter Roeck } 165c5e67636SGuenter Roeck break; 166c5e67636SGuenter Roeck default: 167c5e67636SGuenter Roeck ret = -ENODATA; 168c5e67636SGuenter Roeck break; 169c5e67636SGuenter Roeck } 170c5e67636SGuenter Roeck return ret; 171c5e67636SGuenter Roeck } 172c5e67636SGuenter Roeck 17387102808SGuenter Roeck static const struct i2c_device_id adm1275_id[] = { 17487102808SGuenter Roeck { "adm1275", adm1275 }, 17587102808SGuenter Roeck { "adm1276", adm1276 }, 17687102808SGuenter Roeck { } 17787102808SGuenter Roeck }; 17887102808SGuenter Roeck MODULE_DEVICE_TABLE(i2c, adm1275_id); 17987102808SGuenter Roeck 1809d2ecfb7SGuenter Roeck static int adm1275_probe(struct i2c_client *client, 1819d2ecfb7SGuenter Roeck const struct i2c_device_id *id) 1829d2ecfb7SGuenter Roeck { 18387102808SGuenter Roeck u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; 184c5e67636SGuenter Roeck int config, device_config; 1859d2ecfb7SGuenter Roeck int ret; 1869d2ecfb7SGuenter Roeck struct pmbus_driver_info *info; 187c5e67636SGuenter Roeck struct adm1275_data *data; 18887102808SGuenter Roeck const struct i2c_device_id *mid; 1899d2ecfb7SGuenter Roeck 1909d2ecfb7SGuenter Roeck if (!i2c_check_functionality(client->adapter, 19187102808SGuenter Roeck I2C_FUNC_SMBUS_READ_BYTE_DATA 19287102808SGuenter Roeck | I2C_FUNC_SMBUS_BLOCK_DATA)) 1939d2ecfb7SGuenter Roeck return -ENODEV; 1949d2ecfb7SGuenter Roeck 19587102808SGuenter Roeck ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); 19687102808SGuenter Roeck if (ret < 0) { 19787102808SGuenter Roeck dev_err(&client->dev, "Failed to read Manufacturer ID\n"); 19887102808SGuenter Roeck return ret; 19987102808SGuenter Roeck } 20087102808SGuenter Roeck if (ret != 3 || strncmp(block_buffer, "ADI", 3)) { 20187102808SGuenter Roeck dev_err(&client->dev, "Unsupported Manufacturer ID\n"); 20287102808SGuenter Roeck return -ENODEV; 20387102808SGuenter Roeck } 20487102808SGuenter Roeck 20587102808SGuenter Roeck ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); 20687102808SGuenter Roeck if (ret < 0) { 20787102808SGuenter Roeck dev_err(&client->dev, "Failed to read Manufacturer Model\n"); 20887102808SGuenter Roeck return ret; 20987102808SGuenter Roeck } 21087102808SGuenter Roeck for (mid = adm1275_id; mid->name[0]; mid++) { 21187102808SGuenter Roeck if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) 21287102808SGuenter Roeck break; 21387102808SGuenter Roeck } 21487102808SGuenter Roeck if (!mid->name[0]) { 21587102808SGuenter Roeck dev_err(&client->dev, "Unsupported device\n"); 21687102808SGuenter Roeck return -ENODEV; 21787102808SGuenter Roeck } 21887102808SGuenter Roeck 21987102808SGuenter Roeck if (id->driver_data != mid->driver_data) 22087102808SGuenter Roeck dev_notice(&client->dev, 22187102808SGuenter Roeck "Device mismatch: Configured %s, detected %s\n", 22287102808SGuenter Roeck id->name, mid->name); 22387102808SGuenter Roeck 22487102808SGuenter Roeck config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); 22587102808SGuenter Roeck if (config < 0) 22687102808SGuenter Roeck return config; 22787102808SGuenter Roeck 22887102808SGuenter Roeck device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG); 22987102808SGuenter Roeck if (device_config < 0) 23087102808SGuenter Roeck return device_config; 23187102808SGuenter Roeck 232*8b313ca7SGuenter Roeck data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data), 233*8b313ca7SGuenter Roeck GFP_KERNEL); 234c5e67636SGuenter Roeck if (!data) 2359d2ecfb7SGuenter Roeck return -ENOMEM; 2369d2ecfb7SGuenter Roeck 23787102808SGuenter Roeck data->id = mid->driver_data; 2389d2ecfb7SGuenter Roeck 239c5e67636SGuenter Roeck info = &data->info; 240c5e67636SGuenter Roeck 2419d2ecfb7SGuenter Roeck info->pages = 1; 2421061d851SGuenter Roeck info->format[PSC_VOLTAGE_IN] = direct; 2431061d851SGuenter Roeck info->format[PSC_VOLTAGE_OUT] = direct; 2441061d851SGuenter Roeck info->format[PSC_CURRENT_OUT] = direct; 2459d2ecfb7SGuenter Roeck info->m[PSC_CURRENT_OUT] = 807; 2469d2ecfb7SGuenter Roeck info->b[PSC_CURRENT_OUT] = 20475; 2479d2ecfb7SGuenter Roeck info->R[PSC_CURRENT_OUT] = -1; 2489d2ecfb7SGuenter Roeck info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; 2499d2ecfb7SGuenter Roeck 250c576e30cSGuenter Roeck info->read_word_data = adm1275_read_word_data; 251c5e67636SGuenter Roeck info->read_byte_data = adm1275_read_byte_data; 252c576e30cSGuenter Roeck info->write_word_data = adm1275_write_word_data; 253c576e30cSGuenter Roeck 2549d2ecfb7SGuenter Roeck if (config & ADM1275_VRANGE) { 2559d2ecfb7SGuenter Roeck info->m[PSC_VOLTAGE_IN] = 19199; 2569d2ecfb7SGuenter Roeck info->b[PSC_VOLTAGE_IN] = 0; 2579d2ecfb7SGuenter Roeck info->R[PSC_VOLTAGE_IN] = -2; 2589d2ecfb7SGuenter Roeck info->m[PSC_VOLTAGE_OUT] = 19199; 2599d2ecfb7SGuenter Roeck info->b[PSC_VOLTAGE_OUT] = 0; 2609d2ecfb7SGuenter Roeck info->R[PSC_VOLTAGE_OUT] = -2; 2619d2ecfb7SGuenter Roeck } else { 2629d2ecfb7SGuenter Roeck info->m[PSC_VOLTAGE_IN] = 6720; 2639d2ecfb7SGuenter Roeck info->b[PSC_VOLTAGE_IN] = 0; 2649d2ecfb7SGuenter Roeck info->R[PSC_VOLTAGE_IN] = -1; 2659d2ecfb7SGuenter Roeck info->m[PSC_VOLTAGE_OUT] = 6720; 2669d2ecfb7SGuenter Roeck info->b[PSC_VOLTAGE_OUT] = 0; 2679d2ecfb7SGuenter Roeck info->R[PSC_VOLTAGE_OUT] = -1; 2689d2ecfb7SGuenter Roeck } 2699d2ecfb7SGuenter Roeck 270c5e67636SGuenter Roeck if (device_config & ADM1275_IOUT_WARN2_SELECT) 271c5e67636SGuenter Roeck data->have_oc_fault = true; 272c5e67636SGuenter Roeck 27387102808SGuenter Roeck switch (data->id) { 2745cf231a3SGuenter Roeck case adm1275: 2759d2ecfb7SGuenter Roeck if (config & ADM1275_VIN_VOUT_SELECT) 2765cf231a3SGuenter Roeck info->func[0] |= 2775cf231a3SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 2789d2ecfb7SGuenter Roeck else 2795cf231a3SGuenter Roeck info->func[0] |= 2805cf231a3SGuenter Roeck PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; 2815cf231a3SGuenter Roeck break; 2825cf231a3SGuenter Roeck case adm1276: 2835cf231a3SGuenter Roeck info->format[PSC_POWER] = direct; 2845cf231a3SGuenter Roeck info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN 2855cf231a3SGuenter Roeck | PMBUS_HAVE_STATUS_INPUT; 2865cf231a3SGuenter Roeck if (config & ADM1275_VIN_VOUT_SELECT) 2875cf231a3SGuenter Roeck info->func[0] |= 2885cf231a3SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; 2895cf231a3SGuenter Roeck if (config & ADM1275_VRANGE) { 2905cf231a3SGuenter Roeck info->m[PSC_POWER] = 6043; 2915cf231a3SGuenter Roeck info->b[PSC_POWER] = 0; 2925cf231a3SGuenter Roeck info->R[PSC_POWER] = -2; 2935cf231a3SGuenter Roeck } else { 2945cf231a3SGuenter Roeck info->m[PSC_POWER] = 2115; 2955cf231a3SGuenter Roeck info->b[PSC_POWER] = 0; 2965cf231a3SGuenter Roeck info->R[PSC_POWER] = -1; 2975cf231a3SGuenter Roeck } 2985cf231a3SGuenter Roeck break; 2995cf231a3SGuenter Roeck } 3009d2ecfb7SGuenter Roeck 301*8b313ca7SGuenter Roeck return pmbus_do_probe(client, id, info); 3029d2ecfb7SGuenter Roeck } 3039d2ecfb7SGuenter Roeck 3049d2ecfb7SGuenter Roeck static int adm1275_remove(struct i2c_client *client) 3059d2ecfb7SGuenter Roeck { 306866cf12aSGuenter Roeck pmbus_do_remove(client); 307866cf12aSGuenter Roeck return 0; 3089d2ecfb7SGuenter Roeck } 3099d2ecfb7SGuenter Roeck 3109d2ecfb7SGuenter Roeck static struct i2c_driver adm1275_driver = { 3119d2ecfb7SGuenter Roeck .driver = { 3129d2ecfb7SGuenter Roeck .name = "adm1275", 3139d2ecfb7SGuenter Roeck }, 3149d2ecfb7SGuenter Roeck .probe = adm1275_probe, 3159d2ecfb7SGuenter Roeck .remove = adm1275_remove, 3169d2ecfb7SGuenter Roeck .id_table = adm1275_id, 3179d2ecfb7SGuenter Roeck }; 3189d2ecfb7SGuenter Roeck 319f0967eeaSAxel Lin module_i2c_driver(adm1275_driver); 3209d2ecfb7SGuenter Roeck 3219d2ecfb7SGuenter Roeck MODULE_AUTHOR("Guenter Roeck"); 3225cf231a3SGuenter Roeck MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles"); 3239d2ecfb7SGuenter Roeck MODULE_LICENSE("GPL"); 324