brintos

brintos / linux-shallow public Read only

0
0
Text · 3.5 KiB · 5ac476d Raw
152 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Hardware monitoring driver for Infineon PXE16104 *5 * Copyright (c) 2019 Facebook Inc6 *7 */8 9#include <linux/err.h>10#include <linux/i2c.h>11#include <linux/init.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include "pmbus.h"15 16#define PXE1610_NUM_PAGES 317 18/* Identify chip parameters. */19static int pxe1610_identify(struct i2c_client *client,20			     struct pmbus_driver_info *info)21{22	int i;23 24	for (i = 0; i < PXE1610_NUM_PAGES; i++) {25		if (pmbus_check_byte_register(client, i, PMBUS_VOUT_MODE)) {26			u8 vout_mode;27			int ret;28 29			/* Read the register with VOUT scaling value.*/30			ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);31			if (ret < 0)32				return ret;33 34			vout_mode = ret & GENMASK(4, 0);35 36			switch (vout_mode) {37			case 1:38				info->vrm_version[i] = vr12;39				break;40			case 2:41				info->vrm_version[i] = vr13;42				break;43			default:44				/*45				 * If prior pages are available limit operation46				 * to them47				 */48				if (i != 0) {49					info->pages = i;50					return 0;51				}52 53				return -ENODEV;54			}55		}56	}57 58	return 0;59}60 61static struct pmbus_driver_info pxe1610_info = {62	.pages = PXE1610_NUM_PAGES,63	.format[PSC_VOLTAGE_IN] = linear,64	.format[PSC_VOLTAGE_OUT] = vid,65	.format[PSC_CURRENT_IN] = linear,66	.format[PSC_CURRENT_OUT] = linear,67	.format[PSC_TEMPERATURE] = linear,68	.format[PSC_POWER] = linear,69	.func[0] = PMBUS_HAVE_VIN70		| PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN71		| PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN72		| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP73		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT74		| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,75	.func[1] = PMBUS_HAVE_VIN76		| PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN77		| PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN78		| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP79		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT80		| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,81	.func[2] = PMBUS_HAVE_VIN82		| PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN83		| PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN84		| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP85		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT86		| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,87	.identify = pxe1610_identify,88};89 90static int pxe1610_probe(struct i2c_client *client)91{92	struct pmbus_driver_info *info;93	u8 buf[I2C_SMBUS_BLOCK_MAX];94	int ret;95 96	if (!i2c_check_functionality(97			client->adapter,98			I2C_FUNC_SMBUS_READ_BYTE_DATA99			| I2C_FUNC_SMBUS_READ_WORD_DATA100			| I2C_FUNC_SMBUS_READ_BLOCK_DATA))101		return -ENODEV;102 103	/*104	 * By default this device doesn't boot to page 0, so set page 0105	 * to access all pmbus registers.106	 */107	i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);108 109	/* Read Manufacturer id */110	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);111	if (ret < 0) {112		dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");113		return ret;114	}115	if (ret != 2 || strncmp(buf, "XP", 2)) {116		dev_err(&client->dev, "MFR_ID unrecognized\n");117		return -ENODEV;118	}119 120	info = devm_kmemdup(&client->dev, &pxe1610_info,121			    sizeof(struct pmbus_driver_info),122			    GFP_KERNEL);123	if (!info)124		return -ENOMEM;125 126	return pmbus_do_probe(client, info);127}128 129static const struct i2c_device_id pxe1610_id[] = {130	{"pxe1610"},131	{"pxe1110"},132	{"pxm1310"},133	{}134};135 136MODULE_DEVICE_TABLE(i2c, pxe1610_id);137 138static struct i2c_driver pxe1610_driver = {139	.driver = {140			.name = "pxe1610",141			},142	.probe = pxe1610_probe,143	.id_table = pxe1610_id,144};145 146module_i2c_driver(pxe1610_driver);147 148MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>");149MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310");150MODULE_LICENSE("GPL");151MODULE_IMPORT_NS(PMBUS);152