Lines Matching +full:no +full:- +full:read +full:- +full:rollover

1 // SPDX-License-Identifier: GPL-2.0-or-later
22 #include <linux/spi/spi-mem.h>
24 #include <linux/nvmem-provider.h>
51 #define AT25_RDSR 0x05 /* read status register */
53 #define AT25_READ 0x03 /* read byte(s) */
56 #define FM25_RDID 0x9f /* read device ID */
57 #define FM25_RDSN 0xc3 /* read S/N */
59 #define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */
75 /*-------------------------------------------------------------------------*/
82 if (!(at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)) in at25_instr()
84 if (off < BIT(at25->addrlen * 8)) in at25_instr()
101 return -ENOMEM; in at25_ee_read()
103 if (unlikely(offset >= at25->chip.byte_len)) in at25_ee_read()
104 return -EINVAL; in at25_ee_read()
105 if ((offset + count) > at25->chip.byte_len) in at25_ee_read()
106 count = at25->chip.byte_len - offset; in at25_ee_read()
108 return -EINVAL; in at25_ee_read()
117 SPI_MEM_OP_ADDR(at25->addrlen, msg_offset, 1), in at25_ee_read()
121 status = spi_mem_adjust_op_size(at25->spimem, &op); in at25_ee_read()
126 mutex_lock(&at25->lock); in at25_ee_read()
127 status = spi_mem_exec_op(at25->spimem, &op); in at25_ee_read()
128 mutex_unlock(&at25->lock); in at25_ee_read()
135 bytes_left -= segment; in at25_ee_read()
138 dev_dbg(&at25->spimem->spi->dev, "read %zu bytes at %d\n", in at25_ee_read()
144 * Read extra registers as ID or serial number
146 * Allow for the callers to provide @buf on stack (not necessary DMA-capable)
157 return -ENOMEM; in fm25_aux_read()
164 status = spi_mem_exec_op(at25->spimem, &op); in fm25_aux_read()
165 dev_dbg(&at25->spimem->spi->dev, "read %d aux bytes --> %d\n", len, status); in fm25_aux_read()
179 return sysfs_emit(buf, "%*ph\n", (int)sizeof(at25->sernum), at25->sernum); in sernum_show()
190 * Poll Read Status Register with timeout
194 * [positive] Status Register value as-is, if the chip is busy
195 * [negative] error code in case of read failure
204 return -ENOMEM; in at25_wait_ready()
214 at25->spimem, &op); in at25_wait_ready()
231 if (unlikely(off >= at25->chip.byte_len)) in at25_ee_write()
232 return -EFBIG; in at25_ee_write()
233 if ((off + count) > at25->chip.byte_len) in at25_ee_write()
234 count = at25->chip.byte_len - off; in at25_ee_write()
236 return -EINVAL; in at25_ee_write()
238 buf_size = at25->chip.page_size; in at25_ee_write()
241 return -ENOMEM; in at25_ee_write()
244 * For write, rollover is within the page ... so we write at in at25_ee_write()
247 guard(mutex)(&at25->lock); in at25_ee_write()
255 status = spi_mem_exec_op(at25->spimem, &op); in at25_ee_write()
257 dev_dbg(&at25->spimem->spi->dev, "WREN --> %d\n", status); in at25_ee_write()
262 segment = buf_size - (off % buf_size); in at25_ee_write()
270 SPI_MEM_OP_ADDR(at25->addrlen, off, 1), in at25_ee_write()
274 status = spi_mem_adjust_op_size(at25->spimem, &op); in at25_ee_write()
281 status = spi_mem_exec_op(at25->spimem, &op); in at25_ee_write()
282 dev_dbg(&at25->spimem->spi->dev, "write %u bytes at %u --> %d\n", in at25_ee_write()
289 * to read-only sections of the EEPROM... in at25_ee_write()
294 dev_err_probe(&at25->spimem->spi->dev, status, in at25_ee_write()
295 "Read Status Redister command failed\n"); in at25_ee_write()
299 dev_dbg(&at25->spimem->spi->dev, in at25_ee_write()
301 dev_err(&at25->spimem->spi->dev, in at25_ee_write()
304 return -ETIMEDOUT; in at25_ee_write()
309 count -= segment; in at25_ee_write()
316 /*-------------------------------------------------------------------------*/
323 strscpy(chip->name, "at25", sizeof(chip->name)); in at25_fw_to_chip()
327 err = device_property_read_u32(dev, "at25,byte-len", &val); in at25_fw_to_chip()
332 chip->byte_len = val; in at25_fw_to_chip()
336 err = device_property_read_u32(dev, "at25,page-size", &val); in at25_fw_to_chip()
341 chip->page_size = val; in at25_fw_to_chip()
343 err = device_property_read_u32(dev, "address-width", &val); in at25_fw_to_chip()
345 err = device_property_read_u32(dev, "at25,addr-mode", &val); in at25_fw_to_chip()
347 dev_err(dev, "Error: missing \"address-width\" property\n"); in at25_fw_to_chip()
350 chip->flags = (u16)val; in at25_fw_to_chip()
354 chip->flags |= EE_INSTR_BIT3_IS_ADDR; in at25_fw_to_chip()
357 chip->flags |= EE_ADDR1; in at25_fw_to_chip()
360 chip->flags |= EE_ADDR2; in at25_fw_to_chip()
363 chip->flags |= EE_ADDR3; in at25_fw_to_chip()
367 "Error: bad \"address-width\" property: %u\n", in at25_fw_to_chip()
369 return -ENODEV; in at25_fw_to_chip()
371 if (device_property_present(dev, "read-only")) in at25_fw_to_chip()
372 chip->flags |= EE_READONLY; in at25_fw_to_chip()
385 strscpy(chip->name, "fm25", sizeof(chip->name)); in at25_fram_to_chip()
388 chip->byte_len = val; in at25_fram_to_chip()
392 /* There are inside-out FRAM variations, detect them and reverse the ID bytes */ in at25_fram_to_chip()
396 int j = ARRAY_SIZE(id) - i - 1; in at25_fram_to_chip()
402 dev_err(dev, "Error: no Cypress FRAM with device ID (manufacturer ID bank 7: %02x)\n", id[6]); in at25_fram_to_chip()
403 return -ENODEV; in at25_fram_to_chip()
408 chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024; in at25_fram_to_chip()
412 chip->byte_len = BIT(((id[7] >> 1) & 0xf) + 13); in at25_fram_to_chip()
416 return -ENODEV; in at25_fram_to_chip()
423 at25->sernum[i] = sernum[FM25_SN_LEN - 1 - i]; in at25_fram_to_chip()
427 if (chip->byte_len > 64 * 1024) in at25_fram_to_chip()
428 chip->flags |= EE_ADDR3; in at25_fram_to_chip()
430 chip->flags |= EE_ADDR2; in at25_fram_to_chip()
432 chip->page_size = PAGE_SIZE; in at25_fram_to_chip()
452 struct spi_device *spi = mem->spi; in at25_probe()
458 at25 = devm_kzalloc(&spi->dev, sizeof(*at25), GFP_KERNEL); in at25_probe()
460 return -ENOMEM; in at25_probe()
462 at25->spimem = mem; in at25_probe()
470 return dev_err_probe(&spi->dev, err, "Read Status Register command failed\n"); in at25_probe()
472 dev_err(&spi->dev, "Not ready (%02x)\n", err); in at25_probe()
473 return -ENXIO; in at25_probe()
476 mutex_init(&at25->lock); in at25_probe()
479 is_fram = fwnode_device_is_compatible(dev_fwnode(&spi->dev), "cypress,fm25"); in at25_probe()
482 pdata = dev_get_platdata(&spi->dev); in at25_probe()
484 at25->chip = *pdata; in at25_probe()
487 err = at25_fram_to_chip(&spi->dev, &at25->chip); in at25_probe()
489 err = at25_fw_to_chip(&spi->dev, &at25->chip); in at25_probe()
495 if (at25->chip.flags & EE_ADDR1) in at25_probe()
496 at25->addrlen = 1; in at25_probe()
497 else if (at25->chip.flags & EE_ADDR2) in at25_probe()
498 at25->addrlen = 2; in at25_probe()
499 else if (at25->chip.flags & EE_ADDR3) in at25_probe()
500 at25->addrlen = 3; in at25_probe()
502 dev_dbg(&spi->dev, "unsupported address type\n"); in at25_probe()
503 return -EINVAL; in at25_probe()
506 at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM; in at25_probe()
507 at25->nvmem_config.name = dev_name(&spi->dev); in at25_probe()
508 at25->nvmem_config.dev = &spi->dev; in at25_probe()
509 at25->nvmem_config.read_only = at25->chip.flags & EE_READONLY; in at25_probe()
510 at25->nvmem_config.root_only = true; in at25_probe()
511 at25->nvmem_config.owner = THIS_MODULE; in at25_probe()
512 at25->nvmem_config.compat = true; in at25_probe()
513 at25->nvmem_config.base_dev = &spi->dev; in at25_probe()
514 at25->nvmem_config.reg_read = at25_ee_read; in at25_probe()
515 at25->nvmem_config.reg_write = at25_ee_write; in at25_probe()
516 at25->nvmem_config.priv = at25; in at25_probe()
517 at25->nvmem_config.stride = 1; in at25_probe()
518 at25->nvmem_config.word_size = 1; in at25_probe()
519 at25->nvmem_config.size = at25->chip.byte_len; in at25_probe()
521 at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config); in at25_probe()
522 if (IS_ERR(at25->nvmem)) in at25_probe()
523 return PTR_ERR(at25->nvmem); in at25_probe()
525 dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n", in at25_probe()
526 (at25->chip.byte_len < 1024) ? in at25_probe()
527 at25->chip.byte_len : (at25->chip.byte_len / 1024), in at25_probe()
528 (at25->chip.byte_len < 1024) ? "Byte" : "KByte", in at25_probe()
529 at25->chip.name, is_fram ? "fram" : "eeprom", in at25_probe()
530 (at25->chip.flags & EE_READONLY) ? " (readonly)" : "", in at25_probe()
531 at25->chip.page_size); in at25_probe()
535 /*-------------------------------------------------------------------------*/