|
9 | 9 | #include <linux/sysfs.h>
|
10 | 10 | #include <linux/slab.h>
|
11 | 11 | #include <linux/dmi.h>
|
| 12 | +#include "pddf_client_defs.h" |
12 | 13 | #include "pddf_psu_defs.h"
|
| 14 | +#include "pddf_psu_driver.h" |
| 15 | +#include "pddf_psu_api.h" |
13 | 16 |
|
14 | 17 | ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *da, char *buf);
|
15 | 18 | extern PSU_SYSFS_ATTR_DATA access_psu_v_out;
|
| 19 | +int pddf_post_get_custom_psu_model_name(void *i2c_client, PSU_DATA_ATTR *adata, void *data); |
| 20 | +extern PSU_SYSFS_ATTR_DATA access_psu_model_name; |
| 21 | +int pddf_post_get_custom_psu_fan_dir(void *i2c_client, PSU_DATA_ATTR *adata, void *data); |
| 22 | +extern PSU_SYSFS_ATTR_DATA access_psu_fan_dir; |
| 23 | +int pddf_custom_psu_post_probe(struct i2c_client *client, const struct i2c_device_id *dev_id); |
| 24 | +int pddf_custom_psu_post_remove(struct i2c_client *client); |
| 25 | +extern struct pddf_ops_t pddf_psu_ops; |
| 26 | + |
| 27 | +const char FAN_DIR_F2B[] = "F2B\0"; |
| 28 | +const char FAN_DIR_B2F[] = "B2F\0"; |
| 29 | + |
| 30 | +static LIST_HEAD(psu_eeprom_client_list); |
| 31 | +static struct mutex list_lock; |
| 32 | + |
| 33 | +struct psu_eeprom_client_node { |
| 34 | + struct i2c_client *client; |
| 35 | + struct list_head list; |
| 36 | +}; |
16 | 37 |
|
17 | 38 | static int two_complement_to_int(u16 data, u8 valid_bit, int mask)
|
18 | 39 | {
|
@@ -95,11 +116,147 @@ ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *
|
95 | 116 | }
|
96 | 117 |
|
97 | 118 |
|
| 119 | +int pddf_post_get_custom_psu_model_name(void *i2c_client, PSU_DATA_ATTR *adata, void *data) |
| 120 | +{ |
| 121 | + struct psu_attr_info *sysfs_attr_info = (struct psu_attr_info *)data; |
| 122 | + |
| 123 | + if (strlen(sysfs_attr_info->val.strval) > 8) { |
| 124 | + sysfs_attr_info->val.strval[8] = '-'; |
| 125 | + } |
| 126 | + |
| 127 | + return 0; |
| 128 | +} |
| 129 | + |
| 130 | +/* |
| 131 | + * Get the PSU EEPROM I2C client with the same bus number. |
| 132 | + */ |
| 133 | +static struct i2c_client *find_psu_eeprom_client(struct i2c_client *pmbus_client) |
| 134 | +{ |
| 135 | + struct list_head *list_node = NULL; |
| 136 | + struct psu_eeprom_client_node *psu_eeprom_node = NULL; |
| 137 | + struct i2c_client *eeprom_client = NULL; |
| 138 | + |
| 139 | + mutex_lock(&list_lock); |
| 140 | + list_for_each(list_node, &psu_eeprom_client_list) { |
| 141 | + psu_eeprom_node = list_entry(list_node, struct psu_eeprom_client_node, list); |
| 142 | + /* Check if the bus adapter is the same or not. */ |
| 143 | + if (psu_eeprom_node->client->adapter == pmbus_client->adapter) { |
| 144 | + eeprom_client = psu_eeprom_node->client; |
| 145 | + break; |
| 146 | + } |
| 147 | + } |
| 148 | + mutex_unlock(&list_lock); |
| 149 | + |
| 150 | + return eeprom_client; |
| 151 | +} |
| 152 | + |
| 153 | +int pddf_post_get_custom_psu_fan_dir(void *i2c_client, PSU_DATA_ATTR *adata, void *data) |
| 154 | +{ |
| 155 | + int i; |
| 156 | + struct i2c_client *client = (struct i2c_client *)i2c_client; |
| 157 | + struct psu_attr_info *psu_fan_dir_attr_info = (struct psu_attr_info *)data; |
| 158 | + struct psu_data *psu_eeprom_client_data = NULL; |
| 159 | + struct psu_attr_info *psu_eeprom_model_name = NULL; |
| 160 | + struct i2c_client *psu_eeprom_client = NULL; |
| 161 | + |
| 162 | + psu_eeprom_client = find_psu_eeprom_client(client); |
| 163 | + if (!psu_eeprom_client) { |
| 164 | + return 0; |
| 165 | + } |
| 166 | + |
| 167 | + /* |
| 168 | + * Get the model name from the PSU EEPROM I2C client. |
| 169 | + */ |
| 170 | + psu_eeprom_client_data = i2c_get_clientdata(psu_eeprom_client); |
| 171 | + if (!psu_eeprom_client_data) { |
| 172 | + return 0; |
| 173 | + } |
| 174 | + for (i = 0; i < psu_eeprom_client_data->num_attr; i++) { |
| 175 | + if (strcmp(psu_eeprom_client_data->attr_info[i].name, "psu_model_name") == 0) { |
| 176 | + psu_eeprom_model_name = &psu_eeprom_client_data->attr_info[i]; |
| 177 | + break; |
| 178 | + } |
| 179 | + } |
| 180 | + if (!psu_eeprom_model_name) { |
| 181 | + return 0; |
| 182 | + } |
| 183 | + |
| 184 | + /* |
| 185 | + * Compare the model name, then replace the content of psu_fan_dir. |
| 186 | + */ |
| 187 | + if (strcmp(psu_eeprom_model_name->val.strval, "YM-2401H-CR") == 0) { |
| 188 | + strscpy(psu_fan_dir_attr_info->val.strval, |
| 189 | + FAN_DIR_F2B, |
| 190 | + sizeof(psu_fan_dir_attr_info->val.strval)); |
| 191 | + } else if (strcmp(psu_eeprom_model_name->val.strval, "YM-2401H-DR") == 0) { |
| 192 | + strscpy(psu_fan_dir_attr_info->val.strval, |
| 193 | + FAN_DIR_B2F, |
| 194 | + sizeof(psu_fan_dir_attr_info->val.strval)); |
| 195 | + } |
| 196 | + |
| 197 | + return 0; |
| 198 | +} |
| 199 | + |
| 200 | +int pddf_custom_psu_post_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) |
| 201 | +{ |
| 202 | + struct psu_eeprom_client_node *psu_eeprom_node; |
| 203 | + |
| 204 | + if (strcmp(dev_id->name, "psu_eeprom") != 0) { |
| 205 | + return 0; |
| 206 | + } |
| 207 | + |
| 208 | + psu_eeprom_node = kzalloc(sizeof(struct psu_eeprom_client_node), GFP_KERNEL); |
| 209 | + if (!psu_eeprom_node) { |
| 210 | + dev_dbg(&client->dev, "Can't allocate psu_eeprom_client_node (0x%x)\n", client->addr); |
| 211 | + return -ENOMEM; |
| 212 | + } |
| 213 | + |
| 214 | + psu_eeprom_node->client = client; |
| 215 | + |
| 216 | + mutex_lock(&list_lock); |
| 217 | + list_add(&psu_eeprom_node->list, &psu_eeprom_client_list); |
| 218 | + mutex_unlock(&list_lock); |
| 219 | + |
| 220 | + return 0; |
| 221 | +} |
| 222 | + |
| 223 | +int pddf_custom_psu_post_remove(struct i2c_client *client) |
| 224 | +{ |
| 225 | + struct list_head *list_node = NULL; |
| 226 | + struct psu_eeprom_client_node *psu_eeprom_node = NULL; |
| 227 | + int found = 0; |
| 228 | + |
| 229 | + mutex_lock(&list_lock); |
| 230 | + |
| 231 | + list_for_each(list_node, &psu_eeprom_client_list) { |
| 232 | + psu_eeprom_node = list_entry(list_node, struct psu_eeprom_client_node, list); |
| 233 | + |
| 234 | + if (psu_eeprom_node->client == client) { |
| 235 | + list_del_init(&psu_eeprom_node->list); |
| 236 | + found = 1; |
| 237 | + break; |
| 238 | + } |
| 239 | + } |
| 240 | + |
| 241 | + if (found) { |
| 242 | + kfree(psu_eeprom_node); |
| 243 | + } |
| 244 | + |
| 245 | + mutex_unlock(&list_lock); |
| 246 | + |
| 247 | + return 0; |
| 248 | +} |
| 249 | + |
98 | 250 |
|
99 | 251 | static int __init pddf_custom_psu_init(void)
|
100 | 252 | {
|
| 253 | + mutex_init(&list_lock); |
101 | 254 | access_psu_v_out.show = pddf_show_custom_psu_v_out;
|
102 | 255 | access_psu_v_out.do_get = NULL;
|
| 256 | + access_psu_model_name.post_get = pddf_post_get_custom_psu_model_name; |
| 257 | + access_psu_fan_dir.post_get = pddf_post_get_custom_psu_fan_dir; |
| 258 | + pddf_psu_ops.post_probe = pddf_custom_psu_post_probe; |
| 259 | + pddf_psu_ops.post_remove = pddf_custom_psu_post_remove; |
103 | 260 | return 0;
|
104 | 261 | }
|
105 | 262 |
|
|
0 commit comments