xref: /linux/drivers/nvmem/lpc18xx_eeprom.c (revision 151ebcf0797b1a3ba53c8843dc21748c80e098c7)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver
4  *
5  * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
6  */
7 
8 #include <linux/clk.h>
9 #include <linux/device.h>
10 #include <linux/delay.h>
11 #include <linux/err.h>
12 #include <linux/io.h>
13 #include <linux/module.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/nvmem-provider.h>
16 #include <linux/platform_device.h>
17 #include <linux/reset.h>
18 
19 /* Registers */
20 #define LPC18XX_EEPROM_AUTOPROG			0x00c
21 #define LPC18XX_EEPROM_AUTOPROG_WORD		0x1
22 
23 #define LPC18XX_EEPROM_CLKDIV			0x014
24 
25 #define LPC18XX_EEPROM_PWRDWN			0x018
26 #define LPC18XX_EEPROM_PWRDWN_NO		0x0
27 #define LPC18XX_EEPROM_PWRDWN_YES		0x1
28 
29 #define LPC18XX_EEPROM_INTSTAT			0xfe0
30 #define LPC18XX_EEPROM_INTSTAT_END_OF_PROG	BIT(2)
31 
32 #define LPC18XX_EEPROM_INTSTATCLR		0xfe8
33 #define LPC18XX_EEPROM_INTSTATCLR_PROG_CLR_ST	BIT(2)
34 
35 /* Fixed page size (bytes) */
36 #define LPC18XX_EEPROM_PAGE_SIZE		0x80
37 
38 /* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) */
39 #define LPC18XX_EEPROM_CLOCK_HZ			1500000
40 
41 /* EEPROM requires 3 ms of erase/program time between each writing */
42 #define LPC18XX_EEPROM_PROGRAM_TIME		3
43 
44 struct lpc18xx_eeprom_dev {
45 	struct clk *clk;
46 	void __iomem *reg_base;
47 	void __iomem *mem_base;
48 	struct nvmem_device *nvmem;
49 	unsigned reg_bytes;
50 	unsigned val_bytes;
51 	int size;
52 };
53 
54 static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev *eeprom,
55 					 u32 reg, u32 val)
56 {
57 	writel(val, eeprom->reg_base + reg);
58 }
59 
60 static inline u32 lpc18xx_eeprom_readl(struct lpc18xx_eeprom_dev *eeprom,
61 				       u32 reg)
62 {
63 	return readl(eeprom->reg_base + reg);
64 }
65 
66 static int lpc18xx_eeprom_busywait_until_prog(struct lpc18xx_eeprom_dev *eeprom)
67 {
68 	unsigned long end;
69 	u32 val;
70 
71 	/* Wait until EEPROM program operation has finished */
72 	end = jiffies + msecs_to_jiffies(LPC18XX_EEPROM_PROGRAM_TIME * 10);
73 
74 	while (time_is_after_jiffies(end)) {
75 		val = lpc18xx_eeprom_readl(eeprom, LPC18XX_EEPROM_INTSTAT);
76 
77 		if (val & LPC18XX_EEPROM_INTSTAT_END_OF_PROG) {
78 			lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_INTSTATCLR,
79 					LPC18XX_EEPROM_INTSTATCLR_PROG_CLR_ST);
80 			return 0;
81 		}
82 
83 		usleep_range(LPC18XX_EEPROM_PROGRAM_TIME * USEC_PER_MSEC,
84 			     (LPC18XX_EEPROM_PROGRAM_TIME + 1) * USEC_PER_MSEC);
85 	}
86 
87 	return -ETIMEDOUT;
88 }
89 
90 static int lpc18xx_eeprom_gather_write(void *context, unsigned int reg,
91 				       void *val, size_t bytes)
92 {
93 	struct lpc18xx_eeprom_dev *eeprom = context;
94 	unsigned int offset = reg;
95 	int ret;
96 
97 	/*
98 	 * The last page contains the EEPROM initialization data and is not
99 	 * writable.
100 	 */
101 	if ((reg > eeprom->size - LPC18XX_EEPROM_PAGE_SIZE) ||
102 			(reg + bytes > eeprom->size - LPC18XX_EEPROM_PAGE_SIZE))
103 		return -EINVAL;
104 
105 
106 	lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
107 			      LPC18XX_EEPROM_PWRDWN_NO);
108 
109 	/* Wait 100 us while the EEPROM wakes up */
110 	usleep_range(100, 200);
111 
112 	while (bytes) {
113 		writel(*(u32 *)val, eeprom->mem_base + offset);
114 		ret = lpc18xx_eeprom_busywait_until_prog(eeprom);
115 		if (ret < 0)
116 			return ret;
117 
118 		bytes -= eeprom->val_bytes;
119 		val += eeprom->val_bytes;
120 		offset += eeprom->val_bytes;
121 	}
122 
123 	lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
124 			      LPC18XX_EEPROM_PWRDWN_YES);
125 
126 	return 0;
127 }
128 
129 static int lpc18xx_eeprom_read(void *context, unsigned int offset,
130 			       void *val, size_t bytes)
131 {
132 	struct lpc18xx_eeprom_dev *eeprom = context;
133 
134 	lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
135 			      LPC18XX_EEPROM_PWRDWN_NO);
136 
137 	/* Wait 100 us while the EEPROM wakes up */
138 	usleep_range(100, 200);
139 
140 	while (bytes) {
141 		*(u32 *)val = readl(eeprom->mem_base + offset);
142 		bytes -= eeprom->val_bytes;
143 		val += eeprom->val_bytes;
144 		offset += eeprom->val_bytes;
145 	}
146 
147 	lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
148 			      LPC18XX_EEPROM_PWRDWN_YES);
149 
150 	return 0;
151 }
152 
153 
154 static struct nvmem_config lpc18xx_nvmem_config = {
155 	.name = "lpc18xx-eeprom",
156 	.stride = 4,
157 	.word_size = 4,
158 	.reg_read = lpc18xx_eeprom_read,
159 	.reg_write = lpc18xx_eeprom_gather_write,
160 };
161 
162 static int lpc18xx_eeprom_probe(struct platform_device *pdev)
163 {
164 	struct lpc18xx_eeprom_dev *eeprom;
165 	struct device *dev = &pdev->dev;
166 	struct reset_control *rst;
167 	unsigned long clk_rate;
168 	struct resource *res;
169 	int ret;
170 
171 	eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
172 	if (!eeprom)
173 		return -ENOMEM;
174 
175 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
176 	eeprom->reg_base = devm_ioremap_resource(dev, res);
177 	if (IS_ERR(eeprom->reg_base))
178 		return PTR_ERR(eeprom->reg_base);
179 
180 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
181 	eeprom->mem_base = devm_ioremap_resource(dev, res);
182 	if (IS_ERR(eeprom->mem_base))
183 		return PTR_ERR(eeprom->mem_base);
184 
185 	eeprom->clk = devm_clk_get(&pdev->dev, "eeprom");
186 	if (IS_ERR(eeprom->clk)) {
187 		dev_err(&pdev->dev, "failed to get eeprom clock\n");
188 		return PTR_ERR(eeprom->clk);
189 	}
190 
191 	ret = clk_prepare_enable(eeprom->clk);
192 	if (ret < 0) {
193 		dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret);
194 		return ret;
195 	}
196 
197 	rst = devm_reset_control_get_exclusive(dev, NULL);
198 	if (IS_ERR(rst)) {
199 		dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst));
200 		ret = PTR_ERR(rst);
201 		goto err_clk;
202 	}
203 
204 	ret = reset_control_assert(rst);
205 	if (ret < 0) {
206 		dev_err(dev, "failed to assert reset: %d\n", ret);
207 		goto err_clk;
208 	}
209 
210 	eeprom->val_bytes = 4;
211 	eeprom->reg_bytes = 4;
212 
213 	/*
214 	 * Clock rate is generated by dividing the system bus clock by the
215 	 * division factor, contained in the divider register (minus 1 encoded).
216 	 */
217 	clk_rate = clk_get_rate(eeprom->clk);
218 	clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1;
219 	lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate);
220 
221 	/*
222 	 * Writing a single word to the page will start the erase/program cycle
223 	 * automatically
224 	 */
225 	lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG,
226 			      LPC18XX_EEPROM_AUTOPROG_WORD);
227 
228 	lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
229 			      LPC18XX_EEPROM_PWRDWN_YES);
230 
231 	eeprom->size = resource_size(res);
232 	lpc18xx_nvmem_config.size = resource_size(res);
233 	lpc18xx_nvmem_config.dev = dev;
234 	lpc18xx_nvmem_config.priv = eeprom;
235 
236 	eeprom->nvmem = devm_nvmem_register(dev, &lpc18xx_nvmem_config);
237 	if (IS_ERR(eeprom->nvmem)) {
238 		ret = PTR_ERR(eeprom->nvmem);
239 		goto err_clk;
240 	}
241 
242 	platform_set_drvdata(pdev, eeprom);
243 
244 	return 0;
245 
246 err_clk:
247 	clk_disable_unprepare(eeprom->clk);
248 
249 	return ret;
250 }
251 
252 static void lpc18xx_eeprom_remove(struct platform_device *pdev)
253 {
254 	struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev);
255 
256 	clk_disable_unprepare(eeprom->clk);
257 }
258 
259 static const struct of_device_id lpc18xx_eeprom_of_match[] = {
260 	{ .compatible = "nxp,lpc1857-eeprom" },
261 	{ },
262 };
263 MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match);
264 
265 static struct platform_driver lpc18xx_eeprom_driver = {
266 	.probe = lpc18xx_eeprom_probe,
267 	.remove_new = lpc18xx_eeprom_remove,
268 	.driver = {
269 		.name = "lpc18xx-eeprom",
270 		.of_match_table = lpc18xx_eeprom_of_match,
271 	},
272 };
273 
274 module_platform_driver(lpc18xx_eeprom_driver);
275 
276 MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>");
277 MODULE_DESCRIPTION("NXP LPC18xx EEPROM memory Driver");
278 MODULE_LICENSE("GPL v2");
279