blob: bee727ed98db5734af2effa82ef47ce8da9546e8 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
David Brownellb587b132007-02-12 00:52:48 -08002/*
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +02003 * Driver for most of the SPI EEPROMs, such as Atmel AT25 models
4 * and Cypress FRAMs FM25 models.
David Brownellb587b132007-02-12 00:52:48 -08005 *
6 * Copyright (C) 2006 David Brownell
David Brownellb587b132007-02-12 00:52:48 -08007 */
8
Andy Shevchenkod059ed12021-11-25 23:31:59 +02009#include <linux/bits.h>
David Brownellb587b132007-02-12 00:52:48 -080010#include <linux/delay.h>
11#include <linux/device.h>
Andy Shevchenkod5fb1302021-11-25 23:32:01 +020012#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/property.h>
David Brownellb587b132007-02-12 00:52:48 -080015#include <linux/sched.h>
Andy Shevchenkod5fb1302021-11-25 23:32:01 +020016#include <linux/slab.h>
17
18#include <linux/spi/eeprom.h>
19#include <linux/spi/spi.h>
David Brownellb587b132007-02-12 00:52:48 -080020
Andrew Lunn5a99f572016-02-26 20:59:22 +010021#include <linux/nvmem-provider.h>
David Brownellb587b132007-02-12 00:52:48 -080022
David Brownell3f86f142007-12-04 23:45:10 -080023/*
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +020024 * NOTE: this is an *EEPROM* driver. The vagaries of product naming
David Brownell3f86f142007-12-04 23:45:10 -080025 * mean that some AT25 products are EEPROMs, and others are FLASH.
26 * Handle FLASH chips with the drivers/mtd/devices/m25p80.c driver,
27 * not this one!
Jonathan Neuschäfer667aef02020-11-07 14:33:35 +010028 *
29 * EEPROMs that can be used with this driver include, for example:
30 * AT25M02, AT25128B
David Brownell3f86f142007-12-04 23:45:10 -080031 */
32
Jiri Prchalfd307a42021-06-11 11:45:58 +020033#define FM25_SN_LEN 8 /* serial number length */
David Brownellb587b132007-02-12 00:52:48 -080034struct at25_data {
Andy Shevchenko31a45d22021-11-25 23:32:00 +020035 struct spi_eeprom chip;
David Brownellb587b132007-02-12 00:52:48 -080036 struct spi_device *spi;
37 struct mutex lock;
David Brownellb587b132007-02-12 00:52:48 -080038 unsigned addrlen;
Andrew Lunn5a99f572016-02-26 20:59:22 +010039 struct nvmem_config nvmem_config;
40 struct nvmem_device *nvmem;
Jiri Prchalfd307a42021-06-11 11:45:58 +020041 u8 sernum[FM25_SN_LEN];
David Brownellb587b132007-02-12 00:52:48 -080042};
43
44#define AT25_WREN 0x06 /* latch the write enable */
45#define AT25_WRDI 0x04 /* reset the write enable */
46#define AT25_RDSR 0x05 /* read status register */
47#define AT25_WRSR 0x01 /* write status register */
48#define AT25_READ 0x03 /* read byte(s) */
49#define AT25_WRITE 0x02 /* write byte(s)/sector */
Jiri Prchalfd307a42021-06-11 11:45:58 +020050#define FM25_SLEEP 0xb9 /* enter sleep mode */
51#define FM25_RDID 0x9f /* read device ID */
52#define FM25_RDSN 0xc3 /* read S/N */
David Brownellb587b132007-02-12 00:52:48 -080053
54#define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */
55#define AT25_SR_WEN 0x02 /* write enable (latched) */
56#define AT25_SR_BP0 0x04 /* BP for software writeprotect */
57#define AT25_SR_BP1 0x08
58#define AT25_SR_WPEN 0x80 /* writeprotect enable */
59
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +020060#define AT25_INSTR_BIT3 0x08 /* additional address bit in instr */
David Brownellb587b132007-02-12 00:52:48 -080061
Jiri Prchalfd307a42021-06-11 11:45:58 +020062#define FM25_ID_LEN 9 /* ID length */
63
David Brownellb587b132007-02-12 00:52:48 -080064#define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */
65
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +020066/*
67 * Specs often allow 5ms for a page write, sometimes 20ms;
David Brownellb587b132007-02-12 00:52:48 -080068 * it's important to recover from write timeouts.
69 */
70#define EE_TIMEOUT 25
71
72/*-------------------------------------------------------------------------*/
73
74#define io_limit PAGE_SIZE /* bytes */
75
Srinivas Kandagatla01973a02016-04-24 20:28:07 +010076static int at25_ee_read(void *priv, unsigned int offset,
77 void *val, size_t count)
David Brownellb587b132007-02-12 00:52:48 -080078{
Srinivas Kandagatla01973a02016-04-24 20:28:07 +010079 struct at25_data *at25 = priv;
80 char *buf = val;
David Brownellb587b132007-02-12 00:52:48 -080081 u8 command[EE_MAXADDRLEN + 1];
82 u8 *cp;
83 ssize_t status;
84 struct spi_transfer t[2];
85 struct spi_message m;
Ivo Siebenb4161f02012-04-18 08:29:34 +020086 u8 instr;
David Brownellb587b132007-02-12 00:52:48 -080087
Andrew Lunn5a99f572016-02-26 20:59:22 +010088 if (unlikely(offset >= at25->chip.byte_len))
Srinivas Kandagatla01973a02016-04-24 20:28:07 +010089 return -EINVAL;
Andrew Lunn5a99f572016-02-26 20:59:22 +010090 if ((offset + count) > at25->chip.byte_len)
91 count = at25->chip.byte_len - offset;
David Brownell14dd1ff2009-04-02 16:56:58 -070092 if (unlikely(!count))
Srinivas Kandagatla01973a02016-04-24 20:28:07 +010093 return -EINVAL;
David Brownell14dd1ff2009-04-02 16:56:58 -070094
David Brownellb587b132007-02-12 00:52:48 -080095 cp = command;
Ivo Siebenb4161f02012-04-18 08:29:34 +020096
97 instr = AT25_READ;
98 if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
Andy Shevchenkod059ed12021-11-25 23:31:59 +020099 if (offset >= BIT(at25->addrlen * 8))
Ivo Siebenb4161f02012-04-18 08:29:34 +0200100 instr |= AT25_INSTR_BIT3;
101 *cp++ = instr;
David Brownellb587b132007-02-12 00:52:48 -0800102
103 /* 8/16/24-bit address is written MSB first */
104 switch (at25->addrlen) {
105 default: /* case 3 */
106 *cp++ = offset >> 16;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500107 fallthrough;
David Brownellb587b132007-02-12 00:52:48 -0800108 case 2:
109 *cp++ = offset >> 8;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500110 fallthrough;
David Brownellb587b132007-02-12 00:52:48 -0800111 case 1:
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +0200112 case 0: /* can't happen: for better code generation */
David Brownellb587b132007-02-12 00:52:48 -0800113 *cp++ = offset >> 0;
114 }
115
116 spi_message_init(&m);
Devang Panchalc84f2592018-03-21 11:04:35 +0530117 memset(t, 0, sizeof(t));
David Brownellb587b132007-02-12 00:52:48 -0800118
119 t[0].tx_buf = command;
120 t[0].len = at25->addrlen + 1;
121 spi_message_add_tail(&t[0], &m);
122
123 t[1].rx_buf = buf;
124 t[1].len = count;
125 spi_message_add_tail(&t[1], &m);
126
127 mutex_lock(&at25->lock);
128
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +0200129 /*
130 * Read it all at once.
David Brownellb587b132007-02-12 00:52:48 -0800131 *
132 * REVISIT that's potentially a problem with large chips, if
133 * other devices on the bus need to be accessed regularly or
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +0200134 * this chip is clocked very slowly.
David Brownellb587b132007-02-12 00:52:48 -0800135 */
136 status = spi_sync(at25->spi, &m);
Andy Shevchenko3936e4c2016-09-11 14:58:26 +0300137 dev_dbg(&at25->spi->dev, "read %zu bytes at %d --> %zd\n",
138 count, offset, status);
David Brownellb587b132007-02-12 00:52:48 -0800139
140 mutex_unlock(&at25->lock);
Srinivas Kandagatla01973a02016-04-24 20:28:07 +0100141 return status;
David Brownellb587b132007-02-12 00:52:48 -0800142}
143
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +0200144/* Read extra registers as ID or serial number */
Jiri Prchalfd307a42021-06-11 11:45:58 +0200145static int fm25_aux_read(struct at25_data *at25, u8 *buf, uint8_t command,
146 int len)
147{
148 int status;
149 struct spi_transfer t[2];
150 struct spi_message m;
151
152 spi_message_init(&m);
153 memset(t, 0, sizeof(t));
154
155 t[0].tx_buf = &command;
156 t[0].len = 1;
157 spi_message_add_tail(&t[0], &m);
158
159 t[1].rx_buf = buf;
160 t[1].len = len;
161 spi_message_add_tail(&t[1], &m);
162
163 mutex_lock(&at25->lock);
164
165 status = spi_sync(at25->spi, &m);
166 dev_dbg(&at25->spi->dev, "read %d aux bytes --> %d\n", len, status);
167
168 mutex_unlock(&at25->lock);
169 return status;
170}
171
172static ssize_t sernum_show(struct device *dev, struct device_attribute *attr, char *buf)
173{
174 struct at25_data *at25;
175
176 at25 = dev_get_drvdata(dev);
Jiri Prchal604288b2021-06-11 16:27:06 +0200177 return sysfs_emit(buf, "%*ph\n", (int)sizeof(at25->sernum), at25->sernum);
Jiri Prchalfd307a42021-06-11 11:45:58 +0200178}
179static DEVICE_ATTR_RO(sernum);
180
181static struct attribute *sernum_attrs[] = {
182 &dev_attr_sernum.attr,
183 NULL,
184};
185ATTRIBUTE_GROUPS(sernum);
186
Srinivas Kandagatla01973a02016-04-24 20:28:07 +0100187static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
David Brownellb587b132007-02-12 00:52:48 -0800188{
Srinivas Kandagatla01973a02016-04-24 20:28:07 +0100189 struct at25_data *at25 = priv;
190 const char *buf = val;
191 int status = 0;
David Brownellb587b132007-02-12 00:52:48 -0800192 unsigned buf_size;
193 u8 *bounce;
194
Andrew Lunn5a99f572016-02-26 20:59:22 +0100195 if (unlikely(off >= at25->chip.byte_len))
David Brownell14dd1ff2009-04-02 16:56:58 -0700196 return -EFBIG;
Andrew Lunn5a99f572016-02-26 20:59:22 +0100197 if ((off + count) > at25->chip.byte_len)
198 count = at25->chip.byte_len - off;
David Brownell14dd1ff2009-04-02 16:56:58 -0700199 if (unlikely(!count))
Srinivas Kandagatla01973a02016-04-24 20:28:07 +0100200 return -EINVAL;
David Brownell14dd1ff2009-04-02 16:56:58 -0700201
David Brownellb587b132007-02-12 00:52:48 -0800202 /* Temp buffer starts with command and address */
203 buf_size = at25->chip.page_size;
204 if (buf_size > io_limit)
205 buf_size = io_limit;
206 bounce = kmalloc(buf_size + at25->addrlen + 1, GFP_KERNEL);
207 if (!bounce)
208 return -ENOMEM;
209
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +0200210 /*
211 * For write, rollover is within the page ... so we write at
David Brownellb587b132007-02-12 00:52:48 -0800212 * most one page, then manually roll over to the next page.
213 */
David Brownellb587b132007-02-12 00:52:48 -0800214 mutex_lock(&at25->lock);
215 do {
216 unsigned long timeout, retries;
217 unsigned segment;
218 unsigned offset = (unsigned) off;
Ivo Siebenb4161f02012-04-18 08:29:34 +0200219 u8 *cp = bounce;
Sebastian Heutlingf0d83672009-07-29 15:04:05 -0700220 int sr;
Ivo Siebenb4161f02012-04-18 08:29:34 +0200221 u8 instr;
David Brownellb587b132007-02-12 00:52:48 -0800222
223 *cp = AT25_WREN;
224 status = spi_write(at25->spi, cp, 1);
225 if (status < 0) {
Andy Shevchenko3936e4c2016-09-11 14:58:26 +0300226 dev_dbg(&at25->spi->dev, "WREN --> %d\n", status);
David Brownellb587b132007-02-12 00:52:48 -0800227 break;
228 }
229
Ivo Siebenb4161f02012-04-18 08:29:34 +0200230 instr = AT25_WRITE;
231 if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
Andy Shevchenkod059ed12021-11-25 23:31:59 +0200232 if (offset >= BIT(at25->addrlen * 8))
Ivo Siebenb4161f02012-04-18 08:29:34 +0200233 instr |= AT25_INSTR_BIT3;
234 *cp++ = instr;
235
David Brownellb587b132007-02-12 00:52:48 -0800236 /* 8/16/24-bit address is written MSB first */
237 switch (at25->addrlen) {
238 default: /* case 3 */
239 *cp++ = offset >> 16;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500240 fallthrough;
David Brownellb587b132007-02-12 00:52:48 -0800241 case 2:
242 *cp++ = offset >> 8;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500243 fallthrough;
David Brownellb587b132007-02-12 00:52:48 -0800244 case 1:
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +0200245 case 0: /* can't happen: for better code generation */
David Brownellb587b132007-02-12 00:52:48 -0800246 *cp++ = offset >> 0;
247 }
248
249 /* Write as much of a page as we can */
250 segment = buf_size - (offset % buf_size);
251 if (segment > count)
252 segment = count;
253 memcpy(cp, buf, segment);
254 status = spi_write(at25->spi, bounce,
255 segment + at25->addrlen + 1);
Andy Shevchenko3936e4c2016-09-11 14:58:26 +0300256 dev_dbg(&at25->spi->dev, "write %u bytes at %u --> %d\n",
257 segment, offset, status);
David Brownellb587b132007-02-12 00:52:48 -0800258 if (status < 0)
259 break;
260
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +0200261 /*
262 * REVISIT this should detect (or prevent) failed writes
263 * to read-only sections of the EEPROM...
David Brownellb587b132007-02-12 00:52:48 -0800264 */
265
266 /* Wait for non-busy status */
267 timeout = jiffies + msecs_to_jiffies(EE_TIMEOUT);
268 retries = 0;
269 do {
David Brownellb587b132007-02-12 00:52:48 -0800270
271 sr = spi_w8r8(at25->spi, AT25_RDSR);
272 if (sr < 0 || (sr & AT25_SR_nRDY)) {
273 dev_dbg(&at25->spi->dev,
274 "rdsr --> %d (%02x)\n", sr, sr);
275 /* at HZ=100, this is sloooow */
276 msleep(1);
277 continue;
278 }
279 if (!(sr & AT25_SR_nRDY))
280 break;
281 } while (retries++ < 3 || time_before_eq(jiffies, timeout));
282
Sebastian Heutlingf0d83672009-07-29 15:04:05 -0700283 if ((sr < 0) || (sr & AT25_SR_nRDY)) {
David Brownellb587b132007-02-12 00:52:48 -0800284 dev_err(&at25->spi->dev,
Andy Shevchenko3936e4c2016-09-11 14:58:26 +0300285 "write %u bytes offset %u, timeout after %u msecs\n",
David Brownellb587b132007-02-12 00:52:48 -0800286 segment, offset,
287 jiffies_to_msecs(jiffies -
288 (timeout - EE_TIMEOUT)));
289 status = -ETIMEDOUT;
290 break;
291 }
292
293 off += segment;
294 buf += segment;
295 count -= segment;
David Brownellb587b132007-02-12 00:52:48 -0800296
297 } while (count > 0);
298
299 mutex_unlock(&at25->lock);
300
301 kfree(bounce);
Srinivas Kandagatla01973a02016-04-24 20:28:07 +0100302 return status;
David Brownellb587b132007-02-12 00:52:48 -0800303}
304
David Brownellb587b132007-02-12 00:52:48 -0800305/*-------------------------------------------------------------------------*/
306
Mika Westerbergf60e70742014-10-21 13:33:56 +0200307static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
David Daneyd6ae0d52012-08-22 12:03:57 -0700308{
309 u32 val;
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200310 int err;
David Daneyd6ae0d52012-08-22 12:03:57 -0700311
Mika Westerbergf60e70742014-10-21 13:33:56 +0200312 strncpy(chip->name, "at25", sizeof(chip->name));
David Daneyd6ae0d52012-08-22 12:03:57 -0700313
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200314 err = device_property_read_u32(dev, "size", &val);
315 if (err)
316 err = device_property_read_u32(dev, "at25,byte-len", &val);
317 if (err) {
David Daneyd6ae0d52012-08-22 12:03:57 -0700318 dev_err(dev, "Error: missing \"size\" property\n");
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200319 return err;
David Daneyd6ae0d52012-08-22 12:03:57 -0700320 }
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200321 chip->byte_len = val;
David Daneyd6ae0d52012-08-22 12:03:57 -0700322
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200323 err = device_property_read_u32(dev, "pagesize", &val);
324 if (err)
325 err = device_property_read_u32(dev, "at25,page-size", &val);
326 if (err) {
David Daneyd6ae0d52012-08-22 12:03:57 -0700327 dev_err(dev, "Error: missing \"pagesize\" property\n");
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200328 return err;
David Daneyd6ae0d52012-08-22 12:03:57 -0700329 }
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200330 chip->page_size = val;
David Daneyd6ae0d52012-08-22 12:03:57 -0700331
Andy Shevchenkofb422f42021-11-25 23:31:56 +0200332 err = device_property_read_u32(dev, "address-width", &val);
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200333 if (err) {
Andy Shevchenkofb422f42021-11-25 23:31:56 +0200334 err = device_property_read_u32(dev, "at25,addr-mode", &val);
Andy Shevchenkoc329fe52021-11-25 23:31:55 +0200335 if (err) {
336 dev_err(dev, "Error: missing \"address-width\" property\n");
337 return err;
David Daneyd6ae0d52012-08-22 12:03:57 -0700338 }
Andy Shevchenkofb422f42021-11-25 23:31:56 +0200339 chip->flags = (u16)val;
340 } else {
David Daneyd6ae0d52012-08-22 12:03:57 -0700341 switch (val) {
Geert Uytterhoevenf8d3bc12017-12-08 14:46:41 +0100342 case 9:
343 chip->flags |= EE_INSTR_BIT3_IS_ADDR;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500344 fallthrough;
David Daneyd6ae0d52012-08-22 12:03:57 -0700345 case 8:
346 chip->flags |= EE_ADDR1;
347 break;
348 case 16:
349 chip->flags |= EE_ADDR2;
350 break;
351 case 24:
352 chip->flags |= EE_ADDR3;
353 break;
354 default:
355 dev_err(dev,
356 "Error: bad \"address-width\" property: %u\n",
357 val);
358 return -ENODEV;
359 }
Mika Westerbergf60e70742014-10-21 13:33:56 +0200360 if (device_property_present(dev, "read-only"))
David Daneyd6ae0d52012-08-22 12:03:57 -0700361 chip->flags |= EE_READONLY;
362 }
363 return 0;
364}
365
Andy Shevchenko31a45d22021-11-25 23:32:00 +0200366static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
367{
368 struct at25_data *at25 = container_of(chip, struct at25_data, chip);
369 u8 sernum[FM25_SN_LEN];
370 u8 id[FM25_ID_LEN];
371 int i;
372
373 strncpy(chip->name, "fm25", sizeof(chip->name));
374
375 /* Get ID of chip */
376 fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN);
377 if (id[6] != 0xc2) {
378 dev_err(dev, "Error: no Cypress FRAM (id %02x)\n", id[6]);
379 return -ENODEV;
380 }
381 /* Set size found in ID */
382 if (id[7] < 0x21 || id[7] > 0x26) {
383 dev_err(dev, "Error: unsupported size (id %02x)\n", id[7]);
384 return -ENODEV;
385 }
386
387 chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024;
388 if (chip->byte_len > 64 * 1024)
389 chip->flags |= EE_ADDR3;
390 else
391 chip->flags |= EE_ADDR2;
392
393 if (id[8]) {
394 fm25_aux_read(at25, sernum, FM25_RDSN, FM25_SN_LEN);
395 /* Swap byte order */
396 for (i = 0; i < FM25_SN_LEN; i++)
397 at25->sernum[i] = sernum[FM25_SN_LEN - 1 - i];
398 }
399
400 chip->page_size = PAGE_SIZE;
401 return 0;
402}
403
Jiri Prchalfd307a42021-06-11 11:45:58 +0200404static const struct of_device_id at25_of_match[] = {
Andy Shevchenkod6471ab2021-11-25 23:32:02 +0200405 { .compatible = "atmel,at25" },
406 { .compatible = "cypress,fm25" },
Jiri Prchalfd307a42021-06-11 11:45:58 +0200407 { }
408};
409MODULE_DEVICE_TABLE(of, at25_of_match);
410
Mark Brown9e2cd442021-09-23 18:24:53 +0100411static const struct spi_device_id at25_spi_ids[] = {
Andy Shevchenkod6471ab2021-11-25 23:32:02 +0200412 { .name = "at25" },
413 { .name = "fm25" },
Mark Brown9e2cd442021-09-23 18:24:53 +0100414 { }
415};
416MODULE_DEVICE_TABLE(spi, at25_spi_ids);
417
David Brownellb587b132007-02-12 00:52:48 -0800418static int at25_probe(struct spi_device *spi)
419{
420 struct at25_data *at25 = NULL;
David Brownellb587b132007-02-12 00:52:48 -0800421 int err;
422 int sr;
Andy Shevchenko01d3c422021-11-25 23:31:58 +0200423 struct spi_eeprom *pdata;
Andy Shevchenko5b557292021-11-25 23:27:27 +0200424 bool is_fram;
Jiri Prchalfd307a42021-06-11 11:45:58 +0200425
Andy Shevchenko5b557292021-11-25 23:27:27 +0200426 err = device_property_match_string(&spi->dev, "compatible", "cypress,fm25");
427 if (err >= 0)
428 is_fram = true;
429 else
430 is_fram = false;
David Brownellb587b132007-02-12 00:52:48 -0800431
Andy Shevchenko1ca54ce2021-11-25 23:32:03 +0200432 /*
433 * Ping the chip ... the status register is pretty portable,
434 * unlike probing manufacturer IDs. We do expect that system
David Brownellb587b132007-02-12 00:52:48 -0800435 * firmware didn't write it in the past few milliseconds!
436 */
437 sr = spi_w8r8(spi, AT25_RDSR);
438 if (sr < 0 || sr & AT25_SR_nRDY) {
Atsushi Nemotoc6ca97d2007-03-16 13:38:20 -0800439 dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", sr, sr);
Nikolay Balandin01fe7b432013-05-28 13:01:21 -0700440 return -ENXIO;
David Brownellb587b132007-02-12 00:52:48 -0800441 }
442
Kees Cooka6501e42022-01-18 10:20:03 -0800443 at25 = devm_kzalloc(&spi->dev, sizeof(*at25), GFP_KERNEL);
444 if (!at25)
445 return -ENOMEM;
446
David Brownellb587b132007-02-12 00:52:48 -0800447 mutex_init(&at25->lock);
Mark Brown96b2a452016-04-20 10:16:35 +0100448 at25->spi = spi;
Jingoo Han41ddcf62013-04-05 10:55:35 +0900449 spi_set_drvdata(spi, at25);
David Brownellb587b132007-02-12 00:52:48 -0800450
Andy Shevchenko01d3c422021-11-25 23:31:58 +0200451 /* Chip description */
452 pdata = dev_get_platdata(&spi->dev);
453 if (pdata) {
454 at25->chip = *pdata;
455 } else {
Andy Shevchenko31a45d22021-11-25 23:32:00 +0200456 if (is_fram)
457 err = at25_fram_to_chip(&spi->dev, &at25->chip);
Jiri Prchalfd307a42021-06-11 11:45:58 +0200458 else
Andy Shevchenko31a45d22021-11-25 23:32:00 +0200459 err = at25_fw_to_chip(&spi->dev, &at25->chip);
460 if (err)
461 return err;
Jiri Prchalfd307a42021-06-11 11:45:58 +0200462 }
463
464 /* For now we only support 8/16/24 bit addressing */
465 if (at25->chip.flags & EE_ADDR1)
466 at25->addrlen = 1;
467 else if (at25->chip.flags & EE_ADDR2)
468 at25->addrlen = 2;
469 else if (at25->chip.flags & EE_ADDR3)
470 at25->addrlen = 3;
471 else {
472 dev_dbg(&spi->dev, "unsupported address type\n");
473 return -EINVAL;
474 }
475
476 at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM;
Andrew Lunn5a99f572016-02-26 20:59:22 +0100477 at25->nvmem_config.name = dev_name(&spi->dev);
478 at25->nvmem_config.dev = &spi->dev;
Andy Shevchenko51902c12021-11-25 23:31:54 +0200479 at25->nvmem_config.read_only = at25->chip.flags & EE_READONLY;
Andrew Lunn5a99f572016-02-26 20:59:22 +0100480 at25->nvmem_config.root_only = true;
481 at25->nvmem_config.owner = THIS_MODULE;
482 at25->nvmem_config.compat = true;
483 at25->nvmem_config.base_dev = &spi->dev;
Srinivas Kandagatla01973a02016-04-24 20:28:07 +0100484 at25->nvmem_config.reg_read = at25_ee_read;
485 at25->nvmem_config.reg_write = at25_ee_write;
486 at25->nvmem_config.priv = at25;
Christian Eggers284f52a2020-07-28 11:29:59 +0200487 at25->nvmem_config.stride = 1;
Srinivas Kandagatla01973a02016-04-24 20:28:07 +0100488 at25->nvmem_config.word_size = 1;
Andy Shevchenko51902c12021-11-25 23:31:54 +0200489 at25->nvmem_config.size = at25->chip.byte_len;
David Brownellb587b132007-02-12 00:52:48 -0800490
Bartosz Golaszewski96d08fb2018-09-21 06:40:02 -0700491 at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config);
Andrew Lunn5a99f572016-02-26 20:59:22 +0100492 if (IS_ERR(at25->nvmem))
493 return PTR_ERR(at25->nvmem);
494
Jiri Prchalfd307a42021-06-11 11:45:58 +0200495 dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n",
Ralph Siemsen9a626572021-11-08 13:16:27 -0500496 (at25->chip.byte_len < 1024) ?
497 at25->chip.byte_len : (at25->chip.byte_len / 1024),
Andy Shevchenko51902c12021-11-25 23:31:54 +0200498 (at25->chip.byte_len < 1024) ? "Byte" : "KByte",
Jiri Prchalfd307a42021-06-11 11:45:58 +0200499 at25->chip.name, is_fram ? "fram" : "eeprom",
Andy Shevchenko51902c12021-11-25 23:31:54 +0200500 (at25->chip.flags & EE_READONLY) ? " (readonly)" : "",
Jiri Prchalfd307a42021-06-11 11:45:58 +0200501 at25->chip.page_size);
David Brownellb587b132007-02-12 00:52:48 -0800502 return 0;
David Brownellb587b132007-02-12 00:52:48 -0800503}
504
David Brownellb587b132007-02-12 00:52:48 -0800505/*-------------------------------------------------------------------------*/
506
507static struct spi_driver at25_driver = {
508 .driver = {
509 .name = "at25",
Jan Luebbefbfdb6e2013-10-14 17:14:59 +0200510 .of_match_table = at25_of_match,
Jiri Prchalfd307a42021-06-11 11:45:58 +0200511 .dev_groups = sernum_groups,
David Brownellb587b132007-02-12 00:52:48 -0800512 },
513 .probe = at25_probe,
Mark Brown9e2cd442021-09-23 18:24:53 +0100514 .id_table = at25_spi_ids,
David Brownellb587b132007-02-12 00:52:48 -0800515};
516
Axel Lina3dc3c92012-01-22 15:38:22 +0800517module_spi_driver(at25_driver);
David Brownellb587b132007-02-12 00:52:48 -0800518
519MODULE_DESCRIPTION("Driver for most SPI EEPROMs");
520MODULE_AUTHOR("David Brownell");
521MODULE_LICENSE("GPL");
Anton Vorontsove0626e32009-09-22 16:46:08 -0700522MODULE_ALIAS("spi:at25");