Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * EBI driver for Atmel chips
0004  * inspired by the fsl weim bus driver
0005  *
0006  * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
0007  */
0008 
0009 #include <linux/clk.h>
0010 #include <linux/io.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/mfd/syscon/atmel-matrix.h>
0013 #include <linux/mfd/syscon/atmel-smc.h>
0014 #include <linux/init.h>
0015 #include <linux/of_device.h>
0016 #include <linux/regmap.h>
0017 #include <soc/at91/atmel-sfr.h>
0018 
0019 #define AT91_EBI_NUM_CS     8
0020 
0021 struct atmel_ebi_dev_config {
0022     int cs;
0023     struct atmel_smc_cs_conf smcconf;
0024 };
0025 
0026 struct atmel_ebi;
0027 
0028 struct atmel_ebi_dev {
0029     struct list_head node;
0030     struct atmel_ebi *ebi;
0031     u32 mode;
0032     int numcs;
0033     struct atmel_ebi_dev_config configs[];
0034 };
0035 
0036 struct atmel_ebi_caps {
0037     unsigned int available_cs;
0038     unsigned int ebi_csa_offs;
0039     const char *regmap_name;
0040     void (*get_config)(struct atmel_ebi_dev *ebid,
0041                struct atmel_ebi_dev_config *conf);
0042     int (*xlate_config)(struct atmel_ebi_dev *ebid,
0043                 struct device_node *configs_np,
0044                 struct atmel_ebi_dev_config *conf);
0045     void (*apply_config)(struct atmel_ebi_dev *ebid,
0046                  struct atmel_ebi_dev_config *conf);
0047 };
0048 
0049 struct atmel_ebi {
0050     struct clk *clk;
0051     struct regmap *regmap;
0052     struct  {
0053         struct regmap *regmap;
0054         struct clk *clk;
0055         const struct atmel_hsmc_reg_layout *layout;
0056     } smc;
0057 
0058     struct device *dev;
0059     const struct atmel_ebi_caps *caps;
0060     struct list_head devs;
0061 };
0062 
0063 struct atmel_smc_timing_xlate {
0064     const char *name;
0065     int (*converter)(struct atmel_smc_cs_conf *conf,
0066              unsigned int shift, unsigned int nycles);
0067     unsigned int shift;
0068 };
0069 
0070 #define ATMEL_SMC_SETUP_XLATE(nm, pos)  \
0071     { .name = nm, .converter = atmel_smc_cs_conf_set_setup, .shift = pos}
0072 
0073 #define ATMEL_SMC_PULSE_XLATE(nm, pos)  \
0074     { .name = nm, .converter = atmel_smc_cs_conf_set_pulse, .shift = pos}
0075 
0076 #define ATMEL_SMC_CYCLE_XLATE(nm, pos)  \
0077     { .name = nm, .converter = atmel_smc_cs_conf_set_cycle, .shift = pos}
0078 
0079 static void at91sam9_ebi_get_config(struct atmel_ebi_dev *ebid,
0080                     struct atmel_ebi_dev_config *conf)
0081 {
0082     atmel_smc_cs_conf_get(ebid->ebi->smc.regmap, conf->cs,
0083                   &conf->smcconf);
0084 }
0085 
0086 static void sama5_ebi_get_config(struct atmel_ebi_dev *ebid,
0087                  struct atmel_ebi_dev_config *conf)
0088 {
0089     atmel_hsmc_cs_conf_get(ebid->ebi->smc.regmap, ebid->ebi->smc.layout,
0090                    conf->cs, &conf->smcconf);
0091 }
0092 
0093 static const struct atmel_smc_timing_xlate timings_xlate_table[] = {
0094     ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-rd-setup-ns",
0095                   ATMEL_SMC_NCS_RD_SHIFT),
0096     ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-wr-setup-ns",
0097                   ATMEL_SMC_NCS_WR_SHIFT),
0098     ATMEL_SMC_SETUP_XLATE("atmel,smc-nrd-setup-ns", ATMEL_SMC_NRD_SHIFT),
0099     ATMEL_SMC_SETUP_XLATE("atmel,smc-nwe-setup-ns", ATMEL_SMC_NWE_SHIFT),
0100     ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-rd-pulse-ns",
0101                   ATMEL_SMC_NCS_RD_SHIFT),
0102     ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-wr-pulse-ns",
0103                   ATMEL_SMC_NCS_WR_SHIFT),
0104     ATMEL_SMC_PULSE_XLATE("atmel,smc-nrd-pulse-ns", ATMEL_SMC_NRD_SHIFT),
0105     ATMEL_SMC_PULSE_XLATE("atmel,smc-nwe-pulse-ns", ATMEL_SMC_NWE_SHIFT),
0106     ATMEL_SMC_CYCLE_XLATE("atmel,smc-nrd-cycle-ns", ATMEL_SMC_NRD_SHIFT),
0107     ATMEL_SMC_CYCLE_XLATE("atmel,smc-nwe-cycle-ns", ATMEL_SMC_NWE_SHIFT),
0108 };
0109 
0110 static int atmel_ebi_xslate_smc_timings(struct atmel_ebi_dev *ebid,
0111                     struct device_node *np,
0112                     struct atmel_smc_cs_conf *smcconf)
0113 {
0114     unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
0115     unsigned int clk_period_ns = NSEC_PER_SEC / clk_rate;
0116     bool required = false;
0117     unsigned int ncycles;
0118     int ret, i;
0119     u32 val;
0120 
0121     ret = of_property_read_u32(np, "atmel,smc-tdf-ns", &val);
0122     if (!ret) {
0123         required = true;
0124         ncycles = DIV_ROUND_UP(val, clk_period_ns);
0125         if (ncycles > ATMEL_SMC_MODE_TDF_MAX) {
0126             ret = -EINVAL;
0127             goto out;
0128         }
0129 
0130         if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
0131             ncycles = ATMEL_SMC_MODE_TDF_MIN;
0132 
0133         smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles);
0134     }
0135 
0136     for (i = 0; i < ARRAY_SIZE(timings_xlate_table); i++) {
0137         const struct atmel_smc_timing_xlate *xlate;
0138 
0139         xlate = &timings_xlate_table[i];
0140 
0141         ret = of_property_read_u32(np, xlate->name, &val);
0142         if (ret) {
0143             if (!required)
0144                 continue;
0145             else
0146                 break;
0147         }
0148 
0149         if (!required) {
0150             ret = -EINVAL;
0151             break;
0152         }
0153 
0154         ncycles = DIV_ROUND_UP(val, clk_period_ns);
0155         ret = xlate->converter(smcconf, xlate->shift, ncycles);
0156         if (ret)
0157             goto out;
0158     }
0159 
0160 out:
0161     if (ret) {
0162         dev_err(ebid->ebi->dev,
0163             "missing or invalid timings definition in %pOF",
0164             np);
0165         return ret;
0166     }
0167 
0168     return required;
0169 }
0170 
0171 static int atmel_ebi_xslate_smc_config(struct atmel_ebi_dev *ebid,
0172                        struct device_node *np,
0173                        struct atmel_ebi_dev_config *conf)
0174 {
0175     struct atmel_smc_cs_conf *smcconf = &conf->smcconf;
0176     bool required = false;
0177     const char *tmp_str;
0178     u32 tmp;
0179     int ret;
0180 
0181     ret = of_property_read_u32(np, "atmel,smc-bus-width", &tmp);
0182     if (!ret) {
0183         switch (tmp) {
0184         case 8:
0185             smcconf->mode |= ATMEL_SMC_MODE_DBW_8;
0186             break;
0187 
0188         case 16:
0189             smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
0190             break;
0191 
0192         case 32:
0193             smcconf->mode |= ATMEL_SMC_MODE_DBW_32;
0194             break;
0195 
0196         default:
0197             return -EINVAL;
0198         }
0199 
0200         required = true;
0201     }
0202 
0203     if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) {
0204         smcconf->mode |= ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
0205         required = true;
0206     }
0207 
0208     tmp_str = NULL;
0209     of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str);
0210     if (tmp_str && !strcmp(tmp_str, "write")) {
0211         smcconf->mode |= ATMEL_SMC_MODE_BAT_WRITE;
0212         required = true;
0213     }
0214 
0215     tmp_str = NULL;
0216     of_property_read_string(np, "atmel,smc-read-mode", &tmp_str);
0217     if (tmp_str && !strcmp(tmp_str, "nrd")) {
0218         smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD;
0219         required = true;
0220     }
0221 
0222     tmp_str = NULL;
0223     of_property_read_string(np, "atmel,smc-write-mode", &tmp_str);
0224     if (tmp_str && !strcmp(tmp_str, "nwe")) {
0225         smcconf->mode |= ATMEL_SMC_MODE_WRITEMODE_NWE;
0226         required = true;
0227     }
0228 
0229     tmp_str = NULL;
0230     of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str);
0231     if (tmp_str) {
0232         if (!strcmp(tmp_str, "frozen"))
0233             smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_FROZEN;
0234         else if (!strcmp(tmp_str, "ready"))
0235             smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_READY;
0236         else if (strcmp(tmp_str, "disabled"))
0237             return -EINVAL;
0238 
0239         required = true;
0240     }
0241 
0242     ret = of_property_read_u32(np, "atmel,smc-page-mode", &tmp);
0243     if (!ret) {
0244         switch (tmp) {
0245         case 4:
0246             smcconf->mode |= ATMEL_SMC_MODE_PS_4;
0247             break;
0248 
0249         case 8:
0250             smcconf->mode |= ATMEL_SMC_MODE_PS_8;
0251             break;
0252 
0253         case 16:
0254             smcconf->mode |= ATMEL_SMC_MODE_PS_16;
0255             break;
0256 
0257         case 32:
0258             smcconf->mode |= ATMEL_SMC_MODE_PS_32;
0259             break;
0260 
0261         default:
0262             return -EINVAL;
0263         }
0264 
0265         smcconf->mode |= ATMEL_SMC_MODE_PMEN;
0266         required = true;
0267     }
0268 
0269     ret = atmel_ebi_xslate_smc_timings(ebid, np, &conf->smcconf);
0270     if (ret < 0)
0271         return -EINVAL;
0272 
0273     if ((ret > 0 && !required) || (!ret && required)) {
0274         dev_err(ebid->ebi->dev, "missing atmel,smc- properties in %pOF",
0275             np);
0276         return -EINVAL;
0277     }
0278 
0279     return required;
0280 }
0281 
0282 static void at91sam9_ebi_apply_config(struct atmel_ebi_dev *ebid,
0283                       struct atmel_ebi_dev_config *conf)
0284 {
0285     atmel_smc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs,
0286                 &conf->smcconf);
0287 }
0288 
0289 static void sama5_ebi_apply_config(struct atmel_ebi_dev *ebid,
0290                    struct atmel_ebi_dev_config *conf)
0291 {
0292     atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, ebid->ebi->smc.layout,
0293                  conf->cs, &conf->smcconf);
0294 }
0295 
0296 static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
0297                    int reg_cells)
0298 {
0299     const struct atmel_ebi_caps *caps = ebi->caps;
0300     struct atmel_ebi_dev_config conf = { };
0301     struct device *dev = ebi->dev;
0302     struct atmel_ebi_dev *ebid;
0303     unsigned long cslines = 0;
0304     int ret, numcs = 0, nentries, i;
0305     bool apply = false;
0306     u32 cs;
0307 
0308     nentries = of_property_count_elems_of_size(np, "reg",
0309                            reg_cells * sizeof(u32));
0310     for (i = 0; i < nentries; i++) {
0311         ret = of_property_read_u32_index(np, "reg", i * reg_cells,
0312                          &cs);
0313         if (ret)
0314             return ret;
0315 
0316         if (cs >= AT91_EBI_NUM_CS ||
0317             !(ebi->caps->available_cs & BIT(cs))) {
0318             dev_err(dev, "invalid reg property in %pOF\n", np);
0319             return -EINVAL;
0320         }
0321 
0322         if (!test_and_set_bit(cs, &cslines))
0323             numcs++;
0324     }
0325 
0326     if (!numcs) {
0327         dev_err(dev, "invalid reg property in %pOF\n", np);
0328         return -EINVAL;
0329     }
0330 
0331     ebid = devm_kzalloc(ebi->dev, struct_size(ebid, configs, numcs),
0332                 GFP_KERNEL);
0333     if (!ebid)
0334         return -ENOMEM;
0335 
0336     ebid->ebi = ebi;
0337     ebid->numcs = numcs;
0338 
0339     ret = caps->xlate_config(ebid, np, &conf);
0340     if (ret < 0)
0341         return ret;
0342     else if (ret)
0343         apply = true;
0344 
0345     i = 0;
0346     for_each_set_bit(cs, &cslines, AT91_EBI_NUM_CS) {
0347         ebid->configs[i].cs = cs;
0348 
0349         if (apply) {
0350             conf.cs = cs;
0351             caps->apply_config(ebid, &conf);
0352         }
0353 
0354         caps->get_config(ebid, &ebid->configs[i]);
0355 
0356         /*
0357          * Attach the EBI device to the generic SMC logic if at least
0358          * one "atmel,smc-" property is present.
0359          */
0360         if (ebi->caps->ebi_csa_offs && apply)
0361             regmap_update_bits(ebi->regmap,
0362                        ebi->caps->ebi_csa_offs,
0363                        BIT(cs), 0);
0364 
0365         i++;
0366     }
0367 
0368     list_add_tail(&ebid->node, &ebi->devs);
0369 
0370     return 0;
0371 }
0372 
0373 static const struct atmel_ebi_caps at91sam9260_ebi_caps = {
0374     .available_cs = 0xff,
0375     .ebi_csa_offs = AT91SAM9260_MATRIX_EBICSA,
0376     .regmap_name = "atmel,matrix",
0377     .get_config = at91sam9_ebi_get_config,
0378     .xlate_config = atmel_ebi_xslate_smc_config,
0379     .apply_config = at91sam9_ebi_apply_config,
0380 };
0381 
0382 static const struct atmel_ebi_caps at91sam9261_ebi_caps = {
0383     .available_cs = 0xff,
0384     .ebi_csa_offs = AT91SAM9261_MATRIX_EBICSA,
0385     .regmap_name = "atmel,matrix",
0386     .get_config = at91sam9_ebi_get_config,
0387     .xlate_config = atmel_ebi_xslate_smc_config,
0388     .apply_config = at91sam9_ebi_apply_config,
0389 };
0390 
0391 static const struct atmel_ebi_caps at91sam9263_ebi0_caps = {
0392     .available_cs = 0x3f,
0393     .ebi_csa_offs = AT91SAM9263_MATRIX_EBI0CSA,
0394     .regmap_name = "atmel,matrix",
0395     .get_config = at91sam9_ebi_get_config,
0396     .xlate_config = atmel_ebi_xslate_smc_config,
0397     .apply_config = at91sam9_ebi_apply_config,
0398 };
0399 
0400 static const struct atmel_ebi_caps at91sam9263_ebi1_caps = {
0401     .available_cs = 0x7,
0402     .ebi_csa_offs = AT91SAM9263_MATRIX_EBI1CSA,
0403     .regmap_name = "atmel,matrix",
0404     .get_config = at91sam9_ebi_get_config,
0405     .xlate_config = atmel_ebi_xslate_smc_config,
0406     .apply_config = at91sam9_ebi_apply_config,
0407 };
0408 
0409 static const struct atmel_ebi_caps at91sam9rl_ebi_caps = {
0410     .available_cs = 0x3f,
0411     .ebi_csa_offs = AT91SAM9RL_MATRIX_EBICSA,
0412     .regmap_name = "atmel,matrix",
0413     .get_config = at91sam9_ebi_get_config,
0414     .xlate_config = atmel_ebi_xslate_smc_config,
0415     .apply_config = at91sam9_ebi_apply_config,
0416 };
0417 
0418 static const struct atmel_ebi_caps at91sam9g45_ebi_caps = {
0419     .available_cs = 0x3f,
0420     .ebi_csa_offs = AT91SAM9G45_MATRIX_EBICSA,
0421     .regmap_name = "atmel,matrix",
0422     .get_config = at91sam9_ebi_get_config,
0423     .xlate_config = atmel_ebi_xslate_smc_config,
0424     .apply_config = at91sam9_ebi_apply_config,
0425 };
0426 
0427 static const struct atmel_ebi_caps at91sam9x5_ebi_caps = {
0428     .available_cs = 0x3f,
0429     .ebi_csa_offs = AT91SAM9X5_MATRIX_EBICSA,
0430     .regmap_name = "atmel,matrix",
0431     .get_config = at91sam9_ebi_get_config,
0432     .xlate_config = atmel_ebi_xslate_smc_config,
0433     .apply_config = at91sam9_ebi_apply_config,
0434 };
0435 
0436 static const struct atmel_ebi_caps sama5d3_ebi_caps = {
0437     .available_cs = 0xf,
0438     .get_config = sama5_ebi_get_config,
0439     .xlate_config = atmel_ebi_xslate_smc_config,
0440     .apply_config = sama5_ebi_apply_config,
0441 };
0442 
0443 static const struct atmel_ebi_caps sam9x60_ebi_caps = {
0444     .available_cs = 0x3f,
0445     .ebi_csa_offs = AT91_SFR_CCFG_EBICSA,
0446     .regmap_name = "microchip,sfr",
0447     .get_config = at91sam9_ebi_get_config,
0448     .xlate_config = atmel_ebi_xslate_smc_config,
0449     .apply_config = at91sam9_ebi_apply_config,
0450 };
0451 
0452 static const struct of_device_id atmel_ebi_id_table[] = {
0453     {
0454         .compatible = "atmel,at91sam9260-ebi",
0455         .data = &at91sam9260_ebi_caps,
0456     },
0457     {
0458         .compatible = "atmel,at91sam9261-ebi",
0459         .data = &at91sam9261_ebi_caps,
0460     },
0461     {
0462         .compatible = "atmel,at91sam9263-ebi0",
0463         .data = &at91sam9263_ebi0_caps,
0464     },
0465     {
0466         .compatible = "atmel,at91sam9263-ebi1",
0467         .data = &at91sam9263_ebi1_caps,
0468     },
0469     {
0470         .compatible = "atmel,at91sam9rl-ebi",
0471         .data = &at91sam9rl_ebi_caps,
0472     },
0473     {
0474         .compatible = "atmel,at91sam9g45-ebi",
0475         .data = &at91sam9g45_ebi_caps,
0476     },
0477     {
0478         .compatible = "atmel,at91sam9x5-ebi",
0479         .data = &at91sam9x5_ebi_caps,
0480     },
0481     {
0482         .compatible = "atmel,sama5d3-ebi",
0483         .data = &sama5d3_ebi_caps,
0484     },
0485     {
0486         .compatible = "microchip,sam9x60-ebi",
0487         .data = &sam9x60_ebi_caps,
0488     },
0489     { /* sentinel */ }
0490 };
0491 
0492 static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np)
0493 {
0494     struct device *dev = ebi->dev;
0495     struct property *newprop;
0496 
0497     newprop = devm_kzalloc(dev, sizeof(*newprop), GFP_KERNEL);
0498     if (!newprop)
0499         return -ENOMEM;
0500 
0501     newprop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
0502     if (!newprop->name)
0503         return -ENOMEM;
0504 
0505     newprop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
0506     if (!newprop->value)
0507         return -ENOMEM;
0508 
0509     newprop->length = sizeof("disabled");
0510 
0511     return of_update_property(np, newprop);
0512 }
0513 
0514 static int atmel_ebi_probe(struct platform_device *pdev)
0515 {
0516     struct device *dev = &pdev->dev;
0517     struct device_node *child, *np = dev->of_node, *smc_np;
0518     const struct of_device_id *match;
0519     struct atmel_ebi *ebi;
0520     int ret, reg_cells;
0521     struct clk *clk;
0522     u32 val;
0523 
0524     match = of_match_device(atmel_ebi_id_table, dev);
0525     if (!match || !match->data)
0526         return -EINVAL;
0527 
0528     ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL);
0529     if (!ebi)
0530         return -ENOMEM;
0531 
0532     platform_set_drvdata(pdev, ebi);
0533 
0534     INIT_LIST_HEAD(&ebi->devs);
0535     ebi->caps = match->data;
0536     ebi->dev = dev;
0537 
0538     clk = devm_clk_get(dev, NULL);
0539     if (IS_ERR(clk))
0540         return PTR_ERR(clk);
0541 
0542     ebi->clk = clk;
0543 
0544     smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0);
0545 
0546     ebi->smc.regmap = syscon_node_to_regmap(smc_np);
0547     if (IS_ERR(ebi->smc.regmap)) {
0548         ret = PTR_ERR(ebi->smc.regmap);
0549         goto put_node;
0550     }
0551 
0552     ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np);
0553     if (IS_ERR(ebi->smc.layout)) {
0554         ret = PTR_ERR(ebi->smc.layout);
0555         goto put_node;
0556     }
0557 
0558     ebi->smc.clk = of_clk_get(smc_np, 0);
0559     if (IS_ERR(ebi->smc.clk)) {
0560         if (PTR_ERR(ebi->smc.clk) != -ENOENT) {
0561             ret = PTR_ERR(ebi->smc.clk);
0562             goto put_node;
0563         }
0564 
0565         ebi->smc.clk = NULL;
0566     }
0567     of_node_put(smc_np);
0568     ret = clk_prepare_enable(ebi->smc.clk);
0569     if (ret)
0570         return ret;
0571 
0572     /*
0573      * The sama5d3 does not provide an EBICSA register and thus does need
0574      * to access it.
0575      */
0576     if (ebi->caps->ebi_csa_offs) {
0577         ebi->regmap =
0578             syscon_regmap_lookup_by_phandle(np,
0579                             ebi->caps->regmap_name);
0580         if (IS_ERR(ebi->regmap))
0581             return PTR_ERR(ebi->regmap);
0582     }
0583 
0584     ret = of_property_read_u32(np, "#address-cells", &val);
0585     if (ret) {
0586         dev_err(dev, "missing #address-cells property\n");
0587         return ret;
0588     }
0589 
0590     reg_cells = val;
0591 
0592     ret = of_property_read_u32(np, "#size-cells", &val);
0593     if (ret) {
0594         dev_err(dev, "missing #address-cells property\n");
0595         return ret;
0596     }
0597 
0598     reg_cells += val;
0599 
0600     for_each_available_child_of_node(np, child) {
0601         if (!of_find_property(child, "reg", NULL))
0602             continue;
0603 
0604         ret = atmel_ebi_dev_setup(ebi, child, reg_cells);
0605         if (ret) {
0606             dev_err(dev, "failed to configure EBI bus for %pOF, disabling the device",
0607                 child);
0608 
0609             ret = atmel_ebi_dev_disable(ebi, child);
0610             if (ret) {
0611                 of_node_put(child);
0612                 return ret;
0613             }
0614         }
0615     }
0616 
0617     return of_platform_populate(np, NULL, NULL, dev);
0618 
0619 put_node:
0620     of_node_put(smc_np);
0621     return ret;
0622 }
0623 
0624 static __maybe_unused int atmel_ebi_resume(struct device *dev)
0625 {
0626     struct atmel_ebi *ebi = dev_get_drvdata(dev);
0627     struct atmel_ebi_dev *ebid;
0628 
0629     list_for_each_entry(ebid, &ebi->devs, node) {
0630         int i;
0631 
0632         for (i = 0; i < ebid->numcs; i++)
0633             ebid->ebi->caps->apply_config(ebid, &ebid->configs[i]);
0634     }
0635 
0636     return 0;
0637 }
0638 
0639 static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume);
0640 
0641 static struct platform_driver atmel_ebi_driver = {
0642     .driver = {
0643         .name = "atmel-ebi",
0644         .of_match_table = atmel_ebi_id_table,
0645         .pm = &atmel_ebi_pm_ops,
0646     },
0647 };
0648 builtin_platform_driver_probe(atmel_ebi_driver, atmel_ebi_probe);