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