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

ir35221.c (3817B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Hardware monitoring driver for IR35221
      4 *
      5 * Copyright (C) IBM Corporation 2017.
      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 "pmbus.h"
     14
     15#define IR35221_MFR_VIN_PEAK		0xc5
     16#define IR35221_MFR_VOUT_PEAK		0xc6
     17#define IR35221_MFR_IOUT_PEAK		0xc7
     18#define IR35221_MFR_TEMP_PEAK		0xc8
     19#define IR35221_MFR_VIN_VALLEY		0xc9
     20#define IR35221_MFR_VOUT_VALLEY		0xca
     21#define IR35221_MFR_IOUT_VALLEY		0xcb
     22#define IR35221_MFR_TEMP_VALLEY		0xcc
     23
     24static int ir35221_read_word_data(struct i2c_client *client, int page,
     25				  int phase, int reg)
     26{
     27	int ret;
     28
     29	switch (reg) {
     30	case PMBUS_VIRT_READ_VIN_MAX:
     31		ret = pmbus_read_word_data(client, page, phase,
     32					   IR35221_MFR_VIN_PEAK);
     33		break;
     34	case PMBUS_VIRT_READ_VOUT_MAX:
     35		ret = pmbus_read_word_data(client, page, phase,
     36					   IR35221_MFR_VOUT_PEAK);
     37		break;
     38	case PMBUS_VIRT_READ_IOUT_MAX:
     39		ret = pmbus_read_word_data(client, page, phase,
     40					   IR35221_MFR_IOUT_PEAK);
     41		break;
     42	case PMBUS_VIRT_READ_TEMP_MAX:
     43		ret = pmbus_read_word_data(client, page, phase,
     44					   IR35221_MFR_TEMP_PEAK);
     45		break;
     46	case PMBUS_VIRT_READ_VIN_MIN:
     47		ret = pmbus_read_word_data(client, page, phase,
     48					   IR35221_MFR_VIN_VALLEY);
     49		break;
     50	case PMBUS_VIRT_READ_VOUT_MIN:
     51		ret = pmbus_read_word_data(client, page, phase,
     52					   IR35221_MFR_VOUT_VALLEY);
     53		break;
     54	case PMBUS_VIRT_READ_IOUT_MIN:
     55		ret = pmbus_read_word_data(client, page, phase,
     56					   IR35221_MFR_IOUT_VALLEY);
     57		break;
     58	case PMBUS_VIRT_READ_TEMP_MIN:
     59		ret = pmbus_read_word_data(client, page, phase,
     60					   IR35221_MFR_TEMP_VALLEY);
     61		break;
     62	default:
     63		ret = -ENODATA;
     64		break;
     65	}
     66
     67	return ret;
     68}
     69
     70static int ir35221_probe(struct i2c_client *client)
     71{
     72	struct pmbus_driver_info *info;
     73	u8 buf[I2C_SMBUS_BLOCK_MAX];
     74	int ret;
     75
     76	if (!i2c_check_functionality(client->adapter,
     77				     I2C_FUNC_SMBUS_READ_BYTE_DATA
     78				| I2C_FUNC_SMBUS_READ_WORD_DATA
     79				| I2C_FUNC_SMBUS_READ_BLOCK_DATA))
     80		return -ENODEV;
     81
     82	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
     83	if (ret < 0) {
     84		dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
     85		return ret;
     86	}
     87	if (ret != 2 || strncmp(buf, "RI", strlen("RI"))) {
     88		dev_err(&client->dev, "MFR_ID unrecognised\n");
     89		return -ENODEV;
     90	}
     91
     92	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
     93	if (ret < 0) {
     94		dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
     95		return ret;
     96	}
     97	if (ret != 2 || !(buf[0] == 0x6c && buf[1] == 0x00)) {
     98		dev_err(&client->dev, "MFR_MODEL unrecognised\n");
     99		return -ENODEV;
    100	}
    101
    102	info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
    103			    GFP_KERNEL);
    104	if (!info)
    105		return -ENOMEM;
    106
    107	info->read_word_data = ir35221_read_word_data;
    108
    109	info->pages = 2;
    110	info->format[PSC_VOLTAGE_IN] = linear;
    111	info->format[PSC_VOLTAGE_OUT] = linear;
    112	info->format[PSC_CURRENT_IN] = linear;
    113	info->format[PSC_CURRENT_OUT] = linear;
    114	info->format[PSC_POWER] = linear;
    115	info->format[PSC_TEMPERATURE] = linear;
    116
    117	info->func[0] = PMBUS_HAVE_VIN
    118		| PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
    119		| PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
    120		| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
    121		| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
    122		| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP;
    123	info->func[1] = info->func[0];
    124
    125	return pmbus_do_probe(client, info);
    126}
    127
    128static const struct i2c_device_id ir35221_id[] = {
    129	{"ir35221", 0},
    130	{}
    131};
    132
    133MODULE_DEVICE_TABLE(i2c, ir35221_id);
    134
    135static struct i2c_driver ir35221_driver = {
    136	.driver = {
    137		.name	= "ir35221",
    138	},
    139	.probe_new	= ir35221_probe,
    140	.id_table	= ir35221_id,
    141};
    142
    143module_i2c_driver(ir35221_driver);
    144
    145MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
    146MODULE_DESCRIPTION("PMBus driver for IR35221");
    147MODULE_LICENSE("GPL");
    148MODULE_IMPORT_NS(PMBUS);