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