File Index
Files and directories
Sign in
FILE

qnap-mcu-eeprom.c

File preview with syntax highlighting.

linux-6.19.14/drivers/nvmem/qnap-mcu-eeprom.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * ee1004 - driver for DDR4 SPD EEPROMs
  4 *
  5 * Copyright (C) 2017-2019 Jean Delvare
  6 *
  7 * Based on the at24 driver:
  8 * Copyright (C) 2005-2007 David Brownell
  9 * Copyright (C) 2008 Wolfram Sang, Pengutronix
 10 */
 11
 12#include <linux/mfd/qnap-mcu.h>
 13#include <linux/module.h>
 14#include <linux/nvmem-provider.h>
 15#include <linux/platform_device.h>
 16#include <linux/slab.h>
 17
 18/* Determined by trial and error until read anomalies appeared */
 19#define QNAP_MCU_EEPROM_SIZE		256
 20#define QNAP_MCU_EEPROM_BLOCK_SIZE	32
 21
 22static int qnap_mcu_eeprom_read_block(struct qnap_mcu *mcu, unsigned int offset,
 23				      void *val, size_t bytes)
 24{
 25	const u8 cmd[] = { 0xf7, 0xa1, offset, bytes };
 26	u8 *reply;
 27	int ret = 0;
 28
 29	reply = kzalloc(bytes + sizeof(cmd), GFP_KERNEL);
 30	if (!reply)
 31		return -ENOMEM;
 32
 33	ret = qnap_mcu_exec(mcu, cmd, sizeof(cmd), reply, bytes + sizeof(cmd));
 34	if (ret)
 35		goto out;
 36
 37	/* First bytes must mirror the sent command */
 38	if (memcmp(cmd, reply, sizeof(cmd))) {
 39		ret = -EIO;
 40		goto out;
 41	}
 42
 43	memcpy(val, reply + sizeof(cmd), bytes);
 44
 45out:
 46	kfree(reply);
 47	return ret;
 48}
 49
 50static int qnap_mcu_eeprom_read(void *priv, unsigned int offset, void *val, size_t bytes)
 51{
 52	struct qnap_mcu *mcu = priv;
 53	int pos = 0, ret;
 54	u8 *buf = val;
 55
 56	if (unlikely(!bytes))
 57		return 0;
 58
 59	while (bytes > 0) {
 60		size_t to_read = (bytes > QNAP_MCU_EEPROM_BLOCK_SIZE) ?
 61						QNAP_MCU_EEPROM_BLOCK_SIZE : bytes;
 62
 63		ret = qnap_mcu_eeprom_read_block(mcu, offset + pos, &buf[pos], to_read);
 64		if (ret < 0)
 65			return ret;
 66
 67		pos += to_read;
 68		bytes -= to_read;
 69	}
 70
 71	return 0;
 72}
 73
 74static int qnap_mcu_eeprom_probe(struct platform_device *pdev)
 75{
 76	struct qnap_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
 77	struct nvmem_config nvcfg = {};
 78	struct nvmem_device *ndev;
 79
 80	nvcfg.dev = &pdev->dev;
 81	nvcfg.of_node = pdev->dev.parent->of_node;
 82	nvcfg.name = dev_name(&pdev->dev);
 83	nvcfg.id = NVMEM_DEVID_NONE;
 84	nvcfg.owner = THIS_MODULE;
 85	nvcfg.type = NVMEM_TYPE_EEPROM;
 86	nvcfg.read_only = true;
 87	nvcfg.root_only = false;
 88	nvcfg.reg_read = qnap_mcu_eeprom_read;
 89	nvcfg.size = QNAP_MCU_EEPROM_SIZE,
 90	nvcfg.word_size = 1,
 91	nvcfg.stride = 1,
 92	nvcfg.priv = mcu,
 93
 94	ndev = devm_nvmem_register(&pdev->dev, &nvcfg);
 95	if (IS_ERR(ndev))
 96		return PTR_ERR(ndev);
 97
 98	return 0;
 99}
100
101static struct platform_driver qnap_mcu_eeprom_driver = {
102	.probe = qnap_mcu_eeprom_probe,
103	.driver = {
104		.name = "qnap-mcu-eeprom",
105	},
106};
107module_platform_driver(qnap_mcu_eeprom_driver);
108
109MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
110MODULE_DESCRIPTION("QNAP MCU EEPROM driver");
111MODULE_LICENSE("GPL");
~/ Read-only file preview.