Skip to content

Commit bd2a7a5

Browse files
committed
hwmon: (pmbus/max34440): Add max34451 config load
Adds a few attributes for MAX34451 version ETNA+6 and later. A few attributes reads CRC of the device and the other feature is being able to load a firmware or config file from a hex file. This hex file is assumed to be added in /lib/firmware folder. Signed-off-by: Alexis Czezar Torreno <[email protected]>
1 parent c72cc33 commit bd2a7a5

File tree

1 file changed

+204
-1
lines changed

1 file changed

+204
-1
lines changed

drivers/hwmon/pmbus/max34440.c

Lines changed: 204 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/init.h>
1313
#include <linux/err.h>
1414
#include <linux/i2c.h>
15+
#include <linux/firmware.h>
1516
#include "pmbus.h"
1617

1718
enum chips {
@@ -53,14 +54,212 @@ enum chips {
5354
#define MAX34451_MFR_CHANNEL_CONFIG 0xe4
5455
#define MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK 0x3f
5556

57+
#define MAX34451_MFR_CRC 0xFE
58+
59+
#define to_max34440_data(x) container_of(x, struct max34440_data, info)
60+
5661
struct max34440_data {
5762
int id;
5863
struct pmbus_driver_info info;
64+
struct mutex lock; /* Protects access to device during firmware load */
5965
u8 iout_oc_warn_limit;
6066
u8 iout_oc_fault_limit;
6167
};
6268

63-
#define to_max34440_data(x) container_of(x, struct max34440_data, info)
69+
static int ascii_to_hex(uint8_t c)
70+
{
71+
if (c >= '0' && c <= '9')
72+
return (uint8_t)(c - '0');
73+
74+
if (c >= 'A' && c <= 'F')
75+
return (uint8_t)(c - 'A' + 10);
76+
77+
if (c >= 'a' && c <= 'f')
78+
return (uint8_t)(c - 'a' + 10);
79+
80+
return 0;
81+
}
82+
83+
static ssize_t _read_crc(struct device *dev, struct device_attribute *attr,
84+
char *buf, uint8_t type)
85+
{
86+
struct i2c_client *client = to_i2c_client(dev->parent);
87+
int ret;
88+
89+
ret = i2c_smbus_write_word_data(client, MAX34451_MFR_CRC, type);
90+
if (ret < 0)
91+
return ret;
92+
93+
ret = i2c_smbus_read_word_data(client, MAX34451_MFR_CRC);
94+
if (ret < 0)
95+
return ret;
96+
97+
return snprintf(buf, PAGE_SIZE, "0x%02X\n", ret);
98+
}
99+
100+
static ssize_t main_flash_crc_show(struct device *dev, struct device_attribute *attr,
101+
char *buf)
102+
{
103+
return _read_crc(dev, attr, buf, 0);
104+
}
105+
106+
static ssize_t backup_flash_crc_show(struct device *dev, struct device_attribute *attr,
107+
char *buf)
108+
{
109+
return _read_crc(dev, attr, buf, 1);
110+
}
111+
112+
static ssize_t ram_crc_show(struct device *dev, struct device_attribute *attr,
113+
char *buf)
114+
{
115+
return _read_crc(dev, attr, buf, 2);
116+
}
117+
118+
static ssize_t program_memory_store(struct device *dev, struct device_attribute *attr,
119+
const char *buf, size_t len)
120+
{
121+
const u8 *ptr;
122+
char *fw_path;
123+
const struct firmware *fw;
124+
int ret;
125+
126+
int i;
127+
int count;
128+
int dest_count = 0;
129+
int data_len;
130+
131+
u8 address;
132+
u8 byte_count = 0;
133+
u8 bytes[9];
134+
135+
u16 data_word;
136+
137+
struct i2c_client *client = to_i2c_client(dev->parent);
138+
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
139+
struct max34440_data *data = to_max34440_data(info);
140+
141+
guard(mutex)(&data->lock);
142+
143+
fw_path = kstrdup(buf, GFP_ATOMIC);
144+
if (!fw_path)
145+
return -EINVAL;
146+
147+
fw_path = strim(fw_path);
148+
149+
if (len < 1)
150+
return -EINVAL;
151+
152+
ret = request_firmware(&fw, fw_path, dev);
153+
154+
if (ret < 0 || !fw->data || fw->size <= 0) {
155+
dev_err(dev, "Failed to get hex file: %d\n", ret);
156+
return ret;
157+
}
158+
ptr = fw->data;
159+
160+
//Parse Hex file to an array without the address and checksum
161+
for (count = 0; count < fw->size; count++) {
162+
if (ptr[count] == ':') {
163+
data_len = (ascii_to_hex(ptr[count + 1]) << 4)
164+
| ascii_to_hex(ptr[count + 2]);
165+
if (data_len != 0) {
166+
memmove((u8 *)(ptr + dest_count), ptr + count + 9, data_len * 2);
167+
dest_count = dest_count + data_len * 2;
168+
}
169+
}
170+
}
171+
172+
//Send data to the device
173+
for (count = 0; count < dest_count; count += 2) {
174+
ret = 0;
175+
176+
data_len = ascii_to_hex(ptr[count]) << 4 | ascii_to_hex(ptr[count + 1]);
177+
count += 2;
178+
179+
address = ascii_to_hex(ptr[count]) << 4 | ascii_to_hex(ptr[count + 1]);
180+
count += 2;
181+
182+
switch (data_len) {
183+
case 1:
184+
{
185+
bytes[0] = (ascii_to_hex(ptr[count]) << 4) | ascii_to_hex(ptr[(count + 1)]);
186+
ret = i2c_smbus_write_byte_data(client, address, bytes[0]);
187+
if (ret < 0)
188+
ret = i2c_smbus_write_byte_data(client, address, bytes[0]);
189+
190+
if (address != 00)
191+
byte_count++;
192+
break;
193+
}
194+
case 2:
195+
{
196+
bytes[0] = (ascii_to_hex(ptr[count]) << 4) | ascii_to_hex(ptr[count + 1]);
197+
bytes[1] = (ascii_to_hex(ptr[count + 2]) << 4) | ascii_to_hex(ptr[count + 3]);
198+
data_word = (bytes[1] << 8) | bytes[0];
199+
200+
ret = i2c_smbus_write_word_data(client, address, data_word);
201+
if (ret < 0)
202+
ret = i2c_smbus_write_word_data(client, address, data_word);
203+
204+
count += (data_len * 2) - 2;
205+
byte_count += 2;
206+
break;
207+
}
208+
case 4:
209+
case 8:
210+
{
211+
for (i = 0; i < data_len; i++) {
212+
bytes[i + 1] = (ascii_to_hex(ptr[count + i * 2]) << 4)
213+
| ascii_to_hex(ptr[(count + i * 2) + 1]);
214+
}
215+
216+
bytes[0] = address;
217+
ret = i2c_master_send(client, bytes, data_len + 1);
218+
if (ret < 0)
219+
ret = i2c_master_send(client, bytes, data_len + 1);
220+
221+
count += (data_len * 2) - 2;
222+
byte_count += data_len;
223+
break;
224+
}
225+
default:
226+
break;
227+
}
228+
229+
if (ret < 0)
230+
dev_err(dev, "Configuration File Register Write Error, Addr: 0x%X", address);
231+
232+
if ((count + 9) > fw->size)
233+
break;
234+
}
235+
236+
release_firmware(fw);
237+
kfree(fw_path);
238+
239+
return len;
240+
}
241+
242+
static DEVICE_ATTR_WO(program_memory;
243+
static DEVICE_ATTR_RO(main_flash_crc);
244+
static DEVICE_ATTR_RO(backup_flash_crc);
245+
static DEVICE_ATTR_RO(ram_crc);
246+
247+
static struct attribute *max34451_attributes[] = {
248+
&dev_attr_program_memory.attr,
249+
&dev_attr_main_flash_crc.attr,
250+
&dev_attr_backup_flash_crc.attr,
251+
&dev_attr_ram_crc.attr,
252+
NULL
253+
};
254+
255+
static struct attribute_group max34451_attr_group = {
256+
.attrs = max34451_attributes,
257+
};
258+
259+
static const struct attribute_group *dev_attr_groups[] = {
260+
&max34451_attr_group,
261+
NULL,
262+
};
64263

65264
static const struct i2c_device_id max34440_id[];
66265

@@ -269,6 +468,7 @@ static int max34451_set_supported_funcs(struct i2c_client *client,
269468
data->info.R[PSC_CURRENT_IN] = 2;
270469
data->iout_oc_fault_limit = PMBUS_IOUT_OC_FAULT_LIMIT;
271470
data->iout_oc_warn_limit = PMBUS_IOUT_OC_WARN_LIMIT;
471+
data->info.groups = dev_attr_groups;
272472
}
273473

274474
for (page = 0; page < 16; page++) {
@@ -612,6 +812,9 @@ static int max34440_probe(struct i2c_client *client)
612812
GFP_KERNEL);
613813
if (!data)
614814
return -ENOMEM;
815+
816+
mutex_init(&data->lock);
817+
615818
data->id = i2c_match_id(max34440_id, client)->driver_data;
616819
data->info = max34440_info[data->id];
617820
data->iout_oc_fault_limit = MAX34440_IOUT_OC_FAULT_LIMIT;

0 commit comments

Comments
 (0)