From f9004dbfff8a3fbbd7e2a88c8a4327c7f2f8e5b2 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 01:04:47 +0000 Subject: [PATCH] add driver 5G --- kernel/drivers/pinctrl/tegra/pinctrl-tegra.c | 155 ++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 132 insertions(+), 23 deletions(-) diff --git a/kernel/drivers/pinctrl/tegra/pinctrl-tegra.c b/kernel/drivers/pinctrl/tegra/pinctrl-tegra.c index 26a3f1e..195cfe5 100644 --- a/kernel/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/kernel/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the NVIDIA Tegra pinmux * @@ -7,15 +8,6 @@ * Copyright (C) 2010 Google, Inc. * Copyright (C) 2010 NVIDIA Corporation * Copyright (C) 2009-2011 ST-Ericsson AB - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include <linux/err.h> @@ -283,18 +275,64 @@ return 0; } +static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tegra_pingroup *group; + u32 value; + + if (!pmx->soc->sfsel_in_mux) + return 0; + + group = &pmx->soc->groups[offset]; + + if (group->mux_reg < 0 || group->sfsel_bit < 0) + return -EINVAL; + + value = pmx_readl(pmx, group->mux_bank, group->mux_reg); + value &= ~BIT(group->sfsel_bit); + pmx_writel(pmx, value, group->mux_bank, group->mux_reg); + + return 0; +} + +static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tegra_pingroup *group; + u32 value; + + if (!pmx->soc->sfsel_in_mux) + return; + + group = &pmx->soc->groups[offset]; + + if (group->mux_reg < 0 || group->sfsel_bit < 0) + return; + + value = pmx_readl(pmx, group->mux_bank, group->mux_reg); + value |= BIT(group->sfsel_bit); + pmx_writel(pmx, value, group->mux_bank, group->mux_reg); +} + static const struct pinmux_ops tegra_pinmux_ops = { .get_functions_count = tegra_pinctrl_get_funcs_count, .get_function_name = tegra_pinctrl_get_func_name, .get_function_groups = tegra_pinctrl_get_func_groups, .set_mux = tegra_pinctrl_set_mux, + .gpio_request_enable = tegra_pinctrl_gpio_request_enable, + .gpio_disable_free = tegra_pinctrl_gpio_disable_free, }; static int tegra_pinconf_reg(struct tegra_pmx *pmx, const struct tegra_pingroup *g, enum tegra_pinconf_param param, bool report_err, - s8 *bank, s16 *reg, s8 *bit, s8 *width) + s8 *bank, s32 *reg, s8 *bit, s8 *width) { switch (param) { case TEGRA_PINCONF_PARAM_PULL: @@ -453,7 +491,7 @@ const struct tegra_pingroup *g; int ret; s8 bank, bit, width; - s16 reg; + s32 reg; u32 val, mask; g = &pmx->soc->groups[group]; @@ -482,7 +520,7 @@ const struct tegra_pingroup *g; int ret, i; s8 bank, bit, width; - s16 reg; + s32 reg; u32 val, mask; g = &pmx->soc->groups[group]; @@ -550,7 +588,7 @@ const struct tegra_pingroup *g; int i, ret; s8 bank, bit, width; - s16 reg; + s32 reg; u32 val; g = &pmx->soc->groups[group]; @@ -623,20 +661,86 @@ for (i = 0; i < pmx->soc->ngroups; ++i) { g = &pmx->soc->groups[i]; - if (g->parked_bit >= 0) { - val = pmx_readl(pmx, g->mux_bank, g->mux_reg); - val &= ~(1 << g->parked_bit); - pmx_writel(pmx, val, g->mux_bank, g->mux_reg); + if (g->parked_bitmask > 0) { + unsigned int bank, reg; + + if (g->mux_reg != -1) { + bank = g->mux_bank; + reg = g->mux_reg; + } else { + bank = g->drv_bank; + reg = g->drv_reg; + } + + val = pmx_readl(pmx, bank, reg); + val &= ~g->parked_bitmask; + pmx_writel(pmx, val, bank, reg); } } } -static bool gpio_node_has_range(const char *compatible) +static size_t tegra_pinctrl_get_bank_size(struct device *dev, + unsigned int bank_id) +{ + struct platform_device *pdev = to_platform_device(dev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id); + + return resource_size(res) / 4; +} + +static int tegra_pinctrl_suspend(struct device *dev) +{ + struct tegra_pmx *pmx = dev_get_drvdata(dev); + u32 *backup_regs = pmx->backup_regs; + u32 __iomem *regs; + size_t bank_size; + unsigned int i, k; + + for (i = 0; i < pmx->nbanks; i++) { + bank_size = tegra_pinctrl_get_bank_size(dev, i); + regs = pmx->regs[i]; + for (k = 0; k < bank_size; k++) + *backup_regs++ = readl_relaxed(regs++); + } + + return pinctrl_force_sleep(pmx->pctl); +} + +static int tegra_pinctrl_resume(struct device *dev) +{ + struct tegra_pmx *pmx = dev_get_drvdata(dev); + u32 *backup_regs = pmx->backup_regs; + u32 __iomem *regs; + size_t bank_size; + unsigned int i, k; + + for (i = 0; i < pmx->nbanks; i++) { + bank_size = tegra_pinctrl_get_bank_size(dev, i); + regs = pmx->regs[i]; + for (k = 0; k < bank_size; k++) + writel_relaxed(*backup_regs++, regs++); + } + + /* flush all the prior writes */ + readl_relaxed(pmx->regs[0]); + /* wait for pinctrl register read to complete */ + rmb(); + return 0; +} + +const struct dev_pm_ops tegra_pinctrl_pm = { + .suspend_noirq = &tegra_pinctrl_suspend, + .resume_noirq = &tegra_pinctrl_resume +}; + +static bool tegra_pinctrl_gpio_node_has_range(struct tegra_pmx *pmx) { struct device_node *np; bool has_prop = false; - np = of_find_compatible_node(NULL, NULL, compatible); + np = of_find_compatible_node(NULL, NULL, pmx->soc->gpio_compatible); if (!np) return has_prop; @@ -655,6 +759,7 @@ int i; const char **group_pins; int fn, gn, gfn; + unsigned long backup_regs_size = 0; pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); if (!pmx) @@ -707,6 +812,7 @@ res = platform_get_resource(pdev, IORESOURCE_MEM, i); if (!res) break; + backup_regs_size += resource_size(res); } pmx->nbanks = i; @@ -715,9 +821,13 @@ if (!pmx->regs) return -ENOMEM; + pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size, + GFP_KERNEL); + if (!pmx->backup_regs) + return -ENOMEM; + for (i = 0; i < pmx->nbanks; i++) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res); + pmx->regs[i] = devm_platform_ioremap_resource(pdev, i); if (IS_ERR(pmx->regs[i])) return PTR_ERR(pmx->regs[i]); } @@ -730,7 +840,7 @@ tegra_pinctrl_clear_parked_bits(pmx); - if (!gpio_node_has_range(pmx->soc->gpio_compatible)) + if (pmx->soc->ngpios > 0 && !tegra_pinctrl_gpio_node_has_range(pmx)) pinctrl_add_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range); platform_set_drvdata(pdev, pmx); @@ -739,4 +849,3 @@ return 0; } -EXPORT_SYMBOL_GPL(tegra_pinctrl_probe); -- Gitblit v1.6.2