diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-18 16:59:09 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-18 16:59:09 -0700 |
| commit | faeab166167f5787719eb8683661fd41a3bb1514 (patch) | |
| tree | 4483bcfbe6a67b555360e421860b0f6ef16aa575 /drivers/pinctrl/realtek/pinctrl-rtd.c | |
| parent | 401b0e0bc96543881924d623388a9472b3331b3f (diff) | |
| parent | 90700e10d2ad61c13a5117cfa5e08d9f2e497dcc (diff) | |
Merge tag 'pinctrl-v7.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrlHEADmaster
Pull pin control updates from Linus Walleij:
"Core changes:
- Perform basic checks on pin config properties so as not to allow
directly contradictory settings such as setting a pin to more than
one bias or drive mode
- Handle input-threshold-voltage-microvolt property
- Introduce pinctrl_gpio_get_config() handling in the core for SCMI
GPIO using pin control
New drivers:
- GPIO-by-pin control driver (also appearing in the GPIO pull
request) fulfilling a promise on a comment from Grant Likely many
years ago: "can't GPIO just be a front-end for pin control?" it
turns out it can, if and only if you design something new from
scratch, such as SCMI
- Broadcom BCM7038 as a pinctrl-single delegate
- Mobileye EyeQ6Lplus OLB pin controller
- Qualcomm Eliza and Hawi families TLMM pin controllers
- Qualcomm SDM670 and Milos family LPASS LPI pin controllers
- Qualcomm IPQ5210 pin controller
- Realtek RTD1625 pin controller support
- Rockchip RV1103B pin controller support
- Texas Instruments AM62L as a pinctrl-single delegate
Improvements:
- Set config implementation for the Spacemit K1 pin controller"
* tag 'pinctrl-v7.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (84 commits)
pinctrl: qcom: Add Hawi pinctrl driver
dt-bindings: pinctrl: qcom: Describe Hawi TLMM block
dt-bindings: pinctrl: pinctrl-max77620: convert to DT schema
pinctrl: single: Add bcm7038-padconf compatible matching
dt-bindings: pinctrl: pinctrl-single: Add brcm,bcm7038-padconf
dt-bindings: pinctrl: apple,pinctrl: Add t8122 compatible
pinctrl: qcom: sdm670-lpass-lpi: label variables as static
pinctrl: sophgo: pinctrl-sg2044: Fix wrong module description
pinctrl: sophgo: pinctrl-sg2042: Fix wrong module description
pinctrl: qcom: add sdm670 lpi tlmm
dt-bindings: pinctrl: qcom: Add SDM670 LPASS LPI pinctrl
dt-bindings: qcom: lpass-lpi-common: add reserved GPIOs property
pinctrl: qcom: Introduce IPQ5210 TLMM driver
dt-bindings: pinctrl: qcom: add IPQ5210 pinctrl
pinctrl: qcom: Drop redundant intr_target_reg on modern SoCs
pinctrl: qcom: eliza: Fix interrupt target bit
pinctrl: core: Don't use "proxy" headers
pinctrl: amd: Support new ACPI ID AMDI0033
pinctrl: renesas: rzg2l: Drop superfluous blank line
pinctrl: renesas: rzg2l: Fix save/restore of {IOLH,IEN,PUPD,SMT} registers
...
Diffstat (limited to 'drivers/pinctrl/realtek/pinctrl-rtd.c')
| -rw-r--r-- | drivers/pinctrl/realtek/pinctrl-rtd.c | 224 |
1 files changed, 189 insertions, 35 deletions
diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c index 2440604863327..a2c672508a4bd 100644 --- a/drivers/pinctrl/realtek/pinctrl-rtd.c +++ b/drivers/pinctrl/realtek/pinctrl-rtd.c @@ -30,17 +30,20 @@ struct rtd_pinctrl { struct pinctrl_desc desc; const struct rtd_pinctrl_desc *info; struct regmap *regmap_pinctrl; + u32 **saved_regs; }; /* custom pinconf parameters */ #define RTD_DRIVE_STRENGH_P (PIN_CONFIG_END + 1) #define RTD_DRIVE_STRENGH_N (PIN_CONFIG_END + 2) #define RTD_DUTY_CYCLE (PIN_CONFIG_END + 3) +#define RTD_HIGH_VIL (PIN_CONFIG_END + 4) static const struct pinconf_generic_params rtd_custom_bindings[] = { {"realtek,drive-strength-p", RTD_DRIVE_STRENGH_P, 0}, {"realtek,drive-strength-n", RTD_DRIVE_STRENGH_N, 0}, {"realtek,duty-cycle", RTD_DUTY_CYCLE, 0}, + {"realtek,high-vil-microvolt", RTD_HIGH_VIL, 0}, }; static int rtd_pinctrl_get_groups_count(struct pinctrl_dev *pcdev) @@ -279,7 +282,7 @@ static const struct rtd_pin_sconfig_desc *rtd_pinctrl_find_sconfig(struct rtd_pi static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, unsigned int pinnr, enum pin_config_param param, - enum pin_config_param arg) + unsigned int arg) { const struct rtd_pin_config_desc *config_desc; const struct rtd_pin_sconfig_desc *sconfig_desc; @@ -287,20 +290,21 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, u16 strength; u32 val; u32 mask; - u32 pulsel_off, pulen_off, smt_off, curr_off, pow_off, reg_off, p_off, n_off; + u32 pulsel_off, pulen_off, smt_off, curr_off, pow_off, reg_off, p_off, n_off, + input_volt_off, sr_off, hvil_off; const char *name = data->info->pins[pinnr].name; int ret = 0; config_desc = rtd_pinctrl_find_config(data, pinnr); if (!config_desc) { - dev_err(data->dev, "Not support pin config for pin: %s\n", name); + dev_err(data->dev, "Pin config unsupported for pin: %s\n", name); return -ENOTSUPP; } switch ((u32)param) { case PIN_CONFIG_INPUT_SCHMITT: case PIN_CONFIG_INPUT_SCHMITT_ENABLE: if (config_desc->smt_offset == NA) { - dev_err(data->dev, "Not support input schmitt for pin: %s\n", name); + dev_err(data->dev, "Input schmitt unsupported for pin: %s\n", name); return -ENOTSUPP; } smt_off = config_desc->base_bit + config_desc->smt_offset; @@ -313,7 +317,7 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, case PIN_CONFIG_DRIVE_PUSH_PULL: if (config_desc->pud_en_offset == NA) { - dev_err(data->dev, "Not support push pull for pin: %s\n", name); + dev_err(data->dev, "Push pull unsupported for pin: %s\n", name); return -ENOTSUPP; } pulen_off = config_desc->base_bit + config_desc->pud_en_offset; @@ -325,7 +329,7 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, case PIN_CONFIG_BIAS_DISABLE: if (config_desc->pud_en_offset == NA) { - dev_err(data->dev, "Not support bias disable for pin: %s\n", name); + dev_err(data->dev, "Bias disable unsupported for pin: %s\n", name); return -ENOTSUPP; } pulen_off = config_desc->base_bit + config_desc->pud_en_offset; @@ -337,7 +341,7 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, case PIN_CONFIG_BIAS_PULL_UP: if (config_desc->pud_en_offset == NA) { - dev_err(data->dev, "Not support bias pull up for pin:%s\n", name); + dev_err(data->dev, "Bias pull up unsupported for pin:%s\n", name); return -ENOTSUPP; } pulen_off = config_desc->base_bit + config_desc->pud_en_offset; @@ -350,7 +354,7 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, case PIN_CONFIG_BIAS_PULL_DOWN: if (config_desc->pud_en_offset == NA) { - dev_err(data->dev, "Not support bias pull down for pin: %s\n", name); + dev_err(data->dev, "Bias pull down unsupported for pin: %s\n", name); return -ENOTSUPP; } pulen_off = config_desc->base_bit + config_desc->pud_en_offset; @@ -384,7 +388,7 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, return -EINVAL; break; case NA: - dev_err(data->dev, "Not support drive strength for pin: %s\n", name); + dev_err(data->dev, "Drive strength unsupported for pin: %s\n", name); return -ENOTSUPP; default: return -EINVAL; @@ -394,7 +398,7 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, case PIN_CONFIG_POWER_SOURCE: if (config_desc->power_offset == NA) { - dev_err(data->dev, "Not support power source for pin: %s\n", name); + dev_err(data->dev, "Power source unsupported for pin: %s\n", name); return -ENOTSUPP; } reg_off = config_desc->reg_offset; @@ -408,10 +412,71 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, val = set_val ? mask : 0; break; + case PIN_CONFIG_SLEW_RATE: + if (config_desc->slew_rate_offset == NA) { + dev_err(data->dev, "Slew rate setting unsupported for pin: %s\n", name); + return -ENOTSUPP; + } + + switch (arg) { + case 1: + set_val = 0; + break; + case 10: + set_val = 1; + break; + case 20: + set_val = 2; + break; + case 30: + set_val = 3; + break; + default: + return -EINVAL; + } + + sr_off = config_desc->base_bit + config_desc->slew_rate_offset; + reg_off = config_desc->reg_offset; + mask = 0x3 << sr_off; + val = arg << sr_off; + break; + + case PIN_CONFIG_INPUT_VOLTAGE_UV: + if (config_desc->input_volt_offset == NA) { + dev_err(data->dev, "Input voltage level setting unsupported for pin:%s\n", + name); + return -ENOTSUPP; + } + + if (arg == 3300000) + set_val = 1; + else if (arg == 1800000) + set_val = 0; + else + return -EINVAL; + + input_volt_off = config_desc->base_bit + config_desc->input_volt_offset; + reg_off = config_desc->reg_offset; + + mask = BIT(input_volt_off); + val = set_val ? BIT(input_volt_off) : 0; + break; + + case RTD_HIGH_VIL: + if (config_desc->hvil_offset == NA) { + dev_err(data->dev, "High vil setting unsupported for pin:%s\n", name); + return -ENOTSUPP; + } + hvil_off = config_desc->base_bit + config_desc->hvil_offset; + reg_off = config_desc->reg_offset; + mask = BIT(hvil_off); + val = 1; + break; + case RTD_DRIVE_STRENGH_P: sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr); if (!sconfig_desc) { - dev_err(data->dev, "Not support P driving for pin: %s\n", name); + dev_err(data->dev, "P driving unsupported for pin: %s\n", name); return -ENOTSUPP; } set_val = arg; @@ -428,7 +493,7 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, case RTD_DRIVE_STRENGH_N: sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr); if (!sconfig_desc) { - dev_err(data->dev, "Not support N driving for pin: %s\n", name); + dev_err(data->dev, "N driving unsupported for pin: %s\n", name); return -ENOTSUPP; } set_val = arg; @@ -445,7 +510,7 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, case RTD_DUTY_CYCLE: sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr); if (!sconfig_desc || sconfig_desc->dcycle_offset == NA) { - dev_err(data->dev, "Not support duty cycle for pin: %s\n", name); + dev_err(data->dev, "Duty cycle unsupported for pin: %s\n", name); return -ENOTSUPP; } set_val = arg; @@ -456,8 +521,8 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, break; default: - dev_err(data->dev, "unsupported pinconf: %d\n", (u32)param); - return -EINVAL; + dev_dbg(data->dev, "unsupported pinconf: %d\n", (u32)param); + return -ENOTSUPP; } ret = regmap_update_bits(data->regmap_pinctrl, reg_off, mask, val); @@ -540,18 +605,42 @@ static const struct regmap_config rtd_pinctrl_regmap_config = { .use_relaxed_mmio = true, }; +static int rtd_pinctrl_init_pm(struct rtd_pinctrl *data) +{ + const struct rtd_pin_range *pin_range = data->info->pin_range; + struct device *dev = data->pcdev->dev; + const struct rtd_reg_range *range; + size_t num_entries; + int i; + + data->saved_regs = devm_kcalloc(dev, pin_range->num_ranges, sizeof(u32 *), GFP_KERNEL); + if (!data->saved_regs) + return -ENOMEM; + + for (i = 0; i < pin_range->num_ranges; i++) { + range = &pin_range->ranges[i]; + num_entries = range->len / 4; + + data->saved_regs[i] = devm_kzalloc(dev, num_entries * sizeof(u32), GFP_KERNEL); + if (!data->saved_regs[i]) + return -ENOMEM; + } + + return 0; +} + int rtd_pinctrl_probe(struct platform_device *pdev, const struct rtd_pinctrl_desc *desc) { struct rtd_pinctrl *data; - int ret; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->base = of_iomap(pdev->dev.of_node, 0); - if (!data->base) - return -ENOMEM; + data->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(data->base)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->base), + "Failed to ioremap resource\n"); data->dev = &pdev->dev; data->info = desc; @@ -567,30 +656,95 @@ int rtd_pinctrl_probe(struct platform_device *pdev, const struct rtd_pinctrl_des data->regmap_pinctrl = devm_regmap_init_mmio(data->dev, data->base, &rtd_pinctrl_regmap_config); - if (IS_ERR(data->regmap_pinctrl)) { - dev_err(data->dev, "failed to init regmap: %ld\n", - PTR_ERR(data->regmap_pinctrl)); - ret = PTR_ERR(data->regmap_pinctrl); - goto unmap; - } + if (IS_ERR(data->regmap_pinctrl)) + return dev_err_probe(data->dev, PTR_ERR(data->regmap_pinctrl), + "Failed to init regmap\n"); - data->pcdev = pinctrl_register(&data->desc, &pdev->dev, data); - if (IS_ERR(data->pcdev)) { - ret = PTR_ERR(data->pcdev); - goto unmap; - } + data->pcdev = devm_pinctrl_register(&pdev->dev, &data->desc, data); + if (IS_ERR(data->pcdev)) + return dev_err_probe(data->dev, PTR_ERR(data->pcdev), + "Failed to register pinctrl\n"); platform_set_drvdata(pdev, data); dev_dbg(&pdev->dev, "probed\n"); - return 0; + if (data->info->pin_range) { + if (rtd_pinctrl_init_pm(data)) + return -ENOMEM; + } -unmap: - iounmap(data->base); - return ret; + return 0; } EXPORT_SYMBOL(rtd_pinctrl_probe); +static int realtek_pinctrl_suspend(struct device *dev) +{ + struct rtd_pinctrl *data = dev_get_drvdata(dev); + const struct rtd_pin_range *pin_range = data->info->pin_range; + const struct rtd_reg_range *range; + u32 *range_regs; + int count; + int i, j; + int ret; + + if (!data->saved_regs) + return 0; + + for (i = 0; i < pin_range->num_ranges; i++) { + range = &pin_range->ranges[i]; + range_regs = data->saved_regs[i]; + count = range->len / 4; + + for (j = 0; j < count; j++) { + ret = regmap_read(data->regmap_pinctrl, range->offset + (j * 4), + &range_regs[j]); + if (ret) { + dev_err(dev, "failed to store register 0x%x: %d\n", + range->offset + (j * 4), ret); + return ret; + } + } + } + + return 0; +} + +static int realtek_pinctrl_resume(struct device *dev) +{ + struct rtd_pinctrl *data = dev_get_drvdata(dev); + const struct rtd_pin_range *pin_range = data->info->pin_range; + const struct rtd_reg_range *range; + u32 *range_regs; + int count; + int i, j; + int ret; + + if (!data->saved_regs) + return 0; + + for (i = 0; i < pin_range->num_ranges; i++) { + range = &pin_range->ranges[i]; + range_regs = data->saved_regs[i]; + count = range->len / 4; + + for (j = 0; j < count; j++) { + ret = regmap_write(data->regmap_pinctrl, range->offset + (j * 4), + range_regs[j]); + if (ret) { + dev_err(dev, "failed to restore register 0x%x: %d\n", + range->offset + (j * 4), ret); + return ret; + } + } + } + return 0; +} + +const struct dev_pm_ops realtek_pinctrl_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(realtek_pinctrl_suspend, realtek_pinctrl_resume) +}; +EXPORT_SYMBOL_GPL(realtek_pinctrl_pm_ops); + MODULE_DESCRIPTION("Realtek DHC SoC pinctrl driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); |
