summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2018-04-04 22:52:52 +0530
committerLinus Walleij <linus.walleij@linaro.org>2018-05-02 14:36:08 +0200
commit2242ddfbf4d699b58d12467bbebae167d7563700 (patch)
tree6fffaf43e663209b384e4e49771a076ea3dac408
parent4e21264abb20d2dd6a25ff1cd166ef83844c7edc (diff)
downloadlinux-2242ddfbf4d699b58d12467bbebae167d7563700.tar.gz
linux-2242ddfbf4d699b58d12467bbebae167d7563700.tar.bz2
linux-2242ddfbf4d699b58d12467bbebae167d7563700.zip
pinctrl: actions: Add Actions S900 pinctrl driver
Add pinctrl driver for Actions Semi S900 SoC. The driver supports pinctrl, pinmux and pinconf functionalities through a range of registers common to both gpio driver and pinctrl driver. Pinmux functionality is available only for the pin groups while the pinconf functionality is available for both pin groups and individual pins. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/pinctrl/Kconfig1
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/actions/Kconfig12
-rw-r--r--drivers/pinctrl/actions/Makefile2
-rw-r--r--drivers/pinctrl/actions/pinctrl-owl.c585
-rw-r--r--drivers/pinctrl/actions/pinctrl-owl.h142
-rw-r--r--drivers/pinctrl/actions/pinctrl-s900.c1861
7 files changed, 2604 insertions, 0 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 01fe8e0455a0..dd50371225bc 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -337,6 +337,7 @@ config PINCTRL_OCELOT
select GENERIC_PINMUX_FUNCTIONS
select REGMAP_MMIO
+source "drivers/pinctrl/actions/Kconfig"
source "drivers/pinctrl/aspeed/Kconfig"
source "drivers/pinctrl/bcm/Kconfig"
source "drivers/pinctrl/berlin/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 657332b121fb..de40863e7297 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o
obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o
obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o
+obj-y += actions/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
obj-y += bcm/
obj-$(CONFIG_PINCTRL_BERLIN) += berlin/
diff --git a/drivers/pinctrl/actions/Kconfig b/drivers/pinctrl/actions/Kconfig
new file mode 100644
index 000000000000..1c7309c90f0d
--- /dev/null
+++ b/drivers/pinctrl/actions/Kconfig
@@ -0,0 +1,12 @@
+config PINCTRL_OWL
+ bool
+ depends on (ARCH_ACTIONS || COMPILE_TEST) && OF
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+
+config PINCTRL_S900
+ bool "Actions Semi S900 pinctrl driver"
+ select PINCTRL_OWL
+ help
+ Say Y here to enable Actions Semi S900 pinctrl driver
diff --git a/drivers/pinctrl/actions/Makefile b/drivers/pinctrl/actions/Makefile
new file mode 100644
index 000000000000..bd232d28400f
--- /dev/null
+++ b/drivers/pinctrl/actions/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PINCTRL_OWL) += pinctrl-owl.o
+obj-$(CONFIG_PINCTRL_S900) += pinctrl-s900.o
diff --git a/drivers/pinctrl/actions/pinctrl-owl.c b/drivers/pinctrl/actions/pinctrl-owl.c
new file mode 100644
index 000000000000..928b40f71a3c
--- /dev/null
+++ b/drivers/pinctrl/actions/pinctrl-owl.c
@@ -0,0 +1,585 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OWL SoC's Pinctrl driver
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2018 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+#include "pinctrl-owl.h"
+
+/**
+ * struct owl_pinctrl - pinctrl state of the device
+ * @dev: device handle
+ * @pctrldev: pinctrl handle
+ * @lock: spinlock to protect registers
+ * @soc: reference to soc_data
+ * @base: pinctrl register base address
+ */
+struct owl_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctrldev;
+ raw_spinlock_t lock;
+ struct clk *clk;
+ const struct owl_pinctrl_soc_data *soc;
+ void __iomem *base;
+};
+
+static void owl_update_bits(void __iomem *base, u32 mask, u32 val)
+{
+ u32 reg_val;
+
+ reg_val = readl_relaxed(base);
+
+ reg_val = (reg_val & ~mask) | (val & mask);
+
+ writel_relaxed(reg_val, base);
+}
+
+static u32 owl_read_field(struct owl_pinctrl *pctrl, u32 reg,
+ u32 bit, u32 width)
+{
+ u32 tmp, mask;
+
+ tmp = readl_relaxed(pctrl->base + reg);
+ mask = (1 << width) - 1;
+
+ return (tmp >> bit) & mask;
+}
+
+static void owl_write_field(struct owl_pinctrl *pctrl, u32 reg, u32 arg,
+ u32 bit, u32 width)
+{
+ u32 mask;
+
+ mask = (1 << width) - 1;
+ mask = mask << bit;
+
+ owl_update_bits(pctrl->base + reg, mask, (arg << bit));
+}
+
+static int owl_get_groups_count(struct pinctrl_dev *pctrldev)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+ return pctrl->soc->ngroups;
+}
+
+static const char *owl_get_group_name(struct pinctrl_dev *pctrldev,
+ unsigned int group)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+ return pctrl->soc->groups[group].name;
+}
+
+static int owl_get_group_pins(struct pinctrl_dev *pctrldev,
+ unsigned int group,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+ *pins = pctrl->soc->groups[group].pads;
+ *num_pins = pctrl->soc->groups[group].npads;
+
+ return 0;
+}
+
+static void owl_pin_dbg_show(struct pinctrl_dev *pctrldev,
+ struct seq_file *s,
+ unsigned int offset)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+ seq_printf(s, "%s", dev_name(pctrl->dev));
+}
+
+static struct pinctrl_ops owl_pinctrl_ops = {
+ .get_groups_count = owl_get_groups_count,
+ .get_group_name = owl_get_group_name,
+ .get_group_pins = owl_get_group_pins,
+ .pin_dbg_show = owl_pin_dbg_show,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int owl_get_funcs_count(struct pinctrl_dev *pctrldev)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+ return pctrl->soc->nfunctions;
+}
+
+static const char *owl_get_func_name(struct pinctrl_dev *pctrldev,
+ unsigned int function)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+ return pctrl->soc->functions[function].name;
+}
+
+static int owl_get_func_groups(struct pinctrl_dev *pctrldev,
+ unsigned int function,
+ const char * const **groups,
+ unsigned int * const num_groups)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+ *groups = pctrl->soc->functions[function].groups;
+ *num_groups = pctrl->soc->functions[function].ngroups;
+
+ return 0;
+}
+
+static inline int get_group_mfp_mask_val(const struct owl_pingroup *g,
+ int function,
+ u32 *mask,
+ u32 *val)
+{
+ int id;
+ u32 option_num;
+ u32 option_mask;
+
+ for (id = 0; id < g->nfuncs; id++) {
+ if (g->funcs[id] == function)
+ break;
+ }
+ if (WARN_ON(id == g->nfuncs))
+ return -EINVAL;
+
+ option_num = (1 << g->mfpctl_width);
+ if (id > option_num)
+ id -= option_num;
+
+ option_mask = option_num - 1;
+ *mask = (option_mask << g->mfpctl_shift);
+ *val = (id << g->mfpctl_shift);
+
+ return 0;
+}
+
+static int owl_set_mux(struct pinctrl_dev *pctrldev,
+ unsigned int function,
+ unsigned int group)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+ const struct owl_pingroup *g;
+ unsigned long flags;
+ u32 val, mask;
+
+ g = &pctrl->soc->groups[group];
+
+ if (get_group_mfp_mask_val(g, function, &mask, &val))
+ return -EINVAL;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+ owl_update_bits(pctrl->base + g->mfpctl_reg, mask, val);
+
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static struct pinmux_ops owl_pinmux_ops = {
+ .get_functions_count = owl_get_funcs_count,
+ .get_function_name = owl_get_func_name,
+ .get_function_groups = owl_get_func_groups,
+ .set_mux = owl_set_mux,
+};
+
+static int owl_pad_pinconf_reg(const struct owl_padinfo *info,
+ unsigned int param,
+ u32 *reg,
+ u32 *bit,
+ u32 *width)
+{
+ switch (param) {
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (!info->pullctl)
+ return -EINVAL;
+ *reg = info->pullctl->reg;
+ *bit = info->pullctl->shift;
+ *width = info->pullctl->width;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if (!info->st)
+ return -EINVAL;
+ *reg = info->st->reg;
+ *bit = info->st->shift;
+ *width = info->st->width;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int owl_pad_pinconf_arg2val(const struct owl_padinfo *info,
+ unsigned int param,
+ u32 *arg)
+{
+ switch (param) {
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ *arg = OWL_PINCONF_PULL_HOLD;
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ *arg = OWL_PINCONF_PULL_HIZ;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ *arg = OWL_PINCONF_PULL_DOWN;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ *arg = OWL_PINCONF_PULL_UP;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ *arg = (*arg >= 1 ? 1 : 0);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int owl_pad_pinconf_val2arg(const struct owl_padinfo *padinfo,
+ unsigned int param,
+ u32 *arg)
+{
+ switch (param) {
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ *arg = *arg == OWL_PINCONF_PULL_HOLD;
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ *arg = *arg == OWL_PINCONF_PULL_HIZ;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ *arg = *arg == OWL_PINCONF_PULL_DOWN;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ *arg = *arg == OWL_PINCONF_PULL_UP;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ *arg = *arg == 1;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int owl_pin_config_get(struct pinctrl_dev *pctrldev,
+ unsigned int pin,
+ unsigned long *config)
+{
+ int ret = 0;
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+ const struct owl_padinfo *info;
+ unsigned int param = pinconf_to_config_param(*config);
+ u32 reg, bit, width, arg;
+
+ info = &pctrl->soc->padinfo[pin];
+
+ ret = owl_pad_pinconf_reg(info, param, &reg, &bit, &width);
+ if (ret)
+ return ret;
+
+ arg = owl_read_field(pctrl, reg, bit, width);
+
+ ret = owl_pad_pinconf_val2arg(info, param, &arg);
+ if (ret)
+ return ret;
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return ret;
+}
+
+static int owl_pin_config_set(struct pinctrl_dev *pctrldev,
+ unsigned int pin,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+ const struct owl_padinfo *info;
+ unsigned long flags;
+ unsigned int param;
+ u32 reg, bit, width, arg;
+ int ret, i;
+
+ info = &pctrl->soc->padinfo[pin];
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ ret = owl_pad_pinconf_reg(info, param, &reg, &bit, &width);
+ if (ret)
+ return ret;
+
+ ret = owl_pad_pinconf_arg2val(info, param, &arg);
+ if (ret)
+ return ret;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+ owl_write_field(pctrl, reg, arg, bit, width);
+
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ }
+
+ return ret;
+}
+
+static int owl_group_pinconf_reg(const struct owl_pingroup *g,
+ unsigned int param,
+ u32 *reg,
+ u32 *bit,
+ u32 *width)
+{
+ switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (g->drv_reg < 0)
+ return -EINVAL;
+ *reg = g->drv_reg;
+ *bit = g->drv_shift;
+ *width = g->drv_width;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ if (g->sr_reg < 0)
+ return -EINVAL;
+ *reg = g->sr_reg;
+ *bit = g->sr_shift;
+ *width = g->sr_width;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int owl_group_pinconf_arg2val(const struct owl_pingroup *g,
+ unsigned int param,
+ u32 *arg)
+{
+ switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ switch (*arg) {
+ case 2:
+ *arg = OWL_PINCONF_DRV_2MA;
+ break;
+ case 4:
+ *arg = OWL_PINCONF_DRV_4MA;
+ break;
+ case 8:
+ *arg = OWL_PINCONF_DRV_8MA;
+ break;
+ case 12:
+ *arg = OWL_PINCONF_DRV_12MA;
+ break;
+ default:
+ return -EINVAL;
+ }
+ case PIN_CONFIG_SLEW_RATE:
+ if (*arg)
+ *arg = OWL_PINCONF_SLEW_FAST;
+ else
+ *arg = OWL_PINCONF_SLEW_SLOW;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int owl_group_pinconf_val2arg(const struct owl_pingroup *g,
+ unsigned int param,
+ u32 *arg)
+{
+ switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ switch (*arg) {
+ case OWL_PINCONF_DRV_2MA:
+ *arg = 2;
+ break;
+ case OWL_PINCONF_DRV_4MA:
+ *arg = 4;
+ break;
+ case OWL_PINCONF_DRV_8MA:
+ *arg = 8;
+ break;
+ case OWL_PINCONF_DRV_12MA:
+ *arg = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+ case PIN_CONFIG_SLEW_RATE:
+ if (*arg)
+ *arg = 1;
+ else
+ *arg = 0;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int owl_group_config_get(struct pinctrl_dev *pctrldev,
+ unsigned int group,
+ unsigned long *config)
+{
+ const struct owl_pingroup *g;
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+ unsigned int param = pinconf_to_config_param(*config);
+ u32 reg, bit, width, arg;
+ int ret;
+
+ g = &pctrl->soc->groups[group];
+
+ ret = owl_group_pinconf_reg(g, param, &reg, &bit, &width);
+ if (ret)
+ return ret;
+
+ arg = owl_read_field(pctrl, reg, bit, width);
+
+ ret = owl_group_pinconf_val2arg(g, param, &arg);
+ if (ret)
+ return ret;
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return ret;
+
+}
+
+static int owl_group_config_set(struct pinctrl_dev *pctrldev,
+ unsigned int group,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ const struct owl_pingroup *g;
+ struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+ unsigned long flags;
+ unsigned int param;
+ u32 reg, bit, width, arg;
+ int ret, i;
+
+ g = &pctrl->soc->groups[group];
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ ret = owl_group_pinconf_reg(g, param, &reg, &bit, &width);
+ if (ret)
+ return ret;
+
+ ret = owl_group_pinconf_arg2val(g, param, &arg);
+ if (ret)
+ return ret;
+
+ /* Update register */
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+ owl_write_field(pctrl, reg, arg, bit, width);
+
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops owl_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = owl_pin_config_get,
+ .pin_config_set = owl_pin_config_set,
+ .pin_config_group_get = owl_group_config_get,
+ .pin_config_group_set = owl_group_config_set,
+};
+
+static struct pinctrl_desc owl_pinctrl_desc = {
+ .pctlops = &owl_pinctrl_ops,
+ .pmxops = &owl_pinmux_ops,
+ .confops = &owl_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+int owl_pinctrl_probe(struct platform_device *pdev,
+ struct owl_pinctrl_soc_data *soc_data)
+{
+ struct resource *res;
+ struct owl_pinctrl *pctrl;
+ int ret;
+
+ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pctrl->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctrl->base))
+ return PTR_ERR(pctrl->base);
+
+ /* enable GPIO/MFP clock */
+ pctrl->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pctrl->clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ return PTR_ERR(pctrl->clk);
+ }
+
+ ret = clk_prepare_enable(pctrl->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk enable failed\n");
+ return ret;
+ }
+
+ raw_spin_lock_init(&pctrl->lock);
+
+ owl_pinctrl_desc.name = dev_name(&pdev->dev);
+ owl_pinctrl_desc.pins = soc_data->pins;
+ owl_pinctrl_desc.npins = soc_data->npins;
+
+ pctrl->soc = soc_data;
+ pctrl->dev = &pdev->dev;
+
+ pctrl->pctrldev = devm_pinctrl_register(&pdev->dev,
+ &owl_pinctrl_desc, pctrl);
+ if (IS_ERR(pctrl->pctrldev)) {
+ dev_err(&pdev->dev, "could not register Actions OWL pinmux driver\n");
+ return PTR_ERR(pctrl->pctrldev);
+ }
+
+ platform_set_drvdata(pdev, pctrl);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/actions/pinctrl-owl.h b/drivers/pinctrl/actions/pinctrl-owl.h
new file mode 100644
index 000000000000..448f81a6db3b
--- /dev/null
+++ b/drivers/pinctrl/actions/pinctrl-owl.h
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OWL SoC's Pinctrl definitions
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2018 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#ifndef __PINCTRL_OWL_H__
+#define __PINCTRL_OWL_H__
+
+#define OWL_PINCONF_SLEW_SLOW 0
+#define OWL_PINCONF_SLEW_FAST 1
+
+enum owl_pinconf_pull {
+ OWL_PINCONF_PULL_HIZ,
+ OWL_PINCONF_PULL_DOWN,
+ OWL_PINCONF_PULL_UP,
+ OWL_PINCONF_PULL_HOLD,
+};
+
+enum owl_pinconf_drv {
+ OWL_PINCONF_DRV_2MA,
+ OWL_PINCONF_DRV_4MA,
+ OWL_PINCONF_DRV_8MA,
+ OWL_PINCONF_DRV_12MA,
+};
+
+/**
+ * struct owl_pullctl - Actions pad pull control register
+ * @reg: offset to the pull control register
+ * @shift: shift value of the register
+ * @width: width of the register
+ */
+struct owl_pullctl {
+ int reg;
+ unsigned int shift;
+ unsigned int width;
+};
+
+/**
+ * struct owl_st - Actions pad schmitt trigger enable register
+ * @reg: offset to the schmitt trigger enable register
+ * @shift: shift value of the register
+ * @width: width of the register
+ */
+struct owl_st {
+ int reg;
+ unsigned int shift;
+ unsigned int width;
+};
+
+/**
+ * struct owl_pingroup - Actions pingroup definition
+ * @name: name of the pin group
+ * @pads: list of pins assigned to this pingroup
+ * @npads: size of @pads array
+ * @funcs: list of pinmux functions for this pingroup
+ * @nfuncs: size of @funcs array
+ * @mfpctl_reg: multiplexing control register offset
+ * @mfpctl_shift: multiplexing control register bit mask
+ * @mfpctl_width: multiplexing control register width
+ * @drv_reg: drive control register offset
+ * @drv_shift: drive control register bit mask
+ * @drv_width: driver control register width
+ * @sr_reg: slew rate control register offset
+ * @sr_shift: slew rate control register bit mask
+ * @sr_width: slew rate control register width
+ */
+struct owl_pingroup {
+ const char *name;
+ unsigned int *pads;
+ unsigned int npads;
+ unsigned int *funcs;
+ unsigned int nfuncs;
+
+ int mfpctl_reg;
+ unsigned int mfpctl_shift;
+ unsigned int mfpctl_width;
+
+ int drv_reg;
+ unsigned int drv_shift;
+ unsigned int drv_width;
+
+ int sr_reg;
+ unsigned int sr_shift;
+ unsigned int sr_width;
+};
+
+/**
+ * struct owl_padinfo - Actions pinctrl pad info
+ * @pad: pad name of the SoC
+ * @pullctl: pull control register info
+ * @st: schmitt trigger register info
+ */
+struct owl_padinfo {
+ int pad;
+ struct owl_pullctl *pullctl;
+ struct owl_st *st;
+};
+
+/**
+ * struct owl_pinmux_func - Actions pinctrl mux functions
+ * @name: name of the pinmux function.
+ * @groups: array of pin groups that may select this function.
+ * @ngroups: number of entries in @groups.
+ */
+struct owl_pinmux_func {
+ const char *name;
+ const char * const *groups;
+ unsigned int ngroups;
+};
+
+/**
+ * struct owl_pinctrl_soc_data - Actions pin controller driver configuration
+ * @pins: array describing all pins of the pin controller.
+ * @npins: number of entries in @pins.
+ * @functions: array describing all mux functions of this SoC.
+ * @nfunction: number of entries in @functions.
+ * @groups: array describing all pin groups of this SoC.
+ * @ngroups: number of entries in @groups.
+ * @padinfo: array describing the pad info of this SoC.
+ * @ngpios: number of pingroups the driver should expose as GPIOs.
+ */
+struct owl_pinctrl_soc_data {
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ const struct owl_pinmux_func *functions;
+ unsigned int nfunctions;
+ const struct owl_pingroup *groups;
+ unsigned int ngroups;
+ const struct owl_padinfo *padinfo;
+ unsigned int ngpios;
+};
+
+int owl_pinctrl_probe(struct platform_device *pdev,
+ struct owl_pinctrl_soc_data *soc_data);
+
+#endif /* __PINCTRL_OWL_H__ */
diff --git a/drivers/pinctrl/actions/pinctrl-s900.c b/drivers/pinctrl/actions/pinctrl-s900.c
new file mode 100644
index 000000000000..49a04e224ee6
--- /dev/null
+++ b/drivers/pinctrl/actions/pinctrl-s900.c
@@ -0,0 +1,1861 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OWL S900 Pinctrl driver
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2018 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-owl.h"
+
+/* Pinctrl registers offset */
+#define MFCTL0 (0x0040)
+#define MFCTL1 (0x0044)
+#define MFCTL2 (0x0048)
+#define MFCTL3 (0x004C)
+#define PAD_PULLCTL0 (0x0060)
+#define PAD_PULLCTL1 (0x0064)
+#define PAD_PULLCTL2 (0x0068)
+#define PAD_ST0 (0x006C)
+#define PAD_ST1 (0x0070)
+#define PAD_CTL (0x0074)
+#define PAD_DRV0 (0x0080)
+#define PAD_DRV1 (0x0084)
+#define PAD_DRV2 (0x0088)
+#define PAD_SR0 (0x0270)
+#define PAD_SR1 (0x0274)
+#define PAD_SR2 (0x0278)
+
+#define _GPIOA(offset) (offset)
+#define _GPIOB(offset) (32 + (offset))
+#define _GPIOC(offset) (64 + (offset))
+#define _GPIOD(offset) (76 + (offset))
+#define _GPIOE(offset) (106 + (offset))
+#define _GPIOF(offset) (138 + (offset))
+
+#define NUM_GPIOS (_GPIOF(7) + 1)
+#define _PIN(offset) (NUM_GPIOS + (offset))
+
+#define ETH_TXD0 _GPIOA(0)
+#define ETH_TXD1 _GPIOA(1)
+#define ETH_TXEN _GPIOA(2)
+#define ETH_RXER _GPIOA(3)
+#define ETH_CRS_DV _GPIOA(4)
+#define ETH_RXD1 _GPIOA(5)
+#define ETH_RXD0 _GPIOA(6)
+#define ETH_REF_CLK _GPIOA(7)
+#define ETH_MDC _GPIOA(8)
+#define ETH_MDIO _GPIOA(9)
+#define SIRQ0 _GPIOA(10)
+#define SIRQ1 _GPIOA(11)
+#define SIRQ2 _GPIOA(12)
+#define I2S_D0 _GPIOA(13)
+#define I2S_BCLK0 _GPIOA(14)
+#define I2S_LRCLK0 _GPIOA(15)
+#define I2S_MCLK0 _GPIOA(16)
+#define I2S_D1 _GPIOA(17)
+#define I2S_BCLK1 _GPIOA(18)
+#define I2S_LRCLK1 _GPIOA(19)
+#define I2S_MCLK1 _GPIOA(20)
+#define ERAM_A5 _GPIOA(21)
+#define ERAM_A6 _GPIOA(22)
+#define ERAM_A7 _GPIOA(23)
+#define ERAM_A8 _GPIOA(24)
+#define ERAM_A9 _GPIOA(25)
+#define ERAM_A10 _GPIOA(26)
+#define ERAM_A11 _GPIOA(27)
+#define SD0_D0 _GPIOA(28)
+#define SD0_D1 _GPIOA(29)
+#define SD0_D2 _GPIOA(30)
+#define SD0_D3 _GPIOA(31)
+
+#define SD1_D0 _GPIOB(0)
+#define SD1_D1 _GPIOB(1)
+#define SD1_D2 _GPIOB(2)
+#define SD1_D3 _GPIOB(3)
+#define SD0_CMD _GPIOB(4)
+#define SD0_CLK _GPIOB(5)
+#define SD1_CMD _GPIOB(6)
+#define SD1_CLK _GPIOB(7)
+#define SPI0_SCLK _GPIOB(8)
+#define SPI0_SS _GPIOB(9)
+#define SPI0_MISO _GPIOB(10)
+#define SPI0_MOSI _GPIOB(11)
+#define UART0_RX _GPIOB(12)
+#define UART0_TX _GPIOB(13)
+#define UART2_RX _GPIOB(14)
+#define UART2_TX _GPIOB(15)
+#define UART2_RTSB _GPIOB(16)
+#define UART2_CTSB _GPIOB(17)
+#define UART4_RX _GPIOB(18)
+#define UART4_TX _GPIOB(19)
+#define I2C0_SCLK _GPIOB(20)
+#define I2C0_SDATA _GPIOB(21)
+#define I2C1_SCLK _GPIOB(22)
+#define I2C1_SDATA _GPIOB(23)
+#define I2C2_SCLK _GPIOB(24)
+#define I2C2_SDATA _GPIOB(25)
+#define CSI0_DN0 _GPIOB(26)
+#define CSI0_DP0 _GPIOB(27)
+#define CSI0_DN1 _GPIOB(28)
+#define CSI0_DP1 _GPIOB(29)
+#define CSI0_CN _GPIOB(30)
+#define CSI0_CP _GPIOB(31)
+
+#define CSI0_DN2 _GPIOC(0)
+#define CSI0_DP2 _GPIOC(1)
+#define CSI0_DN3 _GPIOC(2)
+#define CSI0_DP3 _GPIOC(3)
+#define SENSOR0_PCLK _GPIOC(4)
+#define CSI1_DN0 _GPIOC(5)
+#define CSI1_DP0 _GPIOC(6)
+#define CSI1_DN1 _GPIOC(7)
+#define CSI1_DP1 _GPIOC(8)
+#define CSI1_CN _GPIOC(9)
+#define CSI1_CP _GPIOC(10)
+#define SENSOR0_CKOUT _GPIOC(11)
+
+#define LVDS_OEP _GPIOD(0)
+#define LVDS_OEN _GPIOD(1)
+#define LVDS_ODP _GPIOD(2)
+#define LVDS_ODN _GPIOD(3)
+#define LVDS_OCP _GPIOD(4)
+#define LVDS_OCN _GPIOD(5)
+#define LVDS_OBP _GPIOD(6)
+#define LVDS_OBN _GPIOD(7)
+#define LVDS_OAP _GPIOD(8)
+#define LVDS_OAN _GPIOD(9)
+#define LVDS_EEP _GPIOD(10)
+#define LVDS_EEN _GPIOD(11)
+#define LVDS_EDP _GPIOD(12)
+#define LVDS_EDN _GPIOD(13)
+#define LVDS_ECP _GPIOD(14)
+#define LVDS_ECN _GPIOD(15)
+#define LVDS_EBP _GPIOD(16)
+#define LVDS_EBN _GPIOD(17)
+#define LVDS_EAP _GPIOD(18)
+#define LVDS_EAN _GPIOD(19)
+#define DSI_DP3 _GPIOD(20)
+#define DSI_DN3 _GPIOD(21)
+#define DSI_DP1 _GPIOD(22)
+#define DSI_DN1 _GPIOD(23)
+#define DSI_CP _GPIOD(24)
+#define DSI_CN _GPIOD(25)
+#define DSI_DP0 _GPIOD(26)
+#define DSI_DN0 _GPIOD(27)
+#define DSI_DP2 _GPIOD(28)
+#define DSI_DN2 _GPIOD(29)
+
+#define NAND0_D0 _GPIOE(0)
+#define NAND0_D1 _GPIOE(1)
+#define NAND0_D2 _GPIOE(2)
+#define NAND0_D3 _GPIOE(3)
+#define NAND0_D4 _GPIOE(4)
+#define NAND0_D5 _GPIOE(5)
+#define NAND0_D6 _GPIOE(6)
+#define NAND0_D7 _GPIOE(7)
+#define NAND0_DQS _GPIOE(8)
+#define NAND0_DQSN _GPIOE(9)
+#define NAND0_ALE _GPIOE(10)
+#define NAND0_CLE _GPIOE(11)
+#define NAND0_CEB0 _GPIOE(12)
+#define NAND0_CEB1 _GPIOE(13)
+#define NAND0_CEB2 _GPIOE(14)
+#define NAND0_CEB3 _GPIOE(15)
+#define NAND1_D0 _GPIOE(16)
+#define NAND1_D1 _GPIOE(17)
+#define NAND1_D2 _GPIOE(18)
+#define NAND1_D3 _GPIOE(19)
+#define NAND1_D4 _GPIOE(20)
+#define NAND1_D5 _GPIOE(21)
+#define NAND1_D6 _GPIOE(22)
+#define NAND1_D7 _GPIOE(23)
+#define NAND1_DQS _GPIOE(24)
+#define NAND1_DQSN _GPIOE(25)
+#define NAND1_ALE _GPIOE(26)
+#define NAND1_CLE _GPIOE(27)
+#define NAND1_CEB0 _GPIOE(28)
+#define NAND1_CEB1 _GPIOE(29)
+#define NAND1_CEB2 _GPIOE(30)
+#define NAND1_CEB3 _GPIOE(31)
+
+#define PCM1_IN _GPIOF(0)
+#define PCM1_CLK _GPIOF(1)
+#define PCM1_SYNC _GPIOF(2)
+#define PCM1_OUT _GPIOF(3)
+#define UART3_RX _GPIOF(4)
+#define UART3_TX _GPIOF(5)
+#define UART3_RTSB _GPIOF(6)
+#define UART3_CTSB _GPIOF(7)
+
+/* System */
+#define SGPIO0 _PIN(0)
+#define SGPIO1 _PIN(1)
+#define SGPIO2 _PIN(2)
+#define SGPIO3 _PIN(3)
+
+#define NUM_PADS (_PIN(3) + 1)
+
+/* Pad names as specified in datasheet */
+const struct pinctrl_pin_desc s900_pads[] = {
+ PINCTRL_PIN(ETH_TXD0, "eth_txd0"),
+ PINCTRL_PIN(ETH_TXD1, "eth_txd1"),
+ PINCTRL_PIN(ETH_TXEN, "eth_txen"),
+ PINCTRL_PIN(ETH_RXER, "eth_rxer"),
+ PINCTRL_PIN(ETH_CRS_DV, "eth_crs_dv"),
+ PINCTRL_PIN(ETH_RXD1, "eth_rxd1"),
+ PINCTRL_PIN(ETH_RXD0, "eth_rxd0"),
+ PINCTRL_PIN(ETH_REF_CLK, "eth_ref_clk"),
+ PINCTRL_PIN(ETH_MDC, "eth_mdc"),
+ PINCTRL_PIN(ETH_MDIO, "eth_mdio"),
+ PINCTRL_PIN(SIRQ0, "sirq0"),
+ PINCTRL_PIN(SIRQ1, "sirq1"),
+ PINCTRL_PIN(SIRQ2, "sirq2"),
+ PINCTRL_PIN(I2S_D0, "i2s_d0"),
+ PINCTRL_PIN(I2S_BCLK0, "i2s_bclk0"),
+ PINCTRL_PIN(I2S_LRCLK0, "i2s_lrclk0"),
+ PINCTRL_PIN(I2S_MCLK0, "i2s_mclk0"),
+ PINCTRL_PIN(I2S_D1, "i2s_d1"),
+ PINCTRL_PIN(I2S_BCLK1, "i2s_bclk1"),
+ PINCTRL_PIN(I2S_LRCLK1, "i2s_lrclk1"),
+ PINCTRL_PIN(I2S_MCLK1, "i2s_mclk1"),
+ PINCTRL_PIN(PCM1_IN, "pcm1_in"),
+ PINCTRL_PIN(PCM1_CLK, "pcm1_clk"),
+ PINCTRL_PIN(PCM1_SYNC, "pcm1_sync"),
+ PINCTRL_PIN(PCM1_OUT, "pcm1_out"),
+ PINCTRL_PIN(ERAM_A5, "eram_a5"),
+ PINCTRL_PIN(ERAM_A6, "eram_a6"),
+ PINCTRL_PIN(ERAM_A7, "eram_a7"),
+ PINCTRL_PIN(ERAM_A8, "eram_a8"),
+ PINCTRL_PIN(ERAM_A9, "eram_a9"),
+ PINCTRL_PIN(ERAM_A10, "eram_a10"),
+ PINCTRL_PIN(ERAM_A11, "eram_a11"),
+ PINCTRL_PIN(LVDS_OEP, "lvds_oep"),
+ PINCTRL_PIN(LVDS_OEN, "lvds_oen"),
+ PINCTRL_PIN(LVDS_ODP, "lvds_odp"),
+ PINCTRL_PIN(LVDS_ODN, "lvds_odn"),
+ PINCTRL_PIN(LVDS_OCP, "lvds_ocp"),
+ PINCTRL_PIN(LVDS_OCN, "lvds_ocn"),
+ PINCTRL_PIN(LVDS_OBP, "lvds_obp"),
+ PINCTRL_PIN(LVDS_OBN, "lvds_obn"),
+ PINCTRL_PIN(LVDS_OAP, "lvds_oap"),
+ PINCTRL_PIN(LVDS_OAN, "lvds_oan"),
+ PINCTRL_PIN(LVDS_EEP, "lvds_eep"),
+ PINCTRL_PIN(LVDS_EEN, "lvds_een"),
+ PINCTRL_PIN(LVDS_EDP, "lvds_edp"),
+ PINCTRL_PIN(LVDS_EDN, "lvds_edn"),
+ PINCTRL_PIN(LVDS_ECP, "lvds_ecp"),
+ PINCTRL_PIN(LVDS_ECN, "lvds_ecn"),
+ PINCTRL_PIN(LVDS_EBP, "lvds_ebp"),
+ PINCTRL_PIN(LVDS_EBN, "lvds_ebn"),
+ PINCTRL_PIN(LVDS_EAP, "lvds_eap"),
+ PINCTRL_PIN(LVDS_EAN, "lvds_ean"),
+ PINCTRL_PIN(SD0_D0, "sd0_d0"),
+ PINCTRL_PIN(SD0_D1, "sd0_d1"),
+ PINCTRL_PIN(SD0_D2, "sd0_d2"),
+ PINCTRL_PIN(SD0_D3, "sd0_d3"),
+ PINCTRL_PIN(SD1_D0, "sd1_d0"),
+ PINCTRL_PIN(SD1_D1, "sd1_d1"),
+ PINCTRL_PIN(SD1_D2, "sd1_d2"),
+ PINCTRL_PIN(SD1_D3, "sd1_d3"),
+ PINCTRL_PIN(SD0_CMD, "sd0_cmd"),
+ PINCTRL_PIN(SD0_CLK, "sd0_clk"),
+ PINCTRL_PIN(SD1_CMD, "sd1_cmd"),
+ PINCTRL_PIN(SD1_CLK, "sd1_clk"),
+ PINCTRL_PIN(SPI0_SCLK, "spi0_sclk"),
+ PINCTRL_PIN(SPI0_SS, "spi0_ss"),
+ PINCTRL_PIN(SPI0_MISO, "spi0_miso"),
+ PINCTRL_PIN(SPI0_MOSI, "spi0_mosi"),
+ PINCTRL_PIN(UART0_RX, "uart0_rx"),
+ PINCTRL_PIN(UART0_TX, "uart0_tx"),
+ PINCTRL_PIN(UART2_RX, "uart2_rx"),
+ PINCTRL_PIN(UART2_TX, "uart2_tx"),
+ PINCTRL_PIN(UART2_RTSB, "uart2_rtsb"),
+ PINCTRL_PIN(UART2_CTSB, "uart2_ctsb"),
+ PINCTRL_PIN(UART3_RX, "uart3_rx"),
+ PINCTRL_PIN(UART3_TX, "uart3_tx"),
+ PINCTRL_PIN(UART3_RTSB, "uart3_rtsb"),
+ PINCTRL_PIN(UART3_CTSB, "uart3_ctsb"),
+ PINCTRL_PIN(UART4_RX, "uart4_rx"),
+ PINCTRL_PIN(UART4_TX, "uart4_tx"),
+ PINCTRL_PIN(I2C0_SCLK, "i2c0_sclk"),
+ PINCTRL_PIN(I2C0_SDATA, "i2c0_sdata"),
+ PINCTRL_PIN(I2C1_SCLK, "i2c1_sclk"),
+ PINCTRL_PIN(I2C1_SDATA, "i2c1_sdata"),
+ PINCTRL_PIN(I2C2_SCLK, "i2c2_sclk"),
+ PINCTRL_PIN(I2C2_SDATA, "i2c2_sdata"),
+ PINCTRL_PIN(CSI0_DN0, "csi0_dn0"),
+ PINCTRL_PIN(CSI0_DP0, "csi0_dp0"),
+ PINCTRL_PIN(CSI0_DN1, "csi0_dn1"),
+ PINCTRL_PIN(CSI0_DP1, "csi0_dp1"),
+ PINCTRL_PIN(CSI0_CN, "csi0_cn"),
+ PINCTRL_PIN(CSI0_CP, "csi0_cp"),
+ PINCTRL_PIN(CSI0_DN2, "csi0_dn2"),
+ PINCTRL_PIN(CSI0_DP2, "csi0_dp2"),
+ PINCTRL_PIN(CSI0_DN3, "csi0_dn3"),
+ PINCTRL_PIN(CSI0_DP3, "csi0_dp3"),
+ PINCTRL_PIN(DSI_DP3, "dsi_dp3"),
+ PINCTRL_PIN(DSI_DN3, "dsi_dn3"),
+ PINCTRL_PIN(DSI_DP1, "dsi_dp1"),
+ PINCTRL_PIN(DSI_DN1, "dsi_dn1"),
+ PINCTRL_PIN(DSI_CP, "dsi_c