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

pli1209bc.c (3967B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Hardware monitoring driver for Vicor PLI1209BC Digital Supervisor
      4 *
      5 * Copyright (c) 2022 9elements GmbH
      6 */
      7
      8#include <linux/i2c.h>
      9#include <linux/module.h>
     10#include <linux/pmbus.h>
     11#include <linux/regulator/driver.h>
     12#include "pmbus.h"
     13
     14/*
     15 * The capability command is only supported at page 0. Probing the device while
     16 * the page register is set to 1 will falsely enable PEC support. Disable
     17 * capability probing accordingly, since the PLI1209BC does not have any
     18 * additional capabilities.
     19 */
     20static struct pmbus_platform_data pli1209bc_plat_data = {
     21	.flags = PMBUS_NO_CAPABILITY,
     22};
     23
     24static int pli1209bc_read_word_data(struct i2c_client *client, int page,
     25				    int phase, int reg)
     26{
     27	int data;
     28
     29	switch (reg) {
     30	/* PMBUS_READ_POUT uses a direct format with R=0 */
     31	case PMBUS_READ_POUT:
     32		data = pmbus_read_word_data(client, page, phase, reg);
     33		if (data < 0)
     34			return data;
     35		data = sign_extend32(data, 15) * 10;
     36		return clamp_val(data, -32768, 32767) & 0xffff;
     37	/*
     38	 * PMBUS_READ_VOUT and PMBUS_READ_TEMPERATURE_1 return invalid data
     39	 * when the BCM is turned off. Since it is not possible to return
     40	 * ENODATA error, return zero instead.
     41	 */
     42	case PMBUS_READ_VOUT:
     43	case PMBUS_READ_TEMPERATURE_1:
     44		data = pmbus_read_word_data(client, page, phase,
     45					    PMBUS_STATUS_WORD);
     46		if (data < 0)
     47			return data;
     48		if (data & PB_STATUS_POWER_GOOD_N)
     49			return 0;
     50		return pmbus_read_word_data(client, page, phase, reg);
     51	default:
     52		return -ENODATA;
     53	}
     54}
     55
     56#if IS_ENABLED(CONFIG_SENSORS_PLI1209BC_REGULATOR)
     57static const struct regulator_desc pli1209bc_reg_desc = {
     58	.name = "vout2",
     59	.id = 1,
     60	.of_match = of_match_ptr("vout2"),
     61	.regulators_node = of_match_ptr("regulators"),
     62	.ops = &pmbus_regulator_ops,
     63	.type = REGULATOR_VOLTAGE,
     64	.owner = THIS_MODULE,
     65};
     66#endif
     67
     68static struct pmbus_driver_info pli1209bc_info = {
     69	.pages = 2,
     70	.format[PSC_VOLTAGE_IN] = direct,
     71	.format[PSC_VOLTAGE_OUT] = direct,
     72	.format[PSC_CURRENT_IN] = direct,
     73	.format[PSC_CURRENT_OUT] = direct,
     74	.format[PSC_POWER] = direct,
     75	.format[PSC_TEMPERATURE] = direct,
     76	.m[PSC_VOLTAGE_IN] = 1,
     77	.b[PSC_VOLTAGE_IN] = 0,
     78	.R[PSC_VOLTAGE_IN] = 1,
     79	.m[PSC_VOLTAGE_OUT] = 1,
     80	.b[PSC_VOLTAGE_OUT] = 0,
     81	.R[PSC_VOLTAGE_OUT] = 1,
     82	.m[PSC_CURRENT_IN] = 1,
     83	.b[PSC_CURRENT_IN] = 0,
     84	.R[PSC_CURRENT_IN] = 3,
     85	.m[PSC_CURRENT_OUT] = 1,
     86	.b[PSC_CURRENT_OUT] = 0,
     87	.R[PSC_CURRENT_OUT] = 2,
     88	.m[PSC_POWER] = 1,
     89	.b[PSC_POWER] = 0,
     90	.R[PSC_POWER] = 1,
     91	.m[PSC_TEMPERATURE] = 1,
     92	.b[PSC_TEMPERATURE] = 0,
     93	.R[PSC_TEMPERATURE] = 0,
     94	/*
     95	 * Page 0 sums up all attributes except voltage readings.
     96	 * The pli1209 digital supervisor only contains a single BCM, making
     97	 * page 0 redundant.
     98	 */
     99	.func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT
    100	    | PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT
    101	    | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT
    102	    | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
    103	    | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT,
    104	.read_word_data = pli1209bc_read_word_data,
    105#if IS_ENABLED(CONFIG_SENSORS_PLI1209BC_REGULATOR)
    106	.num_regulators = 1,
    107	.reg_desc = &pli1209bc_reg_desc,
    108#endif
    109};
    110
    111static int pli1209bc_probe(struct i2c_client *client)
    112{
    113	client->dev.platform_data = &pli1209bc_plat_data;
    114	return pmbus_do_probe(client, &pli1209bc_info);
    115}
    116
    117static const struct i2c_device_id pli1209bc_id[] = {
    118	{"pli1209bc", 0},
    119	{}
    120};
    121
    122MODULE_DEVICE_TABLE(i2c, pli1209bc_id);
    123
    124#ifdef CONFIG_OF
    125static const struct of_device_id pli1209bc_of_match[] = {
    126	{ .compatible = "vicor,pli1209bc" },
    127	{ },
    128};
    129MODULE_DEVICE_TABLE(of, pli1209bc_of_match);
    130#endif
    131
    132static struct i2c_driver pli1209bc_driver = {
    133	.driver = {
    134		   .name = "pli1209bc",
    135		   .of_match_table = of_match_ptr(pli1209bc_of_match),
    136		   },
    137	.probe_new = pli1209bc_probe,
    138	.id_table = pli1209bc_id,
    139};
    140
    141module_i2c_driver(pli1209bc_driver);
    142
    143MODULE_AUTHOR("Marcello Sylvester Bauer <sylv@sylv.io>");
    144MODULE_DESCRIPTION("PMBus driver for Vicor PLI1209BC");
    145MODULE_LICENSE("GPL");
    146MODULE_IMPORT_NS(PMBUS);