162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Hardware monitoring driver for BEL PFE family power supplies. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2019 Facebook Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/err.h> 962306a36Sopenharmony_ci#include <linux/i2c.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/pmbus.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "pmbus.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cienum chips {pfe1100, pfe3000}; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Disable status check because some devices report communication error 2162306a36Sopenharmony_ci * (invalid command) for VOUT_MODE command (0x20) although the correct 2262306a36Sopenharmony_ci * VOUT_MODE (0x16) is returned: it leads to incorrect exponent in linear 2362306a36Sopenharmony_ci * mode. 2462306a36Sopenharmony_ci * This affects both pfe3000 and pfe1100. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_cistatic struct pmbus_platform_data pfe_plat_data = { 2762306a36Sopenharmony_ci .flags = PMBUS_SKIP_STATUS_CHECK, 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic struct pmbus_driver_info pfe_driver_info[] = { 3162306a36Sopenharmony_ci [pfe1100] = { 3262306a36Sopenharmony_ci .pages = 1, 3362306a36Sopenharmony_ci .format[PSC_VOLTAGE_IN] = linear, 3462306a36Sopenharmony_ci .format[PSC_VOLTAGE_OUT] = linear, 3562306a36Sopenharmony_ci .format[PSC_CURRENT_IN] = linear, 3662306a36Sopenharmony_ci .format[PSC_CURRENT_OUT] = linear, 3762306a36Sopenharmony_ci .format[PSC_POWER] = linear, 3862306a36Sopenharmony_ci .format[PSC_TEMPERATURE] = linear, 3962306a36Sopenharmony_ci .format[PSC_FAN] = linear, 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 4262306a36Sopenharmony_ci PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 4362306a36Sopenharmony_ci PMBUS_HAVE_POUT | 4462306a36Sopenharmony_ci PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | 4562306a36Sopenharmony_ci PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | 4662306a36Sopenharmony_ci PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | 4762306a36Sopenharmony_ci PMBUS_HAVE_STATUS_TEMP | 4862306a36Sopenharmony_ci PMBUS_HAVE_FAN12, 4962306a36Sopenharmony_ci }, 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci [pfe3000] = { 5262306a36Sopenharmony_ci .pages = 7, 5362306a36Sopenharmony_ci .format[PSC_VOLTAGE_IN] = linear, 5462306a36Sopenharmony_ci .format[PSC_VOLTAGE_OUT] = linear, 5562306a36Sopenharmony_ci .format[PSC_CURRENT_IN] = linear, 5662306a36Sopenharmony_ci .format[PSC_CURRENT_OUT] = linear, 5762306a36Sopenharmony_ci .format[PSC_POWER] = linear, 5862306a36Sopenharmony_ci .format[PSC_TEMPERATURE] = linear, 5962306a36Sopenharmony_ci .format[PSC_FAN] = linear, 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Page 0: V1. */ 6262306a36Sopenharmony_ci .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 6362306a36Sopenharmony_ci PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 6462306a36Sopenharmony_ci PMBUS_HAVE_POUT | PMBUS_HAVE_FAN12 | 6562306a36Sopenharmony_ci PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | 6662306a36Sopenharmony_ci PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | 6762306a36Sopenharmony_ci PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | 6862306a36Sopenharmony_ci PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP | 6962306a36Sopenharmony_ci PMBUS_HAVE_VCAP, 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Page 1: Vsb. */ 7262306a36Sopenharmony_ci .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 7362306a36Sopenharmony_ci PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 7462306a36Sopenharmony_ci PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | 7562306a36Sopenharmony_ci PMBUS_HAVE_POUT, 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * Page 2: V1 Ishare. 7962306a36Sopenharmony_ci * Page 3: Reserved. 8062306a36Sopenharmony_ci * Page 4: V1 Cathode. 8162306a36Sopenharmony_ci * Page 5: Vsb Cathode. 8262306a36Sopenharmony_ci * Page 6: V1 Sense. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci .func[2] = PMBUS_HAVE_VOUT, 8562306a36Sopenharmony_ci .func[4] = PMBUS_HAVE_VOUT, 8662306a36Sopenharmony_ci .func[5] = PMBUS_HAVE_VOUT, 8762306a36Sopenharmony_ci .func[6] = PMBUS_HAVE_VOUT, 8862306a36Sopenharmony_ci }, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct i2c_device_id pfe_device_id[]; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int pfe_pmbus_probe(struct i2c_client *client) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci int model; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci model = (int)i2c_match_id(pfe_device_id, client)->driver_data; 9862306a36Sopenharmony_ci client->dev.platform_data = &pfe_plat_data; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* 10162306a36Sopenharmony_ci * PFE3000-12-069RA devices may not stay in page 0 during device 10262306a36Sopenharmony_ci * probe which leads to probe failure (read status word failed). 10362306a36Sopenharmony_ci * So let's set the device to page 0 at the beginning. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci if (model == pfe3000) 10662306a36Sopenharmony_ci i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return pmbus_do_probe(client, &pfe_driver_info[model]); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic const struct i2c_device_id pfe_device_id[] = { 11262306a36Sopenharmony_ci {"pfe1100", pfe1100}, 11362306a36Sopenharmony_ci {"pfe3000", pfe3000}, 11462306a36Sopenharmony_ci {} 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pfe_device_id); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic struct i2c_driver pfe_pmbus_driver = { 12062306a36Sopenharmony_ci .driver = { 12162306a36Sopenharmony_ci .name = "bel-pfe", 12262306a36Sopenharmony_ci }, 12362306a36Sopenharmony_ci .probe = pfe_pmbus_probe, 12462306a36Sopenharmony_ci .id_table = pfe_device_id, 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cimodule_i2c_driver(pfe_pmbus_driver); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ciMODULE_AUTHOR("Tao Ren <rentao.bupt@gmail.com>"); 13062306a36Sopenharmony_ciMODULE_DESCRIPTION("PMBus driver for BEL PFE Family Power Supplies"); 13162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 13262306a36Sopenharmony_ciMODULE_IMPORT_NS(PMBUS); 133