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

inspur-ipsps.c (5870B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2019 Inspur Corp.
      4 */
      5
      6#include <linux/debugfs.h>
      7#include <linux/device.h>
      8#include <linux/fs.h>
      9#include <linux/i2c.h>
     10#include <linux/module.h>
     11#include <linux/pmbus.h>
     12#include <linux/hwmon-sysfs.h>
     13
     14#include "pmbus.h"
     15
     16#define IPSPS_REG_VENDOR_ID	0x99
     17#define IPSPS_REG_MODEL		0x9A
     18#define IPSPS_REG_FW_VERSION	0x9B
     19#define IPSPS_REG_PN		0x9C
     20#define IPSPS_REG_SN		0x9E
     21#define IPSPS_REG_HW_VERSION	0xB0
     22#define IPSPS_REG_MODE		0xFC
     23
     24#define MODE_ACTIVE		0x55
     25#define MODE_STANDBY		0x0E
     26#define MODE_REDUNDANCY		0x00
     27
     28#define MODE_ACTIVE_STRING		"active"
     29#define MODE_STANDBY_STRING		"standby"
     30#define MODE_REDUNDANCY_STRING		"redundancy"
     31
     32enum ipsps_index {
     33	vendor,
     34	model,
     35	fw_version,
     36	part_number,
     37	serial_number,
     38	hw_version,
     39	mode,
     40	num_regs,
     41};
     42
     43static const u8 ipsps_regs[num_regs] = {
     44	[vendor] = IPSPS_REG_VENDOR_ID,
     45	[model] = IPSPS_REG_MODEL,
     46	[fw_version] = IPSPS_REG_FW_VERSION,
     47	[part_number] = IPSPS_REG_PN,
     48	[serial_number] = IPSPS_REG_SN,
     49	[hw_version] = IPSPS_REG_HW_VERSION,
     50	[mode] = IPSPS_REG_MODE,
     51};
     52
     53static ssize_t ipsps_string_show(struct device *dev,
     54				 struct device_attribute *devattr,
     55				 char *buf)
     56{
     57	u8 reg;
     58	int rc;
     59	char *p;
     60	char data[I2C_SMBUS_BLOCK_MAX + 1];
     61	struct i2c_client *client = to_i2c_client(dev->parent);
     62	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
     63
     64	reg = ipsps_regs[attr->index];
     65	rc = i2c_smbus_read_block_data(client, reg, data);
     66	if (rc < 0)
     67		return rc;
     68
     69	/* filled with printable characters, ending with # */
     70	p = memscan(data, '#', rc);
     71	*p = '\0';
     72
     73	return sysfs_emit(buf, "%s\n", data);
     74}
     75
     76static ssize_t ipsps_fw_version_show(struct device *dev,
     77				     struct device_attribute *devattr,
     78				     char *buf)
     79{
     80	u8 reg;
     81	int rc;
     82	u8 data[I2C_SMBUS_BLOCK_MAX] = { 0 };
     83	struct i2c_client *client = to_i2c_client(dev->parent);
     84	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
     85
     86	reg = ipsps_regs[attr->index];
     87	rc = i2c_smbus_read_block_data(client, reg, data);
     88	if (rc < 0)
     89		return rc;
     90
     91	if (rc != 6)
     92		return -EPROTO;
     93
     94	return sysfs_emit(buf, "%u.%02u%u-%u.%02u\n",
     95			  data[1], data[2]/* < 100 */, data[3]/*< 10*/,
     96			  data[4], data[5]/* < 100 */);
     97}
     98
     99static ssize_t ipsps_mode_show(struct device *dev,
    100			       struct device_attribute *devattr, char *buf)
    101{
    102	u8 reg;
    103	int rc;
    104	struct i2c_client *client = to_i2c_client(dev->parent);
    105	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
    106
    107	reg = ipsps_regs[attr->index];
    108	rc = i2c_smbus_read_byte_data(client, reg);
    109	if (rc < 0)
    110		return rc;
    111
    112	switch (rc) {
    113	case MODE_ACTIVE:
    114		return sysfs_emit(buf, "[%s] %s %s\n",
    115				  MODE_ACTIVE_STRING,
    116				  MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
    117	case MODE_STANDBY:
    118		return sysfs_emit(buf, "%s [%s] %s\n",
    119				  MODE_ACTIVE_STRING,
    120				  MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
    121	case MODE_REDUNDANCY:
    122		return sysfs_emit(buf, "%s %s [%s]\n",
    123				  MODE_ACTIVE_STRING,
    124				  MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
    125	default:
    126		return sysfs_emit(buf, "unspecified\n");
    127	}
    128}
    129
    130static ssize_t ipsps_mode_store(struct device *dev,
    131				struct device_attribute *devattr,
    132				const char *buf, size_t count)
    133{
    134	u8 reg;
    135	int rc;
    136	struct i2c_client *client = to_i2c_client(dev->parent);
    137	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
    138
    139	reg = ipsps_regs[attr->index];
    140	if (sysfs_streq(MODE_STANDBY_STRING, buf)) {
    141		rc = i2c_smbus_write_byte_data(client, reg,
    142					       MODE_STANDBY);
    143		if (rc < 0)
    144			return rc;
    145		return count;
    146	} else if (sysfs_streq(MODE_ACTIVE_STRING, buf)) {
    147		rc = i2c_smbus_write_byte_data(client, reg,
    148					       MODE_ACTIVE);
    149		if (rc < 0)
    150			return rc;
    151		return count;
    152	}
    153
    154	return -EINVAL;
    155}
    156
    157static SENSOR_DEVICE_ATTR_RO(vendor, ipsps_string, vendor);
    158static SENSOR_DEVICE_ATTR_RO(model, ipsps_string, model);
    159static SENSOR_DEVICE_ATTR_RO(part_number, ipsps_string, part_number);
    160static SENSOR_DEVICE_ATTR_RO(serial_number, ipsps_string, serial_number);
    161static SENSOR_DEVICE_ATTR_RO(hw_version, ipsps_string, hw_version);
    162static SENSOR_DEVICE_ATTR_RO(fw_version, ipsps_fw_version, fw_version);
    163static SENSOR_DEVICE_ATTR_RW(mode, ipsps_mode, mode);
    164
    165static struct attribute *ipsps_attrs[] = {
    166	&sensor_dev_attr_vendor.dev_attr.attr,
    167	&sensor_dev_attr_model.dev_attr.attr,
    168	&sensor_dev_attr_part_number.dev_attr.attr,
    169	&sensor_dev_attr_serial_number.dev_attr.attr,
    170	&sensor_dev_attr_hw_version.dev_attr.attr,
    171	&sensor_dev_attr_fw_version.dev_attr.attr,
    172	&sensor_dev_attr_mode.dev_attr.attr,
    173	NULL,
    174};
    175
    176ATTRIBUTE_GROUPS(ipsps);
    177
    178static struct pmbus_driver_info ipsps_info = {
    179	.pages = 1,
    180	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
    181		PMBUS_HAVE_IIN | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN |
    182		PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
    183		PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
    184		PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
    185		PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12,
    186	.groups = ipsps_groups,
    187};
    188
    189static struct pmbus_platform_data ipsps_pdata = {
    190	.flags = PMBUS_SKIP_STATUS_CHECK,
    191};
    192
    193static int ipsps_probe(struct i2c_client *client)
    194{
    195	client->dev.platform_data = &ipsps_pdata;
    196	return pmbus_do_probe(client, &ipsps_info);
    197}
    198
    199static const struct i2c_device_id ipsps_id[] = {
    200	{ "ipsps1", 0 },
    201	{}
    202};
    203MODULE_DEVICE_TABLE(i2c, ipsps_id);
    204
    205#ifdef CONFIG_OF
    206static const struct of_device_id ipsps_of_match[] = {
    207	{ .compatible = "inspur,ipsps1" },
    208	{}
    209};
    210MODULE_DEVICE_TABLE(of, ipsps_of_match);
    211#endif
    212
    213static struct i2c_driver ipsps_driver = {
    214	.driver = {
    215		.name = "inspur-ipsps",
    216		.of_match_table = of_match_ptr(ipsps_of_match),
    217	},
    218	.probe_new = ipsps_probe,
    219	.id_table = ipsps_id,
    220};
    221
    222module_i2c_driver(ipsps_driver);
    223
    224MODULE_AUTHOR("John Wang");
    225MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies");
    226MODULE_LICENSE("GPL");
    227MODULE_IMPORT_NS(PMBUS);