| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * EBI driver for Atmel chips |
|---|
| 3 | 4 | * inspired by the fsl weim bus driver |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This file is licensed under the terms of the GNU General Public |
|---|
| 8 | | - * License version 2. This program is licensed "as is" without any |
|---|
| 9 | | - * warranty of any kind, whether express or implied. |
|---|
| 10 | 7 | */ |
|---|
| 11 | 8 | |
|---|
| 12 | 9 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 17 | 14 | #include <linux/init.h> |
|---|
| 18 | 15 | #include <linux/of_device.h> |
|---|
| 19 | 16 | #include <linux/regmap.h> |
|---|
| 17 | +#include <soc/at91/atmel-sfr.h> |
|---|
| 18 | + |
|---|
| 19 | +#define AT91_EBI_NUM_CS 8 |
|---|
| 20 | 20 | |
|---|
| 21 | 21 | struct atmel_ebi_dev_config { |
|---|
| 22 | 22 | int cs; |
|---|
| .. | .. |
|---|
| 36 | 36 | struct atmel_ebi_caps { |
|---|
| 37 | 37 | unsigned int available_cs; |
|---|
| 38 | 38 | unsigned int ebi_csa_offs; |
|---|
| 39 | + const char *regmap_name; |
|---|
| 39 | 40 | void (*get_config)(struct atmel_ebi_dev *ebid, |
|---|
| 40 | 41 | struct atmel_ebi_dev_config *conf); |
|---|
| 41 | 42 | int (*xlate_config)(struct atmel_ebi_dev *ebid, |
|---|
| .. | .. |
|---|
| 47 | 48 | |
|---|
| 48 | 49 | struct atmel_ebi { |
|---|
| 49 | 50 | struct clk *clk; |
|---|
| 50 | | - struct regmap *matrix; |
|---|
| 51 | + struct regmap *regmap; |
|---|
| 51 | 52 | struct { |
|---|
| 52 | 53 | struct regmap *regmap; |
|---|
| 53 | 54 | struct clk *clk; |
|---|
| .. | .. |
|---|
| 312 | 313 | if (ret) |
|---|
| 313 | 314 | return ret; |
|---|
| 314 | 315 | |
|---|
| 315 | | - if (cs >= AT91_MATRIX_EBI_NUM_CS || |
|---|
| 316 | + if (cs >= AT91_EBI_NUM_CS || |
|---|
| 316 | 317 | !(ebi->caps->available_cs & BIT(cs))) { |
|---|
| 317 | 318 | dev_err(dev, "invalid reg property in %pOF\n", np); |
|---|
| 318 | 319 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 327 | 328 | return -EINVAL; |
|---|
| 328 | 329 | } |
|---|
| 329 | 330 | |
|---|
| 330 | | - ebid = devm_kzalloc(ebi->dev, |
|---|
| 331 | | - sizeof(*ebid) + (numcs * sizeof(*ebid->configs)), |
|---|
| 331 | + ebid = devm_kzalloc(ebi->dev, struct_size(ebid, configs, numcs), |
|---|
| 332 | 332 | GFP_KERNEL); |
|---|
| 333 | 333 | if (!ebid) |
|---|
| 334 | 334 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 343 | 343 | apply = true; |
|---|
| 344 | 344 | |
|---|
| 345 | 345 | i = 0; |
|---|
| 346 | | - for_each_set_bit(cs, &cslines, AT91_MATRIX_EBI_NUM_CS) { |
|---|
| 346 | + for_each_set_bit(cs, &cslines, AT91_EBI_NUM_CS) { |
|---|
| 347 | 347 | ebid->configs[i].cs = cs; |
|---|
| 348 | 348 | |
|---|
| 349 | 349 | if (apply) { |
|---|
| .. | .. |
|---|
| 358 | 358 | * one "atmel,smc-" property is present. |
|---|
| 359 | 359 | */ |
|---|
| 360 | 360 | if (ebi->caps->ebi_csa_offs && apply) |
|---|
| 361 | | - regmap_update_bits(ebi->matrix, |
|---|
| 361 | + regmap_update_bits(ebi->regmap, |
|---|
| 362 | 362 | ebi->caps->ebi_csa_offs, |
|---|
| 363 | 363 | BIT(cs), 0); |
|---|
| 364 | 364 | |
|---|
| .. | .. |
|---|
| 373 | 373 | static const struct atmel_ebi_caps at91sam9260_ebi_caps = { |
|---|
| 374 | 374 | .available_cs = 0xff, |
|---|
| 375 | 375 | .ebi_csa_offs = AT91SAM9260_MATRIX_EBICSA, |
|---|
| 376 | + .regmap_name = "atmel,matrix", |
|---|
| 376 | 377 | .get_config = at91sam9_ebi_get_config, |
|---|
| 377 | 378 | .xlate_config = atmel_ebi_xslate_smc_config, |
|---|
| 378 | 379 | .apply_config = at91sam9_ebi_apply_config, |
|---|
| .. | .. |
|---|
| 381 | 382 | static const struct atmel_ebi_caps at91sam9261_ebi_caps = { |
|---|
| 382 | 383 | .available_cs = 0xff, |
|---|
| 383 | 384 | .ebi_csa_offs = AT91SAM9261_MATRIX_EBICSA, |
|---|
| 385 | + .regmap_name = "atmel,matrix", |
|---|
| 384 | 386 | .get_config = at91sam9_ebi_get_config, |
|---|
| 385 | 387 | .xlate_config = atmel_ebi_xslate_smc_config, |
|---|
| 386 | 388 | .apply_config = at91sam9_ebi_apply_config, |
|---|
| .. | .. |
|---|
| 389 | 391 | static const struct atmel_ebi_caps at91sam9263_ebi0_caps = { |
|---|
| 390 | 392 | .available_cs = 0x3f, |
|---|
| 391 | 393 | .ebi_csa_offs = AT91SAM9263_MATRIX_EBI0CSA, |
|---|
| 394 | + .regmap_name = "atmel,matrix", |
|---|
| 392 | 395 | .get_config = at91sam9_ebi_get_config, |
|---|
| 393 | 396 | .xlate_config = atmel_ebi_xslate_smc_config, |
|---|
| 394 | 397 | .apply_config = at91sam9_ebi_apply_config, |
|---|
| .. | .. |
|---|
| 397 | 400 | static const struct atmel_ebi_caps at91sam9263_ebi1_caps = { |
|---|
| 398 | 401 | .available_cs = 0x7, |
|---|
| 399 | 402 | .ebi_csa_offs = AT91SAM9263_MATRIX_EBI1CSA, |
|---|
| 403 | + .regmap_name = "atmel,matrix", |
|---|
| 400 | 404 | .get_config = at91sam9_ebi_get_config, |
|---|
| 401 | 405 | .xlate_config = atmel_ebi_xslate_smc_config, |
|---|
| 402 | 406 | .apply_config = at91sam9_ebi_apply_config, |
|---|
| .. | .. |
|---|
| 405 | 409 | static const struct atmel_ebi_caps at91sam9rl_ebi_caps = { |
|---|
| 406 | 410 | .available_cs = 0x3f, |
|---|
| 407 | 411 | .ebi_csa_offs = AT91SAM9RL_MATRIX_EBICSA, |
|---|
| 412 | + .regmap_name = "atmel,matrix", |
|---|
| 408 | 413 | .get_config = at91sam9_ebi_get_config, |
|---|
| 409 | 414 | .xlate_config = atmel_ebi_xslate_smc_config, |
|---|
| 410 | 415 | .apply_config = at91sam9_ebi_apply_config, |
|---|
| .. | .. |
|---|
| 413 | 418 | static const struct atmel_ebi_caps at91sam9g45_ebi_caps = { |
|---|
| 414 | 419 | .available_cs = 0x3f, |
|---|
| 415 | 420 | .ebi_csa_offs = AT91SAM9G45_MATRIX_EBICSA, |
|---|
| 421 | + .regmap_name = "atmel,matrix", |
|---|
| 416 | 422 | .get_config = at91sam9_ebi_get_config, |
|---|
| 417 | 423 | .xlate_config = atmel_ebi_xslate_smc_config, |
|---|
| 418 | 424 | .apply_config = at91sam9_ebi_apply_config, |
|---|
| .. | .. |
|---|
| 421 | 427 | static const struct atmel_ebi_caps at91sam9x5_ebi_caps = { |
|---|
| 422 | 428 | .available_cs = 0x3f, |
|---|
| 423 | 429 | .ebi_csa_offs = AT91SAM9X5_MATRIX_EBICSA, |
|---|
| 430 | + .regmap_name = "atmel,matrix", |
|---|
| 424 | 431 | .get_config = at91sam9_ebi_get_config, |
|---|
| 425 | 432 | .xlate_config = atmel_ebi_xslate_smc_config, |
|---|
| 426 | 433 | .apply_config = at91sam9_ebi_apply_config, |
|---|
| .. | .. |
|---|
| 431 | 438 | .get_config = sama5_ebi_get_config, |
|---|
| 432 | 439 | .xlate_config = atmel_ebi_xslate_smc_config, |
|---|
| 433 | 440 | .apply_config = sama5_ebi_apply_config, |
|---|
| 441 | +}; |
|---|
| 442 | + |
|---|
| 443 | +static 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, |
|---|
| 434 | 450 | }; |
|---|
| 435 | 451 | |
|---|
| 436 | 452 | static const struct of_device_id atmel_ebi_id_table[] = { |
|---|
| .. | .. |
|---|
| 465 | 481 | { |
|---|
| 466 | 482 | .compatible = "atmel,sama5d3-ebi", |
|---|
| 467 | 483 | .data = &sama5d3_ebi_caps, |
|---|
| 484 | + }, |
|---|
| 485 | + { |
|---|
| 486 | + .compatible = "microchip,sam9x60-ebi", |
|---|
| 487 | + .data = &sam9x60_ebi_caps, |
|---|
| 468 | 488 | }, |
|---|
| 469 | 489 | { /* sentinel */ } |
|---|
| 470 | 490 | }; |
|---|
| .. | .. |
|---|
| 524 | 544 | smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0); |
|---|
| 525 | 545 | |
|---|
| 526 | 546 | ebi->smc.regmap = syscon_node_to_regmap(smc_np); |
|---|
| 527 | | - if (IS_ERR(ebi->smc.regmap)) |
|---|
| 528 | | - return PTR_ERR(ebi->smc.regmap); |
|---|
| 547 | + if (IS_ERR(ebi->smc.regmap)) { |
|---|
| 548 | + ret = PTR_ERR(ebi->smc.regmap); |
|---|
| 549 | + goto put_node; |
|---|
| 550 | + } |
|---|
| 529 | 551 | |
|---|
| 530 | 552 | ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np); |
|---|
| 531 | | - if (IS_ERR(ebi->smc.layout)) |
|---|
| 532 | | - return PTR_ERR(ebi->smc.layout); |
|---|
| 553 | + if (IS_ERR(ebi->smc.layout)) { |
|---|
| 554 | + ret = PTR_ERR(ebi->smc.layout); |
|---|
| 555 | + goto put_node; |
|---|
| 556 | + } |
|---|
| 533 | 557 | |
|---|
| 534 | 558 | ebi->smc.clk = of_clk_get(smc_np, 0); |
|---|
| 535 | 559 | if (IS_ERR(ebi->smc.clk)) { |
|---|
| 536 | | - if (PTR_ERR(ebi->smc.clk) != -ENOENT) |
|---|
| 537 | | - return PTR_ERR(ebi->smc.clk); |
|---|
| 560 | + if (PTR_ERR(ebi->smc.clk) != -ENOENT) { |
|---|
| 561 | + ret = PTR_ERR(ebi->smc.clk); |
|---|
| 562 | + goto put_node; |
|---|
| 563 | + } |
|---|
| 538 | 564 | |
|---|
| 539 | 565 | ebi->smc.clk = NULL; |
|---|
| 540 | 566 | } |
|---|
| 567 | + of_node_put(smc_np); |
|---|
| 541 | 568 | ret = clk_prepare_enable(ebi->smc.clk); |
|---|
| 542 | 569 | if (ret) |
|---|
| 543 | 570 | return ret; |
|---|
| 544 | 571 | |
|---|
| 545 | 572 | /* |
|---|
| 546 | 573 | * The sama5d3 does not provide an EBICSA register and thus does need |
|---|
| 547 | | - * to access the matrix registers. |
|---|
| 574 | + * to access it. |
|---|
| 548 | 575 | */ |
|---|
| 549 | 576 | if (ebi->caps->ebi_csa_offs) { |
|---|
| 550 | | - ebi->matrix = |
|---|
| 551 | | - syscon_regmap_lookup_by_phandle(np, "atmel,matrix"); |
|---|
| 552 | | - if (IS_ERR(ebi->matrix)) |
|---|
| 553 | | - return PTR_ERR(ebi->matrix); |
|---|
| 577 | + ebi->regmap = |
|---|
| 578 | + syscon_regmap_lookup_by_phandle(np, |
|---|
| 579 | + ebi->caps->regmap_name); |
|---|
| 580 | + if (IS_ERR(ebi->regmap)) |
|---|
| 581 | + return PTR_ERR(ebi->regmap); |
|---|
| 554 | 582 | } |
|---|
| 555 | 583 | |
|---|
| 556 | 584 | ret = of_property_read_u32(np, "#address-cells", &val); |
|---|
| .. | .. |
|---|
| 587 | 615 | } |
|---|
| 588 | 616 | |
|---|
| 589 | 617 | return of_platform_populate(np, NULL, NULL, dev); |
|---|
| 618 | + |
|---|
| 619 | +put_node: |
|---|
| 620 | + of_node_put(smc_np); |
|---|
| 621 | + return ret; |
|---|
| 590 | 622 | } |
|---|
| 591 | 623 | |
|---|
| 592 | 624 | static __maybe_unused int atmel_ebi_resume(struct device *dev) |
|---|