[as7712-32x] Support ACBEL FSF019 PSU

This commit is contained in:
brandonchuang
2018-11-02 16:45:12 +08:00
parent 17978ad957
commit 78e073afd5
5 changed files with 175 additions and 27 deletions

View File

@@ -35,6 +35,7 @@
#include <linux/dmi.h>
#define MAX_MODEL_NAME 16
#define MAX_SERIAL_NUMBER 19
#define DC12V_FAN_DIR_OFFSET 0x34
#define DC12V_FAN_DIR_LEN 3
@@ -47,6 +48,13 @@ extern int as7712_32x_cpld_read (unsigned short cpld_addr, u8 reg);
*/
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
enum psu_type {
PSU_TYPE_AC_110V,
PSU_TYPE_DC_48V,
PSU_TYPE_DC_12V,
PSU_TYPE_AC_ACBEL_FSF019,
};
/* Each client has this additional data
*/
struct as7712_32x_psu_data {
@@ -58,6 +66,8 @@ struct as7712_32x_psu_data {
u8 status; /* Status(present/power_good) register read from CPLD */
char model_name[MAX_MODEL_NAME]; /* Model name, read from eeprom */
char fan_dir[DC12V_FAN_DIR_LEN+1]; /* DC12V fan direction */
char serial_number[MAX_SERIAL_NUMBER];
enum psu_type type;
};
static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf);
@@ -66,6 +76,7 @@ static struct as7712_32x_psu_data *as7712_32x_psu_update_device(struct device *d
enum as7712_32x_psu_sysfs_attributes {
PSU_PRESENT,
PSU_MODEL_NAME,
PSU_SERIAL_NUMBER, /* For ACBEL PSU only */
PSU_POWER_GOOD,
PSU_FAN_DIR /* For DC12V only */
};
@@ -74,12 +85,14 @@ enum as7712_32x_psu_sysfs_attributes {
*/
static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT);
static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME);
static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER);
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD);
static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_string, NULL, PSU_FAN_DIR);
static struct attribute *as7712_32x_psu_attributes[] = {
&sensor_dev_attr_psu_present.dev_attr.attr,
&sensor_dev_attr_psu_model_name.dev_attr.attr,
&sensor_dev_attr_psu_serial_number.dev_attr.attr,
&sensor_dev_attr_psu_power_good.dev_attr.attr,
&sensor_dev_attr_psu_fan_dir.dev_attr.attr,
NULL
@@ -117,12 +130,19 @@ static ssize_t show_string(struct device *dev, struct device_attribute *da,
return -EIO;
}
if (attr->index == PSU_MODEL_NAME) {
ptr = data->model_name;
}
else { /* PSU_FAN_DIR */
ptr = data->fan_dir;
}
switch (attr->index) {
case PSU_MODEL_NAME:
ptr = data->model_name;
break;
case PSU_SERIAL_NUMBER:
ptr = data->serial_number;
break;
case PSU_FAN_DIR:
ptr = data->fan_dir;
break;
default:
return -EINVAL;
}
return sprintf(buf, "%s\n", ptr);
}
@@ -245,12 +265,6 @@ static int as7712_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *
return result;
}
enum psu_type {
PSU_TYPE_AC_110V,
PSU_TYPE_DC_48V,
PSU_TYPE_DC_12V
};
struct model_name_info {
enum psu_type type;
u8 offset;
@@ -258,10 +272,38 @@ struct model_name_info {
char* model_name;
};
static int acbel_psu_serial_number_get(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as7712_32x_psu_data *data = i2c_get_clientdata(client);
int i, status;
memset(data->serial_number, 0, sizeof(data->serial_number));
/* Read from offset 0x2e ~ 0x3d (16 bytes) */
status = as7712_32x_psu_read_block(client, 0x2e,data->serial_number, 16);
if (status < 0) {
data->serial_number[0] = '\0';
dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x2e)\n", client->addr);
return status;
}
/* Read from offset 0x4f ~ 0x50 (2 bytes) */
status = as7712_32x_psu_read_block(client, 0x4f, data->serial_number + 16, 2);
if (status < 0) {
data->serial_number[0] = '\0';
dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x4f)\n", client->addr);
return status;
}
return 0;
}
struct model_name_info models[] = {
{PSU_TYPE_AC_110V, 0x20, 8, "YM-2651Y"},
{PSU_TYPE_DC_48V, 0x20, 8, "YM-2651V"},
{PSU_TYPE_DC_12V, 0x00, 11, "PSU-12V-750"},
{PSU_TYPE_AC_ACBEL_FSF019, 0x15, 7, "FSF019-"},
};
static int as7712_32x_psu_model_name_get(struct device *dev)
@@ -285,6 +327,20 @@ static int as7712_32x_psu_model_name_get(struct device *dev)
data->model_name[models[i].length] = '\0';
}
/* Get the remaining model name for FSF019 */
if (strncmp(data->model_name, "FSF019-", 7) == 0) {
char buf[5] = {0};
status = as7712_32x_psu_read_block(client, 0x48, data->model_name + models[i].length, 4);
if (status < 0) {
data->model_name[0] = '\0';
dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x48)\n", client->addr);
return status;
}
data->type = PSU_TYPE_AC_ACBEL_FSF019;
}
/* Determine if the model name is known, if not, read next index
*/
if (strncmp(data->model_name, models[i].model_name, models[i].length) == 0) {
@@ -348,6 +404,11 @@ static struct as7712_32x_psu_data *as7712_32x_psu_update_device(struct device *d
goto exit;
}
}
if (data->type == PSU_TYPE_AC_ACBEL_FSF019 &&
acbel_psu_serial_number_get(dev) < 0) {
goto exit;
}
}
data->last_updated = jiffies;

