cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xdpe12284.c (4973B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers
      4 *
      5 * Copyright (c) 2020 Mellanox Technologies. All rights reserved.
      6 */
      7
      8#include <linux/err.h>
      9#include <linux/i2c.h>
     10#include <linux/init.h>
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/regulator/driver.h>
     14
     15#include "pmbus.h"
     16
     17#define XDPE122_PROT_VR12_5MV		0x01 /* VR12.0 mode, 5-mV DAC */
     18#define XDPE122_PROT_VR12_5_10MV	0x02 /* VR12.5 mode, 10-mV DAC */
     19#define XDPE122_PROT_IMVP9_10MV		0x03 /* IMVP9 mode, 10-mV DAC */
     20#define XDPE122_AMD_625MV		0x10 /* AMD mode 6.25mV */
     21#define XDPE122_PAGE_NUM		2
     22
     23static int xdpe122_read_word_data(struct i2c_client *client, int page,
     24				  int phase, int reg)
     25{
     26	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
     27	long val;
     28	s16 exponent;
     29	s32 mantissa;
     30	int ret;
     31
     32	switch (reg) {
     33	case PMBUS_VOUT_OV_FAULT_LIMIT:
     34	case PMBUS_VOUT_UV_FAULT_LIMIT:
     35		ret = pmbus_read_word_data(client, page, phase, reg);
     36		if (ret < 0)
     37			return ret;
     38
     39		/* Convert register value to LINEAR11 data. */
     40		exponent = ((s16)ret) >> 11;
     41		mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5;
     42		val = mantissa * 1000L;
     43		if (exponent >= 0)
     44			val <<= exponent;
     45		else
     46			val >>= -exponent;
     47
     48		/* Convert data to VID register. */
     49		switch (info->vrm_version[page]) {
     50		case vr13:
     51			if (val >= 500)
     52				return 1 + DIV_ROUND_CLOSEST(val - 500, 10);
     53			return 0;
     54		case vr12:
     55			if (val >= 250)
     56				return 1 + DIV_ROUND_CLOSEST(val - 250, 5);
     57			return 0;
     58		case imvp9:
     59			if (val >= 200)
     60				return 1 + DIV_ROUND_CLOSEST(val - 200, 10);
     61			return 0;
     62		case amd625mv:
     63			if (val >= 200 && val <= 1550)
     64				return DIV_ROUND_CLOSEST((1550 - val) * 100,
     65							 625);
     66			return 0;
     67		default:
     68			return -EINVAL;
     69		}
     70	default:
     71		return -ENODATA;
     72	}
     73
     74	return 0;
     75}
     76
     77static int xdpe122_identify(struct i2c_client *client,
     78			    struct pmbus_driver_info *info)
     79{
     80	u8 vout_params;
     81	int i, ret, vout_mode;
     82
     83	vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
     84	if (vout_mode >= 0 && vout_mode != 0xff) {
     85		switch (vout_mode >> 5) {
     86		case 0:
     87			info->format[PSC_VOLTAGE_OUT] = linear;
     88			return 0;
     89		case 1:
     90			info->format[PSC_VOLTAGE_OUT] = vid;
     91			info->read_word_data = xdpe122_read_word_data;
     92			break;
     93		default:
     94			return -ENODEV;
     95		}
     96	}
     97
     98	for (i = 0; i < XDPE122_PAGE_NUM; i++) {
     99		/* Read the register with VOUT scaling value.*/
    100		ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
    101		if (ret < 0)
    102			return ret;
    103
    104		vout_params = ret & GENMASK(4, 0);
    105
    106		switch (vout_params) {
    107		case XDPE122_PROT_VR12_5_10MV:
    108			info->vrm_version[i] = vr13;
    109			break;
    110		case XDPE122_PROT_VR12_5MV:
    111			info->vrm_version[i] = vr12;
    112			break;
    113		case XDPE122_PROT_IMVP9_10MV:
    114			info->vrm_version[i] = imvp9;
    115			break;
    116		case XDPE122_AMD_625MV:
    117			info->vrm_version[i] = amd625mv;
    118			break;
    119		default:
    120			return -EINVAL;
    121		}
    122	}
    123
    124	return 0;
    125}
    126
    127static const struct regulator_desc __maybe_unused xdpe122_reg_desc[] = {
    128	PMBUS_REGULATOR("vout", 0),
    129	PMBUS_REGULATOR("vout", 1),
    130};
    131
    132static struct pmbus_driver_info xdpe122_info = {
    133	.pages = XDPE122_PAGE_NUM,
    134	.format[PSC_VOLTAGE_IN] = linear,
    135	.format[PSC_TEMPERATURE] = linear,
    136	.format[PSC_CURRENT_IN] = linear,
    137	.format[PSC_CURRENT_OUT] = linear,
    138	.format[PSC_POWER] = linear,
    139	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
    140		PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
    141		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
    142		PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
    143	.func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
    144		PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
    145		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
    146		PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
    147	.identify = xdpe122_identify,
    148#if IS_ENABLED(CONFIG_SENSORS_XDPE122_REGULATOR)
    149	.num_regulators = 2,
    150	.reg_desc = xdpe122_reg_desc,
    151#endif
    152};
    153
    154static int xdpe122_probe(struct i2c_client *client)
    155{
    156	struct pmbus_driver_info *info;
    157
    158	info = devm_kmemdup(&client->dev, &xdpe122_info, sizeof(*info),
    159			    GFP_KERNEL);
    160	if (!info)
    161		return -ENOMEM;
    162
    163	return pmbus_do_probe(client, info);
    164}
    165
    166static const struct i2c_device_id xdpe122_id[] = {
    167	{"xdpe11280", 0},
    168	{"xdpe12254", 0},
    169	{"xdpe12284", 0},
    170	{}
    171};
    172
    173MODULE_DEVICE_TABLE(i2c, xdpe122_id);
    174
    175static const struct of_device_id __maybe_unused xdpe122_of_match[] = {
    176	{.compatible = "infineon,xdpe11280"},
    177	{.compatible = "infineon,xdpe12254"},
    178	{.compatible = "infineon,xdpe12284"},
    179	{}
    180};
    181MODULE_DEVICE_TABLE(of, xdpe122_of_match);
    182
    183static struct i2c_driver xdpe122_driver = {
    184	.driver = {
    185		.name = "xdpe12284",
    186		.of_match_table = of_match_ptr(xdpe122_of_match),
    187	},
    188	.probe_new = xdpe122_probe,
    189	.id_table = xdpe122_id,
    190};
    191
    192module_i2c_driver(xdpe122_driver);
    193
    194MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
    195MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family");
    196MODULE_LICENSE("GPL");
    197MODULE_IMPORT_NS(PMBUS);