atmel-ebi.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * EBI driver for Atmel chips
  4. * inspired by the fsl weim bus driver
  5. *
  6. * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
  7. */
  8. #include <linux/cleanup.h>
  9. #include <linux/clk.h>
  10. #include <linux/io.h>
  11. #include <linux/mfd/syscon.h>
  12. #include <linux/mfd/syscon/atmel-matrix.h>
  13. #include <linux/mfd/syscon/atmel-smc.h>
  14. #include <linux/init.h>
  15. #include <linux/of.h>
  16. #include <linux/of_platform.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/property.h>
  19. #include <linux/regmap.h>
  20. #include <soc/at91/atmel-sfr.h>
  21. #define AT91_EBI_NUM_CS 8
  22. struct atmel_ebi_dev_config {
  23. int cs;
  24. struct atmel_smc_cs_conf smcconf;
  25. };
  26. struct atmel_ebi;
  27. struct atmel_ebi_dev {
  28. struct list_head node;
  29. struct atmel_ebi *ebi;
  30. u32 mode;
  31. int numcs;
  32. struct atmel_ebi_dev_config configs[] __counted_by(numcs);
  33. };
  34. struct atmel_ebi_caps {
  35. unsigned int available_cs;
  36. unsigned int ebi_csa_offs;
  37. const char *regmap_name;
  38. void (*get_config)(struct atmel_ebi_dev *ebid,
  39. struct atmel_ebi_dev_config *conf);
  40. int (*xlate_config)(struct atmel_ebi_dev *ebid,
  41. struct device_node *configs_np,
  42. struct atmel_ebi_dev_config *conf);
  43. void (*apply_config)(struct atmel_ebi_dev *ebid,
  44. struct atmel_ebi_dev_config *conf);
  45. };
  46. struct atmel_ebi {
  47. struct clk *clk;
  48. struct regmap *regmap;
  49. struct {
  50. struct regmap *regmap;
  51. struct clk *clk;
  52. const struct atmel_hsmc_reg_layout *layout;
  53. } smc;
  54. struct device *dev;
  55. const struct atmel_ebi_caps *caps;
  56. struct list_head devs;
  57. };
  58. struct atmel_smc_timing_xlate {
  59. const char *name;
  60. int (*converter)(struct atmel_smc_cs_conf *conf,
  61. unsigned int shift, unsigned int nycles);
  62. unsigned int shift;
  63. };
  64. #define ATMEL_SMC_SETUP_XLATE(nm, pos) \
  65. { .name = nm, .converter = atmel_smc_cs_conf_set_setup, .shift = pos}
  66. #define ATMEL_SMC_PULSE_XLATE(nm, pos) \
  67. { .name = nm, .converter = atmel_smc_cs_conf_set_pulse, .shift = pos}
  68. #define ATMEL_SMC_CYCLE_XLATE(nm, pos) \
  69. { .name = nm, .converter = atmel_smc_cs_conf_set_cycle, .shift = pos}
  70. static void at91sam9_ebi_get_config(struct atmel_ebi_dev *ebid,
  71. struct atmel_ebi_dev_config *conf)
  72. {
  73. atmel_smc_cs_conf_get(ebid->ebi->smc.regmap, conf->cs,
  74. &conf->smcconf);
  75. }
  76. static void sama5_ebi_get_config(struct atmel_ebi_dev *ebid,
  77. struct atmel_ebi_dev_config *conf)
  78. {
  79. atmel_hsmc_cs_conf_get(ebid->ebi->smc.regmap, ebid->ebi->smc.layout,
  80. conf->cs, &conf->smcconf);
  81. }
  82. static const struct atmel_smc_timing_xlate timings_xlate_table[] = {
  83. ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-rd-setup-ns",
  84. ATMEL_SMC_NCS_RD_SHIFT),
  85. ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-wr-setup-ns",
  86. ATMEL_SMC_NCS_WR_SHIFT),
  87. ATMEL_SMC_SETUP_XLATE("atmel,smc-nrd-setup-ns", ATMEL_SMC_NRD_SHIFT),
  88. ATMEL_SMC_SETUP_XLATE("atmel,smc-nwe-setup-ns", ATMEL_SMC_NWE_SHIFT),
  89. ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-rd-pulse-ns",
  90. ATMEL_SMC_NCS_RD_SHIFT),
  91. ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-wr-pulse-ns",
  92. ATMEL_SMC_NCS_WR_SHIFT),
  93. ATMEL_SMC_PULSE_XLATE("atmel,smc-nrd-pulse-ns", ATMEL_SMC_NRD_SHIFT),
  94. ATMEL_SMC_PULSE_XLATE("atmel,smc-nwe-pulse-ns", ATMEL_SMC_NWE_SHIFT),
  95. ATMEL_SMC_CYCLE_XLATE("atmel,smc-nrd-cycle-ns", ATMEL_SMC_NRD_SHIFT),
  96. ATMEL_SMC_CYCLE_XLATE("atmel,smc-nwe-cycle-ns", ATMEL_SMC_NWE_SHIFT),
  97. };
  98. static int atmel_ebi_xslate_smc_timings(struct atmel_ebi_dev *ebid,
  99. struct device_node *np,
  100. struct atmel_smc_cs_conf *smcconf)
  101. {
  102. unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
  103. unsigned int clk_period_ns = NSEC_PER_SEC / clk_rate;
  104. bool required = false;
  105. unsigned int ncycles;
  106. int ret, i;
  107. u32 val;
  108. ret = of_property_read_u32(np, "atmel,smc-tdf-ns", &val);
  109. if (!ret) {
  110. required = true;
  111. ncycles = DIV_ROUND_UP(val, clk_period_ns);
  112. if (ncycles > ATMEL_SMC_MODE_TDF_MAX) {
  113. ret = -EINVAL;
  114. goto out;
  115. }
  116. if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
  117. ncycles = ATMEL_SMC_MODE_TDF_MIN;
  118. smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles);
  119. }
  120. for (i = 0; i < ARRAY_SIZE(timings_xlate_table); i++) {
  121. const struct atmel_smc_timing_xlate *xlate;
  122. xlate = &timings_xlate_table[i];
  123. ret = of_property_read_u32(np, xlate->name, &val);
  124. if (ret) {
  125. if (!required)
  126. continue;
  127. else
  128. break;
  129. }
  130. if (!required) {
  131. ret = -EINVAL;
  132. break;
  133. }
  134. ncycles = DIV_ROUND_UP(val, clk_period_ns);
  135. ret = xlate->converter(smcconf, xlate->shift, ncycles);
  136. if (ret)
  137. goto out;
  138. }
  139. out:
  140. if (ret) {
  141. dev_err(ebid->ebi->dev,
  142. "missing or invalid timings definition in %pOF",
  143. np);
  144. return ret;
  145. }
  146. return required;
  147. }
  148. static int atmel_ebi_xslate_smc_config(struct atmel_ebi_dev *ebid,
  149. struct device_node *np,
  150. struct atmel_ebi_dev_config *conf)
  151. {
  152. struct atmel_smc_cs_conf *smcconf = &conf->smcconf;
  153. bool required = false;
  154. const char *tmp_str;
  155. u32 tmp;
  156. int ret;
  157. ret = of_property_read_u32(np, "atmel,smc-bus-width", &tmp);
  158. if (!ret) {
  159. switch (tmp) {
  160. case 8:
  161. smcconf->mode |= ATMEL_SMC_MODE_DBW_8;
  162. break;
  163. case 16:
  164. smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
  165. break;
  166. case 32:
  167. smcconf->mode |= ATMEL_SMC_MODE_DBW_32;
  168. break;
  169. default:
  170. return -EINVAL;
  171. }
  172. required = true;
  173. }
  174. if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) {
  175. smcconf->mode |= ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
  176. required = true;
  177. }
  178. tmp_str = NULL;
  179. of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str);
  180. if (tmp_str && !strcmp(tmp_str, "write")) {
  181. smcconf->mode |= ATMEL_SMC_MODE_BAT_WRITE;
  182. required = true;
  183. }
  184. tmp_str = NULL;
  185. of_property_read_string(np, "atmel,smc-read-mode", &tmp_str);
  186. if (tmp_str && !strcmp(tmp_str, "nrd")) {
  187. smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD;
  188. required = true;
  189. }
  190. tmp_str = NULL;
  191. of_property_read_string(np, "atmel,smc-write-mode", &tmp_str);
  192. if (tmp_str && !strcmp(tmp_str, "nwe")) {
  193. smcconf->mode |= ATMEL_SMC_MODE_WRITEMODE_NWE;
  194. required = true;
  195. }
  196. tmp_str = NULL;
  197. of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str);
  198. if (tmp_str) {
  199. if (!strcmp(tmp_str, "frozen"))
  200. smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_FROZEN;
  201. else if (!strcmp(tmp_str, "ready"))
  202. smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_READY;
  203. else if (strcmp(tmp_str, "disabled"))
  204. return -EINVAL;
  205. required = true;
  206. }
  207. ret = of_property_read_u32(np, "atmel,smc-page-mode", &tmp);
  208. if (!ret) {
  209. switch (tmp) {
  210. case 4:
  211. smcconf->mode |= ATMEL_SMC_MODE_PS_4;
  212. break;
  213. case 8:
  214. smcconf->mode |= ATMEL_SMC_MODE_PS_8;
  215. break;
  216. case 16:
  217. smcconf->mode |= ATMEL_SMC_MODE_PS_16;
  218. break;
  219. case 32:
  220. smcconf->mode |= ATMEL_SMC_MODE_PS_32;
  221. break;
  222. default:
  223. return -EINVAL;
  224. }
  225. smcconf->mode |= ATMEL_SMC_MODE_PMEN;
  226. required = true;
  227. }
  228. ret = atmel_ebi_xslate_smc_timings(ebid, np, &conf->smcconf);
  229. if (ret < 0)
  230. return -EINVAL;
  231. if ((ret > 0 && !required) || (!ret && required)) {
  232. dev_err(ebid->ebi->dev, "missing atmel,smc- properties in %pOF",
  233. np);
  234. return -EINVAL;
  235. }
  236. return required;
  237. }
  238. static void at91sam9_ebi_apply_config(struct atmel_ebi_dev *ebid,
  239. struct atmel_ebi_dev_config *conf)
  240. {
  241. atmel_smc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs,
  242. &conf->smcconf);
  243. }
  244. static void sama5_ebi_apply_config(struct atmel_ebi_dev *ebid,
  245. struct atmel_ebi_dev_config *conf)
  246. {
  247. atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, ebid->ebi->smc.layout,
  248. conf->cs, &conf->smcconf);
  249. }
  250. static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
  251. int reg_cells)
  252. {
  253. const struct atmel_ebi_caps *caps = ebi->caps;
  254. struct atmel_ebi_dev_config conf = { };
  255. struct device *dev = ebi->dev;
  256. struct atmel_ebi_dev *ebid;
  257. unsigned long cslines = 0;
  258. int ret, numcs = 0, nentries, i;
  259. bool apply = false;
  260. u32 cs;
  261. nentries = of_property_count_elems_of_size(np, "reg",
  262. reg_cells * sizeof(u32));
  263. for (i = 0; i < nentries; i++) {
  264. ret = of_property_read_u32_index(np, "reg", i * reg_cells,
  265. &cs);
  266. if (ret)
  267. return ret;
  268. if (cs >= AT91_EBI_NUM_CS ||
  269. !(ebi->caps->available_cs & BIT(cs))) {
  270. dev_err(dev, "invalid reg property in %pOF\n", np);
  271. return -EINVAL;
  272. }
  273. if (!test_and_set_bit(cs, &cslines))
  274. numcs++;
  275. }
  276. if (!numcs) {
  277. dev_err(dev, "invalid reg property in %pOF\n", np);
  278. return -EINVAL;
  279. }
  280. ebid = devm_kzalloc(ebi->dev, struct_size(ebid, configs, numcs),
  281. GFP_KERNEL);
  282. if (!ebid)
  283. return -ENOMEM;
  284. ebid->ebi = ebi;
  285. ebid->numcs = numcs;
  286. ret = caps->xlate_config(ebid, np, &conf);
  287. if (ret < 0)
  288. return ret;
  289. else if (ret)
  290. apply = true;
  291. i = 0;
  292. for_each_set_bit(cs, &cslines, AT91_EBI_NUM_CS) {
  293. ebid->configs[i].cs = cs;
  294. if (apply) {
  295. conf.cs = cs;
  296. caps->apply_config(ebid, &conf);
  297. }
  298. caps->get_config(ebid, &ebid->configs[i]);
  299. /*
  300. * Attach the EBI device to the generic SMC logic if at least
  301. * one "atmel,smc-" property is present.
  302. */
  303. if (ebi->caps->ebi_csa_offs && apply)
  304. regmap_update_bits(ebi->regmap,
  305. ebi->caps->ebi_csa_offs,
  306. BIT(cs), 0);
  307. i++;
  308. }
  309. list_add_tail(&ebid->node, &ebi->devs);
  310. return 0;
  311. }
  312. static const struct atmel_ebi_caps at91sam9260_ebi_caps = {
  313. .available_cs = 0xff,
  314. .ebi_csa_offs = AT91SAM9260_MATRIX_EBICSA,
  315. .regmap_name = "atmel,matrix",
  316. .get_config = at91sam9_ebi_get_config,
  317. .xlate_config = atmel_ebi_xslate_smc_config,
  318. .apply_config = at91sam9_ebi_apply_config,
  319. };
  320. static const struct atmel_ebi_caps at91sam9261_ebi_caps = {
  321. .available_cs = 0xff,
  322. .ebi_csa_offs = AT91SAM9261_MATRIX_EBICSA,
  323. .regmap_name = "atmel,matrix",
  324. .get_config = at91sam9_ebi_get_config,
  325. .xlate_config = atmel_ebi_xslate_smc_config,
  326. .apply_config = at91sam9_ebi_apply_config,
  327. };
  328. static const struct atmel_ebi_caps at91sam9263_ebi0_caps = {
  329. .available_cs = 0x3f,
  330. .ebi_csa_offs = AT91SAM9263_MATRIX_EBI0CSA,
  331. .regmap_name = "atmel,matrix",
  332. .get_config = at91sam9_ebi_get_config,
  333. .xlate_config = atmel_ebi_xslate_smc_config,
  334. .apply_config = at91sam9_ebi_apply_config,
  335. };
  336. static const struct atmel_ebi_caps at91sam9263_ebi1_caps = {
  337. .available_cs = 0x7,
  338. .ebi_csa_offs = AT91SAM9263_MATRIX_EBI1CSA,
  339. .regmap_name = "atmel,matrix",
  340. .get_config = at91sam9_ebi_get_config,
  341. .xlate_config = atmel_ebi_xslate_smc_config,
  342. .apply_config = at91sam9_ebi_apply_config,
  343. };
  344. static const struct atmel_ebi_caps at91sam9rl_ebi_caps = {
  345. .available_cs = 0x3f,
  346. .ebi_csa_offs = AT91SAM9RL_MATRIX_EBICSA,
  347. .regmap_name = "atmel,matrix",
  348. .get_config = at91sam9_ebi_get_config,
  349. .xlate_config = atmel_ebi_xslate_smc_config,
  350. .apply_config = at91sam9_ebi_apply_config,
  351. };
  352. static const struct atmel_ebi_caps at91sam9g45_ebi_caps = {
  353. .available_cs = 0x3f,
  354. .ebi_csa_offs = AT91SAM9G45_MATRIX_EBICSA,
  355. .regmap_name = "atmel,matrix",
  356. .get_config = at91sam9_ebi_get_config,
  357. .xlate_config = atmel_ebi_xslate_smc_config,
  358. .apply_config = at91sam9_ebi_apply_config,
  359. };
  360. static const struct atmel_ebi_caps at91sam9x5_ebi_caps = {
  361. .available_cs = 0x3f,
  362. .ebi_csa_offs = AT91SAM9X5_MATRIX_EBICSA,
  363. .regmap_name = "atmel,matrix",
  364. .get_config = at91sam9_ebi_get_config,
  365. .xlate_config = atmel_ebi_xslate_smc_config,
  366. .apply_config = at91sam9_ebi_apply_config,
  367. };
  368. static const struct atmel_ebi_caps sama5d3_ebi_caps = {
  369. .available_cs = 0xf,
  370. .get_config = sama5_ebi_get_config,
  371. .xlate_config = atmel_ebi_xslate_smc_config,
  372. .apply_config = sama5_ebi_apply_config,
  373. };
  374. static const struct atmel_ebi_caps sam9x60_ebi_caps = {
  375. .available_cs = 0x3f,
  376. .ebi_csa_offs = AT91_SFR_CCFG_EBICSA,
  377. .regmap_name = "microchip,sfr",
  378. .get_config = at91sam9_ebi_get_config,
  379. .xlate_config = atmel_ebi_xslate_smc_config,
  380. .apply_config = at91sam9_ebi_apply_config,
  381. };
  382. static const struct of_device_id atmel_ebi_id_table[] = {
  383. {
  384. .compatible = "atmel,at91sam9260-ebi",
  385. .data = &at91sam9260_ebi_caps,
  386. },
  387. {
  388. .compatible = "atmel,at91sam9261-ebi",
  389. .data = &at91sam9261_ebi_caps,
  390. },
  391. {
  392. .compatible = "atmel,at91sam9263-ebi0",
  393. .data = &at91sam9263_ebi0_caps,
  394. },
  395. {
  396. .compatible = "atmel,at91sam9263-ebi1",
  397. .data = &at91sam9263_ebi1_caps,
  398. },
  399. {
  400. .compatible = "atmel,at91sam9rl-ebi",
  401. .data = &at91sam9rl_ebi_caps,
  402. },
  403. {
  404. .compatible = "atmel,at91sam9g45-ebi",
  405. .data = &at91sam9g45_ebi_caps,
  406. },
  407. {
  408. .compatible = "atmel,at91sam9x5-ebi",
  409. .data = &at91sam9x5_ebi_caps,
  410. },
  411. {
  412. .compatible = "atmel,sama5d3-ebi",
  413. .data = &sama5d3_ebi_caps,
  414. },
  415. {
  416. .compatible = "microchip,sam9x60-ebi",
  417. .data = &sam9x60_ebi_caps,
  418. },
  419. { /* sentinel */ }
  420. };
  421. static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np)
  422. {
  423. struct device *dev = ebi->dev;
  424. struct property *newprop;
  425. newprop = devm_kzalloc(dev, sizeof(*newprop), GFP_KERNEL);
  426. if (!newprop)
  427. return -ENOMEM;
  428. newprop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
  429. if (!newprop->name)
  430. return -ENOMEM;
  431. newprop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
  432. if (!newprop->value)
  433. return -ENOMEM;
  434. newprop->length = sizeof("disabled");
  435. return of_update_property(np, newprop);
  436. }
  437. static int atmel_ebi_probe(struct platform_device *pdev)
  438. {
  439. struct device *dev = &pdev->dev;
  440. struct device_node *np = dev->of_node;
  441. struct atmel_ebi *ebi;
  442. int ret, reg_cells;
  443. struct clk *clk;
  444. u32 val;
  445. ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL);
  446. if (!ebi)
  447. return -ENOMEM;
  448. platform_set_drvdata(pdev, ebi);
  449. INIT_LIST_HEAD(&ebi->devs);
  450. ebi->caps = device_get_match_data(dev);
  451. if (!ebi->caps)
  452. return -EINVAL;
  453. ebi->dev = dev;
  454. clk = devm_clk_get(dev, NULL);
  455. if (IS_ERR(clk))
  456. return PTR_ERR(clk);
  457. ebi->clk = clk;
  458. struct device_node *smc_np __free(device_node) =
  459. of_parse_phandle(dev->of_node, "atmel,smc", 0);
  460. ebi->smc.regmap = syscon_node_to_regmap(smc_np);
  461. if (IS_ERR(ebi->smc.regmap))
  462. return PTR_ERR(ebi->smc.regmap);
  463. ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np);
  464. if (IS_ERR(ebi->smc.layout))
  465. return PTR_ERR(ebi->smc.layout);
  466. ebi->smc.clk = of_clk_get(smc_np, 0);
  467. if (IS_ERR(ebi->smc.clk)) {
  468. if (PTR_ERR(ebi->smc.clk) != -ENOENT)
  469. return PTR_ERR(ebi->smc.clk);
  470. ebi->smc.clk = NULL;
  471. }
  472. ret = clk_prepare_enable(ebi->smc.clk);
  473. if (ret)
  474. return ret;
  475. /*
  476. * The sama5d3 does not provide an EBICSA register and thus does need
  477. * to access it.
  478. */
  479. if (ebi->caps->ebi_csa_offs) {
  480. ebi->regmap =
  481. syscon_regmap_lookup_by_phandle(np,
  482. ebi->caps->regmap_name);
  483. if (IS_ERR(ebi->regmap))
  484. return PTR_ERR(ebi->regmap);
  485. }
  486. ret = of_property_read_u32(np, "#address-cells", &val);
  487. if (ret) {
  488. dev_err(dev, "missing #address-cells property\n");
  489. return ret;
  490. }
  491. reg_cells = val;
  492. ret = of_property_read_u32(np, "#size-cells", &val);
  493. if (ret) {
  494. dev_err(dev, "missing #address-cells property\n");
  495. return ret;
  496. }
  497. reg_cells += val;
  498. for_each_available_child_of_node_scoped(np, child) {
  499. if (!of_property_present(child, "reg"))
  500. continue;
  501. ret = atmel_ebi_dev_setup(ebi, child, reg_cells);
  502. if (ret) {
  503. dev_err(dev, "failed to configure EBI bus for %pOF, disabling the device",
  504. child);
  505. ret = atmel_ebi_dev_disable(ebi, child);
  506. if (ret)
  507. return ret;
  508. }
  509. }
  510. return of_platform_populate(np, NULL, NULL, dev);
  511. }
  512. static __maybe_unused int atmel_ebi_resume(struct device *dev)
  513. {
  514. struct atmel_ebi *ebi = dev_get_drvdata(dev);
  515. struct atmel_ebi_dev *ebid;
  516. list_for_each_entry(ebid, &ebi->devs, node) {
  517. int i;
  518. for (i = 0; i < ebid->numcs; i++)
  519. ebid->ebi->caps->apply_config(ebid, &ebid->configs[i]);
  520. }
  521. return 0;
  522. }
  523. static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume);
  524. static struct platform_driver atmel_ebi_driver = {
  525. .driver = {
  526. .name = "atmel-ebi",
  527. .of_match_table = atmel_ebi_id_table,
  528. .pm = &atmel_ebi_pm_ops,
  529. },
  530. };
  531. builtin_platform_driver_probe(atmel_ebi_driver, atmel_ebi_probe);