aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2016-05-23 03:44:54 -0400
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2016-06-02 02:32:25 -0400
commit6a4ec4cd08888b19837d343e52d0b9a986f94db8 (patch)
treee87dcaf78aec1d44336d0783acb2aeeb43c90354
parent1a695a905c18548062509178b98bc91e67510864 (diff)
memory: add Atmel EBI (External Bus Interface) driver
The EBI (External Bus Interface) is used to access external peripherals (NOR, SRAM, NAND, and other specific devices like ethernet controllers). Each device is assigned a CS line and an address range and can have its own configuration (timings, access mode, bus width, ...). This driver provides a generic DT binding to configure a device according to its requirements. For specific device controllers (like the NAND one) the SMC timings should be configured by the controller driver through the matrix and smc syscon regmaps. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-rw-r--r--drivers/memory/Kconfig11
-rw-r--r--drivers/memory/Makefile1
-rw-r--r--drivers/memory/atmel-ebi.c771
3 files changed, 783 insertions, 0 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 81ddb17575a9..133712346911 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -25,6 +25,17 @@ config ATMEL_SDRAMC
25 Starting with the at91sam9g45, this controller supports SDR, DDR and 25 Starting with the at91sam9g45, this controller supports SDR, DDR and
26 LP-DDR memories. 26 LP-DDR memories.
27 27
28config ATMEL_EBI
29 bool "Atmel EBI driver"
30 default y
31 depends on ARCH_AT91 && OF
32 select MFD_SYSCON
33 help
34 Driver for Atmel EBI controller.
35 Used to configure the EBI (external bus interface) when the device-
36 tree is used. This bus supports NANDs, external ethernet controller,
37 SRAMs, ATA devices, etc.
38
28config TI_AEMIF 39config TI_AEMIF
29 tristate "Texas Instruments AEMIF driver" 40 tristate "Texas Instruments AEMIF driver"
30 depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF 41 depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index cb0b7a1df11a..b20ae38b5bfb 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_OF) += of_memory.o
7endif 7endif
8obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o 8obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
9obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o 9obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
10obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
10obj-$(CONFIG_TI_AEMIF) += ti-aemif.o 11obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
11obj-$(CONFIG_TI_EMIF) += emif.o 12obj-$(CONFIG_TI_EMIF) += emif.o
12obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o 13obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
new file mode 100644
index 000000000000..17d9d3f60f20
--- /dev/null
+++ b/drivers/memory/atmel-ebi.c
@@ -0,0 +1,771 @@
1/*
2 * EBI driver for Atmel chips
3 * inspired by the fsl weim bus driver
4 *
5 * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
12#include <linux/clk.h>
13#include <linux/io.h>
14#include <linux/mfd/syscon.h>
15#include <linux/mfd/syscon/atmel-matrix.h>
16#include <linux/mfd/syscon/atmel-smc.h>
17#include <linux/module.h>
18#include <linux/of_device.h>
19#include <linux/regmap.h>
20
21struct at91sam9_smc_timings {
22 u32 ncs_rd_setup_ns;
23 u32 nrd_setup_ns;
24 u32 ncs_wr_setup_ns;
25 u32 nwe_setup_ns;
26 u32 ncs_rd_pulse_ns;
27 u32 nrd_pulse_ns;
28 u32 ncs_wr_pulse_ns;
29 u32 nwe_pulse_ns;
30 u32 nrd_cycle_ns;
31 u32 nwe_cycle_ns;
32 u32 tdf_ns;
33};
34
35struct at91sam9_smc_generic_fields {
36 struct regmap_field *setup;
37 struct regmap_field *pulse;
38 struct regmap_field *cycle;
39 struct regmap_field *mode;
40};
41
42struct at91sam9_ebi_dev_config {
43 struct at91sam9_smc_timings timings;
44 u32 mode;
45};
46
47struct at91_ebi_dev_config {
48 int cs;
49 union {
50 struct at91sam9_ebi_dev_config sam9;
51 };
52};
53
54struct at91_ebi;
55
56struct at91_ebi_dev {
57 struct list_head node;
58 struct at91_ebi *ebi;
59 u32 mode;
60 int numcs;
61 struct at91_ebi_dev_config configs[];
62};
63
64struct at91_ebi_caps {
65 unsigned int available_cs;
66 const struct reg_field *ebi_csa;
67 void (*get_config)(struct at91_ebi_dev *ebid,
68 struct at91_ebi_dev_config *conf);
69 int (*xlate_config)(struct at91_ebi_dev *ebid,
70 struct device_node *configs_np,
71 struct at91_ebi_dev_config *conf);
72 int (*apply_config)(struct at91_ebi_dev *ebid,
73 struct at91_ebi_dev_config *conf);
74 int (*init)(struct at91_ebi *ebi);
75};
76
77struct at91_ebi {
78 struct clk *clk;
79 struct regmap *smc;
80 struct regmap *matrix;
81
82 struct regmap_field *ebi_csa;
83
84 struct device *dev;
85 const struct at91_ebi_caps *caps;
86 struct list_head devs;
87 union {
88 struct at91sam9_smc_generic_fields sam9;
89 };
90};
91
92static void at91sam9_ebi_get_config(struct at91_ebi_dev *ebid,
93 struct at91_ebi_dev_config *conf)
94{
95 struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
96 unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
97 struct at91sam9_ebi_dev_config *config = &conf->sam9;
98 struct at91sam9_smc_timings *timings = &config->timings;
99 unsigned int val;
100
101 regmap_fields_read(fields->mode, conf->cs, &val);
102 config->mode = val & ~AT91_SMC_TDF;
103
104 val = (val & AT91_SMC_TDF) >> 16;
105 timings->tdf_ns = clk_rate * val;
106
107 regmap_fields_read(fields->setup, conf->cs, &val);
108 timings->ncs_rd_setup_ns = (val >> 24) & 0x1f;
109 timings->ncs_rd_setup_ns += ((val >> 29) & 0x1) * 128;
110 timings->ncs_rd_setup_ns *= clk_rate;
111 timings->nrd_setup_ns = (val >> 16) & 0x1f;
112 timings->nrd_setup_ns += ((val >> 21) & 0x1) * 128;
113 timings->nrd_setup_ns *= clk_rate;
114 timings->ncs_wr_setup_ns = (val >> 8) & 0x1f;
115 timings->ncs_wr_setup_ns += ((val >> 13) & 0x1) * 128;
116 timings->ncs_wr_setup_ns *= clk_rate;
117 timings->nwe_setup_ns = val & 0x1f;
118 timings->nwe_setup_ns += ((val >> 5) & 0x1) * 128;
119 timings->nwe_setup_ns *= clk_rate;
120
121 regmap_fields_read(fields->pulse, conf->cs, &val);
122 timings->ncs_rd_pulse_ns = (val >> 24) & 0x3f;
123 timings->ncs_rd_pulse_ns += ((val >> 30) & 0x1) * 256;
124 timings->ncs_rd_pulse_ns *= clk_rate;
125 timings->nrd_pulse_ns = (val >> 16) & 0x3f;
126 timings->nrd_pulse_ns += ((val >> 22) & 0x1) * 256;
127 timings->nrd_pulse_ns *= clk_rate;
128 timings->ncs_wr_pulse_ns = (val >> 8) & 0x3f;
129 timings->ncs_wr_pulse_ns += ((val >> 14) & 0x1) * 256;
130 timings->ncs_wr_pulse_ns *= clk_rate;
131 timings->nwe_pulse_ns = val & 0x3f;
132 timings->nwe_pulse_ns += ((val >> 6) & 0x1) * 256;
133 timings->nwe_pulse_ns *= clk_rate;
134
135 regmap_fields_read(fields->cycle, conf->cs, &val);
136 timings->nrd_cycle_ns = (val >> 16) & 0x7f;
137 timings->nrd_cycle_ns += ((val >> 23) & 0x3) * 256;
138 timings->nrd_cycle_ns *= clk_rate;
139 timings->nwe_cycle_ns = val & 0x7f;
140 timings->nwe_cycle_ns += ((val >> 7) & 0x3) * 256;
141 timings->nwe_cycle_ns *= clk_rate;
142}
143
144static int at91_xlate_timing(struct device_node *np, const char *prop,
145 u32 *val, bool *required)
146{
147 if (!of_property_read_u32(np, prop, val)) {
148 *required = true;
149 return 0;
150 }
151
152 if (*required)
153 return -EINVAL;
154
155 return 0;
156}
157
158static int at91sam9_smc_xslate_timings(struct at91_ebi_dev *ebid,
159 struct device_node *np,
160 struct at91sam9_smc_timings *timings,
161 bool *required)
162{
163 int ret;
164
165 ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-setup-ns",
166 &timings->ncs_rd_setup_ns, required);
167 if (ret)
168 goto out;
169
170 ret = at91_xlate_timing(np, "atmel,smc-nrd-setup-ns",
171 &timings->nrd_setup_ns, required);
172 if (ret)
173 goto out;
174
175 ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-setup-ns",
176 &timings->ncs_wr_setup_ns, required);
177 if (ret)
178 goto out;
179
180 ret = at91_xlate_timing(np, "atmel,smc-nwe-setup-ns",
181 &timings->nwe_setup_ns, required);
182 if (ret)
183 goto out;
184
185 ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-pulse-ns",
186 &timings->ncs_rd_pulse_ns, required);
187 if (ret)
188 goto out;
189
190 ret = at91_xlate_timing(np, "atmel,smc-nrd-pulse-ns",
191 &timings->nrd_pulse_ns, required);
192 if (ret)
193 goto out;
194
195 ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-pulse-ns",
196 &timings->ncs_wr_pulse_ns, required);
197 if (ret)
198 goto out;
199
200 ret = at91_xlate_timing(np, "atmel,smc-nwe-pulse-ns",
201 &timings->nwe_pulse_ns, required);
202 if (ret)
203 goto out;
204
205 ret = at91_xlate_timing(np, "atmel,smc-nwe-cycle-ns",
206 &timings->nwe_cycle_ns, required);
207 if (ret)
208 goto out;
209
210 ret = at91_xlate_timing(np, "atmel,smc-nrd-cycle-ns",
211 &timings->nrd_cycle_ns, required);
212 if (ret)
213 goto out;
214
215 ret = at91_xlate_timing(np, "atmel,smc-tdf-ns",
216 &timings->tdf_ns, required);
217
218out:
219 if (ret)
220 dev_err(ebid->ebi->dev,
221 "missing or invalid timings definition in %s",
222 np->full_name);
223
224 return ret;
225}
226
227static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid,
228 struct device_node *np,
229 struct at91_ebi_dev_config *conf)
230{
231 struct at91sam9_ebi_dev_config *config = &conf->sam9;
232 bool required = false;
233 const char *tmp_str;
234 u32 tmp;
235 int ret;
236
237 ret = of_property_read_u32(np, "atmel,smc-bus-width", &tmp);
238 if (!ret) {
239 switch (tmp) {
240 case 8:
241 config->mode |= AT91_SMC_DBW_8;
242 break;
243
244 case 16:
245 config->mode |= AT91_SMC_DBW_16;
246 break;
247
248 case 32:
249 config->mode |= AT91_SMC_DBW_32;
250 break;
251
252 default:
253 return -EINVAL;
254 }
255
256 required = true;
257 }
258
259 if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) {
260 config->mode |= AT91_SMC_TDFMODE_OPTIMIZED;
261 required = true;
262 }
263
264 tmp_str = NULL;
265 of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str);
266 if (tmp_str && !strcmp(tmp_str, "write")) {
267 config->mode |= AT91_SMC_BAT_WRITE;
268 required = true;
269 }
270
271 tmp_str = NULL;
272 of_property_read_string(np, "atmel,smc-read-mode", &tmp_str);
273 if (tmp_str && !strcmp(tmp_str, "nrd")) {
274 config->mode |= AT91_SMC_READMODE_NRD;
275 required = true;
276 }
277
278 tmp_str = NULL;
279 of_property_read_string(np, "atmel,smc-write-mode", &tmp_str);
280 if (tmp_str && !strcmp(tmp_str, "nwe")) {
281 config->mode |= AT91_SMC_WRITEMODE_NWE;
282 required = true;
283 }
284
285 tmp_str = NULL;
286 of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str);
287 if (tmp_str) {
288 if (!strcmp(tmp_str, "frozen"))
289 config->mode |= AT91_SMC_EXNWMODE_FROZEN;
290 else if (!strcmp(tmp_str, "ready"))
291 config->mode |= AT91_SMC_EXNWMODE_READY;
292 else if (strcmp(tmp_str, "disabled"))
293 return -EINVAL;
294
295 required = true;
296 }
297
298 ret = of_property_read_u32(np, "atmel,smc-page-mode", &tmp);
299 if (!ret) {
300 switch (tmp) {
301 case 4:
302 config->mode |= AT91_SMC_PS_4;
303 break;
304
305 case 8:
306 config->mode |= AT91_SMC_PS_8;
307 break;
308
309 case 16:
310 config->mode |= AT91_SMC_PS_16;
311 break;
312
313 case 32:
314 config->mode |= AT91_SMC_PS_32;
315 break;
316
317 default:
318 return -EINVAL;
319 }
320
321 config->mode |= AT91_SMC_PMEN;
322 required = true;
323 }
324
325 ret = at91sam9_smc_xslate_timings(ebid, np, &config->timings,
326 &required);
327 if (ret)
328 return ret;
329
330 return required;
331}
332
333static int at91sam9_ebi_apply_config(struct at91_ebi_dev *ebid,
334 struct at91_ebi_dev_config *conf)
335{
336 unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
337 struct at91sam9_ebi_dev_config *config = &conf->sam9;
338 struct at91sam9_smc_timings *timings = &config->timings;
339 struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
340 u32 coded_val;
341 u32 val;
342
343 coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
344 timings->ncs_rd_setup_ns);
345 val = AT91SAM9_SMC_NCS_NRDSETUP(coded_val);
346 coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
347 timings->nrd_setup_ns);
348 val |= AT91SAM9_SMC_NRDSETUP(coded_val);
349 coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
350 timings->ncs_wr_setup_ns);
351 val |= AT91SAM9_SMC_NCS_WRSETUP(coded_val);
352 coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
353 timings->nwe_setup_ns);
354 val |= AT91SAM9_SMC_NWESETUP(coded_val);
355 regmap_fields_write(fields->setup, conf->cs, val);
356
357 coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
358 timings->ncs_rd_pulse_ns);
359 val = AT91SAM9_SMC_NCS_NRDPULSE(coded_val);
360 coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
361 timings->nrd_pulse_ns);
362 val |= AT91SAM9_SMC_NRDPULSE(coded_val);
363 coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
364 timings->ncs_wr_pulse_ns);
365 val |= AT91SAM9_SMC_NCS_WRPULSE(coded_val);
366 coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
367 timings->nwe_pulse_ns);
368 val |= AT91SAM9_SMC_NWEPULSE(coded_val);
369 regmap_fields_write(fields->pulse, conf->cs, val);
370
371 coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate,
372 timings->nrd_cycle_ns);
373 val = AT91SAM9_SMC_NRDCYCLE(coded_val);
374 coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate,
375 timings->nwe_cycle_ns);
376 val |= AT91SAM9_SMC_NWECYCLE(coded_val);
377 regmap_fields_write(fields->cycle, conf->cs, val);
378
379 val = DIV_ROUND_UP(timings->tdf_ns, clk_rate);
380 if (val > AT91_SMC_TDF_MAX)
381 val = AT91_SMC_TDF_MAX;
382 regmap_fields_write(fields->mode, conf->cs,
383 config->mode | AT91_SMC_TDF_(val));
384
385 return 0;
386}
387
388static int at91sam9_ebi_init(struct at91_ebi *ebi)
389{
390 struct at91sam9_smc_generic_fields *fields = &ebi->sam9;
391 struct reg_field field = REG_FIELD(0, 0, 31);
392
393 field.id_size = fls(ebi->caps->available_cs);
394 field.id_offset = AT91SAM9_SMC_GENERIC_BLK_SZ;
395
396 field.reg = AT91SAM9_SMC_SETUP(AT91SAM9_SMC_GENERIC);
397 fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
398 if (IS_ERR(fields->setup))
399 return PTR_ERR(fields->setup);
400
401 field.reg = AT91SAM9_SMC_PULSE(AT91SAM9_SMC_GENERIC);
402 fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
403 if (IS_ERR(fields->pulse))
404 return PTR_ERR(fields->pulse);
405
406 field.reg = AT91SAM9_SMC_CYCLE(AT91SAM9_SMC_GENERIC);
407 fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
408 if (IS_ERR(fields->cycle))
409 return PTR_ERR(fields->cycle);
410
411 field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC);
412 fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
413 if (IS_ERR(fields->mode))
414 return PTR_ERR(fields->mode);
415
416 return 0;
417}
418
419static int sama5d3_ebi_init(struct at91_ebi *ebi)
420{
421 struct at91sam9_smc_generic_fields *fields = &ebi->sam9;
422 struct reg_field field = REG_FIELD(0, 0, 31);
423
424 field.id_size = fls(ebi->caps->available_cs);
425 field.id_offset = SAMA5_SMC_GENERIC_BLK_SZ;
426
427 field.reg = AT91SAM9_SMC_SETUP(SAMA5_SMC_GENERIC);
428 fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
429 if (IS_ERR(fields->setup))
430 return PTR_ERR(fields->setup);
431
432 field.reg = AT91SAM9_SMC_PULSE(SAMA5_SMC_GENERIC);
433 fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
434 if (IS_ERR(fields->pulse))
435 return PTR_ERR(fields->pulse);
436
437 field.reg = AT91SAM9_SMC_CYCLE(SAMA5_SMC_GENERIC);
438 fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
439 if (IS_ERR(fields->cycle))
440 return PTR_ERR(fields->cycle);
441
442 field.reg = SAMA5_SMC_MODE(SAMA5_SMC_GENERIC);
443 fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
444 if (IS_ERR(fields->mode))
445 return PTR_ERR(fields->mode);
446
447 return 0;
448}
449
450static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
451 int reg_cells)
452{
453 const struct at91_ebi_caps *caps = ebi->caps;
454 struct at91_ebi_dev_config conf = { };
455 struct device *dev = ebi->dev;
456 struct at91_ebi_dev *ebid;
457 int ret, numcs = 0, i;
458 bool apply = false;
459
460 numcs = of_property_count_elems_of_size(np, "reg",
461 reg_cells * sizeof(u32));
462 if (numcs <= 0) {
463 dev_err(dev, "invalid reg property in %s\n", np->full_name);
464 return -EINVAL;
465 }
466
467 ebid = devm_kzalloc(ebi->dev,
468 sizeof(*ebid) + (numcs * sizeof(*ebid->configs)),
469 GFP_KERNEL);
470 if (!ebid)
471 return -ENOMEM;
472
473 ebid->ebi = ebi;
474
475 ret = caps->xlate_config(ebid, np, &conf);
476 if (ret < 0)
477 return ret;
478 else if (ret)
479 apply = true;
480
481 for (i = 0; i < numcs; i++) {
482 u32 cs;
483
484 ret = of_property_read_u32_index(np, "reg", i * reg_cells,
485 &cs);
486 if (ret)
487 return ret;
488
489 if (cs > AT91_MATRIX_EBI_NUM_CS ||
490 !(ebi->caps->available_cs & BIT(cs))) {
491 dev_err(dev, "invalid reg property in %s\n",
492 np->full_name);
493 return -EINVAL;
494 }
495
496 ebid->configs[i].cs = cs;
497
498 if (apply) {
499 conf.cs = cs;
500 ret = caps->apply_config(ebid, &conf);
501 if (ret)
502 return ret;
503 }
504
505 caps->get_config(ebid, &ebid->configs[i]);
506
507 /*
508 * Attach the EBI device to the generic SMC logic if at least
509 * one "atmel,smc-" property is present.
510 */
511 if (ebi->ebi_csa && ret)
512 regmap_field_update_bits(ebi->ebi_csa,
513 BIT(cs), 0);
514 }
515
516 list_add_tail(&ebid->node, &ebi->devs);
517
518 return 0;
519}
520
521static const struct reg_field at91sam9260_ebi_csa =
522 REG_FIELD(AT91SAM9260_MATRIX_EBICSA, 0,
523 AT91_MATRIX_EBI_NUM_CS - 1);
524
525static const struct at91_ebi_caps at91sam9260_ebi_caps = {
526 .available_cs = 0xff,
527 .ebi_csa = &at91sam9260_ebi_csa,
528 .get_config = at91sam9_ebi_get_config,
529 .xlate_config = at91sam9_ebi_xslate_config,
530 .apply_config = at91sam9_ebi_apply_config,
531 .init = at91sam9_ebi_init,
532};
533
534static const struct reg_field at91sam9261_ebi_csa =
535 REG_FIELD(AT91SAM9261_MATRIX_EBICSA, 0,
536 AT91_MATRIX_EBI_NUM_CS - 1);
537
538static const struct at91_ebi_caps at91sam9261_ebi_caps = {
539 .available_cs = 0xff,
540 .ebi_csa = &at91sam9261_ebi_csa,
541 .get_config = at91sam9_ebi_get_config,
542 .xlate_config = at91sam9_ebi_xslate_config,
543 .apply_config = at91sam9_ebi_apply_config,
544 .init = at91sam9_ebi_init,
545};
546
547static const struct reg_field at91sam9263_ebi0_csa =
548 REG_FIELD(AT91SAM9263_MATRIX_EBI0CSA, 0,
549 AT91_MATRIX_EBI_NUM_CS - 1);
550
551static const struct at91_ebi_caps at91sam9263_ebi0_caps = {
552 .available_cs = 0x3f,
553 .ebi_csa = &at91sam9263_ebi0_csa,
554 .get_config = at91sam9_ebi_get_config,
555 .xlate_config = at91sam9_ebi_xslate_config,
556 .apply_config = at91sam9_ebi_apply_config,
557 .init = at91sam9_ebi_init,
558};
559
560static const struct reg_field at91sam9263_ebi1_csa =
561 REG_FIELD(AT91SAM9263_MATRIX_EBI1CSA, 0,
562 AT91_MATRIX_EBI_NUM_CS - 1);
563
564static const struct at91_ebi_caps at91sam9263_ebi1_caps = {
565 .available_cs = 0x7,
566 .ebi_csa = &at91sam9263_ebi1_csa,
567 .get_config = at91sam9_ebi_get_config,
568 .xlate_config = at91sam9_ebi_xslate_config,
569 .apply_config = at91sam9_ebi_apply_config,
570 .init = at91sam9_ebi_init,
571};
572
573static const struct reg_field at91sam9rl_ebi_csa =
574 REG_FIELD(AT91SAM9RL_MATRIX_EBICSA, 0,
575 AT91_MATRIX_EBI_NUM_CS - 1);
576
577static const struct at91_ebi_caps at91sam9rl_ebi_caps = {
578 .available_cs = 0x3f,
579 .ebi_csa = &at91sam9rl_ebi_csa,
580 .get_config = at91sam9_ebi_get_config,
581 .xlate_config = at91sam9_ebi_xslate_config,
582 .apply_config = at91sam9_ebi_apply_config,
583 .init = at91sam9_ebi_init,
584};
585
586static const struct reg_field at91sam9g45_ebi_csa =
587 REG_FIELD(AT91SAM9G45_MATRIX_EBICSA, 0,
588 AT91_MATRIX_EBI_NUM_CS - 1);
589
590static const struct at91_ebi_caps at91sam9g45_ebi_caps = {
591 .available_cs = 0x3f,
592 .ebi_csa = &at91sam9g45_ebi_csa,
593 .get_config = at91sam9_ebi_get_config,
594 .xlate_config = at91sam9_ebi_xslate_config,
595 .apply_config = at91sam9_ebi_apply_config,
596 .init = at91sam9_ebi_init,
597};
598
599static const struct at91_ebi_caps at91sam9x5_ebi_caps = {
600 .available_cs = 0x3f,
601 .ebi_csa = &at91sam9263_ebi0_csa,
602 .get_config = at91sam9_ebi_get_config,
603 .xlate_config = at91sam9_ebi_xslate_config,
604 .apply_config = at91sam9_ebi_apply_config,
605 .init = at91sam9_ebi_init,
606};
607
608static const struct at91_ebi_caps sama5d3_ebi_caps = {
609 .available_cs = 0xf,
610 .get_config = at91sam9_ebi_get_config,
611 .xlate_config = at91sam9_ebi_xslate_config,
612 .apply_config = at91sam9_ebi_apply_config,
613 .init = sama5d3_ebi_init,
614};
615
616static const struct of_device_id at91_ebi_id_table[] = {
617 {
618 .compatible = "atmel,at91sam9260-ebi",
619 .data = &at91sam9260_ebi_caps,
620 },
621 {
622 .compatible = "atmel,at91sam9261-ebi",
623 .data = &at91sam9261_ebi_caps,
624 },
625 {
626 .compatible = "atmel,at91sam9263-ebi0",
627 .data = &at91sam9263_ebi0_caps,
628 },
629 {
630 .compatible = "atmel,at91sam9263-ebi1",
631 .data = &at91sam9263_ebi1_caps,
632 },
633 {
634 .compatible = "atmel,at91sam9rl-ebi",
635 .data = &at91sam9rl_ebi_caps,
636 },
637 {
638 .compatible = "atmel,at91sam9g45-ebi",
639 .data = &at91sam9g45_ebi_caps,
640 },
641 {
642 .compatible = "atmel,at91sam9x5-ebi",
643 .data = &at91sam9x5_ebi_caps,
644 },
645 {
646 .compatible = "atmel,sama5d3-ebi",
647 .data = &sama5d3_ebi_caps,
648 },
649 { /* sentinel */ }
650};
651MODULE_DEVICE_TABLE(of, at91_ebi_id_table);
652
653static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np)
654{
655 struct device *dev = ebi->dev;
656 struct property *newprop;
657
658 newprop = devm_kzalloc(dev, sizeof(*newprop), GFP_KERNEL);
659 if (!newprop)
660 return -ENOMEM;
661
662 newprop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
663 if (!newprop->name)
664 return -ENOMEM;
665
666 newprop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
667 if (!newprop->name)
668 return -ENOMEM;
669
670 newprop->length = sizeof("disabled");
671
672 return of_update_property(np, newprop);
673}
674
675static int at91_ebi_probe(struct platform_device *pdev)
676{
677 struct device *dev = &pdev->dev;
678 struct device_node *child, *np = dev->of_node;
679 const struct of_device_id *match;
680 struct at91_ebi *ebi;
681 int ret, reg_cells;
682 struct clk *clk;
683 u32 val;
684
685 match = of_match_device(at91_ebi_id_table, dev);
686 if (!match || !match->data)
687 return -EINVAL;
688
689 ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL);
690 if (!ebi)
691 return -ENOMEM;
692
693 INIT_LIST_HEAD(&ebi->devs);
694 ebi->caps = match->data;
695 ebi->dev = dev;
696
697 clk = devm_clk_get(dev, NULL);
698 if (IS_ERR(clk))
699 return PTR_ERR(clk);
700
701 ebi->clk = clk;
702
703 ebi->smc = syscon_regmap_lookup_by_phandle(np, "atmel,smc");
704 if (IS_ERR(ebi->smc))
705 return PTR_ERR(ebi->smc);
706
707 /*
708 * The sama5d3 does not provide an EBICSA register and thus does need
709 * to access the matrix registers.
710 */
711 if (ebi->caps->ebi_csa) {
712 ebi->matrix =
713 syscon_regmap_lookup_by_phandle(np, "atmel,matrix");
714 if (IS_ERR(ebi->matrix))
715 return PTR_ERR(ebi->matrix);
716
717 ebi->ebi_csa = regmap_field_alloc(ebi->matrix,
718 *ebi->caps->ebi_csa);
719 if (IS_ERR(ebi->ebi_csa))
720 return PTR_ERR(ebi->ebi_csa);
721 }
722
723 ret = ebi->caps->init(ebi);
724 if (ret)
725 return ret;
726
727 ret = of_property_read_u32(np, "#address-cells", &val);
728 if (ret) {
729 dev_err(dev, "missing #address-cells property\n");
730 return ret;
731 }
732
733 reg_cells = val;
734
735 ret = of_property_read_u32(np, "#size-cells", &val);
736 if (ret) {
737 dev_err(dev, "missing #address-cells property\n");
738 return ret;
739 }
740
741 reg_cells += val;
742
743 for_each_available_child_of_node(np, child) {
744 if (!of_find_property(child, "reg", NULL))
745 continue;
746
747 ret = at91_ebi_dev_setup(ebi, child, reg_cells);
748 if (ret) {
749 dev_err(dev, "failed to configure EBI bus for %s, disabling the device",
750 child->full_name);
751
752 ret = at91_ebi_dev_disable(ebi, child);
753 if (ret)
754 return ret;
755 }
756 }
757
758 return of_platform_populate(np, NULL, NULL, dev);
759}
760
761static struct platform_driver at91_ebi_driver = {
762 .driver = {
763 .name = "atmel-ebi",
764 .of_match_table = at91_ebi_id_table,
765 },
766};
767module_platform_driver_probe(at91_ebi_driver, at91_ebi_probe);
768
769MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>");
770MODULE_DESCRIPTION("Atmel EBI driver");
771MODULE_LICENSE("GPL");