// SPDX-License-Identifier: GPL-2.0 /* * OTP Memory controller * * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries * * Author: Claudiu Beznea <[email protected]> */ #include <linux/bitfield.h> #include <linux/iopoll.h> #include <linux/module.h> #include <linux/nvmem-provider.h> #include <linux/of.h> #include <linux/platform_device.h> #define MCHP_OTPC_CR … #define MCHP_OTPC_CR_READ … #define MCHP_OTPC_MR … #define MCHP_OTPC_MR_ADDR … #define MCHP_OTPC_AR … #define MCHP_OTPC_SR … #define MCHP_OTPC_SR_READ … #define MCHP_OTPC_HR … #define MCHP_OTPC_HR_SIZE … #define MCHP_OTPC_DR … #define MCHP_OTPC_NAME … #define MCHP_OTPC_SIZE … /** * struct mchp_otpc - OTPC private data structure * @base: base address * @dev: struct device pointer * @packets: list of packets in OTP memory * @npackets: number of packets in OTP memory */ struct mchp_otpc { … }; /** * struct mchp_otpc_packet - OTPC packet data structure * @list: list head * @id: packet ID * @offset: packet offset (in words) in OTP memory */ struct mchp_otpc_packet { … }; static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *otpc, u32 id) { … } static int mchp_otpc_prepare_read(struct mchp_otpc *otpc, unsigned int offset) { … } /* * OTPC memory is organized into packets. Each packets contains a header and * a payload. Header is 4 bytes long and contains the size of the payload. * Payload size varies. The memory footprint is something as follows: * * Memory offset Memory footprint Packet ID * ------------- ---------------- --------- * * 0x0 +------------+ <-- packet 0 * | header 0 | * 0x4 +------------+ * | payload 0 | * . . * . ... . * . . * offset1 +------------+ <-- packet 1 * | header 1 | * offset1 + 0x4 +------------+ * | payload 1 | * . . * . ... . * . . * offset2 +------------+ <-- packet 2 * . . * . ... . * . . * offsetN +------------+ <-- packet N * | header N | * offsetN + 0x4 +------------+ * | payload N | * . . * . ... . * . . * +------------+ * * where offset1, offset2, offsetN depends on the size of payload 0, payload 1, * payload N-1. * * The access to memory is done on a per packet basis: the control registers * need to be updated with an offset address (within a packet range) and the * data registers will be update by controller with information contained by * that packet. E.g. if control registers are updated with any address within * the range [offset1, offset2) the data registers are updated by controller * with packet 1. Header data is accessible though MCHP_OTPC_HR register. * Payload data is accessible though MCHP_OTPC_DR and MCHP_OTPC_AR registers. * There is no direct mapping b/w the offset requested by software and the * offset returned by hardware. * * For this, the read function will return the first requested bytes in the * packet. The user will have to be aware of the memory footprint before doing * the read request. */ static int mchp_otpc_read(void *priv, unsigned int off, void *val, size_t bytes) { … } static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size) { … } static struct nvmem_config mchp_nvmem_config = …; static int mchp_otpc_probe(struct platform_device *pdev) { … } static const struct of_device_id __maybe_unused mchp_otpc_ids[] = …; MODULE_DEVICE_TABLE(of, mchp_otpc_ids); static struct platform_driver mchp_otpc_driver = …; module_platform_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;