.. | .. |
---|
| 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>"); |
---|