123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * Copyright 2019 Inspur Corp.
- */
- #include <linux/debugfs.h>
- #include <linux/device.h>
- #include <linux/fs.h>
- #include <linux/i2c.h>
- #include <linux/module.h>
- #include <linux/pmbus.h>
- #include <linux/hwmon-sysfs.h>
- #include "pmbus.h"
- #define IPSPS_REG_VENDOR_ID 0x99
- #define IPSPS_REG_MODEL 0x9A
- #define IPSPS_REG_FW_VERSION 0x9B
- #define IPSPS_REG_PN 0x9C
- #define IPSPS_REG_SN 0x9E
- #define IPSPS_REG_HW_VERSION 0xB0
- #define IPSPS_REG_MODE 0xFC
- #define MODE_ACTIVE 0x55
- #define MODE_STANDBY 0x0E
- #define MODE_REDUNDANCY 0x00
- #define MODE_ACTIVE_STRING "active"
- #define MODE_STANDBY_STRING "standby"
- #define MODE_REDUNDANCY_STRING "redundancy"
- enum ipsps_index {
- vendor,
- model,
- fw_version,
- part_number,
- serial_number,
- hw_version,
- mode,
- num_regs,
- };
- static const u8 ipsps_regs[num_regs] = {
- [vendor] = IPSPS_REG_VENDOR_ID,
- [model] = IPSPS_REG_MODEL,
- [fw_version] = IPSPS_REG_FW_VERSION,
- [part_number] = IPSPS_REG_PN,
- [serial_number] = IPSPS_REG_SN,
- [hw_version] = IPSPS_REG_HW_VERSION,
- [mode] = IPSPS_REG_MODE,
- };
- static ssize_t ipsps_string_show(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
- {
- u8 reg;
- int rc;
- char *p;
- char data[I2C_SMBUS_BLOCK_MAX + 1];
- struct i2c_client *client = to_i2c_client(dev->parent);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- reg = ipsps_regs[attr->index];
- rc = i2c_smbus_read_block_data(client, reg, data);
- if (rc < 0)
- return rc;
- /* filled with printable characters, ending with # */
- p = memscan(data, '#', rc);
- *p = '\0';
- return sysfs_emit(buf, "%s\n", data);
- }
- static ssize_t ipsps_fw_version_show(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
- {
- u8 reg;
- int rc;
- u8 data[I2C_SMBUS_BLOCK_MAX] = { 0 };
- struct i2c_client *client = to_i2c_client(dev->parent);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- reg = ipsps_regs[attr->index];
- rc = i2c_smbus_read_block_data(client, reg, data);
- if (rc < 0)
- return rc;
- if (rc != 6)
- return -EPROTO;
- return sysfs_emit(buf, "%u.%02u%u-%u.%02u\n",
- data[1], data[2]/* < 100 */, data[3]/*< 10*/,
- data[4], data[5]/* < 100 */);
- }
- static ssize_t ipsps_mode_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
- {
- u8 reg;
- int rc;
- struct i2c_client *client = to_i2c_client(dev->parent);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- reg = ipsps_regs[attr->index];
- rc = i2c_smbus_read_byte_data(client, reg);
- if (rc < 0)
- return rc;
- switch (rc) {
- case MODE_ACTIVE:
- return sysfs_emit(buf, "[%s] %s %s\n",
- MODE_ACTIVE_STRING,
- MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
- case MODE_STANDBY:
- return sysfs_emit(buf, "%s [%s] %s\n",
- MODE_ACTIVE_STRING,
- MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
- case MODE_REDUNDANCY:
- return sysfs_emit(buf, "%s %s [%s]\n",
- MODE_ACTIVE_STRING,
- MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
- default:
- return sysfs_emit(buf, "unspecified\n");
- }
- }
- static ssize_t ipsps_mode_store(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
- {
- u8 reg;
- int rc;
- struct i2c_client *client = to_i2c_client(dev->parent);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- reg = ipsps_regs[attr->index];
- if (sysfs_streq(MODE_STANDBY_STRING, buf)) {
- rc = i2c_smbus_write_byte_data(client, reg,
- MODE_STANDBY);
- if (rc < 0)
- return rc;
- return count;
- } else if (sysfs_streq(MODE_ACTIVE_STRING, buf)) {
- rc = i2c_smbus_write_byte_data(client, reg,
- MODE_ACTIVE);
- if (rc < 0)
- return rc;
- return count;
- }
- return -EINVAL;
- }
- static SENSOR_DEVICE_ATTR_RO(vendor, ipsps_string, vendor);
- static SENSOR_DEVICE_ATTR_RO(model, ipsps_string, model);
- static SENSOR_DEVICE_ATTR_RO(part_number, ipsps_string, part_number);
- static SENSOR_DEVICE_ATTR_RO(serial_number, ipsps_string, serial_number);
- static SENSOR_DEVICE_ATTR_RO(hw_version, ipsps_string, hw_version);
- static SENSOR_DEVICE_ATTR_RO(fw_version, ipsps_fw_version, fw_version);
- static SENSOR_DEVICE_ATTR_RW(mode, ipsps_mode, mode);
- static struct attribute *ipsps_attrs[] = {
- &sensor_dev_attr_vendor.dev_attr.attr,
- &sensor_dev_attr_model.dev_attr.attr,
- &sensor_dev_attr_part_number.dev_attr.attr,
- &sensor_dev_attr_serial_number.dev_attr.attr,
- &sensor_dev_attr_hw_version.dev_attr.attr,
- &sensor_dev_attr_fw_version.dev_attr.attr,
- &sensor_dev_attr_mode.dev_attr.attr,
- NULL,
- };
- ATTRIBUTE_GROUPS(ipsps);
- static struct pmbus_driver_info ipsps_info = {
- .pages = 1,
- .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
- PMBUS_HAVE_IIN | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN |
- PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
- PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
- PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
- PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12,
- .groups = ipsps_groups,
- };
- static struct pmbus_platform_data ipsps_pdata = {
- .flags = PMBUS_SKIP_STATUS_CHECK,
- };
- static int ipsps_probe(struct i2c_client *client)
- {
- client->dev.platform_data = &ipsps_pdata;
- return pmbus_do_probe(client, &ipsps_info);
- }
- static const struct i2c_device_id ipsps_id[] = {
- { "ipsps1", 0 },
- {}
- };
- MODULE_DEVICE_TABLE(i2c, ipsps_id);
- #ifdef CONFIG_OF
- static const struct of_device_id ipsps_of_match[] = {
- { .compatible = "inspur,ipsps1" },
- {}
- };
- MODULE_DEVICE_TABLE(of, ipsps_of_match);
- #endif
- static struct i2c_driver ipsps_driver = {
- .driver = {
- .name = "inspur-ipsps",
- .of_match_table = of_match_ptr(ipsps_of_match),
- },
- .probe_new = ipsps_probe,
- .id_table = ipsps_id,
- };
- module_i2c_driver(ipsps_driver);
- MODULE_AUTHOR("John Wang");
- MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies");
- MODULE_LICENSE("GPL");
- MODULE_IMPORT_NS(PMBUS);
|