mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2025-12-25 17:27:01 +00:00
[as7712-32x] Support ACBEL FSF019 PSU
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user