View File

@@ -148,11 +148,13 @@ _onlp_fani_info_get_psu_fan_direction(void)
}
switch (psu_type) {
case PSU_TYPE_AC_F2B:
case PSU_TYPE_AC_F2B_3YPOWER:
case PSU_TYPE_AC_F2B_ACBEL:
case PSU_TYPE_DC_48V_F2B:
case PSU_TYPE_DC_12V_F2B:
return ONLP_FAN_STATUS_F2B;
case PSU_TYPE_AC_B2F:
case PSU_TYPE_AC_B2F_3YPOWER:
case PSU_TYPE_AC_B2F_ACBEL:
case PSU_TYPE_DC_48V_B2F:
case PSU_TYPE_DC_12V_B2F:
return ONLP_FAN_STATUS_B2F;

View File

@@ -148,11 +148,11 @@ psu_type_t get_psu_type(int id, char* modelname, int modelname_len)
}
if (strncmp(fan_dir, "F2B", strlen("F2B")) == 0) {
return PSU_TYPE_AC_F2B;
return PSU_TYPE_AC_F2B_3YPOWER;
}
if (strncmp(fan_dir, "B2F", strlen("B2F")) == 0) {
return PSU_TYPE_AC_B2F;
return PSU_TYPE_AC_B2F_3YPOWER;
}
}
@@ -198,12 +198,37 @@ psu_type_t get_psu_type(int id, char* modelname, int modelname_len)
}
}
if (strncmp(model_name, "FSF019", 6) == 0) {
if (modelname) {
strncpy(modelname, model_name, 11); /* Copy full model name */
}
/* Read model */
char *string = NULL;
char *prefix = (id == PSU1_ID) ? PSU1_AC_PMBUS_PREFIX : PSU2_AC_PMBUS_PREFIX;
int len = onlp_file_read_str(&string, "%s""psu_fan_dir", prefix);
if (!string || len <= 0) {
return PSU_TYPE_UNKNOWN;
}
strncpy(fan_dir, string, len);
aim_free(string);
if (strncmp(fan_dir, "F2B", strlen("F2B")) == 0) {
return PSU_TYPE_AC_F2B_ACBEL;
}
if (strncmp(fan_dir, "B2F", strlen("B2F")) == 0) {
return PSU_TYPE_AC_B2F_ACBEL;
}
}
return PSU_TYPE_UNKNOWN;
}
#define PSU_SERIAL_NUMBER_LEN 18
int psu_serial_number_get(int id, char *serial, int serial_len)
int psu_pmbus_serial_number_get(int id, char *serial, int serial_len)
{
int size = 0;
int ret = ONLP_STATUS_OK;
@@ -225,3 +250,20 @@ int psu_serial_number_get(int id, char *serial, int serial_len)
return ONLP_STATUS_OK;
}
int psu_acbel_serial_number_get(int id, char *serial, int serial_len)
{
char *serial_number = NULL;
char *prefix = (id == PSU1_ID) ? PSU1_AC_HWMON_PREFIX : PSU2_AC_HWMON_PREFIX;
int len = onlp_file_read_str(&serial_number, "%s""psu_serial_number", prefix);
if (!serial || len <= 0) {
return ONLP_STATUS_E_INTERNAL;
}
strncpy(serial, serial_number, len);
aim_free(serial_number);
serial[len] = '\0';
return ONLP_STATUS_OK;
}

View File

