From 95099d4622f8cb224d94e314c7a8e0df60b13f87 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 08:38:01 +0000
Subject: [PATCH] enable docker ppp
---
kernel/drivers/pinctrl/meson/pinctrl-meson.c | 437 +++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 335 insertions(+), 102 deletions(-)
diff --git a/kernel/drivers/pinctrl/meson/pinctrl-meson.c b/kernel/drivers/pinctrl/meson/pinctrl-meson.c
index c8eff70..4985144 100644
--- a/kernel/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/kernel/drivers/pinctrl/meson/pinctrl-meson.c
@@ -1,14 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Pin controller and GPIO driver for Amlogic Meson SoCs
*
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
@@ -31,6 +25,9 @@
* In some cases the register ranges for pull enable and pull
* direction are the same and thus there are only 3 register ranges.
*
+ * Since Meson G12A SoC, the ao register ranges for gpio, pull enable
+ * and pull direction are the same, so there are only 2 register ranges.
+ *
* For the pull and GPIO configuration every bank uses a contiguous
* set of bits in the register sets described above; the same register
* can be shared by more banks with different offsets.
@@ -41,7 +38,7 @@
*/
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -58,6 +55,10 @@
#include "../core.h"
#include "../pinctrl-utils.h"
#include "pinctrl-meson.h"
+
+static const unsigned int meson_bit_strides[] = {
+ 1, 1, 1, 1, 1, 2, 1
+};
/**
* meson_get_bank() - find the bank containing a given pin
@@ -99,8 +100,9 @@
{
struct meson_reg_desc *desc = &bank->regs[reg_type];
- *reg = desc->reg * 4;
- *bit = desc->bit + pin - bank->first;
+ *bit = (desc->bit + pin - bank->first) * meson_bit_strides[reg_type];
+ *reg = (desc->reg + (*bit / 32)) * 4;
+ *bit &= 0x1f;
}
static int meson_get_groups_count(struct pinctrl_dev *pcdev)
@@ -150,6 +152,7 @@
return pc->data->num_funcs;
}
+EXPORT_SYMBOL_GPL(meson_pmx_get_funcs_count);
const char *meson_pmx_get_func_name(struct pinctrl_dev *pcdev,
unsigned selector)
@@ -158,6 +161,7 @@
return pc->data->funcs[selector].name;
}
+EXPORT_SYMBOL_GPL(meson_pmx_get_func_name);
int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector,
const char * const **groups,
@@ -170,69 +174,224 @@
return 0;
}
+EXPORT_SYMBOL_GPL(meson_pmx_get_groups);
-static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
- unsigned long *configs, unsigned num_configs)
+static int meson_pinconf_set_gpio_bit(struct meson_pinctrl *pc,
+ unsigned int pin,
+ unsigned int reg_type,
+ bool arg)
{
- struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
struct meson_bank *bank;
- enum pin_config_param param;
unsigned int reg, bit;
- int i, ret;
+ int ret;
ret = meson_get_bank(pc, pin, &bank);
if (ret)
return ret;
+ meson_calc_reg_and_bit(bank, pin, reg_type, ®, &bit);
+ return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
+ arg ? BIT(bit) : 0);
+}
+
+static int meson_pinconf_get_gpio_bit(struct meson_pinctrl *pc,
+ unsigned int pin,
+ unsigned int reg_type)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit, val;
+ int ret;
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, reg_type, ®, &bit);
+ ret = regmap_read(pc->reg_gpio, reg, &val);
+ if (ret)
+ return ret;
+
+ return BIT(bit) & val ? 1 : 0;
+}
+
+static int meson_pinconf_set_output(struct meson_pinctrl *pc,
+ unsigned int pin,
+ bool out)
+{
+ return meson_pinconf_set_gpio_bit(pc, pin, REG_DIR, !out);
+}
+
+static int meson_pinconf_get_output(struct meson_pinctrl *pc,
+ unsigned int pin)
+{
+ int ret = meson_pinconf_get_gpio_bit(pc, pin, REG_DIR);
+
+ if (ret < 0)
+ return ret;
+
+ return !ret;
+}
+
+static int meson_pinconf_set_drive(struct meson_pinctrl *pc,
+ unsigned int pin,
+ bool high)
+{
+ return meson_pinconf_set_gpio_bit(pc, pin, REG_OUT, high);
+}
+
+static int meson_pinconf_get_drive(struct meson_pinctrl *pc,
+ unsigned int pin)
+{
+ return meson_pinconf_get_gpio_bit(pc, pin, REG_OUT);
+}
+
+static int meson_pinconf_set_output_drive(struct meson_pinctrl *pc,
+ unsigned int pin,
+ bool high)
+{
+ int ret;
+
+ ret = meson_pinconf_set_output(pc, pin, true);
+ if (ret)
+ return ret;
+
+ return meson_pinconf_set_drive(pc, pin, high);
+}
+
+static int meson_pinconf_disable_bias(struct meson_pinctrl *pc,
+ unsigned int pin)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit = 0;
+ int ret;
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit);
+ ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin,
+ bool pull_up)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit, val = 0;
+ int ret;
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit);
+ if (pull_up)
+ val = BIT(bit);
+
+ ret = regmap_update_bits(pc->reg_pull, reg, BIT(bit), val);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit);
+ ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), BIT(bit));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int meson_pinconf_set_drive_strength(struct meson_pinctrl *pc,
+ unsigned int pin,
+ u16 drive_strength_ua)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit, ds_val;
+ int ret;
+
+ if (!pc->reg_ds) {
+ dev_err(pc->dev, "drive-strength not supported\n");
+ return -ENOTSUPP;
+ }
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit);
+
+ if (drive_strength_ua <= 500) {
+ ds_val = MESON_PINCONF_DRV_500UA;
+ } else if (drive_strength_ua <= 2500) {
+ ds_val = MESON_PINCONF_DRV_2500UA;
+ } else if (drive_strength_ua <= 3000) {
+ ds_val = MESON_PINCONF_DRV_3000UA;
+ } else if (drive_strength_ua <= 4000) {
+ ds_val = MESON_PINCONF_DRV_4000UA;
+ } else {
+ dev_warn_once(pc->dev,
+ "pin %u: invalid drive-strength : %d , default to 4mA\n",
+ pin, drive_strength_ua);
+ ds_val = MESON_PINCONF_DRV_4000UA;
+ }
+
+ ret = regmap_update_bits(pc->reg_ds, reg, 0x3 << bit, ds_val << bit);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+ enum pin_config_param param;
+ unsigned int arg = 0;
+ int i, ret;
+
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
switch (param) {
- case PIN_CONFIG_BIAS_DISABLE:
- dev_dbg(pc->dev, "pin %u: disable bias\n", pin);
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ case PIN_CONFIG_OUTPUT:
+ arg = pinconf_to_config_argument(configs[i]);
+ break;
- meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®,
- &bit);
- ret = regmap_update_bits(pc->reg_pullen, reg,
- BIT(bit), 0);
- if (ret)
- return ret;
+ default:
+ break;
+ }
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ ret = meson_pinconf_disable_bias(pc, pin);
break;
case PIN_CONFIG_BIAS_PULL_UP:
- dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin);
-
- meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
- ®, &bit);
- ret = regmap_update_bits(pc->reg_pullen, reg,
- BIT(bit), BIT(bit));
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit);
- ret = regmap_update_bits(pc->reg_pull, reg,
- BIT(bit), BIT(bit));
- if (ret)
- return ret;
+ ret = meson_pinconf_enable_bias(pc, pin, true);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin);
-
- meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
- ®, &bit);
- ret = regmap_update_bits(pc->reg_pullen, reg,
- BIT(bit), BIT(bit));
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit);
- ret = regmap_update_bits(pc->reg_pull, reg,
- BIT(bit), 0);
- if (ret)
- return ret;
+ ret = meson_pinconf_enable_bias(pc, pin, false);
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ ret = meson_pinconf_set_drive_strength(pc, pin, arg);
+ break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ ret = meson_pinconf_set_output(pc, pin, arg);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ ret = meson_pinconf_set_output_drive(pc, pin, arg);
break;
default:
- return -ENOTSUPP;
+ ret = -ENOTSUPP;
}
+
+ if (ret)
+ return ret;
}
return 0;
@@ -272,12 +431,55 @@
return conf;
}
+static int meson_pinconf_get_drive_strength(struct meson_pinctrl *pc,
+ unsigned int pin,
+ u16 *drive_strength_ua)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit;
+ unsigned int val;
+ int ret;
+
+ if (!pc->reg_ds)
+ return -ENOTSUPP;
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit);
+
+ ret = regmap_read(pc->reg_ds, reg, &val);
+ if (ret)
+ return ret;
+
+ switch ((val >> bit) & 0x3) {
+ case MESON_PINCONF_DRV_500UA:
+ *drive_strength_ua = 500;
+ break;
+ case MESON_PINCONF_DRV_2500UA:
+ *drive_strength_ua = 2500;
+ break;
+ case MESON_PINCONF_DRV_3000UA:
+ *drive_strength_ua = 3000;
+ break;
+ case MESON_PINCONF_DRV_4000UA:
+ *drive_strength_ua = 4000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
unsigned long *config)
{
struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
enum pin_config_param param = pinconf_to_config_param(*config);
u16 arg;
+ int ret;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
@@ -288,6 +490,29 @@
else
return -EINVAL;
break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ ret = meson_pinconf_get_drive_strength(pc, pin, &arg);
+ if (ret)
+ return ret;
+ break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ ret = meson_pinconf_get_output(pc, pin);
+ if (ret <= 0)
+ return -EINVAL;
+ arg = 1;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ ret = meson_pinconf_get_output(pc, pin);
+ if (ret <= 0)
+ return -EINVAL;
+
+ ret = meson_pinconf_get_drive(pc, pin);
+ if (ret < 0)
+ return -EINVAL;
+
+ arg = ret;
+ break;
+
default:
return -ENOTSUPP;
}
@@ -330,58 +555,33 @@
.is_generic = true,
};
-static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+static int meson_gpio_get_direction(struct gpio_chip *chip, unsigned gpio)
{
struct meson_pinctrl *pc = gpiochip_get_data(chip);
- unsigned int reg, bit;
- struct meson_bank *bank;
int ret;
- ret = meson_get_bank(pc, gpio, &bank);
- if (ret)
+ ret = meson_pinconf_get_output(pc, gpio);
+ if (ret < 0)
return ret;
- meson_calc_reg_and_bit(bank, gpio, REG_DIR, ®, &bit);
+ return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
- return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), BIT(bit));
+static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ return meson_pinconf_set_output(gpiochip_get_data(chip), gpio, false);
}
static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct meson_pinctrl *pc = gpiochip_get_data(chip);
- unsigned int reg, bit;
- struct meson_bank *bank;
- int ret;
-
- ret = meson_get_bank(pc, gpio, &bank);
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, gpio, REG_DIR, ®, &bit);
- ret = regmap_update_bits(pc->reg_gpio, reg, BIT(bit), 0);
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, gpio, REG_OUT, ®, &bit);
- return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
- value ? BIT(bit) : 0);
+ return meson_pinconf_set_output_drive(gpiochip_get_data(chip),
+ gpio, value);
}
static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
{
- struct meson_pinctrl *pc = gpiochip_get_data(chip);
- unsigned int reg, bit;
- struct meson_bank *bank;
- int ret;
-
- ret = meson_get_bank(pc, gpio, &bank);
- if (ret)
- return;
-
- meson_calc_reg_and_bit(bank, gpio, REG_OUT, ®, &bit);
- regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
- value ? BIT(bit) : 0);
+ meson_pinconf_set_drive(gpiochip_get_data(chip), gpio, value);
}
static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
@@ -409,6 +609,8 @@
pc->chip.parent = pc->dev;
pc->chip.request = gpiochip_generic_request;
pc->chip.free = gpiochip_generic_free;
+ pc->chip.set_config = gpiochip_generic_config;
+ pc->chip.get_direction = meson_gpio_get_direction;
pc->chip.direction_input = meson_gpio_direction_input;
pc->chip.direction_output = meson_gpio_direction_output;
pc->chip.get = meson_gpio_get;
@@ -444,7 +646,7 @@
i = of_property_match_string(node, "reg-names", name);
if (of_address_to_resource(node, i, &res))
- return ERR_PTR(-ENOENT);
+ return NULL;
base = devm_ioremap_resource(pc->dev, &res);
if (IS_ERR(base))
@@ -452,7 +654,7 @@
meson_regmap_config.max_register = resource_size(&res) - 4;
meson_regmap_config.name = devm_kasprintf(pc->dev, GFP_KERNEL,
- "%s-%s", node->name,
+ "%pOFn-%s", node,
name);
if (!meson_regmap_config.name)
return ERR_PTR(-ENOMEM);
@@ -470,6 +672,7 @@
continue;
if (gpio_np) {
dev_err(pc->dev, "multiple gpio nodes\n");
+ of_node_put(np);
return -EINVAL;
}
gpio_np = np;
@@ -483,30 +686,57 @@
pc->of_node = gpio_np;
pc->reg_mux = meson_map_resource(pc, gpio_np, "mux");
- if (IS_ERR(pc->reg_mux)) {
+ if (IS_ERR_OR_NULL(pc->reg_mux)) {
dev_err(pc->dev, "mux registers not found\n");
- return PTR_ERR(pc->reg_mux);
+ return pc->reg_mux ? PTR_ERR(pc->reg_mux) : -ENOENT;
+ }
+
+ pc->reg_gpio = meson_map_resource(pc, gpio_np, "gpio");
+ if (IS_ERR_OR_NULL(pc->reg_gpio)) {
+ dev_err(pc->dev, "gpio registers not found\n");
+ return pc->reg_gpio ? PTR_ERR(pc->reg_gpio) : -ENOENT;
}
pc->reg_pull = meson_map_resource(pc, gpio_np, "pull");
- if (IS_ERR(pc->reg_pull)) {
- dev_err(pc->dev, "pull registers not found\n");
- return PTR_ERR(pc->reg_pull);
- }
+ if (IS_ERR(pc->reg_pull))
+ pc->reg_pull = NULL;
pc->reg_pullen = meson_map_resource(pc, gpio_np, "pull-enable");
- /* Use pull region if pull-enable one is not present */
if (IS_ERR(pc->reg_pullen))
- pc->reg_pullen = pc->reg_pull;
+ pc->reg_pullen = NULL;
- pc->reg_gpio = meson_map_resource(pc, gpio_np, "gpio");
- if (IS_ERR(pc->reg_gpio)) {
- dev_err(pc->dev, "gpio registers not found\n");
- return PTR_ERR(pc->reg_gpio);
+ pc->reg_ds = meson_map_resource(pc, gpio_np, "ds");
+ if (IS_ERR(pc->reg_ds)) {
+ dev_dbg(pc->dev, "ds registers not found - skipping\n");
+ pc->reg_ds = NULL;
}
+
+ if (pc->data->parse_dt)
+ return pc->data->parse_dt(pc);
return 0;
}
+
+int meson8_aobus_parse_dt_extra(struct meson_pinctrl *pc)
+{
+ if (!pc->reg_pull)
+ return -EINVAL;
+
+ pc->reg_pullen = pc->reg_pull;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(meson8_aobus_parse_dt_extra);
+
+int meson_a1_parse_dt_extra(struct meson_pinctrl *pc)
+{
+ pc->reg_pull = pc->reg_gpio;
+ pc->reg_pullen = pc->reg_gpio;
+ pc->reg_ds = pc->reg_gpio;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(meson_a1_parse_dt_extra);
int meson_pinctrl_probe(struct platform_device *pdev)
{
@@ -541,3 +771,6 @@
return meson_gpiolib_register(pc);
}
+EXPORT_SYMBOL_GPL(meson_pinctrl_probe);
+
+MODULE_LICENSE("GPL v2");
--
Gitblit v1.6.2