Commit 79d0df36 authored by Armin Wolf's avatar Armin Wolf Committed by Greg Kroah-Hartman

eeprom: ee1004: Add nvmem support

Currently the driver does not register a nvmem provider, which means
that userspace programs cannot access the ee1004 EEPROM through the
standard nvmem sysfs API.
Fix this by replacing the custom sysfs attribute with a standard nvmem
interface, which also takes care of backwards compatibility.

Tested on a Dell Inspiron 3505.
Signed-off-by: default avatarArmin Wolf <W_Armin@gmx.de>
Link: https://lore.kernel.org/r/20240625063459.429953-2-W_Armin@gmx.deSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 55d57ef6
...@@ -109,6 +109,8 @@ config EEPROM_IDT_89HPESX ...@@ -109,6 +109,8 @@ config EEPROM_IDT_89HPESX
config EEPROM_EE1004 config EEPROM_EE1004
tristate "SPD EEPROMs on DDR4 memory modules" tristate "SPD EEPROMs on DDR4 memory modules"
depends on I2C && SYSFS depends on I2C && SYSFS
select NVMEM
select NVMEM_SYSFS
help help
Enable this driver to get read support to SPD EEPROMs following Enable this driver to get read support to SPD EEPROMs following
the JEDEC EE1004 standard. These are typically found on DDR4 the JEDEC EE1004 standard. These are typically found on DDR4
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/nvmem-provider.h>
/* /*
* DDR4 memory modules use special EEPROMs following the Jedec EE1004 * DDR4 memory modules use special EEPROMs following the Jedec EE1004
...@@ -145,13 +146,17 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, ...@@ -145,13 +146,17 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
return i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf); return i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf);
} }
static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, static int ee1004_read(void *priv, unsigned int off, void *val, size_t count)
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{ {
struct i2c_client *client = kobj_to_i2c_client(kobj); struct i2c_client *client = priv;
size_t requested = count; char *buf = val;
int ret = 0; int ret;
if (unlikely(!count))
return count;
if (off + count > EE1004_EEPROM_SIZE)
return -EINVAL;
/* /*
* Read data from chip, protecting against concurrent access to * Read data from chip, protecting against concurrent access to
...@@ -161,28 +166,21 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, ...@@ -161,28 +166,21 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
while (count) { while (count) {
ret = ee1004_eeprom_read(client, buf, off, count); ret = ee1004_eeprom_read(client, buf, off, count);
if (ret < 0) if (ret < 0) {
goto out; mutex_unlock(&ee1004_bus_lock);
return ret;
}
buf += ret; buf += ret;
off += ret; off += ret;
count -= ret; count -= ret;
} }
out:
mutex_unlock(&ee1004_bus_lock); mutex_unlock(&ee1004_bus_lock);
return ret < 0 ? ret : requested; return 0;
} }
static BIN_ATTR_RO(eeprom, EE1004_EEPROM_SIZE);
static struct bin_attribute *ee1004_attrs[] = {
&bin_attr_eeprom,
NULL
};
BIN_ATTRIBUTE_GROUPS(ee1004);
static void ee1004_probe_temp_sensor(struct i2c_client *client) static void ee1004_probe_temp_sensor(struct i2c_client *client)
{ {
struct i2c_board_info info = { .type = "jc42" }; struct i2c_board_info info = { .type = "jc42" };
...@@ -220,7 +218,24 @@ static void ee1004_cleanup_bus_data(void *data) ...@@ -220,7 +218,24 @@ static void ee1004_cleanup_bus_data(void *data)
static int ee1004_probe(struct i2c_client *client) static int ee1004_probe(struct i2c_client *client)
{ {
struct nvmem_config config = {
.dev = &client->dev,
.name = dev_name(&client->dev),
.id = NVMEM_DEVID_NONE,
.owner = THIS_MODULE,
.type = NVMEM_TYPE_EEPROM,
.read_only = true,
.root_only = false,
.reg_read = ee1004_read,
.size = EE1004_EEPROM_SIZE,
.word_size = 1,
.stride = 1,
.priv = client,
.compat = true,
.base_dev = &client->dev,
};
struct ee1004_bus_data *bd; struct ee1004_bus_data *bd;
struct nvmem_device *ndev;
int err, cnr = 0; int err, cnr = 0;
/* Make sure we can operate on this adapter */ /* Make sure we can operate on this adapter */
...@@ -272,6 +287,10 @@ static int ee1004_probe(struct i2c_client *client) ...@@ -272,6 +287,10 @@ static int ee1004_probe(struct i2c_client *client)
mutex_unlock(&ee1004_bus_lock); mutex_unlock(&ee1004_bus_lock);
ndev = devm_nvmem_register(&client->dev, &config);
if (IS_ERR(ndev))
return PTR_ERR(ndev);
dev_info(&client->dev, dev_info(&client->dev,
"%u byte EE1004-compliant SPD EEPROM, read-only\n", "%u byte EE1004-compliant SPD EEPROM, read-only\n",
EE1004_EEPROM_SIZE); EE1004_EEPROM_SIZE);
...@@ -284,7 +303,6 @@ static int ee1004_probe(struct i2c_client *client) ...@@ -284,7 +303,6 @@ static int ee1004_probe(struct i2c_client *client)
static struct i2c_driver ee1004_driver = { static struct i2c_driver ee1004_driver = {
.driver = { .driver = {
.name = "ee1004", .name = "ee1004",
.dev_groups = ee1004_groups,
}, },
.probe = ee1004_probe, .probe = ee1004_probe,
.id_table = ee1004_ids, .id_table = ee1004_ids,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment