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