1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Freescale MXS On-Chip OTP driver 4 * 5 * Copyright (C) 2015 Stefan Wahren <stefan.wahren@i2se.com> 6 * 7 * Based on the driver from Huang Shijie and Christoph G. Baumann 8 */ 9 #include <linux/clk.h> 10 #include <linux/delay.h> 11 #include <linux/device.h> 12 #include <linux/err.h> 13 #include <linux/io.h> 14 #include <linux/module.h> 15 #include <linux/nvmem-provider.h> 16 #include <linux/of.h> 17 #include <linux/platform_device.h> 18 #include <linux/property.h> 19 #include <linux/slab.h> 20 #include <linux/stmp_device.h> 21 22 /* OCOTP registers and bits */ 23 24 #define BM_OCOTP_CTRL_RD_BANK_OPEN BIT(12) 25 #define BM_OCOTP_CTRL_ERROR BIT(9) 26 #define BM_OCOTP_CTRL_BUSY BIT(8) 27 28 #define OCOTP_TIMEOUT 10000 29 #define OCOTP_DATA_OFFSET 0x20 30 31 struct mxs_ocotp { 32 struct clk *clk; 33 void __iomem *base; 34 struct nvmem_device *nvmem; 35 }; 36 37 static int mxs_ocotp_wait(struct mxs_ocotp *otp) 38 { 39 int timeout = OCOTP_TIMEOUT; 40 unsigned int status = 0; 41 42 while (timeout--) { 43 status = readl(otp->base); 44 45 if (!(status & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR))) 46 break; 47 48 cpu_relax(); 49 } 50 51 if (status & BM_OCOTP_CTRL_BUSY) 52 return -EBUSY; 53 else if (status & BM_OCOTP_CTRL_ERROR) 54 return -EIO; 55 56 return 0; 57 } 58 59 static int mxs_ocotp_read(void *context, unsigned int offset, 60 void *val, size_t bytes) 61 { 62 struct mxs_ocotp *otp = context; 63 u32 *buf = val; 64 int ret; 65 66 ret = clk_enable(otp->clk); 67 if (ret) 68 return ret; 69 70 writel(BM_OCOTP_CTRL_ERROR, otp->base + STMP_OFFSET_REG_CLR); 71 72 ret = mxs_ocotp_wait(otp); 73 if (ret) 74 goto disable_clk; 75 76 /* open OCOTP banks for read */ 77 writel(BM_OCOTP_CTRL_RD_BANK_OPEN, otp->base + STMP_OFFSET_REG_SET); 78 79 /* approximately wait 33 hclk cycles */ 80 udelay(1); 81 82 ret = mxs_ocotp_wait(otp); 83 if (ret) 84 goto close_banks; 85 86 while (bytes) { 87 if ((offset < OCOTP_DATA_OFFSET) || (offset % 16)) { 88 /* fill up non-data register */ 89 *buf++ = 0; 90 } else { 91 *buf++ = readl(otp->base + offset); 92 } 93 94 bytes -= 4; 95 offset += 4; 96 } 97 98 close_banks: 99 /* close banks for power saving */ 100 writel(BM_OCOTP_CTRL_RD_BANK_OPEN, otp->base + STMP_OFFSET_REG_CLR); 101 102 disable_clk: 103 clk_disable(otp->clk); 104 105 return ret; 106 } 107 108 static struct nvmem_config ocotp_config = { 109 .name = "mxs-ocotp", 110 .stride = 16, 111 .word_size = 4, 112 .reg_read = mxs_ocotp_read, 113 }; 114 115 struct mxs_data { 116 int size; 117 }; 118 119 static const struct mxs_data imx23_data = { 120 .size = 0x220, 121 }; 122 123 static const struct mxs_data imx28_data = { 124 .size = 0x2a0, 125 }; 126 127 static const struct of_device_id mxs_ocotp_match[] = { 128 { .compatible = "fsl,imx23-ocotp", .data = &imx23_data }, 129 { .compatible = "fsl,imx28-ocotp", .data = &imx28_data }, 130 { /* sentinel */}, 131 }; 132 MODULE_DEVICE_TABLE(of, mxs_ocotp_match); 133 134 static void mxs_ocotp_action(void *data) 135 { 136 clk_unprepare(data); 137 } 138 139 static int mxs_ocotp_probe(struct platform_device *pdev) 140 { 141 struct device *dev = &pdev->dev; 142 const struct mxs_data *data; 143 struct mxs_ocotp *otp; 144 int ret; 145 146 data = device_get_match_data(dev); 147 if (!data) 148 return -EINVAL; 149 150 otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL); 151 if (!otp) 152 return -ENOMEM; 153 154 otp->base = devm_platform_ioremap_resource(pdev, 0); 155 if (IS_ERR(otp->base)) 156 return PTR_ERR(otp->base); 157 158 otp->clk = devm_clk_get(&pdev->dev, NULL); 159 if (IS_ERR(otp->clk)) 160 return PTR_ERR(otp->clk); 161 162 ret = clk_prepare(otp->clk); 163 if (ret < 0) { 164 dev_err(dev, "failed to prepare clk: %d\n", ret); 165 return ret; 166 } 167 168 ret = devm_add_action_or_reset(&pdev->dev, mxs_ocotp_action, otp->clk); 169 if (ret) 170 return ret; 171 172 ocotp_config.size = data->size; 173 ocotp_config.priv = otp; 174 ocotp_config.dev = dev; 175 otp->nvmem = devm_nvmem_register(dev, &ocotp_config); 176 if (IS_ERR(otp->nvmem)) 177 return PTR_ERR(otp->nvmem); 178 179 platform_set_drvdata(pdev, otp); 180 181 return 0; 182 } 183 184 static struct platform_driver mxs_ocotp_driver = { 185 .probe = mxs_ocotp_probe, 186 .driver = { 187 .name = "mxs-ocotp", 188 .of_match_table = mxs_ocotp_match, 189 }, 190 }; 191 192 module_platform_driver(mxs_ocotp_driver); 193 MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net"); 194 MODULE_DESCRIPTION("driver for OCOTP in i.MX23/i.MX28"); 195 MODULE_LICENSE("GPL v2"); 196