@@ -54,8 +54,10 @@ int deviceNodeReadString(char *filename, char *buffer, int buf_size, int data_le
typedef enum psu_type {
PSU_TYPE_UNKNOWN,
PSU_TYPE_AC_F2B,
PSU_TYPE_AC_B2F,
PSU_TYPE_AC_F2B_3YPOWER,
PSU_TYPE_AC_B2F_3YPOWER,
PSU_TYPE_AC_F2B_ACBEL,
PSU_TYPE_AC_B2F_ACBEL,
PSU_TYPE_DC_48V_F2B,
PSU_TYPE_DC_48V_B2F,
PSU_TYPE_DC_12V_FANLESS,
@@ -64,7 +66,8 @@ typedef enum psu_type {
} psu_type_t;
psu_type_t get_psu_type(int id, char* modelname, int modelname_len);
int psu_serial_number_get(int id, char *serial, int serial_len);
int psu_pmbus_serial_number_get(int id, char *serial, int serial_len);
int psu_acbel_serial_number_get(int id, char *serial, int serial_len);
#define DEBUG_MODE 0

View File

@@ -68,7 +68,7 @@ psu_status_info_get(int id, char *node, int *value)
}
static int
psu_ym2651_pmbus_info_get(int id, char *node, int *value)
psu_pmbus_info_get(int id, char *node, int *value)
{
int ret = 0;
char buf[PSU_NODE_MAX_INT_LEN + 1] = {0};
@@ -113,22 +113,57 @@ psu_ym2651_info_get(onlp_psu_info_t* info)
info->hdr.coids[1] = ONLP_THERMAL_ID_CREATE(index + CHASSIS_THERMAL_COUNT);
/* Read voltage, current and power */
if (psu_ym2651_pmbus_info_get(index, "psu_v_out", &val) == 0) {
if (psu_pmbus_info_get(index, "psu_v_out", &val) == 0) {
info->mvout = val;
info->caps |= ONLP_PSU_CAPS_VOUT;
}
if (psu_ym2651_pmbus_info_get(index, "psu_i_out", &val) == 0) {
if (psu_pmbus_info_get(index, "psu_i_out", &val) == 0) {
info->miout = val;
info->caps |= ONLP_PSU_CAPS_IOUT;
}
if (psu_ym2651_pmbus_info_get(index, "psu_p_out", &val) == 0) {
if (psu_pmbus_info_get(index, "psu_p_out", &val) == 0) {
info->mpout = val;
info->caps |= ONLP_PSU_CAPS_POUT;
}
psu_serial_number_get(index, info->serial, sizeof(info->serial));
psu_pmbus_serial_number_get(index, info->serial, sizeof(info->serial));
return ONLP_STATUS_OK;
}
static int
psu_acbel_info_get(onlp_psu_info_t* info)
{
int val = 0;
int index = ONLP_OID_ID_GET(info->hdr.id);
if (info->status & ONLP_PSU_STATUS_FAILED) {
return ONLP_STATUS_OK;
}
/* Set the associated oid_table */
info->hdr.coids[0] = ONLP_FAN_ID_CREATE(index + CHASSIS_FAN_COUNT);
info->hdr.coids[1] = ONLP_THERMAL_ID_CREATE(index + CHASSIS_THERMAL_COUNT);
/* Read voltage, current and power */
if (psu_pmbus_info_get(index, "psu_v_out", &val) == 0) {
info->mvout = val;
info->caps |= ONLP_PSU_CAPS_VOUT;
}
if (psu_pmbus_info_get(index, "psu_i_out", &val) == 0) {
info->miout = val;
info->caps |= ONLP_PSU_CAPS_IOUT;
}
if (psu_pmbus_info_get(index, "psu_p_out", &val) == 0) {
info->mpout = val;
info->caps |= ONLP_PSU_CAPS_POUT;
}
psu_acbel_serial_number_get(index, info->serial, sizeof(info->serial));
return ONLP_STATUS_OK;
}
@@ -237,11 +272,16 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info)
psu_type = get_psu_type(index, info->model, sizeof(info->model));
switch (psu_type) {
case PSU_TYPE_AC_F2B:
case PSU_TYPE_AC_B2F:
case PSU_TYPE_AC_F2B_3YPOWER:
case PSU_TYPE_AC_B2F_3YPOWER:
info->caps = ONLP_PSU_CAPS_AC;
ret = psu_ym2651_info_get(info);
break;
case PSU_TYPE_AC_F2B_ACBEL:
case PSU_TYPE_AC_B2F_ACBEL:
info->caps = ONLP_PSU_CAPS_AC;
ret = psu_acbel_info_get(info);
break;
case PSU_TYPE_DC_48V_F2B:
case PSU_TYPE_DC_48V_B2F:
info->caps = ONLP_PSU_CAPS_DC48;