| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Spreadtrum pin controller driver |
|---|
| 3 | 4 | * Copyright (C) 2017 Spreadtrum - http://www.spreadtrum.com |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or |
|---|
| 6 | | - * modify it under the terms of the GNU General Public License |
|---|
| 7 | | - * version 2 as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 10 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 12 | | - * General Public License for more details. |
|---|
| 13 | 5 | */ |
|---|
| 14 | 6 | |
|---|
| 15 | 7 | #include <linux/debugfs.h> |
|---|
| .. | .. |
|---|
| 49 | 41 | #define PUBCP_SLEEP_MODE BIT(14) |
|---|
| 50 | 42 | #define TGLDSP_SLEEP_MODE BIT(15) |
|---|
| 51 | 43 | #define AGDSP_SLEEP_MODE BIT(16) |
|---|
| 52 | | -#define SLEEP_MODE_MASK GENMASK(3, 0) |
|---|
| 44 | +#define CM4_SLEEP_MODE BIT(17) |
|---|
| 45 | +#define SLEEP_MODE_MASK GENMASK(5, 0) |
|---|
| 53 | 46 | #define SLEEP_MODE_SHIFT 13 |
|---|
| 54 | 47 | |
|---|
| 55 | 48 | #define SLEEP_INPUT BIT(1) |
|---|
| .. | .. |
|---|
| 75 | 68 | #define SLEEP_PULL_UP_MASK 0x1 |
|---|
| 76 | 69 | #define SLEEP_PULL_UP_SHIFT 3 |
|---|
| 77 | 70 | |
|---|
| 78 | | -#define PULL_UP_20K (BIT(12) | BIT(7)) |
|---|
| 79 | | -#define PULL_UP_4_7K BIT(12) |
|---|
| 71 | +#define PULL_UP_4_7K (BIT(12) | BIT(7)) |
|---|
| 72 | +#define PULL_UP_20K BIT(7) |
|---|
| 80 | 73 | #define PULL_UP_MASK 0x21 |
|---|
| 81 | 74 | #define PULL_UP_SHIFT 7 |
|---|
| 82 | 75 | |
|---|
| .. | .. |
|---|
| 89 | 82 | PUBCP_SLEEP = BIT(1), |
|---|
| 90 | 83 | TGLDSP_SLEEP = BIT(2), |
|---|
| 91 | 84 | AGDSP_SLEEP = BIT(3), |
|---|
| 85 | + CM4_SLEEP = BIT(4), |
|---|
| 92 | 86 | }; |
|---|
| 93 | 87 | |
|---|
| 94 | 88 | enum pin_func_sel { |
|---|
| .. | .. |
|---|
| 462 | 456 | if (pin->type == GLOBAL_CTRL_PIN && |
|---|
| 463 | 457 | param == SPRD_PIN_CONFIG_CONTROL) { |
|---|
| 464 | 458 | arg = reg; |
|---|
| 465 | | - } else if (pin->type == COMMON_PIN) { |
|---|
| 459 | + } else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) { |
|---|
| 466 | 460 | switch (param) { |
|---|
| 467 | 461 | case SPRD_PIN_CONFIG_SLEEP_MODE: |
|---|
| 468 | 462 | arg = (reg >> SLEEP_MODE_SHIFT) & SLEEP_MODE_MASK; |
|---|
| .. | .. |
|---|
| 470 | 464 | case PIN_CONFIG_INPUT_ENABLE: |
|---|
| 471 | 465 | arg = (reg >> SLEEP_INPUT_SHIFT) & SLEEP_INPUT_MASK; |
|---|
| 472 | 466 | break; |
|---|
| 473 | | - case PIN_CONFIG_OUTPUT: |
|---|
| 467 | + case PIN_CONFIG_OUTPUT_ENABLE: |
|---|
| 474 | 468 | arg = reg & SLEEP_OUTPUT_MASK; |
|---|
| 475 | 469 | break; |
|---|
| 476 | | - case PIN_CONFIG_SLEEP_HARDWARE_STATE: |
|---|
| 477 | | - arg = 0; |
|---|
| 470 | + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: |
|---|
| 471 | + if ((reg & SLEEP_OUTPUT) || (reg & SLEEP_INPUT)) |
|---|
| 472 | + return -EINVAL; |
|---|
| 473 | + |
|---|
| 474 | + arg = 1; |
|---|
| 478 | 475 | break; |
|---|
| 479 | | - default: |
|---|
| 480 | | - return -ENOTSUPP; |
|---|
| 481 | | - } |
|---|
| 482 | | - } else if (pin->type == MISC_PIN) { |
|---|
| 483 | | - switch (param) { |
|---|
| 484 | 476 | case PIN_CONFIG_DRIVE_STRENGTH: |
|---|
| 485 | 477 | arg = (reg >> DRIVE_STRENGTH_SHIFT) & |
|---|
| 486 | 478 | DRIVE_STRENGTH_MASK; |
|---|
| .. | .. |
|---|
| 499 | 491 | arg = ((reg >> SLEEP_PULL_UP_SHIFT) & |
|---|
| 500 | 492 | SLEEP_PULL_UP_MASK) << 16; |
|---|
| 501 | 493 | arg |= (reg >> PULL_UP_SHIFT) & PULL_UP_MASK; |
|---|
| 494 | + break; |
|---|
| 495 | + case PIN_CONFIG_BIAS_DISABLE: |
|---|
| 496 | + if ((reg & (SLEEP_PULL_DOWN | SLEEP_PULL_UP)) || |
|---|
| 497 | + (reg & (PULL_DOWN | PULL_UP_4_7K | PULL_UP_20K))) |
|---|
| 498 | + return -EINVAL; |
|---|
| 499 | + |
|---|
| 500 | + arg = 1; |
|---|
| 502 | 501 | break; |
|---|
| 503 | 502 | case PIN_CONFIG_SLEEP_HARDWARE_STATE: |
|---|
| 504 | 503 | arg = 0; |
|---|
| .. | .. |
|---|
| 614 | 613 | if (pin->type == GLOBAL_CTRL_PIN && |
|---|
| 615 | 614 | param == SPRD_PIN_CONFIG_CONTROL) { |
|---|
| 616 | 615 | val = arg; |
|---|
| 617 | | - } else if (pin->type == COMMON_PIN) { |
|---|
| 616 | + } else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) { |
|---|
| 618 | 617 | switch (param) { |
|---|
| 619 | 618 | case SPRD_PIN_CONFIG_SLEEP_MODE: |
|---|
| 620 | 619 | if (arg & AP_SLEEP) |
|---|
| .. | .. |
|---|
| 625 | 624 | val |= TGLDSP_SLEEP_MODE; |
|---|
| 626 | 625 | if (arg & AGDSP_SLEEP) |
|---|
| 627 | 626 | val |= AGDSP_SLEEP_MODE; |
|---|
| 627 | + if (arg & CM4_SLEEP) |
|---|
| 628 | + val |= CM4_SLEEP_MODE; |
|---|
| 628 | 629 | |
|---|
| 629 | 630 | mask = SLEEP_MODE_MASK; |
|---|
| 630 | 631 | shift = SLEEP_MODE_SHIFT; |
|---|
| .. | .. |
|---|
| 640 | 641 | shift = SLEEP_INPUT_SHIFT; |
|---|
| 641 | 642 | } |
|---|
| 642 | 643 | break; |
|---|
| 643 | | - case PIN_CONFIG_OUTPUT: |
|---|
| 644 | + case PIN_CONFIG_OUTPUT_ENABLE: |
|---|
| 644 | 645 | if (is_sleep_config == true) { |
|---|
| 645 | | - val |= SLEEP_OUTPUT; |
|---|
| 646 | + if (arg > 0) |
|---|
| 647 | + val |= SLEEP_OUTPUT; |
|---|
| 648 | + else |
|---|
| 649 | + val &= ~SLEEP_OUTPUT; |
|---|
| 650 | + |
|---|
| 646 | 651 | mask = SLEEP_OUTPUT_MASK; |
|---|
| 647 | 652 | shift = SLEEP_OUTPUT_SHIFT; |
|---|
| 648 | 653 | } |
|---|
| 649 | 654 | break; |
|---|
| 650 | | - case PIN_CONFIG_SLEEP_HARDWARE_STATE: |
|---|
| 651 | | - continue; |
|---|
| 652 | | - default: |
|---|
| 653 | | - return -ENOTSUPP; |
|---|
| 654 | | - } |
|---|
| 655 | | - } else if (pin->type == MISC_PIN) { |
|---|
| 656 | | - switch (param) { |
|---|
| 655 | + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: |
|---|
| 656 | + if (is_sleep_config == true) { |
|---|
| 657 | + val = shift = 0; |
|---|
| 658 | + mask = SLEEP_OUTPUT | SLEEP_INPUT; |
|---|
| 659 | + } |
|---|
| 660 | + break; |
|---|
| 657 | 661 | case PIN_CONFIG_DRIVE_STRENGTH: |
|---|
| 658 | 662 | if (arg < 2 || arg > 60) |
|---|
| 659 | 663 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 695 | 699 | |
|---|
| 696 | 700 | mask = PULL_UP_MASK; |
|---|
| 697 | 701 | shift = PULL_UP_SHIFT; |
|---|
| 702 | + } |
|---|
| 703 | + break; |
|---|
| 704 | + case PIN_CONFIG_BIAS_DISABLE: |
|---|
| 705 | + if (is_sleep_config == true) { |
|---|
| 706 | + val = shift = 0; |
|---|
| 707 | + mask = SLEEP_PULL_DOWN | SLEEP_PULL_UP; |
|---|
| 708 | + } else { |
|---|
| 709 | + val = shift = 0; |
|---|
| 710 | + mask = PULL_DOWN | PULL_UP_20K | |
|---|
| 711 | + PULL_UP_4_7K; |
|---|
| 698 | 712 | } |
|---|
| 699 | 713 | break; |
|---|
| 700 | 714 | case PIN_CONFIG_SLEEP_HARDWARE_STATE: |
|---|
| .. | .. |
|---|
| 948 | 962 | |
|---|
| 949 | 963 | for_each_child_of_node(np, child) { |
|---|
| 950 | 964 | ret = sprd_pinctrl_parse_groups(child, sprd_pctl, grp); |
|---|
| 951 | | - if (ret) |
|---|
| 965 | + if (ret) { |
|---|
| 966 | + of_node_put(child); |
|---|
| 952 | 967 | return ret; |
|---|
| 968 | + } |
|---|
| 953 | 969 | |
|---|
| 954 | 970 | *temp++ = grp->name; |
|---|
| 955 | 971 | grp++; |
|---|
| .. | .. |
|---|
| 958 | 974 | for_each_child_of_node(child, sub_child) { |
|---|
| 959 | 975 | ret = sprd_pinctrl_parse_groups(sub_child, |
|---|
| 960 | 976 | sprd_pctl, grp); |
|---|
| 961 | | - if (ret) |
|---|
| 977 | + if (ret) { |
|---|
| 978 | + of_node_put(sub_child); |
|---|
| 979 | + of_node_put(child); |
|---|
| 962 | 980 | return ret; |
|---|
| 981 | + } |
|---|
| 963 | 982 | |
|---|
| 964 | 983 | *temp++ = grp->name; |
|---|
| 965 | 984 | grp++; |
|---|
| .. | .. |
|---|
| 1028 | 1047 | struct sprd_pinctrl *sprd_pctl; |
|---|
| 1029 | 1048 | struct sprd_pinctrl_soc_info *pinctrl_info; |
|---|
| 1030 | 1049 | struct pinctrl_pin_desc *pin_desc; |
|---|
| 1031 | | - struct resource *res; |
|---|
| 1032 | 1050 | int ret, i; |
|---|
| 1033 | 1051 | |
|---|
| 1034 | 1052 | sprd_pctl = devm_kzalloc(&pdev->dev, sizeof(struct sprd_pinctrl), |
|---|
| .. | .. |
|---|
| 1036 | 1054 | if (!sprd_pctl) |
|---|
| 1037 | 1055 | return -ENOMEM; |
|---|
| 1038 | 1056 | |
|---|
| 1039 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 1040 | | - sprd_pctl->base = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 1057 | + sprd_pctl->base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 1041 | 1058 | if (IS_ERR(sprd_pctl->base)) |
|---|
| 1042 | 1059 | return PTR_ERR(sprd_pctl->base); |
|---|
| 1043 | 1060 | |
|---|
| .. | .. |
|---|
| 1054 | 1071 | ret = sprd_pinctrl_add_pins(sprd_pctl, sprd_soc_pin_info, pins_cnt); |
|---|
| 1055 | 1072 | if (ret) { |
|---|
| 1056 | 1073 | dev_err(&pdev->dev, "fail to add pins information\n"); |
|---|
| 1074 | + return ret; |
|---|
| 1075 | + } |
|---|
| 1076 | + |
|---|
| 1077 | + ret = sprd_pinctrl_parse_dt(sprd_pctl); |
|---|
| 1078 | + if (ret) { |
|---|
| 1079 | + dev_err(&pdev->dev, "fail to parse dt properties\n"); |
|---|
| 1057 | 1080 | return ret; |
|---|
| 1058 | 1081 | } |
|---|
| 1059 | 1082 | |
|---|
| .. | .. |
|---|
| 1081 | 1104 | return PTR_ERR(sprd_pctl->pctl); |
|---|
| 1082 | 1105 | } |
|---|
| 1083 | 1106 | |
|---|
| 1084 | | - ret = sprd_pinctrl_parse_dt(sprd_pctl); |
|---|
| 1085 | | - if (ret) { |
|---|
| 1086 | | - dev_err(&pdev->dev, "fail to parse dt properties\n"); |
|---|
| 1087 | | - pinctrl_unregister(sprd_pctl->pctl); |
|---|
| 1088 | | - return ret; |
|---|
| 1089 | | - } |
|---|
| 1090 | | - |
|---|
| 1091 | 1107 | return 0; |
|---|
| 1092 | 1108 | } |
|---|
| 1109 | +EXPORT_SYMBOL_GPL(sprd_pinctrl_core_probe); |
|---|
| 1093 | 1110 | |
|---|
| 1094 | 1111 | int sprd_pinctrl_remove(struct platform_device *pdev) |
|---|
| 1095 | 1112 | { |
|---|
| .. | .. |
|---|
| 1098 | 1115 | pinctrl_unregister(sprd_pctl->pctl); |
|---|
| 1099 | 1116 | return 0; |
|---|
| 1100 | 1117 | } |
|---|
| 1118 | +EXPORT_SYMBOL_GPL(sprd_pinctrl_remove); |
|---|
| 1101 | 1119 | |
|---|
| 1102 | 1120 | void sprd_pinctrl_shutdown(struct platform_device *pdev) |
|---|
| 1103 | 1121 | { |
|---|
| .. | .. |
|---|
| 1112 | 1130 | return; |
|---|
| 1113 | 1131 | pinctrl_select_state(pinctl, state); |
|---|
| 1114 | 1132 | } |
|---|
| 1133 | +EXPORT_SYMBOL_GPL(sprd_pinctrl_shutdown); |
|---|
| 1115 | 1134 | |
|---|
| 1116 | 1135 | MODULE_DESCRIPTION("SPREADTRUM Pin Controller Driver"); |
|---|
| 1117 | 1136 | MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>"); |
|---|