* [PATCH v2 0/3] Pinctrl driver for Amlogic Meson SoCs
@ 2014-10-14 21:21 Beniamino Galvani
2014-10-14 21:21 ` [PATCH v2 1/3] pinctrl: add " Beniamino Galvani
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Beniamino Galvani @ 2014-10-14 21:21 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-arm-kernel, linux-kernel, Carlo Caione, devicetree,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Jerry Cao, Victor Wan, Beniamino Galvani
Hi,
this series introduces a driver for Amlogic Meson pinctrl and GPIOs,
adding the basic infrastructure for all the SoCs of the Meson family
and configuration data specific for Meson8.
I tested the pinmux and GPIO functionalities on a Tronsmart Vega S89e
TV box and everything seems to work, however I'm not so familiar with
the pinctrl subsystem and thus any feedback is very welcome.
Changes since v1 [https://lkml.org/lkml/2014/10/7/712]
- added missing checks of return values
- indentation fixes
- added missing definitions of groups and functions for Meson8
Beniamino Galvani (3):
pinctrl: add driver for Amlogic Meson SoCs
pinctrl: meson: add device tree bindings documentation
ARM: dts: meson8: add pinctrl and gpio nodes
.../devicetree/bindings/pinctrl/meson,pinctrl.txt | 79 ++
arch/arm/boot/dts/meson8-vega-s89e.dts | 16 +-
arch/arm/boot/dts/meson8.dtsi | 35 +
arch/arm/mach-meson/Kconfig | 3 +
drivers/pinctrl/Kconfig | 8 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/meson/Makefile | 2 +
drivers/pinctrl/meson/pinctrl-meson.c | 824 +++++++++++++++++++++
drivers/pinctrl/meson/pinctrl-meson.h | 217 ++++++
drivers/pinctrl/meson/pinctrl-meson8.c | 534 +++++++++++++
include/dt-bindings/gpio/meson8-gpio.h | 155 ++++
11 files changed, 1873 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
create mode 100644 drivers/pinctrl/meson/Makefile
create mode 100644 drivers/pinctrl/meson/pinctrl-meson.c
create mode 100644 drivers/pinctrl/meson/pinctrl-meson.h
create mode 100644 drivers/pinctrl/meson/pinctrl-meson8.c
create mode 100644 include/dt-bindings/gpio/meson8-gpio.h
--
1.9.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/3] pinctrl: add driver for Amlogic Meson SoCs
2014-10-14 21:21 [PATCH v2 0/3] Pinctrl driver for Amlogic Meson SoCs Beniamino Galvani
@ 2014-10-14 21:21 ` Beniamino Galvani
2014-10-28 14:19 ` Linus Walleij
2014-10-14 21:21 ` [PATCH v2 2/3] pinctrl: meson: add device tree bindings documentation Beniamino Galvani
2014-10-14 21:21 ` [PATCH v2 3/3] ARM: dts: meson8: add pinctrl and gpio nodes Beniamino Galvani
2 siblings, 1 reply; 6+ messages in thread
From: Beniamino Galvani @ 2014-10-14 21:21 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-arm-kernel, linux-kernel, Carlo Caione, devicetree,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Jerry Cao, Victor Wan, Beniamino Galvani
This is a driver for the pinmux and GPIO controller available in
Amlogic Meson SoCs. At the moment it only supports Meson8 devices,
however other SoC families like Meson6 and Meson8b (the Cortex-A5
variant) appear to be similar, with just different sets of banks and
registers.
GPIO interrupts are not supported at the moment due to lack of
documentation.
Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
---
arch/arm/mach-meson/Kconfig | 3 +
drivers/pinctrl/Kconfig | 8 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/meson/Makefile | 2 +
drivers/pinctrl/meson/pinctrl-meson.c | 824 +++++++++++++++++++++++++++++++++
drivers/pinctrl/meson/pinctrl-meson.h | 217 +++++++++
drivers/pinctrl/meson/pinctrl-meson8.c | 534 +++++++++++++++++++++
include/dt-bindings/gpio/meson8-gpio.h | 155 +++++++
8 files changed, 1744 insertions(+)
create mode 100644 drivers/pinctrl/meson/Makefile
create mode 100644 drivers/pinctrl/meson/pinctrl-meson.c
create mode 100644 drivers/pinctrl/meson/pinctrl-meson.h
create mode 100644 drivers/pinctrl/meson/pinctrl-meson8.c
create mode 100644 include/dt-bindings/gpio/meson8-gpio.h
diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig
index b289e8e..7c2988d 100644
--- a/arch/arm/mach-meson/Kconfig
+++ b/arch/arm/mach-meson/Kconfig
@@ -2,6 +2,9 @@ menuconfig ARCH_MESON
bool "Amlogic Meson SoCs" if ARCH_MULTI_V7
select GENERIC_IRQ_CHIP
select ARM_GIC
+ select PINCTRL
+ select PINCTRL_MESON
+ select ARCH_REQUIRE_GPIOLIB
if ARCH_MESON
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index c6a66de..22b05e1 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -108,6 +108,14 @@ config PINCTRL_FALCON
depends on SOC_FALCON
depends on PINCTRL_LANTIQ
+config PINCTRL_MESON
+ bool "Amlogic Meson pin controller driver"
+ depends on ARCH_MESON
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ select OF_GPIO
+
config PINCTRL_ROCKCHIP
bool
select PINMUX
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 51f52d3..7b22f89 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o
obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o
obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o
+obj-$(CONFIG_PINCTRL_MESON) += meson/
obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
new file mode 100644
index 0000000..03a90b4
--- /dev/null
+++ b/drivers/pinctrl/meson/Makefile
@@ -0,0 +1,2 @@
+obj-y += pinctrl-meson.o
+obj-y += pinctrl-meson8.o
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
new file mode 100644
index 0000000..a02f50bc
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -0,0 +1,824 @@
+/*
+ * 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/>.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+#include "pinctrl-meson.h"
+
+static void meson_domain_set_bit(struct meson_domain *domain,
+ void __iomem *addr, unsigned int bit,
+ unsigned int value)
+{
+ unsigned long flags;
+ unsigned int data;
+
+ spin_lock_irqsave(&domain->lock, flags);
+ data = readl(addr);
+
+ if (value)
+ data |= BIT(bit);
+ else
+ data &= ~BIT(bit);
+
+ writel(data, addr);
+ spin_unlock_irqrestore(&domain->lock, flags);
+}
+
+static struct meson_domain *meson_pinctrl_get_domain(struct meson_pinctrl *pc,
+ int pin)
+{
+ struct meson_domain *domain;
+ int i, j;
+
+ for (i = 0; i < pc->num_domains; i++) {
+ domain = &pc->domains[i];
+ for (j = 0; j < domain->data->num_banks; j++) {
+ if (pin >= domain->data->banks[j].first &&
+ pin < domain->data->banks[j].last)
+ return domain;
+ }
+ }
+
+ return NULL;
+}
+
+static int meson_pinctrl_calc_regnum_bit(struct meson_domain *domain,
+ unsigned pin, int reg_type,
+ unsigned int *reg_num,
+ unsigned int *bit)
+{
+ struct meson_bank *bank;
+ int i, found = 0;
+
+ for (i = 0; i < domain->data->num_banks; i++) {
+ bank = &domain->data->banks[i];
+ if (pin >= bank->first && pin <= bank->last) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return 1;
+
+ *reg_num = bank->regs[reg_type].reg;
+ *bit = bank->regs[reg_type].bit + pin - bank->first;
+
+ return 0;
+}
+
+static void *meson_get_mux_reg(struct meson_domain *domain,
+ unsigned int reg_num)
+{
+ if (reg_num < domain->mux_size)
+ return domain->reg_mux + 4 * reg_num;
+
+ return NULL;
+}
+
+static int meson_get_groups_count(struct pinctrl_dev *pcdev)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ return pc->num_groups;
+}
+
+static const char *meson_get_group_name(struct pinctrl_dev *pcdev,
+ unsigned selector)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ return pc->groups[selector].name;
+}
+
+static int meson_get_group_pins(struct pinctrl_dev *pcdev, unsigned selector,
+ const unsigned **pins, unsigned *num_pins)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ *pins = pc->groups[selector].pins;
+ *num_pins = pc->groups[selector].num_pins;
+
+ return 0;
+}
+
+static void meson_pin_dbg_show(struct pinctrl_dev *pcdev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, " %s", dev_name(pcdev->dev));
+}
+
+static const struct pinctrl_ops meson_pctrl_ops = {
+ .get_groups_count = meson_get_groups_count,
+ .get_group_name = meson_get_group_name,
+ .get_group_pins = meson_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+ .pin_dbg_show = meson_pin_dbg_show,
+};
+
+static void meson_pmx_disable_other_groups(struct meson_pinctrl *pc,
+ unsigned int pin, int sel_group)
+{
+ struct meson_pmx_group *group;
+ struct meson_domain *domain;
+ void __iomem *reg;
+ int i, j;
+
+ for (i = 0; i < pc->num_groups; i++) {
+ group = &pc->groups[i];
+
+ if (group->is_gpio || i == sel_group)
+ continue;
+
+ for (j = 0; j < group->num_pins; j++) {
+ if (group->pins[j] == pin) {
+ domain = group->domain;
+ reg = meson_get_mux_reg(domain, group->reg);
+ if (reg)
+ meson_domain_set_bit(domain, reg,
+ group->bit, 0);
+ break;
+ }
+ }
+ }
+}
+
+static int meson_pmx_set_mux(struct pinctrl_dev *pcdev, unsigned func_num,
+ unsigned group_num)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+ struct meson_pmx_func *func = &pc->funcs[func_num];
+ struct meson_pmx_group *group = &pc->groups[group_num];
+ void __iomem *reg;
+ int i;
+
+ dev_dbg(pc->dev, "enable function %s, group %s\n", func->name,
+ group->name);
+
+ reg = meson_get_mux_reg(group->domain, group->reg);
+ if (!reg)
+ return -EINVAL;
+
+ /* Disable other groups using the same pins */
+ for (i = 0; i < group->num_pins; i++)
+ meson_pmx_disable_other_groups(pc, group->pins[i], group_num);
+
+ /*
+ * Function 0 (GPIO) is the default one and doesn't need any
+ * additional settings
+ */
+ if (func_num)
+ meson_domain_set_bit(group->domain, reg, group->bit, 1);
+
+ return 0;
+}
+
+static int meson_pmx_request_gpio(struct pinctrl_dev *pcdev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ meson_pmx_disable_other_groups(pc, offset, -1);
+
+ return 0;
+}
+
+static int meson_pmx_get_funcs_count(struct pinctrl_dev *pcdev)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ return pc->num_funcs;
+}
+
+static const char *meson_pmx_get_func_name(struct pinctrl_dev *pcdev,
+ unsigned selector)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ return pc->funcs[selector].name;
+}
+
+static int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ *groups = pc->funcs[selector].groups;
+ *num_groups = pc->funcs[selector].num_groups;
+
+ return 0;
+}
+
+static const struct pinmux_ops meson_pmx_ops = {
+ .set_mux = meson_pmx_set_mux,
+ .get_functions_count = meson_pmx_get_funcs_count,
+ .get_function_name = meson_pmx_get_func_name,
+ .get_function_groups = meson_pmx_get_groups,
+ .gpio_request_enable = meson_pmx_request_gpio,
+};
+
+static int meson_pinctrl_calc_reg_bit(struct meson_domain *domain,
+ unsigned int pin, int reg_type,
+ void **reg, unsigned int *bit)
+{
+ unsigned int reg_num;
+ int ret;
+
+ *reg = NULL;
+
+ ret = meson_pinctrl_calc_regnum_bit(domain, pin, reg_type,
+ ®_num, bit);
+ if (ret)
+ return -EINVAL;
+
+ if (reg_type == REG_PULLEN) {
+ if (reg_num < domain->pullen_size)
+ *reg = domain->reg_pullen + 4 * reg_num;
+ } else {
+ if (reg_num < domain->pull_size)
+ *reg = domain->reg_pull + 4 * reg_num;
+ }
+
+ return *reg ? 0 : -EINVAL;
+}
+
+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);
+ void __iomem *pullen_reg, __iomem *pull_reg;
+ unsigned int pullen_bit, pull_bit;
+ enum pin_config_param param;
+ struct meson_domain *domain;
+ int i, ret;
+ u16 arg;
+
+ domain = meson_pinctrl_get_domain(pc, pin);
+ if (!domain)
+ return -EINVAL;
+
+ ret = meson_pinctrl_calc_reg_bit(domain, pin, REG_PULL,
+ &pull_reg, &pull_bit);
+ if (ret)
+ return -EINVAL;
+
+ ret = meson_pinctrl_calc_reg_bit(domain, pin, REG_PULLEN,
+ &pullen_reg, &pullen_bit);
+ if (ret)
+ return -EINVAL;
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ dev_dbg(pc->dev, "pin %d bias-disable\n", pin);
+ meson_domain_set_bit(domain, pullen_reg, pullen_bit, 0);
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ dev_dbg(pc->dev, "pin %d pull-up\n", pin);
+ meson_domain_set_bit(domain, pullen_reg, pullen_bit, 1);
+ meson_domain_set_bit(domain, pull_reg, pull_bit, 1);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ dev_dbg(pc->dev, "pin %d pull-down\n", pin);
+ meson_domain_set_bit(domain, pullen_reg, pullen_bit, 1);
+ meson_domain_set_bit(domain, pull_reg, pull_bit, 0);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin)
+{
+ struct meson_domain *domain;
+ unsigned int bit;
+ int ret, conf;
+ void *reg;
+
+ domain = meson_pinctrl_get_domain(pc, pin);
+ if (!domain)
+ return -EINVAL;
+
+ ret = meson_pinctrl_calc_reg_bit(domain, pin, REG_PULLEN, ®, &bit);
+ if (ret) {
+ dev_err(pc->dev, "can't find register for pin %u\n", pin);
+ return -EINVAL;
+ }
+
+ if (!(readl(reg) & BIT(bit))) {
+ conf = PIN_CONFIG_BIAS_DISABLE;
+ } else {
+ ret = meson_pinctrl_calc_reg_bit(domain, pin, REG_PULL,
+ ®, &bit);
+ if (ret) {
+ dev_err(pc->dev, "can't find register for pin %u\n",
+ pin);
+ return -EINVAL;
+ }
+
+ if (!(readl(reg) & BIT(bit)))
+ conf = PIN_CONFIG_BIAS_PULL_DOWN;
+ else
+ conf = PIN_CONFIG_BIAS_PULL_UP;
+ }
+
+ return conf;
+}
+
+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;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (meson_pinconf_get_pull(pc, pin) == param)
+ arg = 1;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
+static int meson_pinconf_group_set(struct pinctrl_dev *pcdev,
+ unsigned int num_group,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+ struct meson_pmx_group *group = &pc->groups[num_group];
+ int i;
+
+ dev_dbg(pc->dev, "set pinconf for group %s\n", group->name);
+
+ for (i = 0; i < group->num_pins; i++) {
+ meson_pinconf_set(pcdev, group->pins[i], configs,
+ num_configs);
+ }
+
+ return 0;
+}
+
+static int meson_pinconf_group_get(struct pinctrl_dev *pcdev,
+ unsigned int group, unsigned long *config)
+{
+ return -ENOSYS;
+}
+
+static const struct pinconf_ops meson_pinconf_ops = {
+ .pin_config_get = meson_pinconf_get,
+ .pin_config_set = meson_pinconf_set,
+ .pin_config_group_get = meson_pinconf_group_get,
+ .pin_config_group_set = meson_pinconf_group_set,
+ .is_generic = true,
+};
+
+static inline struct meson_domain *to_meson_domain(struct gpio_chip *chip)
+{
+ return container_of(chip, struct meson_domain, chip);
+}
+
+static int meson_gpio_request(struct gpio_chip *chip, unsigned gpio)
+{
+ return pinctrl_request_gpio(chip->base + gpio);
+}
+
+static void meson_gpio_free(struct gpio_chip *chip, unsigned gpio)
+{
+ pinctrl_free_gpio(chip->base + gpio);
+}
+
+static int meson_gpio_calc_reg_bit(struct meson_domain *domain, unsigned gpio,
+ int reg_type, void **reg, unsigned int *bit)
+{
+ unsigned int reg_num;
+ int ret;
+
+ ret = meson_pinctrl_calc_regnum_bit(domain, gpio, reg_type,
+ ®_num, bit);
+
+ if (ret)
+ return -EINVAL;
+
+ if (reg_num >= domain->gpio_size)
+ return -EINVAL;
+
+ *reg = domain->reg_gpio + 4 * reg_num;
+
+ return 0;
+}
+
+static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+ void __iomem *addr;
+ unsigned int bit;
+ int ret;
+
+ ret = meson_gpio_calc_reg_bit(domain, chip->base + gpio, REG_DIR,
+ &addr, &bit);
+ if (ret)
+ return ret;
+
+ meson_domain_set_bit(domain, addr, bit, 1);
+
+ return 0;
+}
+
+static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+ void __iomem *addr;
+ unsigned int bit;
+ int ret;
+
+ ret = meson_gpio_calc_reg_bit(domain, chip->base + gpio, REG_DIR,
+ &addr, &bit);
+ if (ret)
+ return ret;
+
+ meson_domain_set_bit(domain, addr, bit, 0);
+
+ return 0;
+}
+
+static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+ void __iomem *addr;
+ unsigned int bit;
+
+ if (meson_gpio_calc_reg_bit(domain, chip->base + gpio, REG_OUT,
+ &addr, &bit))
+ return;
+
+ meson_domain_set_bit(domain, addr, bit, value);
+}
+
+static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+ void __iomem *addr;
+ unsigned int bit;
+
+ if (meson_gpio_calc_reg_bit(domain, chip->base + gpio, REG_IN,
+ &addr, &bit))
+ return 0;
+
+ return (readl(addr) >> bit) & 1;
+}
+
+static const struct of_device_id meson_pinctrl_dt_match[] = {
+ {
+ .compatible = "amlogic,meson8-pinctrl",
+ .data = meson8_domain_data,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, meson_pinctrl_dt_match);
+
+static int meson_gpio_of_xlate(struct gpio_chip *chip,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ unsigned gpio = gpiospec->args[0];
+
+ if (gpio < chip->base || gpio >= chip->base + chip->ngpio)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return gpio - chip->base;
+}
+
+static struct meson_domain_data *get_domain_data(struct device_node *node,
+ struct meson_domain_data *data)
+{
+ while (data->name) {
+ if (!strcmp(node->name, data->name))
+ return data;
+ data++;
+ }
+
+ return NULL;
+}
+
+static int meson_pinctrl_init_data(struct meson_pinctrl *pc)
+{
+ struct meson_domain_data *data;
+ int i, j, pin = 0, func = 0, group = 0;
+
+ /* Copy pin definitions from domains to pinctrl device */
+ pc->pins = devm_kzalloc(pc->dev, pc->num_pins *
+ sizeof(struct pinctrl_pin_desc), GFP_KERNEL);
+ if (!pc->pins)
+ return -ENOMEM;
+
+ for (i = 0; i < pc->num_domains; i++) {
+ data = pc->domains[i].data;
+ for (j = 0; j < data->num_pins; j++) {
+ pc->pins[pin].number = pin;
+ pc->pins[pin++].name = data->pin_names[j];
+ }
+ }
+
+ pc->num_groups = 0;
+ pc->num_funcs = 0;
+
+ for (i = 0; i < pc->num_domains; i++) {
+ data = pc->domains[i].data;
+ pc->num_groups += data->num_groups;
+ pc->num_funcs += data->num_funcs;
+ }
+
+ /* Copy group and function definitions from domains to pinctrl */
+ pc->groups = devm_kzalloc(pc->dev, pc->num_groups *
+ sizeof(struct meson_pmx_group), GFP_KERNEL);
+ pc->funcs = devm_kzalloc(pc->dev, pc->num_funcs *
+ sizeof(struct meson_pmx_func), GFP_KERNEL);
+ if (!pc->groups || !pc->funcs)
+ return -ENOMEM;
+
+ for (i = 0; i < pc->num_domains; i++) {
+ data = pc->domains[i].data;
+
+ for (j = 0; j < data->num_groups; j++) {
+ memcpy(&pc->groups[group], &data->groups[j],
+ sizeof(struct meson_pmx_group));
+ pc->groups[group++].domain = &pc->domains[i];
+ }
+
+ for (j = 0; j < data->num_funcs; j++) {
+ memcpy(&pc->funcs[func++], &data->funcs[j],
+ sizeof(struct meson_pmx_func));
+ }
+ }
+
+ /* Count pins in groups */
+ for (i = 0; i < pc->num_groups; i++) {
+ for (j = 0; ; j++) {
+ if (pc->groups[i].pins[j] == PINS_END) {
+ pc->groups[i].num_pins = j;
+ break;
+ }
+ }
+ }
+
+ /* Count groups in functions */
+ for (i = 0; i < pc->num_funcs; i++) {
+ for (j = 0; ; j++) {
+ if (!pc->funcs[i].groups[j]) {
+ pc->funcs[i].num_groups = j;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void __iomem *meson_map_resource(struct meson_pinctrl *pc,
+ struct device_node *node,
+ char *name, unsigned int *size)
+{
+ struct resource res;
+ int i;
+
+ i = of_property_match_string(node, "reg-names", name);
+ if (of_address_to_resource(node, i, &res))
+ return NULL;
+
+ *size = resource_size(&res) / 4;
+ return devm_ioremap_resource(pc->dev, &res);
+}
+
+static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
+ struct device_node *node,
+ struct meson_domain_data *data)
+{
+ struct device_node *np;
+ struct meson_domain *domain;
+ int i;
+
+ for_each_child_of_node(node, np) {
+ if (!of_find_property(np, "gpio-controller", NULL))
+ continue;
+ pc->num_domains++;
+ }
+
+ pc->domains = devm_kzalloc(pc->dev, pc->num_domains *
+ sizeof(struct meson_domain),
+ GFP_KERNEL);
+ if (!pc->domains)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_child_of_node(node, np) {
+ if (!of_find_property(np, "gpio-controller", NULL))
+ continue;
+
+ domain = &pc->domains[i];
+ domain->reg_mux = meson_map_resource(pc, np, "mux",
+ &domain->mux_size);
+ if (!domain->reg_mux) {
+ dev_err(pc->dev, "mux registers not found\n");
+ return -ENODEV;
+ }
+
+ domain->reg_pull = meson_map_resource(pc, np, "pull",
+ &domain->pull_size);
+ if (!domain->reg_pull) {
+ dev_err(pc->dev, "pull registers not found\n");
+ return -ENODEV;
+ }
+
+ domain->reg_pullen = meson_map_resource(pc, np, "pull-enable",
+ &domain->pullen_size);
+ if (!domain->reg_pullen) {
+ /* Use pull region if pull-enable one is not present */
+ domain->reg_pullen = domain->reg_pull;
+ domain->pullen_size = domain->pull_size;
+ }
+
+ domain->reg_gpio = meson_map_resource(pc, np, "gpio",
+ &domain->gpio_size);
+ if (!domain->reg_gpio) {
+ dev_err(pc->dev, "gpio registers not found\n");
+ return -ENODEV;
+ }
+
+ domain->data = get_domain_data(np, data);
+ if (!domain->data) {
+ dev_err(pc->dev, "domain data not found for node %s\n",
+ np->name);
+ return -ENODEV;
+ }
+
+ domain->of_node = np;
+ pc->num_pins += domain->data->num_pins;
+ i++;
+ }
+
+ return 0;
+}
+
+static int meson_gpiolib_register(struct meson_pinctrl *pc)
+{
+ struct meson_domain *domain;
+ unsigned int base = 0;
+ int i, ret;
+
+ for (i = 0; i < pc->num_domains; i++) {
+ domain = &pc->domains[i];
+
+ domain->chip.label = domain->data->name;
+ domain->chip.dev = pc->dev;
+ domain->chip.request = meson_gpio_request;
+ domain->chip.free = meson_gpio_free;
+ domain->chip.direction_input = meson_gpio_direction_input;
+ domain->chip.direction_output = meson_gpio_direction_output;
+ domain->chip.get = meson_gpio_get;
+ domain->chip.set = meson_gpio_set;
+ domain->chip.base = base;
+ domain->chip.ngpio = domain->data->num_pins;
+ domain->chip.names = domain->data->pin_names;
+ domain->chip.can_sleep = false;
+ domain->chip.of_node = domain->of_node;
+ domain->chip.of_gpio_n_cells = 2;
+ domain->chip.of_xlate = meson_gpio_of_xlate;
+
+ ret = gpiochip_add(&domain->chip);
+ if (ret < 0) {
+ dev_err(pc->dev, "can't add gpio chip %s\n",
+ domain->data->name);
+ goto fail;
+ }
+
+ domain->gpio_range.name = domain->data->name;
+ domain->gpio_range.id = i;
+ domain->gpio_range.base = base;
+ domain->gpio_range.pin_base = base;
+ domain->gpio_range.npins = domain->data->num_pins;
+ domain->gpio_range.gc = &domain->chip;
+
+ pinctrl_add_gpio_range(pc->pcdev, &domain->gpio_range);
+ base += domain->data->num_pins;
+ }
+
+ return 0;
+fail:
+ for (i--; i >= 0; i--)
+ gpiochip_remove(&pc->domains[i].chip);
+
+ return ret;
+}
+
+static int meson_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct meson_domain_data *data;
+ struct meson_pinctrl *pc;
+ int ret;
+
+ pc = devm_kzalloc(dev, sizeof(struct meson_pinctrl), GFP_KERNEL);
+ if (!pc)
+ return -ENOMEM;
+
+ match = of_match_node(meson_pinctrl_dt_match, pdev->dev.of_node);
+ data = (struct meson_domain_data *)match->data;
+ pc->dev = dev;
+
+ ret = meson_pinctrl_parse_dt(pc, pdev->dev.of_node, data);
+ if (ret)
+ return ret;
+
+ ret = meson_pinctrl_init_data(pc);
+ if (ret)
+ return ret;
+
+ pc->desc.name = "pinctrl-meson";
+ pc->desc.owner = THIS_MODULE;
+ pc->desc.pctlops = &meson_pctrl_ops;
+ pc->desc.pmxops = &meson_pmx_ops;
+ pc->desc.confops = &meson_pinconf_ops;
+ pc->desc.pins = pc->pins;
+ pc->desc.npins = pc->num_pins;
+
+ pc->pcdev = pinctrl_register(&pc->desc, pc->dev, pc);
+ if (!pc->pcdev) {
+ dev_err(pc->dev, "can't register pinctrl device");
+ return -EINVAL;
+ }
+
+ ret = meson_gpiolib_register(pc);
+ if (ret) {
+ pinctrl_unregister(pc->pcdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver meson_pinctrl_driver = {
+ .probe = meson_pinctrl_probe,
+ .driver = {
+ .name = "meson-pinctrl",
+ .of_match_table = meson_pinctrl_dt_match,
+ },
+};
+
+static int __init meson_pinctrl_drv_register(void)
+{
+ return platform_driver_register(&meson_pinctrl_driver);
+}
+postcore_initcall(meson_pinctrl_drv_register);
+
+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
+MODULE_DESCRIPTION("Amlogic Meson pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
new file mode 100644
index 0000000..992b62d
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -0,0 +1,217 @@
+/*
+ * 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/>.
+ */
+
+#include <linux/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/**
+ * struct meson_pmx_group - a pinmux group
+ *
+ * @name: group name
+ * @pins: pins in the group
+ * @num_pins: number of pins in the group
+ * @is_gpio: flag set when the group is a single GPIO group
+ * @reg: register offset for the group in the domain mux registers
+ * @bit bit index enabling the group
+ * @domain: pin domain this group belongs to
+ */
+struct meson_pmx_group {
+ const char *name;
+ const unsigned int *pins;
+ unsigned int num_pins;
+ bool is_gpio;
+ unsigned int reg;
+ unsigned int bit;
+ struct meson_domain *domain;
+};
+
+/**
+ * struct meson_pmx_func - a pinmux function
+ *
+ * @name: function name
+ * @groups: groups in the function
+ * @num_groups: number of groups in the function
+ */
+struct meson_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned int num_groups;
+};
+
+/**
+ * struct meson_reg_offset
+ *
+ * @reg: register offset
+ * @bit: bit index
+ */
+struct meson_reg_offset {
+ unsigned int reg;
+ unsigned int bit;
+};
+
+enum {
+ REG_PULLEN,
+ REG_PULL,
+ REG_DIR,
+ REG_OUT,
+ REG_IN,
+ NUM_REG,
+};
+
+/**
+ * struct meson bank
+ *
+ * @name: bank name
+ * @first: first pin of the bank
+ * @last: last pin of the bank
+ * @regs: couples of <reg offset, bit index> controlling the
+ * functionalities of the bank pins (pull, direction, value)
+ *
+ * A bank represents a set of pins controlled by a contiguous set of
+ * bits in the domain registers.
+ */
+struct meson_bank {
+ const char *name;
+ unsigned int first;
+ unsigned int last;
+ struct meson_reg_offset regs[NUM_REG];
+};
+
+/**
+ * struct meson_domain_data - domain platform data
+ *
+ * @name: label for the domain
+ * @pin_names: names of the pins in the domain
+ * @banks: set of banks belonging to the domain
+ * @funcs: available pinmux functions
+ * @groups: available pinmux groups
+ * @num_pins: number of pins in the domain
+ * @num_banks: number of banks in the domain
+ * @num_funcs: number of available pinmux functions
+ * @num_groups: number of available pinmux groups
+ *
+ */
+struct meson_domain_data {
+ const char *name;
+ const char **pin_names;
+ struct meson_bank *banks;
+ struct meson_pmx_func *funcs;
+ struct meson_pmx_group *groups;
+ unsigned int num_pins;
+ unsigned int num_banks;
+ unsigned int num_funcs;
+ unsigned int num_groups;
+};
+
+/**
+ * struct meson_domain
+ *
+ * @reg_mux: registers for mux settings
+ * @reg_pullen: registers for pull-enable settings
+ * @reg_pull: registers for pull settings
+ * @reg_gpio: registers for gpio settings
+ * @mux_size: size of mux register range (in words)
+ * @pullen_size:size of pull-enable register range
+ * @pull_size: size of pull register range
+ * @gpio_size: size of gpio register range
+ * @chip: gpio chip associated with the domain
+ * @data; platform data for the domain
+ * @node: device tree node for the domain
+ * @gpio_range: gpio range that maps domain gpios to the pin controller
+ * @lock: spinlock for accessing domain registers
+ *
+ * A domain represents a set of banks controlled by the same set of
+ * registers. Typically there is a domain for the normal banks and
+ * another one for the Always-On bus.
+ */
+struct meson_domain {
+ void __iomem *reg_mux;
+ void __iomem *reg_pullen;
+ void __iomem *reg_pull;
+ void __iomem *reg_gpio;
+
+ unsigned int mux_size;
+ unsigned int pullen_size;
+ unsigned int pull_size;
+ unsigned int gpio_size;
+
+ struct gpio_chip chip;
+ struct meson_domain_data *data;
+ struct device_node *of_node;
+ struct pinctrl_gpio_range gpio_range;
+
+ spinlock_t lock;
+};
+
+struct meson_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pcdev;
+ struct pinctrl_desc desc;
+
+ struct pinctrl_pin_desc *pins;
+ struct meson_domain *domains;
+ struct meson_pmx_func *funcs;
+ struct meson_pmx_group *groups;
+
+ unsigned int num_pins;
+ unsigned int num_domains;
+ unsigned int num_funcs;
+ unsigned int num_groups;
+};
+
+#define PINS_END 0xffff
+
+#define GROUP(_name, _reg, _bit, _pins...) \
+ { \
+ .name = #_name, \
+ .pins = (const unsigned int[]) { _pins, PINS_END }, \
+ .num_pins = 0, \
+ .is_gpio = false, \
+ .reg = _reg, \
+ .bit = _bit, \
+ }
+
+#define GPIO_GROUP(_gpio) \
+ { \
+ .name = #_gpio, \
+ .pins = (const unsigned int[]){ _gpio, PINS_END }, \
+ .num_pins = 0, \
+ .is_gpio = true, \
+ }
+
+#define FUNCTION(_name, _groups...) \
+ { \
+ .name = _name, \
+ .groups = (const char *[]) { _groups, NULL }, \
+ .num_groups = 0, \
+ }
+
+#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+ { \
+ .name = n, \
+ .first = f, \
+ .last = l, \
+ .regs = { \
+ [REG_PULLEN] = { per, peb }, \
+ [REG_PULL] = { pr, pb }, \
+ [REG_DIR] = { dr, db }, \
+ [REG_OUT] = { or, ob }, \
+ [REG_IN] = { ir, ib }, \
+ }, \
+ }
+
+#define MESON_PIN(x) PINCTRL_PIN(x, #x)
+
+extern struct meson_domain_data meson8_domain_data[];
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
new file mode 100644
index 0000000..c59ddbb
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -0,0 +1,534 @@
+/*
+ * Pin controller and GPIO data for Amlogic Meson8
+ *
+ * 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/>.
+ */
+
+#include <dt-bindings/gpio/meson8-gpio.h>
+
+#include "pinctrl-meson.h"
+
+const char *meson8_pin_names[] = {
+ "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4",
+ "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
+ "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
+ "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19",
+ "GPIOX_20", "GPIOX_21",
+
+ "GPIOY_0", "GPIOY_1", "GPIOY_2", "GPIOY_3", "GPIOY_4",
+ "GPIOY_5", "GPIOY_6", "GPIOY_7", "GPIOY_8", "GPIOY_9",
+ "GPIOY_10", "GPIOY_11", "GPIOY_12", "GPIOY_13", "GPIOY_14",
+ "GPIOY_15", "GPIOY_16",
+
+ "GPIODV_0", "GPIODV_1", "GPIODV_2", "GPIODV_3", "GPIODV_4",
+ "GPIODV_5", "GPIODV_6", "GPIODV_7", "GPIODV_8", "GPIODV_9",
+ "GPIODV_10", "GPIODV_11", "GPIODV_12", "GPIODV_13", "GPIODV_14",
+ "GPIODV_15", "GPIODV_16", "GPIODV_17", "GPIODV_18", "GPIODV_19",
+ "GPIODV_20", "GPIODV_21", "GPIODV_22", "GPIODV_23", "GPIODV_24",
+ "GPIODV_25", "GPIODV_26", "GPIODV_27", "GPIODV_28", "GPIODV_29",
+
+ "GPIOH_0", "GPIOH_1", "GPIOH_2", "GPIOH_3", "GPIOH_4",
+ "GPIOH_5", "GPIOH_6", "GPIOH_7", "GPIOH_8", "GPIOH_9",
+
+ "GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4",
+ "GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9",
+ "GPIOZ_10", "GPIOZ_11", "GPIOZ_12", "GPIOZ_13", "GPIOZ_14",
+
+ "CARD_0", "CARD_1", "CARD_2", "CARD_3", "CARD_4",
+ "CARD_5", "CARD_6",
+
+ "BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4",
+ "BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9",
+ "BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14",
+ "BOOT_15", "BOOT_16", "BOOT_17", "BOOT_18",
+};
+
+const char *meson8_ao_pin_names[] = {
+ "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3",
+ "GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7",
+ "GPIOAO_8", "GPIOAO_9", "GPIOAO_10", "GPIOAO_11",
+ "GPIOAO_12", "GPIOAO_13", "GPIO_BSD_EN", "GPIO_TEST_N",
+};
+
+struct meson_pmx_group meson8_groups[] = {
+ GPIO_GROUP(GPIOX_0),
+ GPIO_GROUP(GPIOX_1),
+ GPIO_GROUP(GPIOX_2),
+ GPIO_GROUP(GPIOX_3),
+ GPIO_GROUP(GPIOX_4),
+ GPIO_GROUP(GPIOX_5),
+ GPIO_GROUP(GPIOX_6),
+ GPIO_GROUP(GPIOX_7),
+ GPIO_GROUP(GPIOX_8),
+ GPIO_GROUP(GPIOX_9),
+ GPIO_GROUP(GPIOX_10),
+ GPIO_GROUP(GPIOX_11),
+ GPIO_GROUP(GPIOX_12),
+ GPIO_GROUP(GPIOX_13),
+ GPIO_GROUP(GPIOX_14),
+ GPIO_GROUP(GPIOX_15),
+ GPIO_GROUP(GPIOX_16),
+ GPIO_GROUP(GPIOX_17),
+ GPIO_GROUP(GPIOX_18),
+ GPIO_GROUP(GPIOX_19),
+ GPIO_GROUP(GPIOX_20),
+ GPIO_GROUP(GPIOX_21),
+ GPIO_GROUP(GPIOY_0),
+ GPIO_GROUP(GPIOY_1),
+ GPIO_GROUP(GPIOY_2),
+ GPIO_GROUP(GPIOY_3),
+ GPIO_GROUP(GPIOY_4),
+ GPIO_GROUP(GPIOY_5),
+ GPIO_GROUP(GPIOY_6),
+ GPIO_GROUP(GPIOY_7),
+ GPIO_GROUP(GPIOY_8),
+ GPIO_GROUP(GPIOY_9),
+ GPIO_GROUP(GPIOY_10),
+ GPIO_GROUP(GPIOY_11),
+ GPIO_GROUP(GPIOY_12),
+ GPIO_GROUP(GPIOY_13),
+ GPIO_GROUP(GPIOY_14),
+ GPIO_GROUP(GPIOY_15),
+ GPIO_GROUP(GPIOY_16),
+ GPIO_GROUP(GPIODV_0),
+ GPIO_GROUP(GPIODV_1),
+ GPIO_GROUP(GPIODV_2),
+ GPIO_GROUP(GPIODV_3),
+ GPIO_GROUP(GPIODV_4),
+ GPIO_GROUP(GPIODV_5),
+ GPIO_GROUP(GPIODV_6),
+ GPIO_GROUP(GPIODV_7),
+ GPIO_GROUP(GPIODV_8),
+ GPIO_GROUP(GPIODV_9),
+ GPIO_GROUP(GPIODV_10),
+ GPIO_GROUP(GPIODV_11),
+ GPIO_GROUP(GPIODV_12),
+ GPIO_GROUP(GPIODV_13),
+ GPIO_GROUP(GPIODV_14),
+ GPIO_GROUP(GPIODV_15),
+ GPIO_GROUP(GPIODV_16),
+ GPIO_GROUP(GPIODV_17),
+ GPIO_GROUP(GPIODV_18),
+ GPIO_GROUP(GPIODV_19),
+ GPIO_GROUP(GPIODV_20),
+ GPIO_GROUP(GPIODV_21),
+ GPIO_GROUP(GPIODV_22),
+ GPIO_GROUP(GPIODV_23),
+ GPIO_GROUP(GPIODV_24),
+ GPIO_GROUP(GPIODV_25),
+ GPIO_GROUP(GPIODV_26),
+ GPIO_GROUP(GPIODV_27),
+ GPIO_GROUP(GPIODV_28),
+ GPIO_GROUP(GPIODV_29),
+ GPIO_GROUP(GPIOH_0),
+ GPIO_GROUP(GPIOH_1),
+ GPIO_GROUP(GPIOH_2),
+ GPIO_GROUP(GPIOH_3),
+ GPIO_GROUP(GPIOH_4),
+ GPIO_GROUP(GPIOH_5),
+ GPIO_GROUP(GPIOH_6),
+ GPIO_GROUP(GPIOH_7),
+ GPIO_GROUP(GPIOH_8),
+ GPIO_GROUP(GPIOH_9),
+ GPIO_GROUP(GPIOZ_0),
+ GPIO_GROUP(GPIOZ_1),
+ GPIO_GROUP(GPIOZ_2),
+ GPIO_GROUP(GPIOZ_3),
+ GPIO_GROUP(GPIOZ_4),
+ GPIO_GROUP(GPIOZ_5),
+ GPIO_GROUP(GPIOZ_6),
+ GPIO_GROUP(GPIOZ_7),
+ GPIO_GROUP(GPIOZ_8),
+ GPIO_GROUP(GPIOZ_9),
+ GPIO_GROUP(GPIOZ_10),
+ GPIO_GROUP(GPIOZ_11),
+ GPIO_GROUP(GPIOZ_12),
+ GPIO_GROUP(GPIOZ_13),
+ GPIO_GROUP(GPIOZ_14),
+ GPIO_GROUP(CARD_0),
+ GPIO_GROUP(CARD_1),
+ GPIO_GROUP(CARD_2),
+ GPIO_GROUP(CARD_3),
+ GPIO_GROUP(CARD_4),
+ GPIO_GROUP(CARD_5),
+ GPIO_GROUP(CARD_6),
+ GPIO_GROUP(BOOT_0),
+ GPIO_GROUP(BOOT_1),
+ GPIO_GROUP(BOOT_2),
+ GPIO_GROUP(BOOT_3),
+ GPIO_GROUP(BOOT_4),
+ GPIO_GROUP(BOOT_5),
+ GPIO_GROUP(BOOT_6),
+ GPIO_GROUP(BOOT_7),
+ GPIO_GROUP(BOOT_8),
+ GPIO_GROUP(BOOT_9),
+ GPIO_GROUP(BOOT_10),
+ GPIO_GROUP(BOOT_11),
+ GPIO_GROUP(BOOT_12),
+ GPIO_GROUP(BOOT_13),
+ GPIO_GROUP(BOOT_14),
+ GPIO_GROUP(BOOT_15),
+ GPIO_GROUP(BOOT_16),
+ GPIO_GROUP(BOOT_17),
+ GPIO_GROUP(BOOT_18),
+
+ /* BANK X */
+
+ /* SD A */
+ GROUP(sd_d0_a, 8, 5, GPIOX_0),
+ GROUP(sd_d1_a, 8, 4, GPIOX_1),
+ GROUP(sd_d2_a, 8, 3, GPIOX_2),
+ GROUP(sd_d3_a, 8, 2, GPIOX_3),
+ GROUP(sd_clk_a, 8, 1, GPIOX_8),
+ GROUP(sd_cmd_a, 8, 0, GPIOX_9),
+ /* SDXC A */
+ GROUP(sdxc_d0_a, 5, 14, GPIOX_0),
+ GROUP(sdxc_d13_a, 5, 13, GPIOX_1, GPIOX_2, GPIOX_3),
+ GROUP(sdxc_d47_a, 5, 12, GPIOX_4, GPIOX_5, GPIOX_6, GPIOX_7),
+ GROUP(sdxc_clk_a, 5, 11, GPIOX_8),
+ GROUP(sdxc_cmd_a, 5, 10, GPIOX_9),
+ /* PCM A */
+ GROUP(pcm_out_a, 3, 30, GPIOX_4),
+ GROUP(pcm_in_a, 3, 29, GPIOX_5),
+ GROUP(pcm_fs_a, 3, 28, GPIOX_6),
+ GROUP(pcm_clk_a, 3, 27, GPIOX_7),
+ /* UART A (0) */
+ GROUP(uart_tx_a0, 4, 17, GPIOX_4),
+ GROUP(uart_rx_a0, 4, 16, GPIOX_5),
+ GROUP(uart_cts_a0, 4, 15, GPIOX_6),
+ GROUP(uart_rts_a0, 4, 14, GPIOX_7),
+ /* UART A (1) */
+ GROUP(uart_tx_a1, 4, 13, GPIOX_12),
+ GROUP(uart_rx_a1, 4, 12, GPIOX_13),
+ GROUP(uart_cts_a1, 4, 11, GPIOX_14),
+ GROUP(uart_rts_a1, 4, 10, GPIOX_15),
+ /* UART B (0) */
+ GROUP(uart_tx_b0, 4, 9, GPIOX_16),
+ GROUP(uart_rx_b0, 4, 8, GPIOX_17),
+ GROUP(uart_cts_b0, 4, 7, GPIOX_18),
+ GROUP(uart_rts_b0, 4, 6, GPIOX_19),
+ /* ISO 7816 */
+ GROUP(iso7816_det, 4, 21, GPIOX_16),
+ GROUP(iso7816_reset, 4, 20, GPIOX_17),
+ GROUP(iso7816_clk, 4, 19, GPIOX_18),
+ GROUP(iso7816_data, 4, 18, GPIOX_19),
+ /* I2C D (0) */
+ GROUP(i2c_sda_d0, 4, 5, GPIOX_16),
+ GROUP(i2c_sck_d0, 4, 4, GPIOX_17),
+ /* XTAL */
+ GROUP(xtal_32k_out, 3, 22, GPIOX_10),
+ GROUP(xtal_24m_out, 3, 23, GPIOX_11),
+
+ /* BANK Y */
+
+ /* UART C */
+ GROUP(uart_tx_c, 1, 19, GPIOY_0),
+ GROUP(uart_rx_c, 1, 18, GPIOY_1),
+ GROUP(uart_cts_c, 1, 17, GPIOY_2),
+ GROUP(uart_rts_c, 1, 16, GPIOY_3),
+ /* PCM B */
+ GROUP(pcm_out_b, 4, 25, GPIOY_4),
+ GROUP(pcm_in_b, 4, 24, GPIOY_5),
+ GROUP(pcm_fs_b, 4, 23, GPIOY_6),
+ GROUP(pcm_clk_b, 4, 22, GPIOY_7),
+ /* I2C C (0) */
+ GROUP(i2c_sda_c0, 1, 15, GPIOY_0),
+ GROUP(i2c_sck_c0, 1, 14, GPIOY_1),
+
+ /* BANK DV */
+
+ /* DVIN */
+ GROUP(dvin_rgb, 0, 6, GPIODV_0, GPIODV_1, GPIODV_2, GPIODV_3,
+ GPIODV_4, GPIODV_5, GPIODV_6, GPIODV_7,
+ GPIODV_8, GPIODV_9, GPIODV_10, GPIODV_11,
+ GPIODV_12, GPIODV_13, GPIODV_14, GPIODV_15,
+ GPIODV_16, GPIODV_17, GPIODV_18, GPIODV_19,
+ GPIODV_20, GPIODV_21, GPIODV_22, GPIODV_23),
+ GROUP(dvin_vs, 0, 9, GPIODV_24),
+ GROUP(dvin_hs, 0, 8, GPIODV_25),
+ GROUP(dvin_clk, 0, 7, GPIODV_26),
+ GROUP(dvin_de, 0, 10, GPIODV_27),
+ /* ENC */
+ GROUP(enc_0, 7, 0, GPIODV_0),
+ GROUP(enc_1, 7, 1, GPIODV_1),
+ GROUP(enc_2, 7, 2, GPIODV_2),
+ GROUP(enc_3, 7, 3, GPIODV_3),
+ GROUP(enc_4, 7, 4, GPIODV_4),
+ GROUP(enc_5, 7, 5, GPIODV_5),
+ GROUP(enc_6, 7, 6, GPIODV_6),
+ GROUP(enc_7, 7, 7, GPIODV_7),
+ GROUP(enc_8, 7, 8, GPIODV_8),
+ GROUP(enc_9, 7, 9, GPIODV_9),
+ GROUP(enc_10, 7, 10, GPIODV_10),
+ GROUP(enc_11, 7, 11, GPIODV_11),
+ GROUP(enc_12, 7, 12, GPIODV_12),
+ GROUP(enc_13, 7, 13, GPIODV_13),
+ GROUP(enc_14, 7, 14, GPIODV_14),
+ GROUP(enc_15, 7, 15, GPIODV_15),
+ GROUP(enc_16, 7, 16, GPIODV_16),
+ GROUP(enc_17, 7, 17, GPIODV_17),
+ /* UART B (1) */
+ GROUP(uart_tx_b1, 6, 23, GPIODV_24),
+ GROUP(uart_rx_b1, 6, 22, GPIODV_25),
+ GROUP(uart_cts_b1, 6, 21, GPIODV_26),
+ GROUP(uart_rts_b1, 6, 20, GPIODV_27),
+ /* VGA */
+ GROUP(vga_vs, 0, 21, GPIODV_24),
+ GROUP(vga_hs, 0, 20, GPIODV_25),
+
+ /* BANK H */
+
+ /* HDMI */
+ GROUP(hdmi_hpd, 1, 26, GPIOH_0),
+ GROUP(hdmi_sda, 1, 25, GPIOH_1),
+ GROUP(hdmi_scl, 1, 24, GPIOH_2),
+ GROUP(hdmi_cec, 1, 23, GPIOH_3),
+ /* SPI (0) */
+ GROUP(spi_ss0_0, 9, 13, GPIOH_3),
+ GROUP(spi_miso_0, 9, 12, GPIOH_4),
+ GROUP(spi_mosi_0, 9, 11, GPIOH_5),
+ GROUP(spi_sclk_0, 9, 10, GPIOH_6),
+ /* I2C D (1) */
+ GROUP(i2c_sda_d1, 4, 3, GPIOH_7),
+ GROUP(i2c_sck_d1, 4, 2, GPIOH_8),
+
+ /* BANK Z */
+
+ /* SPI (1) */
+ GROUP(spi_ss0_1, 8, 16, GPIOZ_9),
+ GROUP(spi_ss1_1, 8, 12, GPIOZ_10),
+ GROUP(spi_sclk_1, 8, 15, GPIOZ_11),
+ GROUP(spi_mosi_1, 8, 14, GPIOZ_12),
+ GROUP(spi_miso_1, 8, 13, GPIOZ_13),
+ GROUP(spi_ss2_1, 8, 17, GPIOZ_14),
+ /* ETHERNET */
+ GROUP(eth_tx_clk_50m, 6, 15, GPIOZ_4),
+ GROUP(eth_tx_en, 6, 14, GPIOZ_5),
+ GROUP(eth_txd1, 6, 13, GPIOZ_6),
+ GROUP(eth_txd0, 6, 12, GPIOZ_7),
+ GROUP(eth_rx_clk_in, 6, 10, GPIOZ_8),
+ GROUP(eth_rx_dv, 6, 11, GPIOZ_9),
+ GROUP(eth_rxd1, 6, 8, GPIOZ_10),
+ GROUP(eth_rxd0, 6, 7, GPIOZ_11),
+ GROUP(eth_mdio, 6, 6, GPIOZ_12),
+ GROUP(eth_mdc, 6, 5, GPIOZ_13),
+ /* I2C A (0) */
+ GROUP(i2c_sda_a0, 5, 31, GPIOZ_0),
+ GROUP(i2c_sck_a0, 5, 30, GPIOZ_1),
+ /* I2C B */
+ GROUP(i2c_sda_b, 5, 27, GPIOZ_2),
+ GROUP(i2c_sck_b, 5, 26, GPIOZ_3),
+ /* I2C C (1) */
+ GROUP(i2c_sda_c1, 5, 25, GPIOZ_4),
+ GROUP(i2c_sck_c1, 5, 24, GPIOZ_5),
+ /* I2C A (1) */
+ GROUP(i2c_sda_a1, 5, 9, GPIOZ_0),
+ GROUP(i2c_sck_a1, 5, 8, GPIOZ_1),
+ /* I2C A (2) */
+ GROUP(i2c_sda_a2, 5, 7, GPIOZ_0),
+ GROUP(i2c_sck_a2, 5, 6, GPIOZ_1),
+
+ /* BANK BOOT */
+
+ /* SD C */
+ GROUP(sd_d0_c, 6, 29, BOOT_0),
+ GROUP(sd_d1_c, 6, 28, BOOT_1),
+ GROUP(sd_d2_c, 6, 27, BOOT_2),
+ GROUP(sd_d3_c, 6, 26, BOOT_3),
+ GROUP(sd_cmd_c, 6, 25, BOOT_16),
+ GROUP(sd_clk_c, 6, 24, BOOT_17),
+ /* SDXC C */
+ GROUP(sdxc_d0_c, 4, 30, BOOT_0),
+ GROUP(sdxc_d13_c, 4, 29, BOOT_1, BOOT_2, BOOT_3),
+ GROUP(sdxc_d47_c, 4, 28, BOOT_4, BOOT_5, BOOT_6, BOOT_7),
+ GROUP(sdxc_cmd_c, 4, 27, BOOT_16),
+ GROUP(sdxc_clk_c, 4, 26, BOOT_17),
+ /* NAND */
+ GROUP(nand_io, 2, 26, BOOT_0, BOOT_1, BOOT_2, BOOT_3,
+ BOOT_4, BOOT_5, BOOT_6, BOOT_7),
+ GROUP(nand_io_ce0, 2, 25, BOOT_8),
+ GROUP(nand_io_ce1, 2, 24, BOOT_9),
+ GROUP(nand_io_rb0, 2, 17, BOOT_10),
+ GROUP(nand_ale, 2, 21, BOOT_11),
+ GROUP(nand_cle, 2, 20, BOOT_12),
+ GROUP(nand_wen_clk, 2, 19, BOOT_13),
+ GROUP(nand_ren_clk, 2, 18, BOOT_14),
+ GROUP(nand_dqs, 2, 27, BOOT_15),
+ GROUP(nand_ce2, 2, 23, BOOT_16),
+ GROUP(nand_ce3, 2, 22, BOOT_17),
+ /* NOR */
+ GROUP(nor_d, 5, 1, BOOT_11),
+ GROUP(nor_q, 5, 3, BOOT_12),
+ GROUP(nor_c, 5, 2, BOOT_13),
+ GROUP(nor_cs, 5, 0, BOOT_18),
+
+ /* BANK CARD */
+
+ /* SD B */
+ GROUP(sd_d1_b, 2, 14, CARD_0),
+ GROUP(sd_d0_b, 2, 15, CARD_1),
+ GROUP(sd_clk_b, 2, 11, CARD_2),
+ GROUP(sd_cmd_b, 2, 10, CARD_3),
+ GROUP(sd_d3_b, 2, 12, CARD_4),
+ GROUP(sd_d2_b, 2, 13, CARD_5),
+ /* SDXC B */
+ GROUP(sdxc_d13_b, 2, 6, CARD_0, CARD_4, CARD_5),
+ GROUP(sdxc_d0_b, 2, 7, CARD_1),
+ GROUP(sdxc_clk_b, 2, 5, CARD_2),
+ GROUP(sdxc_cmd_b, 2, 4, CARD_3),
+};
+
+struct meson_pmx_group meson8_ao_groups[] = {
+ GPIO_GROUP(GPIOAO_0),
+ GPIO_GROUP(GPIOAO_1),
+ GPIO_GROUP(GPIOAO_2),
+ GPIO_GROUP(GPIOAO_3),
+ GPIO_GROUP(GPIOAO_4),
+ GPIO_GROUP(GPIOAO_5),
+ GPIO_GROUP(GPIOAO_6),
+ GPIO_GROUP(GPIOAO_7),
+ GPIO_GROUP(GPIOAO_8),
+ GPIO_GROUP(GPIOAO_9),
+ GPIO_GROUP(GPIOAO_10),
+ GPIO_GROUP(GPIOAO_11),
+ GPIO_GROUP(GPIOAO_12),
+ GPIO_GROUP(GPIOAO_13),
+ GPIO_GROUP(GPIO_BSD_EN),
+ GPIO_GROUP(GPIO_TEST_N),
+ /* UART AO A */
+ GROUP(uart_tx_ao_a, 0, 12, GPIOAO_0),
+ GROUP(uart_rx_ao_a, 0, 11, GPIOAO_1),
+ GROUP(uart_cts_ao_a, 0, 10, GPIOAO_2),
+ GROUP(uart_rts_ao_a, 0, 9, GPIOAO_3),
+ /* REMOTE */
+ GROUP(remote_input, 0, 0, GPIOAO_7),
+ /* I2C SLAVE AO */
+ GROUP(i2c_slave_sck_ao, 0, 2, GPIOAO_4),
+ GROUP(i2c_slave_sda_ao, 0, 1, GPIOAO_5),
+ /* UART AO B (0) */
+ GROUP(uart_tx_ao_b0, 0, 26, GPIOAO_0),
+ GROUP(uart_rx_ao_b0, 0, 25, GPIOAO_1),
+ /* UART AO B (1) */
+ GROUP(uart_tx_ao_b1, 0, 24, GPIOAO_4),
+ GROUP(uart_rx_ao_b1, 0, 23, GPIOAO_5),
+ /* I2C MST AO */
+ GROUP(i2c_mst_sck_ao, 0, 6, GPIOAO_4),
+ GROUP(i2c_mst_sda_ao, 0, 5, GPIOAO_5),
+};
+
+struct meson_pmx_func meson8_functions[] = {
+ {
+ .name = "gpio",
+ .groups = meson8_pin_names,
+ .num_groups = ARRAY_SIZE(meson8_pin_names),
+ },
+ FUNCTION("sd_a", "sd_d0_a", "sd_d1_a", "sd_d2_a", "sd_d3_a",
+ "sd_clk_a", "sd_cmd_a"),
+ FUNCTION("sdxc_a", "sdxc_d0_a", "sdxc_d13_a", "sdxc_d47_a",
+ "sdxc_clk_a", "sdxc_cmd_a"),
+ FUNCTION("pcm_a", "pcm_out_a", "pcm_in_a", "pcm_fs_a", "pcm_clk_a"),
+
+ FUNCTION("uart_a", "uart_tx_a0", "uart_rx_a0", "uart_cts_a0", "uart_rts_a0",
+ "uart_tx_a1", "uart_rx_a1", "uart_cts_a1", "uart_rts_a1"),
+ FUNCTION("uart_b", "uart_tx_b0", "uart_rx_b0", "uart_cts_b0", "uart_rts_b0",
+ "uart_tx_b1", "uart_rx_b1", "uart_cts_b1", "uart_rts_b1"),
+ FUNCTION("iso7816", "iso7816_det", "iso7816_reset", "iso7816_clk",
+ "iso7816_data"),
+ FUNCTION("i2c_d", "i2c_sda_d0", "i2c_sck_d0", "i2c_sda_d1", "i2c_sck_d1"),
+ FUNCTION("xtal", "xtal_32k_out", "xtal_24m_out"),
+ FUNCTION("uart_c", "uart_tx_c", "uart_rx_c", "uart_cts_c", "uart_rts_c"),
+ FUNCTION("pcm_b", "pcm_out_b", "pcm_in_b", "pcm_fs_b", "pcm_clk_b"),
+ FUNCTION("i2c_c", "i2c_sda_c0", "i2c_sck_c0", "i2c_sda_c1", "i2c_sck_c1"),
+ FUNCTION("dvin", "dvin_rgb", "dvin_vs", "dvin_hs", "dvin_clk", "dvin_de"),
+ FUNCTION("enc", "enc_0", "enc_1", "enc_2", "enc_3", "enc_4", "enc_5",
+ "enc_6", "enc_7", "enc_8", "enc_9", "enc_10", "enc_11",
+ "enc_12", "enc_13", "enc_14", "enc_15", "enc_16", "enc_17"),
+ FUNCTION("vga", "vga_vs", "vga_hs"),
+ FUNCTION("hdmi", "hdmi_hpd", "hdmi_sda", "hdmi_scl", "hdmi_cec"),
+ FUNCTION("spi", "spi_ss0_0", "spi_miso_0", "spi_mosi_0", "spi_sclk_0",
+ "spi_ss0_1", "spi_ss1_1", "spi_sclk_1", "spi_mosi_1",
+ "spi_miso_1", "spi_ss2_1"),
+ FUNCTION("ethernet", "eth_tx_clk_50m", "eth_tx_en", "eth_txd1",
+ "eth_txd0", "eth_rx_clk_in", "eth_rx_dv",
+ "eth_rxd1", "eth_rxd0", "eth_mdio", "eth_mdc"),
+ FUNCTION("i2c_a", "i2c_sda_a0", "i2c_sck_a0", "i2c_sda_a1", "i2c_sck_a1",
+ "i2c_sda_a2", "i2c_sck_a2"),
+ FUNCTION("i2c_b", "i2c_sda_b", "i2c_sck_b"),
+ FUNCTION("sd_c", "sd_d0_c", "sd_d1_c" "sd_d2_c", "sd_d3_c",
+ "sd_cmd_c", "sd_clk_c"),
+ FUNCTION("sdxc_c", "sdxc_d0_c", "sdxc_d13_c", "sdxc_d47_c", "sdxc_cmd_c",
+ "sdxc_clk_c"),
+ FUNCTION("nand", "nand_io", "nand_io_ce0", "nand_io_ce1",
+ "nand_io_rb0", "nand_ale", "nand_cle",
+ "nand_wen_clk", "nand_ren_clk", "nand_dqs",
+ "nand_ce2", "nand_ce3"),
+ FUNCTION("nor", "nor_d", "nor_q", "nor_c", "nor_cs"),
+ FUNCTION("sd_b", "sd_d1_b", "sd_d0_b", "sd_clk_b", "sd_cmd_b",
+ "sd_d3_b", "sd_d2_b"),
+ FUNCTION("sdxc_b", "sdxc_d13_b", "sdxc_d0_b", "sdxc_clk_b", "sdxc_cmd_b"),
+};
+
+struct meson_pmx_func meson8_ao_functions[] = {
+ {
+ .name = "gpio",
+ .groups = meson8_ao_pin_names,
+ .num_groups = ARRAY_SIZE(meson8_ao_pin_names),
+ },
+ FUNCTION("uart_ao", "uart_tx_ao_a", "uart_rx_ao_a",
+ "uart_cts_ao_a", "uart_rts_ao_a"),
+ FUNCTION("remote", "remote_input"),
+ FUNCTION("i2c_slave_ao", "i2c_slave_sck_ao", "i2c_slave_sda_ao"),
+ FUNCTION("uart_ao_b", "uart_tx_ao_b0", "uart_rx_ao_b0",
+ "uart_tx_ao_b1", "uart_rx_ao_b1"),
+ FUNCTION("i2c_mst_ao", "i2c_mst_sck_ao", "i2c_mst_sda_ao"),
+};
+
+
+struct meson_bank meson8_banks[] = {
+ /* name first last pullen pull dir out in */
+ BANK("X", GPIOX_0, GPIOX_21, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
+ BANK("Y", GPIOY_0, GPIOY_16, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", GPIODV_0, GPIODV_29, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
+ BANK("H", GPIOH_0, GPIOH_9, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
+ BANK("Z", GPIOZ_0, GPIOZ_14, 1, 0, 1, 0, 3, 17, 4, 17, 5, 17),
+ BANK("CARD", CARD_0, CARD_6, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
+ BANK("BOOT", BOOT_0, BOOT_18, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
+};
+
+struct meson_bank meson8_ao_banks[] = {
+ /* name first last pullen pull dir out in */
+ BANK("AO", GPIOAO_0, GPIO_TEST_N, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+};
+
+struct meson_domain_data meson8_domain_data[] = {
+ {
+ .name = "banks",
+ .banks = meson8_banks,
+ .pin_names = meson8_pin_names,
+ .funcs = meson8_functions,
+ .groups = meson8_groups,
+ .num_pins = ARRAY_SIZE(meson8_pin_names),
+ .num_banks = ARRAY_SIZE(meson8_banks),
+ .num_funcs = ARRAY_SIZE(meson8_functions),
+ .num_groups = ARRAY_SIZE(meson8_groups),
+ },
+ {
+ .name = "ao-bank",
+ .banks = meson8_ao_banks,
+ .pin_names = meson8_ao_pin_names,
+ .funcs = meson8_ao_functions,
+ .groups = meson8_ao_groups,
+ .num_pins = ARRAY_SIZE(meson8_ao_pin_names),
+ .num_banks = ARRAY_SIZE(meson8_ao_banks),
+ .num_funcs = ARRAY_SIZE(meson8_ao_functions),
+ .num_groups = ARRAY_SIZE(meson8_ao_groups),
+ },
+ { },
+};
diff --git a/include/dt-bindings/gpio/meson8-gpio.h b/include/dt-bindings/gpio/meson8-gpio.h
new file mode 100644
index 0000000..584dd92
--- /dev/null
+++ b/include/dt-bindings/gpio/meson8-gpio.h
@@ -0,0 +1,155 @@
+/*
+ * GPIO definitions for Amlogic Meson8
+ *
+ * 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/>.
+ */
+
+#ifndef _DT_BINDINGS_MESON8_GPIO_H
+#define _DT_BINDINGS_MESON8_GPIO_H
+
+#define GPIOX_0 0
+#define GPIOX_1 1
+#define GPIOX_2 2
+#define GPIOX_3 3
+#define GPIOX_4 4
+#define GPIOX_5 5
+#define GPIOX_6 6
+#define GPIOX_7 7
+#define GPIOX_8 8
+#define GPIOX_9 9
+#define GPIOX_10 10
+#define GPIOX_11 11
+#define GPIOX_12 12
+#define GPIOX_13 13
+#define GPIOX_14 14
+#define GPIOX_15 15
+#define GPIOX_16 16
+#define GPIOX_17 17
+#define GPIOX_18 18
+#define GPIOX_19 19
+#define GPIOX_20 20
+#define GPIOX_21 21
+#define GPIOY_0 22
+#define GPIOY_1 23
+#define GPIOY_2 24
+#define GPIOY_3 25
+#define GPIOY_4 26
+#define GPIOY_5 27
+#define GPIOY_6 28
+#define GPIOY_7 29
+#define GPIOY_8 30
+#define GPIOY_9 31
+#define GPIOY_10 32
+#define GPIOY_11 33
+#define GPIOY_12 34
+#define GPIOY_13 35
+#define GPIOY_14 36
+#define GPIOY_15 37
+#define GPIOY_16 38
+#define GPIODV_0 39
+#define GPIODV_1 40
+#define GPIODV_2 41
+#define GPIODV_3 42
+#define GPIODV_4 43
+#define GPIODV_5 44
+#define GPIODV_6 45
+#define GPIODV_7 46
+#define GPIODV_8 47
+#define GPIODV_9 48
+#define GPIODV_10 49
+#define GPIODV_11 50
+#define GPIODV_12 51
+#define GPIODV_13 52
+#define GPIODV_14 53
+#define GPIODV_15 54
+#define GPIODV_16 55
+#define GPIODV_17 56
+#define GPIODV_18 57
+#define GPIODV_19 58
+#define GPIODV_20 59
+#define GPIODV_21 60
+#define GPIODV_22 61
+#define GPIODV_23 62
+#define GPIODV_24 63
+#define GPIODV_25 64
+#define GPIODV_26 65
+#define GPIODV_27 66
+#define GPIODV_28 67
+#define GPIODV_29 68
+#define GPIOH_0 69
+#define GPIOH_1 70
+#define GPIOH_2 71
+#define GPIOH_3 72
+#define GPIOH_4 73
+#define GPIOH_5 74
+#define GPIOH_6 75
+#define GPIOH_7 76
+#define GPIOH_8 77
+#define GPIOH_9 78
+#define GPIOZ_0 79
+#define GPIOZ_1 80
+#define GPIOZ_2 81
+#define GPIOZ_3 82
+#define GPIOZ_4 83
+#define GPIOZ_5 84
+#define GPIOZ_6 85
+#define GPIOZ_7 86
+#define GPIOZ_8 87
+#define GPIOZ_9 88
+#define GPIOZ_10 89
+#define GPIOZ_11 90
+#define GPIOZ_12 91
+#define GPIOZ_13 92
+#define GPIOZ_14 93
+#define CARD_0 94
+#define CARD_1 95
+#define CARD_2 96
+#define CARD_3 97
+#define CARD_4 98
+#define CARD_5 99
+#define CARD_6 100
+#define BOOT_0 101
+#define BOOT_1 102
+#define BOOT_2 103
+#define BOOT_3 104
+#define BOOT_4 105
+#define BOOT_5 106
+#define BOOT_6 107
+#define BOOT_7 108
+#define BOOT_8 109
+#define BOOT_9 110
+#define BOOT_10 111
+#define BOOT_11 112
+#define BOOT_12 113
+#define BOOT_13 114
+#define BOOT_14 115
+#define BOOT_15 116
+#define BOOT_16 117
+#define BOOT_17 118
+#define BOOT_18 119
+
+#define GPIOAO_0 120
+#define GPIOAO_1 121
+#define GPIOAO_2 122
+#define GPIOAO_3 123
+#define GPIOAO_4 124
+#define GPIOAO_5 125
+#define GPIOAO_6 126
+#define GPIOAO_7 127
+#define GPIOAO_8 128
+#define GPIOAO_9 129
+#define GPIOAO_10 130
+#define GPIOAO_11 131
+#define GPIOAO_12 132
+#define GPIOAO_13 133
+#define GPIO_BSD_EN 134
+#define GPIO_TEST_N 135
+
+#endif /* _DT_BINDINGS_MESON8_GPIO_H */
--
1.9.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/3] pinctrl: meson: add device tree bindings documentation
2014-10-14 21:21 [PATCH v2 0/3] Pinctrl driver for Amlogic Meson SoCs Beniamino Galvani
2014-10-14 21:21 ` [PATCH v2 1/3] pinctrl: add " Beniamino Galvani
@ 2014-10-14 21:21 ` Beniamino Galvani
2014-10-28 14:21 ` Linus Walleij
2014-10-14 21:21 ` [PATCH v2 3/3] ARM: dts: meson8: add pinctrl and gpio nodes Beniamino Galvani
2 siblings, 1 reply; 6+ messages in thread
From: Beniamino Galvani @ 2014-10-14 21:21 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-arm-kernel, linux-kernel, Carlo Caione, devicetree,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Jerry Cao, Victor Wan, Beniamino Galvani
Add device tree bindings documentation for Amlogic Meson pinmux and
GPIO controller.
Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
---
.../devicetree/bindings/pinctrl/meson,pinctrl.txt | 79 ++++++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
new file mode 100644
index 0000000..6645fa6
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
@@ -0,0 +1,79 @@
+* Amlogic Meson pinmux controller
+
+Pins are organized in banks; all banks except AO are controlled by the
+same set of registers, while the AO bank uses a dedicated register
+range. The device tree uses sub-nodes to represent set of banks which
+share the same address space.
+
+Required properties for the root node:
+ - compatible: "amlogic,meson8-pinctrl"
+ - reg: address and size of the common registers controlling gpio irq
+ functionality
+
+Required properties for gpio sub-nodes:
+ - reg: should contain address and size for mux, pull-enable, pull and
+ gpio register sets
+ - reg-names: an array of strings describing the "reg" entries. Must
+ contain "mux", "pull" and "gpio". "pull-enable" is optional and
+ when it is missing the "pull" registers are used instead
+ - gpio-controller: identifies the node as a gpio controller
+ - #gpio-cells: must be 2
+
+Valid gpio sub-nodes name are:
+ - "banks" for the standard banks
+ - "ao-bank" for the AO bank which belong to the special always-on
+ power domain
+
+Required properties for configuration nodes:
+ - pins: the name of a pin group. The list of all available groups can
+ be found in driver sources.
+ - function: the name of a function to activate for the specified set
+ of groups. The list of all available functions can be found in
+ driver sources.
+
+Example:
+
+ pinctrl: pinctrl@c1109880 {
+ compatible = "amlogic,meson8-pinctrl";
+ reg = <0xc1109880 0x10>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gpio: banks@c11080b0 {
+ reg = <0xc11080b0 0x28>,
+ <0xc11080e4 0x18>,
+ <0xc1108120 0x18>,
+ <0xc1108030 0x30>;
+ reg-names = "mux", "pull-enable", "pull", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_ao: ao-bank@c1108030 {
+ reg = <0xc8100014 0x4>,
+ <0xc810002c 0x4>,
+ <0xc8100024 0x8>;
+ reg-names = "mux", "pull", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ nand {
+ nand {
+ pins = "nand_io", "nand_io_ce0", "nand_io_ce1",
+ "nand_io_rb0", "nand_ale", "nand_cle",
+ "nand_wen_clk", "nand_ren_clk", "nand_dqs",
+ "nand_ce2", "nand_ce3";
+ function = "nand";
+ };
+ };
+
+ uart_ao_a: uart_ao_a {
+ uart_ao_a {
+ pins = "uart_tx_ao_a", "uart_rx_ao_a";
+ "uart_cts_ao_a", "uart_rts_ao_a";
+ function = "uart_ao";
+ };
+ };
+ };
--
1.9.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 3/3] ARM: dts: meson8: add pinctrl and gpio nodes
2014-10-14 21:21 [PATCH v2 0/3] Pinctrl driver for Amlogic Meson SoCs Beniamino Galvani
2014-10-14 21:21 ` [PATCH v2 1/3] pinctrl: add " Beniamino Galvani
2014-10-14 21:21 ` [PATCH v2 2/3] pinctrl: meson: add device tree bindings documentation Beniamino Galvani
@ 2014-10-14 21:21 ` Beniamino Galvani
2 siblings, 0 replies; 6+ messages in thread
From: Beniamino Galvani @ 2014-10-14 21:21 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-arm-kernel, linux-kernel, Carlo Caione, devicetree,
Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Jerry Cao, Victor Wan, Beniamino Galvani
Add pinctrl node to meson8.dtsi and gpio-leds node to
meson8-vega-s89e.dts
Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
---
arch/arm/boot/dts/meson8-vega-s89e.dts | 16 +++++++++++++++-
arch/arm/boot/dts/meson8.dtsi | 35 ++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/meson8-vega-s89e.dts b/arch/arm/boot/dts/meson8-vega-s89e.dts
index 950998f..70a05c1 100644
--- a/arch/arm/boot/dts/meson8-vega-s89e.dts
+++ b/arch/arm/boot/dts/meson8-vega-s89e.dts
@@ -45,7 +45,9 @@
/dts-v1/;
-/include/ "meson8.dtsi"
+#include "meson8.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/gpio/meson8-gpio.h>
/ {
model = "Tronsmart Vega S89 Elite";
@@ -58,8 +60,20 @@
memory {
reg = <0x40000000 0x80000000>;
};
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ power {
+ gpios = <&gpio_ao GPIO_TEST_N GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "none";
+ };
+ };
+
};
&uart_AO {
status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_ao_a>;
};
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index 42e4026..c82f597 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -85,4 +85,39 @@
compatible = "fixed-clock";
clock-frequency = <141666666>;
};
+
+ pinctrl: pinctrl@c1109880 {
+ compatible = "amlogic,meson8-pinctrl";
+ reg = <0xc1109880 0x10>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gpio: banks@c11080b0 {
+ reg = <0xc11080b0 0x28>,
+ <0xc11080e4 0x18>,
+ <0xc1108120 0x18>,
+ <0xc1108030 0x30>;
+ reg-names = "mux", "pull-enable", "pull", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_ao: ao-bank@c1108030 {
+ reg = <0xc8100014 0x4>,
+ <0xc810002c 0x4>,
+ <0xc8100024 0x8>;
+ reg-names = "mux", "pull", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ uart_ao_a: uart_ao_a {
+ uart_ao_a {
+ pins = "uart_tx_ao_a", "uart_rx_ao_a";
+ function = "uart_ao";
+ };
+ };
+ };
+
}; /* end of / */
--
1.9.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/3] pinctrl: add driver for Amlogic Meson SoCs
2014-10-14 21:21 ` [PATCH v2 1/3] pinctrl: add " Beniamino Galvani
@ 2014-10-28 14:19 ` Linus Walleij
0 siblings, 0 replies; 6+ messages in thread
From: Linus Walleij @ 2014-10-28 14:19 UTC (permalink / raw)
To: Beniamino Galvani
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, Carlo Caione,
devicetree@vger.kernel.org, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Jerry Cao, Victor Wan
On Tue, Oct 14, 2014 at 11:21 PM, Beniamino Galvani <b.galvani@gmail.com> wrote:
> This is a driver for the pinmux and GPIO controller available in
> Amlogic Meson SoCs. At the moment it only supports Meson8 devices,
> however other SoC families like Meson6 and Meson8b (the Cortex-A5
> variant) appear to be similar, with just different sets of banks and
> registers.
>
> GPIO interrupts are not supported at the moment due to lack of
> documentation.
>
> Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
(...)
> arch/arm/mach-meson/Kconfig | 3 +
Still not split off from the main patch.
> +static void meson_domain_set_bit(struct meson_domain *domain,
> + void __iomem *addr, unsigned int bit,
> + unsigned int value)
Still not migrated to regmap MMIO.
> + /* Copy group and function definitions from domains to pinctrl */
> + pc->groups = devm_kzalloc(pc->dev, pc->num_groups *
> + sizeof(struct meson_pmx_group), GFP_KERNEL);
> + pc->funcs = devm_kzalloc(pc->dev, pc->num_funcs *
> + sizeof(struct meson_pmx_func), GFP_KERNEL);
> + if (!pc->groups || !pc->funcs)
> + return -ENOMEM;
Still lots of copying of data.
> +static int meson_gpiolib_register(struct meson_pinctrl *pc)
> +{
> + struct meson_domain *domain;
> + unsigned int base = 0;
No.
> + int i, ret;
> +
> + for (i = 0; i < pc->num_domains; i++) {
> + domain = &pc->domains[i];
> +
> + domain->chip.label = domain->data->name;
> + domain->chip.dev = pc->dev;
> + domain->chip.request = meson_gpio_request;
> + domain->chip.free = meson_gpio_free;
> + domain->chip.direction_input = meson_gpio_direction_input;
> + domain->chip.direction_output = meson_gpio_direction_output;
> + domain->chip.get = meson_gpio_get;
> + domain->chip.set = meson_gpio_set;
> + domain->chip.base = base;
No. Set it to -1 and let the gpiolib assign some random GPIO numbers.
> + domain->chip.ngpio = domain->data->num_pins;
> + domain->chip.names = domain->data->pin_names;
> + domain->chip.can_sleep = false;
> + domain->chip.of_node = domain->of_node;
> + domain->chip.of_gpio_n_cells = 2;
> + domain->chip.of_xlate = meson_gpio_of_xlate;
Go for the generic xlate function instead.
> + domain->gpio_range.name = domain->data->name;
> + domain->gpio_range.id = i;
> + domain->gpio_range.base = base;
> + domain->gpio_range.pin_base = base;
> + domain->gpio_range.npins = domain->data->num_pins;
> + domain->gpio_range.gc = &domain->chip;
> +
> + pinctrl_add_gpio_range(pc->pcdev, &domain->gpio_range);
Don't add the gpio range from the pinctrl side, add it from the
gpiolib side using gpiochip_add_pin_range() instead.
> +static int __init meson_pinctrl_drv_register(void)
> +{
> + return platform_driver_register(&meson_pinctrl_driver);
> +}
> +postcore_initcall(meson_pinctrl_drv_register);
Does it have to be this early?
> +/**
> + * struct meson_domain
> + *
> + * @reg_mux: registers for mux settings
> + * @reg_pullen: registers for pull-enable settings
> + * @reg_pull: registers for pull settings
> + * @reg_gpio: registers for gpio settings
> + * @mux_size: size of mux register range (in words)
> + * @pullen_size:size of pull-enable register range
> + * @pull_size: size of pull register range
> + * @gpio_size: size of gpio register range
> + * @chip: gpio chip associated with the domain
> + * @data; platform data for the domain
> + * @node: device tree node for the domain
> + * @gpio_range: gpio range that maps domain gpios to the pin controller
> + * @lock: spinlock for accessing domain registers
> + *
> + * A domain represents a set of banks controlled by the same set of
> + * registers. Typically there is a domain for the normal banks and
> + * another one for the Always-On bus.
> + */
Insert all the info from your previous mail.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/3] pinctrl: meson: add device tree bindings documentation
2014-10-14 21:21 ` [PATCH v2 2/3] pinctrl: meson: add device tree bindings documentation Beniamino Galvani
@ 2014-10-28 14:21 ` Linus Walleij
0 siblings, 0 replies; 6+ messages in thread
From: Linus Walleij @ 2014-10-28 14:21 UTC (permalink / raw)
To: Beniamino Galvani
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, Carlo Caione,
devicetree@vger.kernel.org, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Jerry Cao, Victor Wan
On Tue, Oct 14, 2014 at 11:21 PM, Beniamino Galvani <b.galvani@gmail.com> wrote:
> Add device tree bindings documentation for Amlogic Meson pinmux and
> GPIO controller.
>
> Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
(...)
> + gpio_ao: ao-bank@c1108030 {
> + reg = <0xc8100014 0x4>,
> + <0xc810002c 0x4>,
> + <0xc8100024 0x8>;
This still has the same problem as in the previous review.
It seems for both patches you posted v2 before I got to review
v1, so sorry for the confusion.
Please take the combined result of my review letters and
fix everything...
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-10-28 14:21 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-14 21:21 [PATCH v2 0/3] Pinctrl driver for Amlogic Meson SoCs Beniamino Galvani
2014-10-14 21:21 ` [PATCH v2 1/3] pinctrl: add " Beniamino Galvani
2014-10-28 14:19 ` Linus Walleij
2014-10-14 21:21 ` [PATCH v2 2/3] pinctrl: meson: add device tree bindings documentation Beniamino Galvani
2014-10-28 14:21 ` Linus Walleij
2014-10-14 21:21 ` [PATCH v2 3/3] ARM: dts: meson8: add pinctrl and gpio nodes Beniamino Galvani
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).