1344757baSVijay Khemka // SPDX-License-Identifier: GPL-2.0+ 2344757baSVijay Khemka /* 3344757baSVijay Khemka * Hardware monitoring driver for Infineon PXE1610 4344757baSVijay Khemka * 5344757baSVijay Khemka * Copyright (c) 2019 Facebook Inc 6344757baSVijay Khemka * 7344757baSVijay Khemka */ 8344757baSVijay Khemka 9344757baSVijay Khemka #include <linux/err.h> 10344757baSVijay Khemka #include <linux/i2c.h> 11344757baSVijay Khemka #include <linux/init.h> 12344757baSVijay Khemka #include <linux/kernel.h> 13344757baSVijay Khemka #include <linux/module.h> 14344757baSVijay Khemka #include "pmbus.h" 15344757baSVijay Khemka 16344757baSVijay Khemka #define PXE1610_NUM_PAGES 3 17344757baSVijay Khemka 18344757baSVijay Khemka /* Identify chip parameters. */ 19344757baSVijay Khemka static int pxe1610_identify(struct i2c_client *client, 20344757baSVijay Khemka struct pmbus_driver_info *info) 21344757baSVijay Khemka { 22*b9fa0a3aSVadim Pasternak int i; 23*b9fa0a3aSVadim Pasternak 24*b9fa0a3aSVadim Pasternak for (i = 0; i < PXE1610_NUM_PAGES; i++) { 25*b9fa0a3aSVadim Pasternak if (pmbus_check_byte_register(client, i, PMBUS_VOUT_MODE)) { 26344757baSVijay Khemka u8 vout_mode; 27344757baSVijay Khemka int ret; 28344757baSVijay Khemka 29344757baSVijay Khemka /* Read the register with VOUT scaling value.*/ 30*b9fa0a3aSVadim Pasternak ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); 31344757baSVijay Khemka if (ret < 0) 32344757baSVijay Khemka return ret; 33344757baSVijay Khemka 34344757baSVijay Khemka vout_mode = ret & GENMASK(4, 0); 35344757baSVijay Khemka 36344757baSVijay Khemka switch (vout_mode) { 37344757baSVijay Khemka case 1: 38*b9fa0a3aSVadim Pasternak info->vrm_version[i] = vr12; 39344757baSVijay Khemka break; 40344757baSVijay Khemka case 2: 41*b9fa0a3aSVadim Pasternak info->vrm_version[i] = vr13; 42344757baSVijay Khemka break; 43344757baSVijay Khemka default: 44344757baSVijay Khemka return -ENODEV; 45344757baSVijay Khemka } 46344757baSVijay Khemka } 47*b9fa0a3aSVadim Pasternak } 48344757baSVijay Khemka 49344757baSVijay Khemka return 0; 50344757baSVijay Khemka } 51344757baSVijay Khemka 52344757baSVijay Khemka static struct pmbus_driver_info pxe1610_info = { 53344757baSVijay Khemka .pages = PXE1610_NUM_PAGES, 54344757baSVijay Khemka .format[PSC_VOLTAGE_IN] = linear, 55344757baSVijay Khemka .format[PSC_VOLTAGE_OUT] = vid, 56344757baSVijay Khemka .format[PSC_CURRENT_IN] = linear, 57344757baSVijay Khemka .format[PSC_CURRENT_OUT] = linear, 58344757baSVijay Khemka .format[PSC_TEMPERATURE] = linear, 59344757baSVijay Khemka .format[PSC_POWER] = linear, 60344757baSVijay Khemka .func[0] = PMBUS_HAVE_VIN 61344757baSVijay Khemka | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN 62344757baSVijay Khemka | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN 63344757baSVijay Khemka | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP 64344757baSVijay Khemka | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT 65344757baSVijay Khemka | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, 66344757baSVijay Khemka .func[1] = PMBUS_HAVE_VIN 67344757baSVijay Khemka | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN 68344757baSVijay Khemka | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN 69344757baSVijay Khemka | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP 70344757baSVijay Khemka | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT 71344757baSVijay Khemka | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, 72344757baSVijay Khemka .func[2] = PMBUS_HAVE_VIN 73344757baSVijay Khemka | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN 74344757baSVijay Khemka | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN 75344757baSVijay Khemka | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP 76344757baSVijay Khemka | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT 77344757baSVijay Khemka | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, 78344757baSVijay Khemka .identify = pxe1610_identify, 79344757baSVijay Khemka }; 80344757baSVijay Khemka 81344757baSVijay Khemka static int pxe1610_probe(struct i2c_client *client, 82344757baSVijay Khemka const struct i2c_device_id *id) 83344757baSVijay Khemka { 84344757baSVijay Khemka struct pmbus_driver_info *info; 85344757baSVijay Khemka u8 buf[I2C_SMBUS_BLOCK_MAX]; 86344757baSVijay Khemka int ret; 87344757baSVijay Khemka 88344757baSVijay Khemka if (!i2c_check_functionality( 89344757baSVijay Khemka client->adapter, 90344757baSVijay Khemka I2C_FUNC_SMBUS_READ_BYTE_DATA 91344757baSVijay Khemka | I2C_FUNC_SMBUS_READ_WORD_DATA 92344757baSVijay Khemka | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) 93344757baSVijay Khemka return -ENODEV; 94344757baSVijay Khemka 95344757baSVijay Khemka /* 96344757baSVijay Khemka * By default this device doesn't boot to page 0, so set page 0 97344757baSVijay Khemka * to access all pmbus registers. 98344757baSVijay Khemka */ 99344757baSVijay Khemka i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 100344757baSVijay Khemka 101344757baSVijay Khemka /* Read Manufacturer id */ 102344757baSVijay Khemka ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); 103344757baSVijay Khemka if (ret < 0) { 104344757baSVijay Khemka dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n"); 105344757baSVijay Khemka return ret; 106344757baSVijay Khemka } 107344757baSVijay Khemka if (ret != 2 || strncmp(buf, "XP", 2)) { 108344757baSVijay Khemka dev_err(&client->dev, "MFR_ID unrecognized\n"); 109344757baSVijay Khemka return -ENODEV; 110344757baSVijay Khemka } 111344757baSVijay Khemka 112344757baSVijay Khemka info = devm_kmemdup(&client->dev, &pxe1610_info, 113344757baSVijay Khemka sizeof(struct pmbus_driver_info), 114344757baSVijay Khemka GFP_KERNEL); 115344757baSVijay Khemka if (!info) 116344757baSVijay Khemka return -ENOMEM; 117344757baSVijay Khemka 118344757baSVijay Khemka return pmbus_do_probe(client, id, info); 119344757baSVijay Khemka } 120344757baSVijay Khemka 121344757baSVijay Khemka static const struct i2c_device_id pxe1610_id[] = { 122344757baSVijay Khemka {"pxe1610", 0}, 123344757baSVijay Khemka {"pxe1110", 0}, 124344757baSVijay Khemka {"pxm1310", 0}, 125344757baSVijay Khemka {} 126344757baSVijay Khemka }; 127344757baSVijay Khemka 128344757baSVijay Khemka MODULE_DEVICE_TABLE(i2c, pxe1610_id); 129344757baSVijay Khemka 130344757baSVijay Khemka static struct i2c_driver pxe1610_driver = { 131344757baSVijay Khemka .driver = { 132344757baSVijay Khemka .name = "pxe1610", 133344757baSVijay Khemka }, 134344757baSVijay Khemka .probe = pxe1610_probe, 135344757baSVijay Khemka .remove = pmbus_do_remove, 136344757baSVijay Khemka .id_table = pxe1610_id, 137344757baSVijay Khemka }; 138344757baSVijay Khemka 139344757baSVijay Khemka module_i2c_driver(pxe1610_driver); 140344757baSVijay Khemka 141344757baSVijay Khemka MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>"); 142344757baSVijay Khemka MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310"); 143344757baSVijay Khemka MODULE_LICENSE("GPL"); 144