brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 3e3cc9a Raw
228 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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	0x9917#define IPSPS_REG_MODEL		0x9A18#define IPSPS_REG_FW_VERSION	0x9B19#define IPSPS_REG_PN		0x9C20#define IPSPS_REG_SN		0x9E21#define IPSPS_REG_HW_VERSION	0xB022#define IPSPS_REG_MODE		0xFC23 24#define MODE_ACTIVE		0x5525#define MODE_STANDBY		0x0E26#define MODE_REDUNDANCY		0x0027 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" },201	{}202};203MODULE_DEVICE_TABLE(i2c, ipsps_id);204 205#ifdef CONFIG_OF206static const struct of_device_id ipsps_of_match[] = {207	{ .compatible = "inspur,ipsps1" },208	{}209};210MODULE_DEVICE_TABLE(of, ipsps_of_match);211#endif212 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 = 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);228