15db3fb40STudor Ambarus // SPDX-License-Identifier: GPL-2.0
26a4ec4cdSBoris Brezillon /*
36a4ec4cdSBoris Brezillon * EBI driver for Atmel chips
46a4ec4cdSBoris Brezillon * inspired by the fsl weim bus driver
56a4ec4cdSBoris Brezillon *
66a4ec4cdSBoris Brezillon * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
76a4ec4cdSBoris Brezillon */
86a4ec4cdSBoris Brezillon
96a4ec4cdSBoris Brezillon #include <linux/clk.h>
106a4ec4cdSBoris Brezillon #include <linux/io.h>
116a4ec4cdSBoris Brezillon #include <linux/mfd/syscon.h>
126a4ec4cdSBoris Brezillon #include <linux/mfd/syscon/atmel-matrix.h>
136a4ec4cdSBoris Brezillon #include <linux/mfd/syscon/atmel-smc.h>
148a86a093SPaul Gortmaker #include <linux/init.h>
156a4ec4cdSBoris Brezillon #include <linux/of_device.h>
166a4ec4cdSBoris Brezillon #include <linux/regmap.h>
173e0863ddSTudor Ambarus #include <soc/at91/atmel-sfr.h>
186a4ec4cdSBoris Brezillon
19dbbf9839STudor Ambarus #define AT91_EBI_NUM_CS 8
20dbbf9839STudor Ambarus
219453fa46SBoris Brezillon struct atmel_ebi_dev_config {
226a4ec4cdSBoris Brezillon int cs;
238eb8c7d8SBoris Brezillon struct atmel_smc_cs_conf smcconf;
246a4ec4cdSBoris Brezillon };
256a4ec4cdSBoris Brezillon
269453fa46SBoris Brezillon struct atmel_ebi;
276a4ec4cdSBoris Brezillon
289453fa46SBoris Brezillon struct atmel_ebi_dev {
296a4ec4cdSBoris Brezillon struct list_head node;
309453fa46SBoris Brezillon struct atmel_ebi *ebi;
316a4ec4cdSBoris Brezillon u32 mode;
326a4ec4cdSBoris Brezillon int numcs;
339453fa46SBoris Brezillon struct atmel_ebi_dev_config configs[];
346a4ec4cdSBoris Brezillon };
356a4ec4cdSBoris Brezillon
369453fa46SBoris Brezillon struct atmel_ebi_caps {
376a4ec4cdSBoris Brezillon unsigned int available_cs;
38d9f81dadSBoris Brezillon unsigned int ebi_csa_offs;
39ad7bdbc8STudor Ambarus const char *regmap_name;
409453fa46SBoris Brezillon void (*get_config)(struct atmel_ebi_dev *ebid,
419453fa46SBoris Brezillon struct atmel_ebi_dev_config *conf);
429453fa46SBoris Brezillon int (*xlate_config)(struct atmel_ebi_dev *ebid,
436a4ec4cdSBoris Brezillon struct device_node *configs_np,
449453fa46SBoris Brezillon struct atmel_ebi_dev_config *conf);
459453fa46SBoris Brezillon void (*apply_config)(struct atmel_ebi_dev *ebid,
469453fa46SBoris Brezillon struct atmel_ebi_dev_config *conf);
476a4ec4cdSBoris Brezillon };
486a4ec4cdSBoris Brezillon
499453fa46SBoris Brezillon struct atmel_ebi {
506a4ec4cdSBoris Brezillon struct clk *clk;
51ad7bdbc8STudor Ambarus struct regmap *regmap;
5287108dc7SBoris Brezillon struct {
5387108dc7SBoris Brezillon struct regmap *regmap;
5487108dc7SBoris Brezillon struct clk *clk;
55b0f3ab20SLudovic Desroches const struct atmel_hsmc_reg_layout *layout;
5687108dc7SBoris Brezillon } smc;
576a4ec4cdSBoris Brezillon
586a4ec4cdSBoris Brezillon struct device *dev;
599453fa46SBoris Brezillon const struct atmel_ebi_caps *caps;
606a4ec4cdSBoris Brezillon struct list_head devs;
616a4ec4cdSBoris Brezillon };
628eb8c7d8SBoris Brezillon
638eb8c7d8SBoris Brezillon struct atmel_smc_timing_xlate {
648eb8c7d8SBoris Brezillon const char *name;
658eb8c7d8SBoris Brezillon int (*converter)(struct atmel_smc_cs_conf *conf,
668eb8c7d8SBoris Brezillon unsigned int shift, unsigned int nycles);
678eb8c7d8SBoris Brezillon unsigned int shift;
686a4ec4cdSBoris Brezillon };
696a4ec4cdSBoris Brezillon
708eb8c7d8SBoris Brezillon #define ATMEL_SMC_SETUP_XLATE(nm, pos) \
718eb8c7d8SBoris Brezillon { .name = nm, .converter = atmel_smc_cs_conf_set_setup, .shift = pos}
728eb8c7d8SBoris Brezillon
738eb8c7d8SBoris Brezillon #define ATMEL_SMC_PULSE_XLATE(nm, pos) \
748eb8c7d8SBoris Brezillon { .name = nm, .converter = atmel_smc_cs_conf_set_pulse, .shift = pos}
758eb8c7d8SBoris Brezillon
768eb8c7d8SBoris Brezillon #define ATMEL_SMC_CYCLE_XLATE(nm, pos) \
773fb3b3c4SAlexander Dahl { .name = nm, .converter = atmel_smc_cs_conf_set_cycle, .shift = pos}
788eb8c7d8SBoris Brezillon
at91sam9_ebi_get_config(struct atmel_ebi_dev * ebid,struct atmel_ebi_dev_config * conf)799453fa46SBoris Brezillon static void at91sam9_ebi_get_config(struct atmel_ebi_dev *ebid,
809453fa46SBoris Brezillon struct atmel_ebi_dev_config *conf)
816a4ec4cdSBoris Brezillon {
828eb8c7d8SBoris Brezillon atmel_smc_cs_conf_get(ebid->ebi->smc.regmap, conf->cs,
838eb8c7d8SBoris Brezillon &conf->smcconf);
846a4ec4cdSBoris Brezillon }
856a4ec4cdSBoris Brezillon
sama5_ebi_get_config(struct atmel_ebi_dev * ebid,struct atmel_ebi_dev_config * conf)869453fa46SBoris Brezillon static void sama5_ebi_get_config(struct atmel_ebi_dev *ebid,
879453fa46SBoris Brezillon struct atmel_ebi_dev_config *conf)
886a4ec4cdSBoris Brezillon {
89b0f3ab20SLudovic Desroches atmel_hsmc_cs_conf_get(ebid->ebi->smc.regmap, ebid->ebi->smc.layout,
90b0f3ab20SLudovic Desroches conf->cs, &conf->smcconf);
916a4ec4cdSBoris Brezillon }
926a4ec4cdSBoris Brezillon
938eb8c7d8SBoris Brezillon static const struct atmel_smc_timing_xlate timings_xlate_table[] = {
948eb8c7d8SBoris Brezillon ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-rd-setup-ns",
958eb8c7d8SBoris Brezillon ATMEL_SMC_NCS_RD_SHIFT),
968eb8c7d8SBoris Brezillon ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-wr-setup-ns",
978eb8c7d8SBoris Brezillon ATMEL_SMC_NCS_WR_SHIFT),
988eb8c7d8SBoris Brezillon ATMEL_SMC_SETUP_XLATE("atmel,smc-nrd-setup-ns", ATMEL_SMC_NRD_SHIFT),
998eb8c7d8SBoris Brezillon ATMEL_SMC_SETUP_XLATE("atmel,smc-nwe-setup-ns", ATMEL_SMC_NWE_SHIFT),
1008eb8c7d8SBoris Brezillon ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-rd-pulse-ns",
1018eb8c7d8SBoris Brezillon ATMEL_SMC_NCS_RD_SHIFT),
1028eb8c7d8SBoris Brezillon ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-wr-pulse-ns",
1038eb8c7d8SBoris Brezillon ATMEL_SMC_NCS_WR_SHIFT),
1048eb8c7d8SBoris Brezillon ATMEL_SMC_PULSE_XLATE("atmel,smc-nrd-pulse-ns", ATMEL_SMC_NRD_SHIFT),
1058eb8c7d8SBoris Brezillon ATMEL_SMC_PULSE_XLATE("atmel,smc-nwe-pulse-ns", ATMEL_SMC_NWE_SHIFT),
1068eb8c7d8SBoris Brezillon ATMEL_SMC_CYCLE_XLATE("atmel,smc-nrd-cycle-ns", ATMEL_SMC_NRD_SHIFT),
1078eb8c7d8SBoris Brezillon ATMEL_SMC_CYCLE_XLATE("atmel,smc-nwe-cycle-ns", ATMEL_SMC_NWE_SHIFT),
1088eb8c7d8SBoris Brezillon };
1096a4ec4cdSBoris Brezillon
atmel_ebi_xslate_smc_timings(struct atmel_ebi_dev * ebid,struct device_node * np,struct atmel_smc_cs_conf * smcconf)1109453fa46SBoris Brezillon static int atmel_ebi_xslate_smc_timings(struct atmel_ebi_dev *ebid,
1116a4ec4cdSBoris Brezillon struct device_node *np,
1128eb8c7d8SBoris Brezillon struct atmel_smc_cs_conf *smcconf)
1136a4ec4cdSBoris Brezillon {
1148eb8c7d8SBoris Brezillon unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
1158eb8c7d8SBoris Brezillon unsigned int clk_period_ns = NSEC_PER_SEC / clk_rate;
1168eb8c7d8SBoris Brezillon bool required = false;
1178eb8c7d8SBoris Brezillon unsigned int ncycles;
1188eb8c7d8SBoris Brezillon int ret, i;
1198eb8c7d8SBoris Brezillon u32 val;
1206a4ec4cdSBoris Brezillon
1218eb8c7d8SBoris Brezillon ret = of_property_read_u32(np, "atmel,smc-tdf-ns", &val);
1228eb8c7d8SBoris Brezillon if (!ret) {
1238eb8c7d8SBoris Brezillon required = true;
1248eb8c7d8SBoris Brezillon ncycles = DIV_ROUND_UP(val, clk_period_ns);
1251f6b5390SAlexander Dahl if (ncycles > ATMEL_SMC_MODE_TDF_MAX) {
1268eb8c7d8SBoris Brezillon ret = -EINVAL;
1278eb8c7d8SBoris Brezillon goto out;
1288eb8c7d8SBoris Brezillon }
1298eb8c7d8SBoris Brezillon
1301f6b5390SAlexander Dahl if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
1311f6b5390SAlexander Dahl ncycles = ATMEL_SMC_MODE_TDF_MIN;
1321f6b5390SAlexander Dahl
1338eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles);
1348eb8c7d8SBoris Brezillon }
1358eb8c7d8SBoris Brezillon
1368eb8c7d8SBoris Brezillon for (i = 0; i < ARRAY_SIZE(timings_xlate_table); i++) {
1378eb8c7d8SBoris Brezillon const struct atmel_smc_timing_xlate *xlate;
1388eb8c7d8SBoris Brezillon
1398eb8c7d8SBoris Brezillon xlate = &timings_xlate_table[i];
1408eb8c7d8SBoris Brezillon
1418eb8c7d8SBoris Brezillon ret = of_property_read_u32(np, xlate->name, &val);
1428eb8c7d8SBoris Brezillon if (ret) {
1438eb8c7d8SBoris Brezillon if (!required)
1448eb8c7d8SBoris Brezillon continue;
1458eb8c7d8SBoris Brezillon else
1468eb8c7d8SBoris Brezillon break;
1478eb8c7d8SBoris Brezillon }
1488eb8c7d8SBoris Brezillon
1498eb8c7d8SBoris Brezillon if (!required) {
1508eb8c7d8SBoris Brezillon ret = -EINVAL;
1518eb8c7d8SBoris Brezillon break;
1528eb8c7d8SBoris Brezillon }
1538eb8c7d8SBoris Brezillon
1548eb8c7d8SBoris Brezillon ncycles = DIV_ROUND_UP(val, clk_period_ns);
1558eb8c7d8SBoris Brezillon ret = xlate->converter(smcconf, xlate->shift, ncycles);
1566a4ec4cdSBoris Brezillon if (ret)
1576a4ec4cdSBoris Brezillon goto out;
1588eb8c7d8SBoris Brezillon }
1596a4ec4cdSBoris Brezillon
1606a4ec4cdSBoris Brezillon out:
1618eb8c7d8SBoris Brezillon if (ret) {
1626a4ec4cdSBoris Brezillon dev_err(ebid->ebi->dev,
163db749d17SRob Herring "missing or invalid timings definition in %pOF",
164db749d17SRob Herring np);
1656a4ec4cdSBoris Brezillon return ret;
1666a4ec4cdSBoris Brezillon }
1676a4ec4cdSBoris Brezillon
1688eb8c7d8SBoris Brezillon return required;
1698eb8c7d8SBoris Brezillon }
1708eb8c7d8SBoris Brezillon
atmel_ebi_xslate_smc_config(struct atmel_ebi_dev * ebid,struct device_node * np,struct atmel_ebi_dev_config * conf)1719453fa46SBoris Brezillon static int atmel_ebi_xslate_smc_config(struct atmel_ebi_dev *ebid,
1726a4ec4cdSBoris Brezillon struct device_node *np,
1739453fa46SBoris Brezillon struct atmel_ebi_dev_config *conf)
1746a4ec4cdSBoris Brezillon {
1758eb8c7d8SBoris Brezillon struct atmel_smc_cs_conf *smcconf = &conf->smcconf;
1766a4ec4cdSBoris Brezillon bool required = false;
1776a4ec4cdSBoris Brezillon const char *tmp_str;
1786a4ec4cdSBoris Brezillon u32 tmp;
1796a4ec4cdSBoris Brezillon int ret;
1806a4ec4cdSBoris Brezillon
1816a4ec4cdSBoris Brezillon ret = of_property_read_u32(np, "atmel,smc-bus-width", &tmp);
1826a4ec4cdSBoris Brezillon if (!ret) {
1836a4ec4cdSBoris Brezillon switch (tmp) {
1846a4ec4cdSBoris Brezillon case 8:
1858eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_DBW_8;
1866a4ec4cdSBoris Brezillon break;
1876a4ec4cdSBoris Brezillon
1886a4ec4cdSBoris Brezillon case 16:
1898eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
1906a4ec4cdSBoris Brezillon break;
1916a4ec4cdSBoris Brezillon
1926a4ec4cdSBoris Brezillon case 32:
1938eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_DBW_32;
1946a4ec4cdSBoris Brezillon break;
1956a4ec4cdSBoris Brezillon
1966a4ec4cdSBoris Brezillon default:
1976a4ec4cdSBoris Brezillon return -EINVAL;
1986a4ec4cdSBoris Brezillon }
1996a4ec4cdSBoris Brezillon
2006a4ec4cdSBoris Brezillon required = true;
2016a4ec4cdSBoris Brezillon }
2026a4ec4cdSBoris Brezillon
2036a4ec4cdSBoris Brezillon if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) {
2048eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
2056a4ec4cdSBoris Brezillon required = true;
2066a4ec4cdSBoris Brezillon }
2076a4ec4cdSBoris Brezillon
2086a4ec4cdSBoris Brezillon tmp_str = NULL;
2096a4ec4cdSBoris Brezillon of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str);
2106a4ec4cdSBoris Brezillon if (tmp_str && !strcmp(tmp_str, "write")) {
2118eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_BAT_WRITE;
2126a4ec4cdSBoris Brezillon required = true;
2136a4ec4cdSBoris Brezillon }
2146a4ec4cdSBoris Brezillon
2156a4ec4cdSBoris Brezillon tmp_str = NULL;
2166a4ec4cdSBoris Brezillon of_property_read_string(np, "atmel,smc-read-mode", &tmp_str);
2176a4ec4cdSBoris Brezillon if (tmp_str && !strcmp(tmp_str, "nrd")) {
2188eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD;
2196a4ec4cdSBoris Brezillon required = true;
2206a4ec4cdSBoris Brezillon }
2216a4ec4cdSBoris Brezillon
2226a4ec4cdSBoris Brezillon tmp_str = NULL;
2236a4ec4cdSBoris Brezillon of_property_read_string(np, "atmel,smc-write-mode", &tmp_str);
2246a4ec4cdSBoris Brezillon if (tmp_str && !strcmp(tmp_str, "nwe")) {
2258eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_WRITEMODE_NWE;
2266a4ec4cdSBoris Brezillon required = true;
2276a4ec4cdSBoris Brezillon }
2286a4ec4cdSBoris Brezillon
2296a4ec4cdSBoris Brezillon tmp_str = NULL;
2306a4ec4cdSBoris Brezillon of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str);
2316a4ec4cdSBoris Brezillon if (tmp_str) {
2326a4ec4cdSBoris Brezillon if (!strcmp(tmp_str, "frozen"))
2338eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_FROZEN;
2346a4ec4cdSBoris Brezillon else if (!strcmp(tmp_str, "ready"))
2358eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_READY;
2366a4ec4cdSBoris Brezillon else if (strcmp(tmp_str, "disabled"))
2376a4ec4cdSBoris Brezillon return -EINVAL;
2386a4ec4cdSBoris Brezillon
2396a4ec4cdSBoris Brezillon required = true;
2406a4ec4cdSBoris Brezillon }
2416a4ec4cdSBoris Brezillon
2426a4ec4cdSBoris Brezillon ret = of_property_read_u32(np, "atmel,smc-page-mode", &tmp);
2436a4ec4cdSBoris Brezillon if (!ret) {
2446a4ec4cdSBoris Brezillon switch (tmp) {
2456a4ec4cdSBoris Brezillon case 4:
2468eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_PS_4;
2476a4ec4cdSBoris Brezillon break;
2486a4ec4cdSBoris Brezillon
2496a4ec4cdSBoris Brezillon case 8:
2508eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_PS_8;
2516a4ec4cdSBoris Brezillon break;
2526a4ec4cdSBoris Brezillon
2536a4ec4cdSBoris Brezillon case 16:
2548eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_PS_16;
2556a4ec4cdSBoris Brezillon break;
2566a4ec4cdSBoris Brezillon
2576a4ec4cdSBoris Brezillon case 32:
2588eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_PS_32;
2596a4ec4cdSBoris Brezillon break;
2606a4ec4cdSBoris Brezillon
2616a4ec4cdSBoris Brezillon default:
2626a4ec4cdSBoris Brezillon return -EINVAL;
2636a4ec4cdSBoris Brezillon }
2646a4ec4cdSBoris Brezillon
2658eb8c7d8SBoris Brezillon smcconf->mode |= ATMEL_SMC_MODE_PMEN;
2666a4ec4cdSBoris Brezillon required = true;
2676a4ec4cdSBoris Brezillon }
2686a4ec4cdSBoris Brezillon
2699453fa46SBoris Brezillon ret = atmel_ebi_xslate_smc_timings(ebid, np, &conf->smcconf);
270bc9b934bSAlexander Dahl if (ret < 0)
2718eb8c7d8SBoris Brezillon return -EINVAL;
2728eb8c7d8SBoris Brezillon
2738eb8c7d8SBoris Brezillon if ((ret > 0 && !required) || (!ret && required)) {
274db749d17SRob Herring dev_err(ebid->ebi->dev, "missing atmel,smc- properties in %pOF",
275db749d17SRob Herring np);
2768eb8c7d8SBoris Brezillon return -EINVAL;
2778eb8c7d8SBoris Brezillon }
2786a4ec4cdSBoris Brezillon
2796a4ec4cdSBoris Brezillon return required;
2806a4ec4cdSBoris Brezillon }
2816a4ec4cdSBoris Brezillon
at91sam9_ebi_apply_config(struct atmel_ebi_dev * ebid,struct atmel_ebi_dev_config * conf)2829453fa46SBoris Brezillon static void at91sam9_ebi_apply_config(struct atmel_ebi_dev *ebid,
2839453fa46SBoris Brezillon struct atmel_ebi_dev_config *conf)
2846a4ec4cdSBoris Brezillon {
2858eb8c7d8SBoris Brezillon atmel_smc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs,
2868eb8c7d8SBoris Brezillon &conf->smcconf);
2876a4ec4cdSBoris Brezillon }
2886a4ec4cdSBoris Brezillon
sama5_ebi_apply_config(struct atmel_ebi_dev * ebid,struct atmel_ebi_dev_config * conf)2899453fa46SBoris Brezillon static void sama5_ebi_apply_config(struct atmel_ebi_dev *ebid,
2909453fa46SBoris Brezillon struct atmel_ebi_dev_config *conf)
2916a4ec4cdSBoris Brezillon {
292b0f3ab20SLudovic Desroches atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, ebid->ebi->smc.layout,
293b0f3ab20SLudovic Desroches conf->cs, &conf->smcconf);
2946a4ec4cdSBoris Brezillon }
2956a4ec4cdSBoris Brezillon
atmel_ebi_dev_setup(struct atmel_ebi * ebi,struct device_node * np,int reg_cells)2969453fa46SBoris Brezillon static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
2976a4ec4cdSBoris Brezillon int reg_cells)
2986a4ec4cdSBoris Brezillon {
2999453fa46SBoris Brezillon const struct atmel_ebi_caps *caps = ebi->caps;
3009453fa46SBoris Brezillon struct atmel_ebi_dev_config conf = { };
3016a4ec4cdSBoris Brezillon struct device *dev = ebi->dev;
3029453fa46SBoris Brezillon struct atmel_ebi_dev *ebid;
303987e079eSBoris Brezillon unsigned long cslines = 0;
304987e079eSBoris Brezillon int ret, numcs = 0, nentries, i;
3056a4ec4cdSBoris Brezillon bool apply = false;
306987e079eSBoris Brezillon u32 cs;
3076a4ec4cdSBoris Brezillon
308987e079eSBoris Brezillon nentries = of_property_count_elems_of_size(np, "reg",
3096a4ec4cdSBoris Brezillon reg_cells * sizeof(u32));
310987e079eSBoris Brezillon for (i = 0; i < nentries; i++) {
311987e079eSBoris Brezillon ret = of_property_read_u32_index(np, "reg", i * reg_cells,
312987e079eSBoris Brezillon &cs);
313987e079eSBoris Brezillon if (ret)
314987e079eSBoris Brezillon return ret;
315987e079eSBoris Brezillon
316dbbf9839STudor Ambarus if (cs >= AT91_EBI_NUM_CS ||
317987e079eSBoris Brezillon !(ebi->caps->available_cs & BIT(cs))) {
318db749d17SRob Herring dev_err(dev, "invalid reg property in %pOF\n", np);
319987e079eSBoris Brezillon return -EINVAL;
320987e079eSBoris Brezillon }
321987e079eSBoris Brezillon
322987e079eSBoris Brezillon if (!test_and_set_bit(cs, &cslines))
323987e079eSBoris Brezillon numcs++;
324987e079eSBoris Brezillon }
325987e079eSBoris Brezillon
326987e079eSBoris Brezillon if (!numcs) {
327db749d17SRob Herring dev_err(dev, "invalid reg property in %pOF\n", np);
3286a4ec4cdSBoris Brezillon return -EINVAL;
3296a4ec4cdSBoris Brezillon }
3306a4ec4cdSBoris Brezillon
331f62df676SGustavo A. R. Silva ebid = devm_kzalloc(ebi->dev, struct_size(ebid, configs, numcs),
3326a4ec4cdSBoris Brezillon GFP_KERNEL);
3336a4ec4cdSBoris Brezillon if (!ebid)
3346a4ec4cdSBoris Brezillon return -ENOMEM;
3356a4ec4cdSBoris Brezillon
3366a4ec4cdSBoris Brezillon ebid->ebi = ebi;
337aaa572b9SBoris Brezillon ebid->numcs = numcs;
3386a4ec4cdSBoris Brezillon
3396a4ec4cdSBoris Brezillon ret = caps->xlate_config(ebid, np, &conf);
3406a4ec4cdSBoris Brezillon if (ret < 0)
3416a4ec4cdSBoris Brezillon return ret;
3426a4ec4cdSBoris Brezillon else if (ret)
3436a4ec4cdSBoris Brezillon apply = true;
3446a4ec4cdSBoris Brezillon
345987e079eSBoris Brezillon i = 0;
346dbbf9839STudor Ambarus for_each_set_bit(cs, &cslines, AT91_EBI_NUM_CS) {
3476a4ec4cdSBoris Brezillon ebid->configs[i].cs = cs;
3486a4ec4cdSBoris Brezillon
3496a4ec4cdSBoris Brezillon if (apply) {
3506a4ec4cdSBoris Brezillon conf.cs = cs;
3518eb8c7d8SBoris Brezillon caps->apply_config(ebid, &conf);
3526a4ec4cdSBoris Brezillon }
3536a4ec4cdSBoris Brezillon
3546a4ec4cdSBoris Brezillon caps->get_config(ebid, &ebid->configs[i]);
3556a4ec4cdSBoris Brezillon
3566a4ec4cdSBoris Brezillon /*
3576a4ec4cdSBoris Brezillon * Attach the EBI device to the generic SMC logic if at least
3586a4ec4cdSBoris Brezillon * one "atmel,smc-" property is present.
3596a4ec4cdSBoris Brezillon */
360d9f81dadSBoris Brezillon if (ebi->caps->ebi_csa_offs && apply)
361ad7bdbc8STudor Ambarus regmap_update_bits(ebi->regmap,
362d9f81dadSBoris Brezillon ebi->caps->ebi_csa_offs,
3636a4ec4cdSBoris Brezillon BIT(cs), 0);
364987e079eSBoris Brezillon
365987e079eSBoris Brezillon i++;
3666a4ec4cdSBoris Brezillon }
3676a4ec4cdSBoris Brezillon
3686a4ec4cdSBoris Brezillon list_add_tail(&ebid->node, &ebi->devs);
3696a4ec4cdSBoris Brezillon
3706a4ec4cdSBoris Brezillon return 0;
3716a4ec4cdSBoris Brezillon }
3726a4ec4cdSBoris Brezillon
3739453fa46SBoris Brezillon static const struct atmel_ebi_caps at91sam9260_ebi_caps = {
3746a4ec4cdSBoris Brezillon .available_cs = 0xff,
375d9f81dadSBoris Brezillon .ebi_csa_offs = AT91SAM9260_MATRIX_EBICSA,
376ad7bdbc8STudor Ambarus .regmap_name = "atmel,matrix",
3776a4ec4cdSBoris Brezillon .get_config = at91sam9_ebi_get_config,
3789453fa46SBoris Brezillon .xlate_config = atmel_ebi_xslate_smc_config,
3796a4ec4cdSBoris Brezillon .apply_config = at91sam9_ebi_apply_config,
3806a4ec4cdSBoris Brezillon };
3816a4ec4cdSBoris Brezillon
3829453fa46SBoris Brezillon static const struct atmel_ebi_caps at91sam9261_ebi_caps = {
3836a4ec4cdSBoris Brezillon .available_cs = 0xff,
384d9f81dadSBoris Brezillon .ebi_csa_offs = AT91SAM9261_MATRIX_EBICSA,
385ad7bdbc8STudor Ambarus .regmap_name = "atmel,matrix",
3866a4ec4cdSBoris Brezillon .get_config = at91sam9_ebi_get_config,
3879453fa46SBoris Brezillon .xlate_config = atmel_ebi_xslate_smc_config,
3886a4ec4cdSBoris Brezillon .apply_config = at91sam9_ebi_apply_config,
3896a4ec4cdSBoris Brezillon };
3906a4ec4cdSBoris Brezillon
3919453fa46SBoris Brezillon static const struct atmel_ebi_caps at91sam9263_ebi0_caps = {
3926a4ec4cdSBoris Brezillon .available_cs = 0x3f,
393d9f81dadSBoris Brezillon .ebi_csa_offs = AT91SAM9263_MATRIX_EBI0CSA,
394ad7bdbc8STudor Ambarus .regmap_name = "atmel,matrix",
3956a4ec4cdSBoris Brezillon .get_config = at91sam9_ebi_get_config,
3969453fa46SBoris Brezillon .xlate_config = atmel_ebi_xslate_smc_config,
3976a4ec4cdSBoris Brezillon .apply_config = at91sam9_ebi_apply_config,
3986a4ec4cdSBoris Brezillon };
3996a4ec4cdSBoris Brezillon
4009453fa46SBoris Brezillon static const struct atmel_ebi_caps at91sam9263_ebi1_caps = {
4016a4ec4cdSBoris Brezillon .available_cs = 0x7,
402d9f81dadSBoris Brezillon .ebi_csa_offs = AT91SAM9263_MATRIX_EBI1CSA,
403ad7bdbc8STudor Ambarus .regmap_name = "atmel,matrix",
4046a4ec4cdSBoris Brezillon .get_config = at91sam9_ebi_get_config,
4059453fa46SBoris Brezillon .xlate_config = atmel_ebi_xslate_smc_config,
4066a4ec4cdSBoris Brezillon .apply_config = at91sam9_ebi_apply_config,
4076a4ec4cdSBoris Brezillon };
4086a4ec4cdSBoris Brezillon
4099453fa46SBoris Brezillon static const struct atmel_ebi_caps at91sam9rl_ebi_caps = {
4106a4ec4cdSBoris Brezillon .available_cs = 0x3f,
411d9f81dadSBoris Brezillon .ebi_csa_offs = AT91SAM9RL_MATRIX_EBICSA,
412ad7bdbc8STudor Ambarus .regmap_name = "atmel,matrix",
4136a4ec4cdSBoris Brezillon .get_config = at91sam9_ebi_get_config,
4149453fa46SBoris Brezillon .xlate_config = atmel_ebi_xslate_smc_config,
4156a4ec4cdSBoris Brezillon .apply_config = at91sam9_ebi_apply_config,
4166a4ec4cdSBoris Brezillon };
4176a4ec4cdSBoris Brezillon
4189453fa46SBoris Brezillon static const struct atmel_ebi_caps at91sam9g45_ebi_caps = {
4196a4ec4cdSBoris Brezillon .available_cs = 0x3f,
420d9f81dadSBoris Brezillon .ebi_csa_offs = AT91SAM9G45_MATRIX_EBICSA,
421ad7bdbc8STudor Ambarus .regmap_name = "atmel,matrix",
4226a4ec4cdSBoris Brezillon .get_config = at91sam9_ebi_get_config,
4239453fa46SBoris Brezillon .xlate_config = atmel_ebi_xslate_smc_config,
4246a4ec4cdSBoris Brezillon .apply_config = at91sam9_ebi_apply_config,
4256a4ec4cdSBoris Brezillon };
4266a4ec4cdSBoris Brezillon
4279453fa46SBoris Brezillon static const struct atmel_ebi_caps at91sam9x5_ebi_caps = {
4286a4ec4cdSBoris Brezillon .available_cs = 0x3f,
429d9f81dadSBoris Brezillon .ebi_csa_offs = AT91SAM9X5_MATRIX_EBICSA,
430ad7bdbc8STudor Ambarus .regmap_name = "atmel,matrix",
4316a4ec4cdSBoris Brezillon .get_config = at91sam9_ebi_get_config,
4329453fa46SBoris Brezillon .xlate_config = atmel_ebi_xslate_smc_config,
4336a4ec4cdSBoris Brezillon .apply_config = at91sam9_ebi_apply_config,
4346a4ec4cdSBoris Brezillon };
4356a4ec4cdSBoris Brezillon
4369453fa46SBoris Brezillon static const struct atmel_ebi_caps sama5d3_ebi_caps = {
4376a4ec4cdSBoris Brezillon .available_cs = 0xf,
4388eb8c7d8SBoris Brezillon .get_config = sama5_ebi_get_config,
4399453fa46SBoris Brezillon .xlate_config = atmel_ebi_xslate_smc_config,
4408eb8c7d8SBoris Brezillon .apply_config = sama5_ebi_apply_config,
4416a4ec4cdSBoris Brezillon };
4426a4ec4cdSBoris Brezillon
4433e0863ddSTudor Ambarus static const struct atmel_ebi_caps sam9x60_ebi_caps = {
4443e0863ddSTudor Ambarus .available_cs = 0x3f,
4453e0863ddSTudor Ambarus .ebi_csa_offs = AT91_SFR_CCFG_EBICSA,
4463e0863ddSTudor Ambarus .regmap_name = "microchip,sfr",
4473e0863ddSTudor Ambarus .get_config = at91sam9_ebi_get_config,
4483e0863ddSTudor Ambarus .xlate_config = atmel_ebi_xslate_smc_config,
4493e0863ddSTudor Ambarus .apply_config = at91sam9_ebi_apply_config,
4503e0863ddSTudor Ambarus };
4513e0863ddSTudor Ambarus
4529453fa46SBoris Brezillon static const struct of_device_id atmel_ebi_id_table[] = {
4536a4ec4cdSBoris Brezillon {
4546a4ec4cdSBoris Brezillon .compatible = "atmel,at91sam9260-ebi",
4556a4ec4cdSBoris Brezillon .data = &at91sam9260_ebi_caps,
4566a4ec4cdSBoris Brezillon },
4576a4ec4cdSBoris Brezillon {
4586a4ec4cdSBoris Brezillon .compatible = "atmel,at91sam9261-ebi",
4596a4ec4cdSBoris Brezillon .data = &at91sam9261_ebi_caps,
4606a4ec4cdSBoris Brezillon },
4616a4ec4cdSBoris Brezillon {
4626a4ec4cdSBoris Brezillon .compatible = "atmel,at91sam9263-ebi0",
4636a4ec4cdSBoris Brezillon .data = &at91sam9263_ebi0_caps,
4646a4ec4cdSBoris Brezillon },
4656a4ec4cdSBoris Brezillon {
4666a4ec4cdSBoris Brezillon .compatible = "atmel,at91sam9263-ebi1",
4676a4ec4cdSBoris Brezillon .data = &at91sam9263_ebi1_caps,
4686a4ec4cdSBoris Brezillon },
4696a4ec4cdSBoris Brezillon {
4706a4ec4cdSBoris Brezillon .compatible = "atmel,at91sam9rl-ebi",
4716a4ec4cdSBoris Brezillon .data = &at91sam9rl_ebi_caps,
4726a4ec4cdSBoris Brezillon },
4736a4ec4cdSBoris Brezillon {
4746a4ec4cdSBoris Brezillon .compatible = "atmel,at91sam9g45-ebi",
4756a4ec4cdSBoris Brezillon .data = &at91sam9g45_ebi_caps,
4766a4ec4cdSBoris Brezillon },
4776a4ec4cdSBoris Brezillon {
4786a4ec4cdSBoris Brezillon .compatible = "atmel,at91sam9x5-ebi",
4796a4ec4cdSBoris Brezillon .data = &at91sam9x5_ebi_caps,
4806a4ec4cdSBoris Brezillon },
4816a4ec4cdSBoris Brezillon {
4826a4ec4cdSBoris Brezillon .compatible = "atmel,sama5d3-ebi",
4836a4ec4cdSBoris Brezillon .data = &sama5d3_ebi_caps,
4846a4ec4cdSBoris Brezillon },
4853e0863ddSTudor Ambarus {
4863e0863ddSTudor Ambarus .compatible = "microchip,sam9x60-ebi",
4873e0863ddSTudor Ambarus .data = &sam9x60_ebi_caps,
4883e0863ddSTudor Ambarus },
4896a4ec4cdSBoris Brezillon { /* sentinel */ }
4906a4ec4cdSBoris Brezillon };
4916a4ec4cdSBoris Brezillon
atmel_ebi_dev_disable(struct atmel_ebi * ebi,struct device_node * np)4929453fa46SBoris Brezillon static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np)
4936a4ec4cdSBoris Brezillon {
4946a4ec4cdSBoris Brezillon struct device *dev = ebi->dev;
4956a4ec4cdSBoris Brezillon struct property *newprop;
4966a4ec4cdSBoris Brezillon
4976a4ec4cdSBoris Brezillon newprop = devm_kzalloc(dev, sizeof(*newprop), GFP_KERNEL);
4986a4ec4cdSBoris Brezillon if (!newprop)
4996a4ec4cdSBoris Brezillon return -ENOMEM;
5006a4ec4cdSBoris Brezillon
5016a4ec4cdSBoris Brezillon newprop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
5026a4ec4cdSBoris Brezillon if (!newprop->name)
5036a4ec4cdSBoris Brezillon return -ENOMEM;
5046a4ec4cdSBoris Brezillon
5056a4ec4cdSBoris Brezillon newprop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
506ecc2d430SWei Yongjun if (!newprop->value)
5076a4ec4cdSBoris Brezillon return -ENOMEM;
5086a4ec4cdSBoris Brezillon
5096a4ec4cdSBoris Brezillon newprop->length = sizeof("disabled");
5106a4ec4cdSBoris Brezillon
5116a4ec4cdSBoris Brezillon return of_update_property(np, newprop);
5126a4ec4cdSBoris Brezillon }
5136a4ec4cdSBoris Brezillon
atmel_ebi_probe(struct platform_device * pdev)5149453fa46SBoris Brezillon static int atmel_ebi_probe(struct platform_device *pdev)
5156a4ec4cdSBoris Brezillon {
5166a4ec4cdSBoris Brezillon struct device *dev = &pdev->dev;
51787108dc7SBoris Brezillon struct device_node *child, *np = dev->of_node, *smc_np;
5186a4ec4cdSBoris Brezillon const struct of_device_id *match;
5199453fa46SBoris Brezillon struct atmel_ebi *ebi;
5206a4ec4cdSBoris Brezillon int ret, reg_cells;
5216a4ec4cdSBoris Brezillon struct clk *clk;
5226a4ec4cdSBoris Brezillon u32 val;
5236a4ec4cdSBoris Brezillon
5249453fa46SBoris Brezillon match = of_match_device(atmel_ebi_id_table, dev);
5256a4ec4cdSBoris Brezillon if (!match || !match->data)
5266a4ec4cdSBoris Brezillon return -EINVAL;
5276a4ec4cdSBoris Brezillon
5286a4ec4cdSBoris Brezillon ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL);
5296a4ec4cdSBoris Brezillon if (!ebi)
5306a4ec4cdSBoris Brezillon return -ENOMEM;
5316a4ec4cdSBoris Brezillon
5324407319dSBoris Brezillon platform_set_drvdata(pdev, ebi);
5334407319dSBoris Brezillon
5346a4ec4cdSBoris Brezillon INIT_LIST_HEAD(&ebi->devs);
5356a4ec4cdSBoris Brezillon ebi->caps = match->data;
5366a4ec4cdSBoris Brezillon ebi->dev = dev;
5376a4ec4cdSBoris Brezillon
5386a4ec4cdSBoris Brezillon clk = devm_clk_get(dev, NULL);
5396a4ec4cdSBoris Brezillon if (IS_ERR(clk))
5406a4ec4cdSBoris Brezillon return PTR_ERR(clk);
5416a4ec4cdSBoris Brezillon
5426a4ec4cdSBoris Brezillon ebi->clk = clk;
5436a4ec4cdSBoris Brezillon
54487108dc7SBoris Brezillon smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0);
54587108dc7SBoris Brezillon
54687108dc7SBoris Brezillon ebi->smc.regmap = syscon_node_to_regmap(smc_np);
5476f296a96SMiaoqian Lin if (IS_ERR(ebi->smc.regmap)) {
5486f296a96SMiaoqian Lin ret = PTR_ERR(ebi->smc.regmap);
5496f296a96SMiaoqian Lin goto put_node;
5506f296a96SMiaoqian Lin }
55187108dc7SBoris Brezillon
552b0f3ab20SLudovic Desroches ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np);
5536f296a96SMiaoqian Lin if (IS_ERR(ebi->smc.layout)) {
5546f296a96SMiaoqian Lin ret = PTR_ERR(ebi->smc.layout);
5556f296a96SMiaoqian Lin goto put_node;
5566f296a96SMiaoqian Lin }
557b0f3ab20SLudovic Desroches
55887108dc7SBoris Brezillon ebi->smc.clk = of_clk_get(smc_np, 0);
55987108dc7SBoris Brezillon if (IS_ERR(ebi->smc.clk)) {
5606f296a96SMiaoqian Lin if (PTR_ERR(ebi->smc.clk) != -ENOENT) {
5616f296a96SMiaoqian Lin ret = PTR_ERR(ebi->smc.clk);
5626f296a96SMiaoqian Lin goto put_node;
5636f296a96SMiaoqian Lin }
56487108dc7SBoris Brezillon
56587108dc7SBoris Brezillon ebi->smc.clk = NULL;
56687108dc7SBoris Brezillon }
5676f296a96SMiaoqian Lin of_node_put(smc_np);
56887108dc7SBoris Brezillon ret = clk_prepare_enable(ebi->smc.clk);
56987108dc7SBoris Brezillon if (ret)
57087108dc7SBoris Brezillon return ret;
5716a4ec4cdSBoris Brezillon
5726a4ec4cdSBoris Brezillon /*
5736a4ec4cdSBoris Brezillon * The sama5d3 does not provide an EBICSA register and thus does need
574ad7bdbc8STudor Ambarus * to access it.
5756a4ec4cdSBoris Brezillon */
576d9f81dadSBoris Brezillon if (ebi->caps->ebi_csa_offs) {
577ad7bdbc8STudor Ambarus ebi->regmap =
578ad7bdbc8STudor Ambarus syscon_regmap_lookup_by_phandle(np,
579ad7bdbc8STudor Ambarus ebi->caps->regmap_name);
580ad7bdbc8STudor Ambarus if (IS_ERR(ebi->regmap))
581ad7bdbc8STudor Ambarus return PTR_ERR(ebi->regmap);
5826a4ec4cdSBoris Brezillon }
5836a4ec4cdSBoris Brezillon
5846a4ec4cdSBoris Brezillon ret = of_property_read_u32(np, "#address-cells", &val);
5856a4ec4cdSBoris Brezillon if (ret) {
5866a4ec4cdSBoris Brezillon dev_err(dev, "missing #address-cells property\n");
5876a4ec4cdSBoris Brezillon return ret;
5886a4ec4cdSBoris Brezillon }
5896a4ec4cdSBoris Brezillon
5906a4ec4cdSBoris Brezillon reg_cells = val;
5916a4ec4cdSBoris Brezillon
5926a4ec4cdSBoris Brezillon ret = of_property_read_u32(np, "#size-cells", &val);
5936a4ec4cdSBoris Brezillon if (ret) {
5946a4ec4cdSBoris Brezillon dev_err(dev, "missing #address-cells property\n");
5956a4ec4cdSBoris Brezillon return ret;
5966a4ec4cdSBoris Brezillon }
5976a4ec4cdSBoris Brezillon
5986a4ec4cdSBoris Brezillon reg_cells += val;
5996a4ec4cdSBoris Brezillon
6006a4ec4cdSBoris Brezillon for_each_available_child_of_node(np, child) {
601*538c7b5bSRob Herring if (!of_property_present(child, "reg"))
6026a4ec4cdSBoris Brezillon continue;
6036a4ec4cdSBoris Brezillon
6049453fa46SBoris Brezillon ret = atmel_ebi_dev_setup(ebi, child, reg_cells);
6056a4ec4cdSBoris Brezillon if (ret) {
606db749d17SRob Herring dev_err(dev, "failed to configure EBI bus for %pOF, disabling the device",
607db749d17SRob Herring child);
6086a4ec4cdSBoris Brezillon
6099453fa46SBoris Brezillon ret = atmel_ebi_dev_disable(ebi, child);
610907c5bbbSKrzysztof Kozlowski if (ret) {
611907c5bbbSKrzysztof Kozlowski of_node_put(child);
6126a4ec4cdSBoris Brezillon return ret;
6136a4ec4cdSBoris Brezillon }
6146a4ec4cdSBoris Brezillon }
615907c5bbbSKrzysztof Kozlowski }
6166a4ec4cdSBoris Brezillon
6176a4ec4cdSBoris Brezillon return of_platform_populate(np, NULL, NULL, dev);
6186f296a96SMiaoqian Lin
6196f296a96SMiaoqian Lin put_node:
6206f296a96SMiaoqian Lin of_node_put(smc_np);
6216f296a96SMiaoqian Lin return ret;
6226a4ec4cdSBoris Brezillon }
6236a4ec4cdSBoris Brezillon
atmel_ebi_resume(struct device * dev)62441b80bb1SArnd Bergmann static __maybe_unused int atmel_ebi_resume(struct device *dev)
6254407319dSBoris Brezillon {
6264407319dSBoris Brezillon struct atmel_ebi *ebi = dev_get_drvdata(dev);
6274407319dSBoris Brezillon struct atmel_ebi_dev *ebid;
6284407319dSBoris Brezillon
6294407319dSBoris Brezillon list_for_each_entry(ebid, &ebi->devs, node) {
6304407319dSBoris Brezillon int i;
6314407319dSBoris Brezillon
6324407319dSBoris Brezillon for (i = 0; i < ebid->numcs; i++)
6334407319dSBoris Brezillon ebid->ebi->caps->apply_config(ebid, &ebid->configs[i]);
6344407319dSBoris Brezillon }
6354407319dSBoris Brezillon
6364407319dSBoris Brezillon return 0;
6374407319dSBoris Brezillon }
6384407319dSBoris Brezillon
6394407319dSBoris Brezillon static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume);
6404407319dSBoris Brezillon
6419453fa46SBoris Brezillon static struct platform_driver atmel_ebi_driver = {
6426a4ec4cdSBoris Brezillon .driver = {
6436a4ec4cdSBoris Brezillon .name = "atmel-ebi",
6449453fa46SBoris Brezillon .of_match_table = atmel_ebi_id_table,
6454407319dSBoris Brezillon .pm = &atmel_ebi_pm_ops,
6466a4ec4cdSBoris Brezillon },
6476a4ec4cdSBoris Brezillon };
6489453fa46SBoris Brezillon builtin_platform_driver_probe(atmel_ebi_driver, atmel_ebi_probe);
649