Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * NXP LPC18xx/43xx OTP memory NVMEM driver
0004  *
0005  * Copyright (c) 2016 Joachim Eastwood <manabian@gmail.com>
0006  *
0007  * Based on the imx ocotp driver,
0008  * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
0009  *
0010  * TODO: add support for writing OTP register via API in boot ROM.
0011  */
0012 
0013 #include <linux/io.h>
0014 #include <linux/module.h>
0015 #include <linux/nvmem-provider.h>
0016 #include <linux/of.h>
0017 #include <linux/of_device.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/slab.h>
0020 
0021 /*
0022  * LPC18xx OTP memory contains 4 banks with 4 32-bit words. Bank 0 starts
0023  * at offset 0 from the base.
0024  *
0025  * Bank 0 contains the part ID for Flashless devices and is reseverd for
0026  * devices with Flash.
0027  * Bank 1/2 is generale purpose or AES key storage for secure devices.
0028  * Bank 3 contains control data, USB ID and generale purpose words.
0029  */
0030 #define LPC18XX_OTP_NUM_BANKS       4
0031 #define LPC18XX_OTP_WORDS_PER_BANK  4
0032 #define LPC18XX_OTP_WORD_SIZE       sizeof(u32)
0033 #define LPC18XX_OTP_SIZE        (LPC18XX_OTP_NUM_BANKS * \
0034                      LPC18XX_OTP_WORDS_PER_BANK * \
0035                      LPC18XX_OTP_WORD_SIZE)
0036 
0037 struct lpc18xx_otp {
0038     void __iomem *base;
0039 };
0040 
0041 static int lpc18xx_otp_read(void *context, unsigned int offset,
0042                 void *val, size_t bytes)
0043 {
0044     struct lpc18xx_otp *otp = context;
0045     unsigned int count = bytes >> 2;
0046     u32 index = offset >> 2;
0047     u32 *buf = val;
0048     int i;
0049 
0050     if (count > (LPC18XX_OTP_SIZE - index))
0051         count = LPC18XX_OTP_SIZE - index;
0052 
0053     for (i = index; i < (index + count); i++)
0054         *buf++ = readl(otp->base + i * LPC18XX_OTP_WORD_SIZE);
0055 
0056     return 0;
0057 }
0058 
0059 static struct nvmem_config lpc18xx_otp_nvmem_config = {
0060     .name = "lpc18xx-otp",
0061     .read_only = true,
0062     .word_size = LPC18XX_OTP_WORD_SIZE,
0063     .stride = LPC18XX_OTP_WORD_SIZE,
0064     .reg_read = lpc18xx_otp_read,
0065 };
0066 
0067 static int lpc18xx_otp_probe(struct platform_device *pdev)
0068 {
0069     struct nvmem_device *nvmem;
0070     struct lpc18xx_otp *otp;
0071     struct resource *res;
0072 
0073     otp = devm_kzalloc(&pdev->dev, sizeof(*otp), GFP_KERNEL);
0074     if (!otp)
0075         return -ENOMEM;
0076 
0077     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0078     otp->base = devm_ioremap_resource(&pdev->dev, res);
0079     if (IS_ERR(otp->base))
0080         return PTR_ERR(otp->base);
0081 
0082     lpc18xx_otp_nvmem_config.size = LPC18XX_OTP_SIZE;
0083     lpc18xx_otp_nvmem_config.dev = &pdev->dev;
0084     lpc18xx_otp_nvmem_config.priv = otp;
0085 
0086     nvmem = devm_nvmem_register(&pdev->dev, &lpc18xx_otp_nvmem_config);
0087 
0088     return PTR_ERR_OR_ZERO(nvmem);
0089 }
0090 
0091 static const struct of_device_id lpc18xx_otp_dt_ids[] = {
0092     { .compatible = "nxp,lpc1850-otp" },
0093     { },
0094 };
0095 MODULE_DEVICE_TABLE(of, lpc18xx_otp_dt_ids);
0096 
0097 static struct platform_driver lpc18xx_otp_driver = {
0098     .probe  = lpc18xx_otp_probe,
0099     .driver = {
0100         .name   = "lpc18xx_otp",
0101         .of_match_table = lpc18xx_otp_dt_ids,
0102     },
0103 };
0104 module_platform_driver(lpc18xx_otp_driver);
0105 
0106 MODULE_AUTHOR("Joachim Eastwoood <manabian@gmail.com>");
0107 MODULE_DESCRIPTION("NXP LPC18xx OTP NVMEM driver");
0108 MODULE_LICENSE("GPL v2");