Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

pinctrl: renesas: rzt2h: Add pin configuration support

Add pin configuration support for the Renesas RZ/T2H SoC. The RZ/T2H SoC
allows configuring several electrical characteristics through the DRCTLm
(I/O Buffer Function Switching) registers. These registers control bias
configuration, Schmitt trigger input, output slew rate, and drive
strength.

Implement pinconf_ops to allow reading and updating these properties
through the generic pin configuration framework. The implementation
supports bias-disable, bias-pull-up, bias-pull-down,
input-schmitt-enable, slew-rate, and drive-strength-microamp.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20260319141515.2053556-3-prabhakar.mahadev-lad.rj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

authored by

Lad Prabhakar and committed by
Geert Uytterhoeven
494feecd 9efe63b7

+258
+258
drivers/pinctrl/renesas/pinctrl-rzt2h.c
··· 7 7 * Copyright (C) 2025 Renesas Electronics Corporation. 8 8 */ 9 9 10 + #include <linux/array_size.h> 10 11 #include <linux/bitfield.h> 11 12 #include <linux/bitops.h> 12 13 #include <linux/bits.h> ··· 44 43 #define PMC(m) (0x400 + (m)) 45 44 #define PFC(m) (0x600 + 8 * (m)) 46 45 #define PIN(m) (0x800 + (m)) 46 + #define DRCTL(n) (0xa00 + 8 * (n)) 47 47 #define RSELP(m) (0xc00 + (m)) 48 48 49 49 #define PM_MASK GENMASK(1, 0) ··· 55 53 #define PFC_MASK GENMASK_ULL(5, 0) 56 54 #define PFC_PIN_MASK(pin) (PFC_MASK << ((pin) * 8)) 57 55 #define PFC_FUNC_INTERRUPT 0 56 + 57 + #define DRCTL_DRV_PIN_MASK(pin) (GENMASK_ULL(1, 0) << ((pin) * 8)) 58 + #define DRCTL_PUD_PIN_MASK(pin) (GENMASK_ULL(3, 2) << ((pin) * 8)) 59 + #define DRCTL_SMT_PIN_MASK(pin) (BIT_ULL(4) << ((pin) * 8)) 60 + #define DRCTL_SR_PIN_MASK(pin) (BIT_ULL(5) << ((pin) * 8)) 61 + 62 + #define DRCTL_PUD_NONE 0 63 + #define DRCTL_PUD_PULL_UP 1 64 + #define DRCTL_PUD_PULL_DOWN 2 58 65 59 66 /* 60 67 * Use 16 lower bits [15:0] for pin identifier ··· 102 91 atomic_t wakeup_path; 103 92 }; 104 93 94 + static const unsigned int rzt2h_drive_strength_ua[] = { 2500, 5000, 9000, 11800 }; 95 + 105 96 #define RZT2H_GET_BASE(pctrl, port) \ 106 97 ((port) > RZT2H_MAX_SAFETY_PORTS ? (pctrl)->base0 : (pctrl)->base1) 107 98 ··· 122 109 RZT2H_PINCTRL_REG_ACCESS(b, u8) 123 110 RZT2H_PINCTRL_REG_ACCESS(w, u16) 124 111 RZT2H_PINCTRL_REG_ACCESS(q, u64) 112 + 113 + static int rzt2h_drive_strength_ua_to_idx(unsigned int ua) 114 + { 115 + unsigned int i; 116 + 117 + for (i = 0; i < ARRAY_SIZE(rzt2h_drive_strength_ua); i++) { 118 + if (rzt2h_drive_strength_ua[i] == ua) 119 + return i; 120 + } 121 + 122 + return -EINVAL; 123 + } 124 + 125 + static int rzt2h_drive_strength_idx_to_ua(unsigned int idx) 126 + { 127 + if (idx >= ARRAY_SIZE(rzt2h_drive_strength_ua)) 128 + return -EINVAL; 129 + 130 + return rzt2h_drive_strength_ua[idx]; 131 + } 132 + 133 + static void rzt2h_pinctrl_drctl_rmwq(struct rzt2h_pinctrl *pctrl, 134 + u32 port, u64 mask, u64 val) 135 + { 136 + u32 offset = DRCTL(port); 137 + u64 drctl; 138 + 139 + guard(raw_spinlock_irqsave)(&pctrl->lock); 140 + drctl = rzt2h_pinctrl_readq(pctrl, port, offset) & ~mask; 141 + rzt2h_pinctrl_writeq(pctrl, port, drctl | val, offset); 142 + } 125 143 126 144 static int rzt2h_validate_pin(struct rzt2h_pinctrl *pctrl, unsigned int offset) 127 145 { ··· 487 443 return ret; 488 444 } 489 445 446 + static int rzt2h_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, 447 + unsigned int pin, 448 + unsigned long *config) 449 + { 450 + struct rzt2h_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 451 + u32 port, param = pinconf_to_config_param(*config); 452 + unsigned int arg; 453 + u8 port_pin; 454 + u64 drctl; 455 + int ret; 456 + 457 + ret = rzt2h_validate_pin(pctrl, pin); 458 + if (ret) 459 + return ret; 460 + 461 + port = RZT2H_PIN_ID_TO_PORT(pin); 462 + port_pin = RZT2H_PIN_ID_TO_PIN(pin); 463 + 464 + switch (param) { 465 + case PIN_CONFIG_SLEW_RATE: 466 + drctl = rzt2h_pinctrl_readq(pctrl, port, DRCTL(port)); 467 + arg = field_get(DRCTL_SR_PIN_MASK(port_pin), drctl); 468 + break; 469 + 470 + case PIN_CONFIG_BIAS_DISABLE: 471 + case PIN_CONFIG_BIAS_PULL_UP: 472 + case PIN_CONFIG_BIAS_PULL_DOWN: 473 + drctl = rzt2h_pinctrl_readq(pctrl, port, DRCTL(port)); 474 + arg = field_get(DRCTL_PUD_PIN_MASK(port_pin), drctl); 475 + /* for PIN_CONFIG_BIAS_PULL_UP/DOWN when enabled we just return 1 */ 476 + switch (arg) { 477 + case DRCTL_PUD_NONE: 478 + if (param != PIN_CONFIG_BIAS_DISABLE) 479 + return -EINVAL; 480 + break; 481 + case DRCTL_PUD_PULL_UP: 482 + if (param != PIN_CONFIG_BIAS_PULL_UP) 483 + return -EINVAL; 484 + arg = 1; 485 + break; 486 + case DRCTL_PUD_PULL_DOWN: 487 + if (param != PIN_CONFIG_BIAS_PULL_DOWN) 488 + return -EINVAL; 489 + arg = 1; 490 + break; 491 + default: 492 + return -EINVAL; 493 + } 494 + break; 495 + 496 + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 497 + drctl = rzt2h_pinctrl_readq(pctrl, port, DRCTL(port)); 498 + arg = field_get(DRCTL_SMT_PIN_MASK(port_pin), drctl); 499 + if (!arg) 500 + return -EINVAL; 501 + break; 502 + 503 + case PIN_CONFIG_DRIVE_STRENGTH_UA: { 504 + int idx_drv; 505 + 506 + drctl = rzt2h_pinctrl_readq(pctrl, port, DRCTL(port)); 507 + arg = field_get(DRCTL_DRV_PIN_MASK(port_pin), drctl); 508 + idx_drv = rzt2h_drive_strength_idx_to_ua(arg); 509 + if (idx_drv < 0) 510 + return idx_drv; 511 + arg = idx_drv; 512 + break; 513 + } 514 + 515 + default: 516 + return -ENOTSUPP; 517 + } 518 + 519 + *config = pinconf_to_config_packed(param, arg); 520 + return 0; 521 + } 522 + 523 + static int rzt2h_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, 524 + unsigned int pin, 525 + unsigned long *configs, 526 + unsigned int num_configs) 527 + { 528 + struct rzt2h_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 529 + unsigned int i; 530 + u8 port_pin; 531 + int ret; 532 + 533 + ret = rzt2h_validate_pin(pctrl, pin); 534 + if (ret) 535 + return ret; 536 + 537 + port_pin = RZT2H_PIN_ID_TO_PIN(pin); 538 + 539 + for (i = 0; i < num_configs; i++) { 540 + u32 arg = pinconf_to_config_argument(configs[i]); 541 + u32 param = pinconf_to_config_param(configs[i]); 542 + u64 mask, val; 543 + 544 + switch (param) { 545 + case PIN_CONFIG_SLEW_RATE: 546 + mask = DRCTL_SR_PIN_MASK(port_pin); 547 + val = field_prep(mask, !!arg); 548 + break; 549 + 550 + case PIN_CONFIG_BIAS_DISABLE: 551 + case PIN_CONFIG_BIAS_PULL_UP: 552 + case PIN_CONFIG_BIAS_PULL_DOWN: { 553 + u32 bias; 554 + 555 + switch (param) { 556 + case PIN_CONFIG_BIAS_DISABLE: 557 + bias = DRCTL_PUD_NONE; 558 + break; 559 + case PIN_CONFIG_BIAS_PULL_UP: 560 + bias = DRCTL_PUD_PULL_UP; 561 + break; 562 + case PIN_CONFIG_BIAS_PULL_DOWN: 563 + bias = DRCTL_PUD_PULL_DOWN; 564 + break; 565 + } 566 + 567 + mask = DRCTL_PUD_PIN_MASK(port_pin); 568 + val = field_prep(mask, bias); 569 + break; 570 + } 571 + 572 + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 573 + mask = DRCTL_SMT_PIN_MASK(port_pin); 574 + val = field_prep(mask, !!arg); 575 + break; 576 + 577 + case PIN_CONFIG_DRIVE_STRENGTH_UA: { 578 + int drv_idx; 579 + 580 + drv_idx = rzt2h_drive_strength_ua_to_idx(arg); 581 + if (drv_idx < 0) 582 + return drv_idx; 583 + 584 + mask = DRCTL_DRV_PIN_MASK(port_pin); 585 + val = field_prep(mask, drv_idx); 586 + break; 587 + } 588 + 589 + default: 590 + return -ENOTSUPP; 591 + } 592 + 593 + rzt2h_pinctrl_drctl_rmwq(pctrl, RZT2H_PIN_ID_TO_PORT(pin), mask, val); 594 + } 595 + 596 + return 0; 597 + } 598 + 599 + static int rzt2h_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, 600 + unsigned int group, 601 + unsigned long *config) 602 + { 603 + unsigned long prev_config = 0; 604 + const unsigned int *pins; 605 + unsigned int i, npins; 606 + int ret; 607 + 608 + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); 609 + if (ret) 610 + return ret; 611 + 612 + for (i = 0; i < npins; i++) { 613 + ret = rzt2h_pinctrl_pinconf_get(pctldev, pins[i], config); 614 + if (ret) 615 + return ret; 616 + 617 + /* Check config matches previous pins */ 618 + if (i && prev_config != *config) 619 + return -ENOTSUPP; 620 + 621 + prev_config = *config; 622 + } 623 + 624 + return 0; 625 + } 626 + 627 + static int rzt2h_pinctrl_pinconf_group_set(struct pinctrl_dev *pctldev, 628 + unsigned int group, 629 + unsigned long *configs, 630 + unsigned int num_configs) 631 + { 632 + const unsigned int *pins; 633 + unsigned int i, npins; 634 + int ret; 635 + 636 + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); 637 + if (ret) 638 + return ret; 639 + 640 + for (i = 0; i < npins; i++) { 641 + ret = rzt2h_pinctrl_pinconf_set(pctldev, pins[i], configs, 642 + num_configs); 643 + if (ret) 644 + return ret; 645 + } 646 + 647 + return 0; 648 + } 649 + 490 650 static const struct pinctrl_ops rzt2h_pinctrl_pctlops = { 491 651 .get_groups_count = pinctrl_generic_get_group_count, 492 652 .get_group_name = pinctrl_generic_get_group_name, ··· 705 457 .get_function_groups = pinmux_generic_get_function_groups, 706 458 .set_mux = rzt2h_pinctrl_set_mux, 707 459 .strict = true, 460 + }; 461 + 462 + static const struct pinconf_ops rzt2h_pinctrl_confops = { 463 + .is_generic = true, 464 + .pin_config_get = rzt2h_pinctrl_pinconf_get, 465 + .pin_config_set = rzt2h_pinctrl_pinconf_set, 466 + .pin_config_group_set = rzt2h_pinctrl_pinconf_group_set, 467 + .pin_config_group_get = rzt2h_pinctrl_pinconf_group_get, 468 + .pin_config_config_dbg_show = pinconf_generic_dump_config, 708 469 }; 709 470 710 471 static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset) ··· 1147 890 desc->npins = pctrl->data->n_port_pins; 1148 891 desc->pctlops = &rzt2h_pinctrl_pctlops; 1149 892 desc->pmxops = &rzt2h_pinctrl_pmxops; 893 + desc->confops = &rzt2h_pinctrl_confops; 1150 894 desc->owner = THIS_MODULE; 1151 895 1152 896 pins = devm_kcalloc(dev, desc->npins, sizeof(*pins), GFP_KERNEL);