xref: /openbmc/linux/drivers/memory/atmel-ebi.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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