1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 288806dafSJoachim Eastwood /* 388806dafSJoachim Eastwood * NXP LPC18xx/43xx OTP memory NVMEM driver 488806dafSJoachim Eastwood * 588806dafSJoachim Eastwood * Copyright (c) 2016 Joachim Eastwood <manabian@gmail.com> 688806dafSJoachim Eastwood * 788806dafSJoachim Eastwood * Based on the imx ocotp driver, 888806dafSJoachim Eastwood * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de> 988806dafSJoachim Eastwood * 1088806dafSJoachim Eastwood * TODO: add support for writing OTP register via API in boot ROM. 1188806dafSJoachim Eastwood */ 1288806dafSJoachim Eastwood 1388806dafSJoachim Eastwood #include <linux/io.h> 1488806dafSJoachim Eastwood #include <linux/module.h> 1588806dafSJoachim Eastwood #include <linux/nvmem-provider.h> 1688806dafSJoachim Eastwood #include <linux/of.h> 1788806dafSJoachim Eastwood #include <linux/of_device.h> 1888806dafSJoachim Eastwood #include <linux/platform_device.h> 1988806dafSJoachim Eastwood #include <linux/slab.h> 2088806dafSJoachim Eastwood 2188806dafSJoachim Eastwood /* 2288806dafSJoachim Eastwood * LPC18xx OTP memory contains 4 banks with 4 32-bit words. Bank 0 starts 2388806dafSJoachim Eastwood * at offset 0 from the base. 2488806dafSJoachim Eastwood * 2588806dafSJoachim Eastwood * Bank 0 contains the part ID for Flashless devices and is reseverd for 2688806dafSJoachim Eastwood * devices with Flash. 2788806dafSJoachim Eastwood * Bank 1/2 is generale purpose or AES key storage for secure devices. 2888806dafSJoachim Eastwood * Bank 3 contains control data, USB ID and generale purpose words. 2988806dafSJoachim Eastwood */ 3088806dafSJoachim Eastwood #define LPC18XX_OTP_NUM_BANKS 4 3188806dafSJoachim Eastwood #define LPC18XX_OTP_WORDS_PER_BANK 4 3288806dafSJoachim Eastwood #define LPC18XX_OTP_WORD_SIZE sizeof(u32) 3388806dafSJoachim Eastwood #define LPC18XX_OTP_SIZE (LPC18XX_OTP_NUM_BANKS * \ 3488806dafSJoachim Eastwood LPC18XX_OTP_WORDS_PER_BANK * \ 3588806dafSJoachim Eastwood LPC18XX_OTP_WORD_SIZE) 3688806dafSJoachim Eastwood 3788806dafSJoachim Eastwood struct lpc18xx_otp { 3888806dafSJoachim Eastwood void __iomem *base; 3988806dafSJoachim Eastwood }; 4088806dafSJoachim Eastwood 4188806dafSJoachim Eastwood static int lpc18xx_otp_read(void *context, unsigned int offset, 4288806dafSJoachim Eastwood void *val, size_t bytes) 4388806dafSJoachim Eastwood { 4488806dafSJoachim Eastwood struct lpc18xx_otp *otp = context; 4588806dafSJoachim Eastwood unsigned int count = bytes >> 2; 4688806dafSJoachim Eastwood u32 index = offset >> 2; 4788806dafSJoachim Eastwood u32 *buf = val; 4888806dafSJoachim Eastwood int i; 4988806dafSJoachim Eastwood 5088806dafSJoachim Eastwood if (count > (LPC18XX_OTP_SIZE - index)) 5188806dafSJoachim Eastwood count = LPC18XX_OTP_SIZE - index; 5288806dafSJoachim Eastwood 5388806dafSJoachim Eastwood for (i = index; i < (index + count); i++) 5488806dafSJoachim Eastwood *buf++ = readl(otp->base + i * LPC18XX_OTP_WORD_SIZE); 5588806dafSJoachim Eastwood 5688806dafSJoachim Eastwood return 0; 5788806dafSJoachim Eastwood } 5888806dafSJoachim Eastwood 5988806dafSJoachim Eastwood static struct nvmem_config lpc18xx_otp_nvmem_config = { 6088806dafSJoachim Eastwood .name = "lpc18xx-otp", 6188806dafSJoachim Eastwood .read_only = true, 6288806dafSJoachim Eastwood .word_size = LPC18XX_OTP_WORD_SIZE, 6388806dafSJoachim Eastwood .stride = LPC18XX_OTP_WORD_SIZE, 6488806dafSJoachim Eastwood .reg_read = lpc18xx_otp_read, 6588806dafSJoachim Eastwood }; 6688806dafSJoachim Eastwood 6788806dafSJoachim Eastwood static int lpc18xx_otp_probe(struct platform_device *pdev) 6888806dafSJoachim Eastwood { 6988806dafSJoachim Eastwood struct nvmem_device *nvmem; 7088806dafSJoachim Eastwood struct lpc18xx_otp *otp; 7188806dafSJoachim Eastwood 7288806dafSJoachim Eastwood otp = devm_kzalloc(&pdev->dev, sizeof(*otp), GFP_KERNEL); 7388806dafSJoachim Eastwood if (!otp) 7488806dafSJoachim Eastwood return -ENOMEM; 7588806dafSJoachim Eastwood 76*0b49178eSYangtao Li otp->base = devm_platform_ioremap_resource(pdev, 0); 7788806dafSJoachim Eastwood if (IS_ERR(otp->base)) 7888806dafSJoachim Eastwood return PTR_ERR(otp->base); 7988806dafSJoachim Eastwood 8088806dafSJoachim Eastwood lpc18xx_otp_nvmem_config.size = LPC18XX_OTP_SIZE; 8188806dafSJoachim Eastwood lpc18xx_otp_nvmem_config.dev = &pdev->dev; 8288806dafSJoachim Eastwood lpc18xx_otp_nvmem_config.priv = otp; 8388806dafSJoachim Eastwood 84b005b2f5SAndrey Smirnov nvmem = devm_nvmem_register(&pdev->dev, &lpc18xx_otp_nvmem_config); 8588806dafSJoachim Eastwood 86b005b2f5SAndrey Smirnov return PTR_ERR_OR_ZERO(nvmem); 8788806dafSJoachim Eastwood } 8888806dafSJoachim Eastwood 8988806dafSJoachim Eastwood static const struct of_device_id lpc18xx_otp_dt_ids[] = { 9088806dafSJoachim Eastwood { .compatible = "nxp,lpc1850-otp" }, 9188806dafSJoachim Eastwood { }, 9288806dafSJoachim Eastwood }; 9388806dafSJoachim Eastwood MODULE_DEVICE_TABLE(of, lpc18xx_otp_dt_ids); 9488806dafSJoachim Eastwood 9588806dafSJoachim Eastwood static struct platform_driver lpc18xx_otp_driver = { 9688806dafSJoachim Eastwood .probe = lpc18xx_otp_probe, 9788806dafSJoachim Eastwood .driver = { 9888806dafSJoachim Eastwood .name = "lpc18xx_otp", 9988806dafSJoachim Eastwood .of_match_table = lpc18xx_otp_dt_ids, 10088806dafSJoachim Eastwood }, 10188806dafSJoachim Eastwood }; 10288806dafSJoachim Eastwood module_platform_driver(lpc18xx_otp_driver); 10388806dafSJoachim Eastwood 10488806dafSJoachim Eastwood MODULE_AUTHOR("Joachim Eastwoood <manabian@gmail.com>"); 10588806dafSJoachim Eastwood MODULE_DESCRIPTION("NXP LPC18xx OTP NVMEM driver"); 10688806dafSJoachim Eastwood MODULE_LICENSE("GPL v2"); 107