Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

eeprom: New ee1004 driver for DDR4 memory

The EEPROMs which hold the SPD data on DDR4 memory modules are no
longer standard AT24C02-compatible EEPROMs. They are 512-byte EEPROMs
which use only 1 I2C address for data access. You need to switch
between the lower page and the upper page of data by sending commands
on the SMBus.

Signed-off-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Jean Delvare and committed by
Greg Kroah-Hartman
3b7584a2 5fe9f6cc

+293
+11
drivers/misc/eeprom/Kconfig
··· 111 111 This driver can also be built as a module. If so, the module 112 112 will be called idt_89hpesx. 113 113 114 + config EEPROM_EE1004 115 + tristate "SPD EEPROMs on DDR4 memory modules" 116 + depends on I2C && SYSFS 117 + help 118 + Enable this driver to get read support to SPD EEPROMs following 119 + the JEDEC EE1004 standard. These are typically found on DDR4 120 + SDRAM memory modules. 121 + 122 + This driver can also be built as a module. If so, the module 123 + will be called ee1004. 124 + 114 125 endmenu
+1
drivers/misc/eeprom/Makefile
··· 7 7 obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o 8 8 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o 9 9 obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o 10 + obj-$(CONFIG_EEPROM_EE1004) += ee1004.o
+281
drivers/misc/eeprom/ee1004.c
··· 1 + /* 2 + * ee1004 - driver for DDR4 SPD EEPROMs 3 + * 4 + * Copyright (C) 2017 Jean Delvare 5 + * 6 + * Based on the at24 driver: 7 + * Copyright (C) 2005-2007 David Brownell 8 + * Copyright (C) 2008 Wolfram Sang, Pengutronix 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License as published by 12 + * the Free Software Foundation; either version 2 of the License, or 13 + * (at your option) any later version. 14 + */ 15 + 16 + #include <linux/i2c.h> 17 + #include <linux/init.h> 18 + #include <linux/kernel.h> 19 + #include <linux/mod_devicetable.h> 20 + #include <linux/module.h> 21 + #include <linux/mutex.h> 22 + 23 + /* 24 + * DDR4 memory modules use special EEPROMs following the Jedec EE1004 25 + * specification. These are 512-byte EEPROMs using a single I2C address 26 + * in the 0x50-0x57 range for data. One of two 256-byte page is selected 27 + * by writing a command to I2C address 0x36 or 0x37 on the same I2C bus. 28 + * 29 + * Therefore we need to request these 2 additional addresses, and serialize 30 + * access to all such EEPROMs with a single mutex. 31 + * 32 + * We assume it is safe to read up to 32 bytes at once from these EEPROMs. 33 + * We use SMBus access even if I2C is available, these EEPROMs are small 34 + * enough, and reading from them infrequent enough, that we favor simplicity 35 + * over performance. 36 + */ 37 + 38 + #define EE1004_ADDR_SET_PAGE 0x36 39 + #define EE1004_EEPROM_SIZE 512 40 + #define EE1004_PAGE_SIZE 256 41 + #define EE1004_PAGE_SHIFT 8 42 + 43 + /* 44 + * Mutex protects ee1004_set_page and ee1004_dev_count, and must be held 45 + * from page selection to end of read. 46 + */ 47 + static DEFINE_MUTEX(ee1004_bus_lock); 48 + static struct i2c_client *ee1004_set_page[2]; 49 + static unsigned int ee1004_dev_count; 50 + static int ee1004_current_page; 51 + 52 + static const struct i2c_device_id ee1004_ids[] = { 53 + { "ee1004", 0 }, 54 + { } 55 + }; 56 + MODULE_DEVICE_TABLE(i2c, ee1004_ids); 57 + 58 + /*-------------------------------------------------------------------------*/ 59 + 60 + static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, 61 + unsigned int offset, size_t count) 62 + { 63 + int status; 64 + 65 + if (count > I2C_SMBUS_BLOCK_MAX) 66 + count = I2C_SMBUS_BLOCK_MAX; 67 + /* Can't cross page boundaries */ 68 + if (unlikely(offset + count > EE1004_PAGE_SIZE)) 69 + count = EE1004_PAGE_SIZE - offset; 70 + 71 + status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset, 72 + count, buf); 73 + dev_dbg(&client->dev, "read %zu@%d --> %d\n", count, offset, status); 74 + 75 + return status; 76 + } 77 + 78 + static ssize_t ee1004_read(struct file *filp, struct kobject *kobj, 79 + struct bin_attribute *bin_attr, 80 + char *buf, loff_t off, size_t count) 81 + { 82 + struct device *dev = kobj_to_dev(kobj); 83 + struct i2c_client *client = to_i2c_client(dev); 84 + size_t requested = count; 85 + int page; 86 + 87 + if (unlikely(!count)) 88 + return count; 89 + 90 + page = off >> EE1004_PAGE_SHIFT; 91 + if (unlikely(page > 1)) 92 + return 0; 93 + off &= (1 << EE1004_PAGE_SHIFT) - 1; 94 + 95 + /* 96 + * Read data from chip, protecting against concurrent access to 97 + * other EE1004 SPD EEPROMs on the same adapter. 98 + */ 99 + mutex_lock(&ee1004_bus_lock); 100 + 101 + while (count) { 102 + int status; 103 + 104 + /* Select page */ 105 + if (page != ee1004_current_page) { 106 + /* Data is ignored */ 107 + status = i2c_smbus_write_byte(ee1004_set_page[page], 108 + 0x00); 109 + if (status < 0) { 110 + dev_err(dev, "Failed to select page %d (%d)\n", 111 + page, status); 112 + mutex_unlock(&ee1004_bus_lock); 113 + return status; 114 + } 115 + dev_dbg(dev, "Selected page %d\n", page); 116 + ee1004_current_page = page; 117 + } 118 + 119 + status = ee1004_eeprom_read(client, buf, off, count); 120 + if (status < 0) { 121 + mutex_unlock(&ee1004_bus_lock); 122 + return status; 123 + } 124 + buf += status; 125 + off += status; 126 + count -= status; 127 + 128 + if (off == EE1004_PAGE_SIZE) { 129 + page++; 130 + off = 0; 131 + } 132 + } 133 + 134 + mutex_unlock(&ee1004_bus_lock); 135 + 136 + return requested; 137 + } 138 + 139 + static const struct bin_attribute eeprom_attr = { 140 + .attr = { 141 + .name = "eeprom", 142 + .mode = 0444, 143 + }, 144 + .size = EE1004_EEPROM_SIZE, 145 + .read = ee1004_read, 146 + }; 147 + 148 + static int ee1004_probe(struct i2c_client *client, 149 + const struct i2c_device_id *id) 150 + { 151 + int err, cnr = 0; 152 + const char *slow = NULL; 153 + 154 + /* Make sure we can operate on this adapter */ 155 + if (!i2c_check_functionality(client->adapter, 156 + I2C_FUNC_SMBUS_READ_BYTE | 157 + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { 158 + if (i2c_check_functionality(client->adapter, 159 + I2C_FUNC_SMBUS_READ_BYTE | 160 + I2C_FUNC_SMBUS_READ_WORD_DATA)) 161 + slow = "word"; 162 + else if (i2c_check_functionality(client->adapter, 163 + I2C_FUNC_SMBUS_READ_BYTE | 164 + I2C_FUNC_SMBUS_READ_BYTE_DATA)) 165 + slow = "byte"; 166 + else 167 + return -EPFNOSUPPORT; 168 + } 169 + 170 + /* Use 2 dummy devices for page select command */ 171 + mutex_lock(&ee1004_bus_lock); 172 + if (++ee1004_dev_count == 1) { 173 + for (cnr = 0; cnr < 2; cnr++) { 174 + ee1004_set_page[cnr] = i2c_new_dummy(client->adapter, 175 + EE1004_ADDR_SET_PAGE + cnr); 176 + if (!ee1004_set_page[cnr]) { 177 + dev_err(&client->dev, 178 + "address 0x%02x unavailable\n", 179 + EE1004_ADDR_SET_PAGE + cnr); 180 + err = -EADDRINUSE; 181 + goto err_clients; 182 + } 183 + } 184 + } else if (i2c_adapter_id(client->adapter) != 185 + i2c_adapter_id(ee1004_set_page[0]->adapter)) { 186 + dev_err(&client->dev, 187 + "Driver only supports devices on a single I2C bus\n"); 188 + err = -EOPNOTSUPP; 189 + goto err_clients; 190 + } 191 + 192 + /* Remember current page to avoid unneeded page select */ 193 + err = i2c_smbus_read_byte(ee1004_set_page[0]); 194 + if (err == -ENXIO) { 195 + /* Nack means page 1 is selected */ 196 + ee1004_current_page = 1; 197 + } else if (err < 0) { 198 + /* Anything else is a real error, bail out */ 199 + goto err_clients; 200 + } else { 201 + /* Ack means page 0 is selected, returned value meaningless */ 202 + ee1004_current_page = 0; 203 + } 204 + dev_dbg(&client->dev, "Currently selected page: %d\n", 205 + ee1004_current_page); 206 + mutex_unlock(&ee1004_bus_lock); 207 + 208 + /* Create the sysfs eeprom file */ 209 + err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); 210 + if (err) 211 + goto err_clients_lock; 212 + 213 + dev_info(&client->dev, 214 + "%u byte EE1004-compliant SPD EEPROM, read-only\n", 215 + EE1004_EEPROM_SIZE); 216 + if (slow) 217 + dev_notice(&client->dev, 218 + "Falling back to %s reads, performance will suffer\n", 219 + slow); 220 + 221 + return 0; 222 + 223 + err_clients_lock: 224 + mutex_lock(&ee1004_bus_lock); 225 + err_clients: 226 + if (--ee1004_dev_count == 0) { 227 + for (cnr--; cnr >= 0; cnr--) { 228 + i2c_unregister_device(ee1004_set_page[cnr]); 229 + ee1004_set_page[cnr] = NULL; 230 + } 231 + } 232 + mutex_unlock(&ee1004_bus_lock); 233 + 234 + return err; 235 + } 236 + 237 + static int ee1004_remove(struct i2c_client *client) 238 + { 239 + int i; 240 + 241 + sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr); 242 + 243 + /* Remove page select clients if this is the last device */ 244 + mutex_lock(&ee1004_bus_lock); 245 + if (--ee1004_dev_count == 0) { 246 + for (i = 0; i < 2; i++) { 247 + i2c_unregister_device(ee1004_set_page[i]); 248 + ee1004_set_page[i] = NULL; 249 + } 250 + } 251 + mutex_unlock(&ee1004_bus_lock); 252 + 253 + return 0; 254 + } 255 + 256 + /*-------------------------------------------------------------------------*/ 257 + 258 + static struct i2c_driver ee1004_driver = { 259 + .driver = { 260 + .name = "ee1004", 261 + }, 262 + .probe = ee1004_probe, 263 + .remove = ee1004_remove, 264 + .id_table = ee1004_ids, 265 + }; 266 + 267 + static int __init ee1004_init(void) 268 + { 269 + return i2c_add_driver(&ee1004_driver); 270 + } 271 + module_init(ee1004_init); 272 + 273 + static void __exit ee1004_exit(void) 274 + { 275 + i2c_del_driver(&ee1004_driver); 276 + } 277 + module_exit(ee1004_exit); 278 + 279 + MODULE_DESCRIPTION("Driver for EE1004-compliant DDR4 SPD EEPROMs"); 280 + MODULE_AUTHOR("Jean Delvare"); 281 + MODULE_LICENSE("GPL");