提交 edb2a385 编写于 作者: L Linus Torvalds

Merge tag 'pinctrl-v4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl

Pull pin control updates from Linus Walleij:
 "This is the bulk of pin control changes for v4.18.

  No core changes this time! Just a calm all-over-the-place drivers,
  updates and fixes cycle as it seems.

  New drivers/subdrivers:

   - Actions Semiconductor S900 driver with more Actions variants for
     S700, S500 in the pipe. Also generic GPIO support on top of the
     same driver and IRQ support is in the pipe.

   - Renesas r8a77470 PFC support.

   - Renesas r8a77990 PFC support.

   - Allwinner Sunxi H6 R_PIO support.

   - Rockchip PX30 support.

   - Meson Meson8m2 support.

   - Remove support for the ill-fated Samsung Exynos 5440 SoC.

  Improvements:

   - Context save/restore support in pinctrl-single.

   - External interrupt support for the Mediatek MT7622.

   - Qualcomm ACPI HID QCOM8002 supported.

  Fixes:

   - Fix up suspend/resume support for Exynos 5433.

   - Fix Strago DMI fixes on the Intel Cherryview"

* tag 'pinctrl-v4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (72 commits)
  pinctrl: cherryview: limit Strago DMI workarounds to version 1.0
  pinctrl: at91-pio4: add missing of_node_put
  pinctrl: armada-37xx: Fix spurious irq management
  gpiolib: discourage gpiochip_add_pin[group]_range for DT pinctrls
  pinctrl: msm: fix gpio-hog related boot issues
  MAINTAINERS: update entry for Mediatek pin controller
  pinctrl: mediatek: remove unused fields in struct mtk_eint_hw
  pinctrl: mediatek: use generic EINT register maps for each SoC
  pinctrl: mediatek: add EINT support to MT7622 SoC
  pinctrl: mediatek: refactor EINT related code for all MediaTek pinctrl can fit
  dt-bindings: pinctrl: add external interrupt support to MT7622 pinctrl
  pinctrl: freescale: Switch to SPDX identifier
  pinctrl: samsung: Fix suspend/resume for Exynos5433 GPF1..5 banks
  pinctrl: sh-pfc: rcar-gen3: Fix grammar in static pin comments
  pinctrl: sh-pfc: r8a77965: Add I2C pin support
  pinctrl: sh-pfc: r8a77990: Add EthernetAVB pins, groups and functions
  pinctrl: sh-pfc: r8a77990: Add I2C{1,2,4,5,6,7} pins, groups and functions
  pinctrl: sh-pfc: r8a77990: Add SCIF pins, groups and functions
  pinctrl: sh-pfc: r8a77990: Add bias pinconf support
  pinctrl: sh-pfc: Initial R8A77990 PFC support
  ...
......@@ -8,6 +8,17 @@ Required Properties:
- reg: Should contain the register base address and size of
the pin controller.
- clocks: phandle of the clock feeding the pin controller
- gpio-controller: Marks the device node as a GPIO controller.
- gpio-ranges: Specifies the mapping between gpio controller and
pin-controller pins.
- #gpio-cells: Should be two. The first cell is the gpio pin number
and the second cell is used for optional parameters.
- interrupt-controller: Marks the device node as an interrupt controller.
- #interrupt-cells: Specifies the number of cells needed to encode an
interrupt. Shall be set to 2. The first cell
defines the interrupt number, the second encodes
the trigger flags described in
bindings/interrupt-controller/interrupts.txt
Please refer to pinctrl-bindings.txt in this directory for details of the
common pinctrl bindings used by client devices, including the meaning of the
......@@ -164,6 +175,11 @@ Example:
compatible = "actions,s900-pinctrl";
reg = <0x0 0xe01b0000 0x0 0x1000>;
clocks = <&cmu CLK_GPIO>;
gpio-controller;
gpio-ranges = <&pinctrl 0 0 146>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
uart2-default: uart2-default {
pinmux {
......
......@@ -28,6 +28,7 @@ Required properties:
"allwinner,sun50i-a64-r-pinctrl"
"allwinner,sun50i-h5-pinctrl"
"allwinner,sun50i-h6-pinctrl"
"allwinner,sun50i-h6-r-pinctrl"
"nextthing,gr8-pinctrl"
- reg: Should contain the register physical address and length for the
......
......@@ -36,6 +36,24 @@ listed. In other words, a subnode that lists only a mux function implies no
information about any pull configuration. Similarly, a subnode that lists only
a pul parameter implies no information about the mux function.
The BCM2835 pin configuration and multiplexing supports the generic bindings.
For details on each properties, you can refer to ./pinctrl-bindings.txt.
Required sub-node properties:
- pins
- function
Optional sub-node properties:
- bias-disable
- bias-pull-up
- bias-pull-down
- output-high
- output-low
Legacy pin configuration and multiplexing binding:
*** (Its use is deprecated, use generic multiplexing and configuration
bindings instead)
Required subnode-properties:
- brcm,pins: An array of cells. Each cell contains the ID of a pin. Valid IDs
are the integer GPIO IDs; 0==GPIO0, 1==GPIO1, ... 53==GPIO53.
......
......@@ -3,8 +3,10 @@
Required properties for the root node:
- compatible: one of "amlogic,meson8-cbus-pinctrl"
"amlogic,meson8b-cbus-pinctrl"
"amlogic,meson8m2-cbus-pinctrl"
"amlogic,meson8-aobus-pinctrl"
"amlogic,meson8b-aobus-pinctrl"
"amlogic,meson8m2-aobus-pinctrl"
"amlogic,meson-gxbb-periphs-pinctrl"
"amlogic,meson-gxbb-aobus-pinctrl"
"amlogic,meson-gxl-periphs-pinctrl"
......
......@@ -18,7 +18,9 @@ Required properties:
removed.
- #gpio-cells : Should be two.
- first cell is the pin number
- second cell is used to specify flags. Flags are currently unused.
- second cell is used to specify flags as described in
'Documentation/devicetree/bindings/gpio/gpio.txt'. Allowed values defined by
'include/dt-bindings/gpio/gpio.h' (e.g. GPIO_ACTIVE_LOW).
- gpio-controller : Marks the device node as a GPIO controller.
- reg : For an address on its bus. I2C uses this a the I2C address of the chip.
SPI uses this to specify the chipselect line which the chip is
......
......@@ -9,6 +9,16 @@ Required properties for the root node:
- #gpio-cells: Should be two. The first cell is the pin number and the
second is the GPIO flags.
Optional properties:
- interrupt-controller : Marks the device node as an interrupt controller
If the property interrupt-controller is defined, following property is required
- reg-names: A string describing the "reg" entries. Must contain "eint".
- interrupts : The interrupt output from the controller.
- #interrupt-cells: Should be two.
- interrupt-parent: Phandle of the interrupt parent to which the external
GPIO interrupts are forwarded to.
Please refer to pinctrl-bindings.txt in this directory for details of the
common pinctrl bindings used by client devices, including the meaning of the
phrase "pin configuration node".
......
......@@ -15,6 +15,7 @@ Required Properties:
- "renesas,pfc-r8a7740": for R8A7740 (R-Mobile A1) compatible pin-controller.
- "renesas,pfc-r8a7743": for R8A7743 (RZ/G1M) compatible pin-controller.
- "renesas,pfc-r8a7745": for R8A7745 (RZ/G1E) compatible pin-controller.
- "renesas,pfc-r8a77470": for R8A77470 (RZ/G1C) compatible pin-controller.
- "renesas,pfc-r8a7778": for R8A7778 (R-Car M1) compatible pin-controller.
- "renesas,pfc-r8a7779": for R8A7779 (R-Car H1) compatible pin-controller.
- "renesas,pfc-r8a7790": for R8A7790 (R-Car H2) compatible pin-controller.
......@@ -27,6 +28,7 @@ Required Properties:
- "renesas,pfc-r8a77965": for R8A77965 (R-Car M3-N) compatible pin-controller.
- "renesas,pfc-r8a77970": for R8A77970 (R-Car V3M) compatible pin-controller.
- "renesas,pfc-r8a77980": for R8A77980 (R-Car V3H) compatible pin-controller.
- "renesas,pfc-r8a77990": for R8A77990 (R-Car E3) compatible pin-controller.
- "renesas,pfc-r8a77995": for R8A77995 (R-Car D3) compatible pin-controller.
- "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller.
......
......@@ -20,6 +20,7 @@ defined as gpio sub-nodes of the pinmux controller.
Required properties for iomux controller:
- compatible: should be
"rockchip,px30-pinctrl": for Rockchip PX30
"rockchip,rv1108-pinctrl": for Rockchip RV1108
"rockchip,rk2928-pinctrl": for Rockchip RK2928
"rockchip,rk3066a-pinctrl": for Rockchip RK3066a
......
......@@ -1135,10 +1135,12 @@ F: arch/arm/mach-actions/
F: arch/arm/boot/dts/owl-*
F: arch/arm64/boot/dts/actions/
F: drivers/clocksource/owl-*
F: drivers/pinctrl/actions/*
F: drivers/soc/actions/
F: include/dt-bindings/power/owl-*
F: include/linux/soc/actions/
F: Documentation/devicetree/bindings/arm/actions.txt
F: Documentation/devicetree/bindings/pinctrl/actions,s900-pinctrl.txt
F: Documentation/devicetree/bindings/power/actions,owl-sps.txt
F: Documentation/devicetree/bindings/timer/actions,owl-timer.txt
......@@ -11225,6 +11227,7 @@ L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
F: Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt
F: drivers/pinctrl/mediatek/mtk-eint.*
F: drivers/pinctrl/mediatek/pinctrl-mtk-common.*
F: drivers/pinctrl/mediatek/pinctrl-mt2701.c
F: drivers/pinctrl/mediatek/pinctrl-mt7622.c
......
......@@ -2078,6 +2078,11 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_config);
* @pctldev: the pin controller to map to
* @gpio_offset: the start offset in the current gpio_chip number space
* @pin_group: name of the pin group inside the pin controller
*
* Calling this function directly from a DeviceTree-supported
* pinctrl driver is DEPRECATED. Please see Section 2.1 of
* Documentation/devicetree/bindings/gpio/gpio.txt on how to
* bind pinctrl and gpio drivers via the "gpio-ranges" property.
*/
int gpiochip_add_pingroup_range(struct gpio_chip *chip,
struct pinctrl_dev *pctldev,
......@@ -2131,6 +2136,11 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
*
* Returns:
* 0 on success, or a negative error-code on failure.
*
* Calling this function directly from a DeviceTree-supported
* pinctrl driver is DEPRECATED. Please see Section 2.1 of
* Documentation/devicetree/bindings/gpio/gpio.txt on how to
* bind pinctrl and gpio drivers via the "gpio-ranges" property.
*/
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset,
......
......@@ -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"
......
......@@ -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/
......
config PINCTRL_OWL
bool "Actions Semi OWL pinctrl driver"
depends on (ARCH_ACTIONS || COMPILE_TEST) && OF
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GPIOLIB
help
Say Y here to enable Actions Semi OWL pinctrl driver
config PINCTRL_S900
bool "Actions Semi S900 pinctrl driver"
depends on PINCTRL_OWL
help
Say Y here to enable Actions Semi S900 pinctrl driver
obj-$(CONFIG_PINCTRL_OWL) += pinctrl-owl.o
obj-$(CONFIG_PINCTRL_S900) += pinctrl-s900.o
// 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/gpio/driver.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
* @chip: gpio chip
* @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;
struct gpio_chip chip;
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;
}
break;
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;
}
break;
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,
};
static const struct owl_gpio_port *
owl_gpio_get_port(struct owl_pinctrl *pctrl, unsigned int *pin)
{
unsigned int start = 0, i;
for (i = 0; i < pctrl->soc->nports; i++) {
const struct owl_gpio_port *port = &pctrl->soc->ports[i];
if (*pin >= start && *pin < start + port->pins) {
*pin -= start;
return port;
}
start += port->pins;
}
return NULL;
}
static void owl_gpio_update_reg(void __iomem *base, unsigned int pin, int flag)
{
u32 val;
val = readl_relaxed(base);
if (flag)
val |= BIT(pin);
else
val &= ~BIT(pin);
writel_relaxed(val, base);
}
static int owl_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
const struct owl_gpio_port *port;
void __iomem *gpio_base;
unsigned long flags;
port = owl_gpio_get_port(pctrl, &offset);
if (WARN_ON(port == NULL))
return -ENODEV;
gpio_base = pctrl->base + port->offset;
/*
* GPIOs have higher priority over other modules, so either setting
* them as OUT or IN is sufficient
*/
raw_spin_lock_irqsave(&pctrl->lock, flags);
owl_gpio_update_reg(gpio_base + port->outen, offset, true);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
}
static void owl_gpio_free(struct gpio_chip *chip, unsigned int offset)
{
struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
const struct owl_gpio_port *port;
void __iomem *gpio_base;
unsigned long flags;
port = owl_gpio_get_port(pctrl, &offset);
if (WARN_ON(port == NULL))
return;
gpio_base = pctrl->base + port->offset;
raw_spin_lock_irqsave(&pctrl->lock, flags);
/* disable gpio output */
owl_gpio_update_reg(gpio_base + port->outen, offset, false);
/* disable gpio input */
owl_gpio_update_reg(gpio_base + port->inen, offset, false);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
static int owl_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
const struct owl_gpio_port *port;
void __iomem *gpio_base;
unsigned long flags;
u32 val;
port = owl_gpio_get_port(pctrl, &offset);
if (WARN_ON(port == NULL))
return -ENODEV;
gpio_base = pctrl->base + port->offset;
raw_spin_lock_irqsave(&pctrl->lock, flags);
val = readl_relaxed(gpio_base + port->dat);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return !!(val & BIT(offset));
}
static void owl_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
const struct owl_gpio_port *port;
void __iomem *gpio_base;
unsigned long flags;
port = owl_gpio_get_port(pctrl, &offset);
if (WARN_ON(port == NULL))
return;
gpio_base = pctrl->base + port->offset;
raw_spin_lock_irqsave(&pctrl->lock, flags);
owl_gpio_update_reg(gpio_base + port->dat, offset, value);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
static int owl_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
const struct owl_gpio_port *port;
void __iomem *gpio_base;
unsigned long flags;
port = owl_gpio_get_port(pctrl, &offset);
if (WARN_ON(port == NULL))
return -ENODEV;
gpio_base = pctrl->base + port->offset;
raw_spin_lock_irqsave(&pctrl->lock, flags);
owl_gpio_update_reg(gpio_base + port->outen, offset, false);
owl_gpio_update_reg(gpio_base + port->inen, offset, true);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
}
static int owl_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
const struct owl_gpio_port *port;
void __iomem *gpio_base;
unsigned long flags;
port = owl_gpio_get_port(pctrl, &offset);
if (WARN_ON(port == NULL))
return -ENODEV;
gpio_base = pctrl->base + port->offset;
raw_spin_lock_irqsave(&pctrl->lock, flags);
owl_gpio_update_reg(gpio_base + port->inen, offset, false);
owl_gpio_update_reg(gpio_base + port->outen, offset, true);
owl_gpio_update_reg(gpio_base + port->dat, offset, value);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
}
static int owl_gpio_init(struct owl_pinctrl *pctrl)
{
struct gpio_chip *chip;
int ret;
chip = &pctrl->chip;
chip->base = -1;
chip->ngpio = pctrl->soc->ngpios;
chip->label = dev_name(pctrl->dev);
chip->parent = pctrl->dev;
chip->owner = THIS_MODULE;
chip->of_node = pctrl->dev->of_node;
ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "failed to register gpiochip\n");
return ret;
}
return 0;
}
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->chip.direction_input = owl_gpio_direction_input;
pctrl->chip.direction_output = owl_gpio_direction_output;
pctrl->chip.get = owl_gpio_get;
pctrl->chip.set = owl_gpio_set;
pctrl->chip.request = owl_gpio_request;
pctrl->chip.free = owl_gpio_free;
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);
}
ret = owl_gpio_init(pctrl);
if (ret)
return ret;
platform_set_drvdata(pdev, pctrl);
return 0;
}
// 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_gpio_port - Actions GPIO port info
* @offset: offset of the GPIO port.
* @pins: number of pins belongs to the GPIO port.
* @outen: offset of the output enable register.
* @inen: offset of the input enable register.
* @dat: offset of the data register.
*/
struct owl_gpio_port {
unsigned int offset;
unsigned int pins;
unsigned int outen;
unsigned int inen;
unsigned int dat;
};
/**
* 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.
* @port: array describing all GPIO ports of this SoC.
* @nports: number of GPIO ports in this SoC.
*/
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;
const struct owl_gpio_port *ports;
unsigned int nports;
};
int owl_pinctrl_probe(struct platform_device *pdev,
struct owl_pinctrl_soc_data *soc_data);
#endif /* __PINCTRL_OWL_H__ */
此差异已折叠。
......@@ -20,6 +20,7 @@ config PINCTRL_BCM2835
bool
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GPIOLIB_IRQCHIP
config PINCTRL_IPROC_GPIO
......
......@@ -36,11 +36,13 @@
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <dt-bindings/pinctrl/bcm2835.h>
#define MODULE_NAME "pinctrl-bcm2835"
#define BCM2835_NUM_GPIOS 54
......@@ -72,13 +74,9 @@
enum bcm2835_pinconf_param {
/* argument: bcm2835_pinconf_pull */
BCM2835_PINCONF_PARAM_PULL,
BCM2835_PINCONF_PARAM_PULL = (PIN_CONFIG_END + 1),
};
#define BCM2835_PINCONF_PACK(_param_, _arg_) ((_param_) << 16 | (_arg_))
#define BCM2835_PINCONF_UNPACK_PARAM(_conf_) ((_conf_) >> 16)
#define BCM2835_PINCONF_UNPACK_ARG(_conf_) ((_conf_) & 0xffff)
struct bcm2835_pinctrl {
struct device *dev;
void __iomem *base;
......@@ -213,14 +211,6 @@ static const char * const bcm2835_gpio_groups[] = {
};
enum bcm2835_fsel {
BCM2835_FSEL_GPIO_IN = 0,
BCM2835_FSEL_GPIO_OUT = 1,
BCM2835_FSEL_ALT0 = 4,
BCM2835_FSEL_ALT1 = 5,
BCM2835_FSEL_ALT2 = 6,
BCM2835_FSEL_ALT3 = 7,
BCM2835_FSEL_ALT4 = 3,
BCM2835_FSEL_ALT5 = 2,
BCM2835_FSEL_COUNT = 8,
BCM2835_FSEL_MASK = 0x7,
};
......@@ -714,7 +704,7 @@ static int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc,
configs = kzalloc(sizeof(*configs), GFP_KERNEL);
if (!configs)
return -ENOMEM;
configs[0] = BCM2835_PINCONF_PACK(BCM2835_PINCONF_PARAM_PULL, pull);
configs[0] = pinconf_to_config_packed(BCM2835_PINCONF_PARAM_PULL, pull);
map->type = PIN_MAP_TYPE_CONFIGS_PIN;
map->data.configs.group_or_pin = bcm2835_gpio_pins[pin].name;
......@@ -727,7 +717,7 @@ static int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc,
static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map, unsigned *num_maps)
struct pinctrl_map **map, unsigned int *num_maps)
{
struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
struct property *pins, *funcs, *pulls;
......@@ -736,6 +726,12 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
int i, err;
u32 pin, func, pull;
/* Check for generic binding in this node */
err = pinconf_generic_dt_node_to_map_all(pctldev, np, map, num_maps);
if (err || *num_maps)
return err;
/* Generic binding did not find anything continue with legacy parse */
pins = of_find_property(np, "brcm,pins", NULL);
if (!pins) {
dev_err(pc->dev, "%pOF: missing brcm,pins property\n", np);
......@@ -917,37 +913,67 @@ static int bcm2835_pinconf_get(struct pinctrl_dev *pctldev,
return -ENOTSUPP;
}
static void bcm2835_pull_config_set(struct bcm2835_pinctrl *pc,
unsigned int pin, unsigned int arg)
{
u32 off, bit;
off = GPIO_REG_OFFSET(pin);
bit = GPIO_REG_SHIFT(pin);
bcm2835_gpio_wr(pc, GPPUD, arg & 3);
/*
* BCM2835 datasheet say to wait 150 cycles, but not of what.
* But the VideoCore firmware delay for this operation
* based nearly on the same amount of VPU cycles and this clock
* runs at 250 MHz.
*/
udelay(1);
bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
udelay(1);
bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
}
static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *configs,
unsigned num_configs)
unsigned int pin, unsigned long *configs,
unsigned int num_configs)
{
struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
enum bcm2835_pinconf_param param;
u16 arg;
u32 off, bit;
u32 param, arg;
int i;
for (i = 0; i < num_configs; i++) {
param = BCM2835_PINCONF_UNPACK_PARAM(configs[i]);
arg = BCM2835_PINCONF_UNPACK_ARG(configs[i]);
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
if (param != BCM2835_PINCONF_PARAM_PULL)
return -EINVAL;
switch (param) {
/* Set legacy brcm,pull */
case BCM2835_PINCONF_PARAM_PULL:
bcm2835_pull_config_set(pc, pin, arg);
break;
off = GPIO_REG_OFFSET(pin);
bit = GPIO_REG_SHIFT(pin);
/* Set pull generic bindings */
case PIN_CONFIG_BIAS_DISABLE:
bcm2835_pull_config_set(pc, pin, BCM2835_PUD_OFF);
break;
bcm2835_gpio_wr(pc, GPPUD, arg & 3);
/*
* BCM2835 datasheet say to wait 150 cycles, but not of what.
* But the VideoCore firmware delay for this operation
* based nearly on the same amount of VPU cycles and this clock
* runs at 250 MHz.
*/
udelay(1);
bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
udelay(1);
bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
case PIN_CONFIG_BIAS_PULL_DOWN:
bcm2835_pull_config_set(pc, pin, BCM2835_PUD_DOWN);
break;
case PIN_CONFIG_BIAS_PULL_UP:
bcm2835_pull_config_set(pc, pin, BCM2835_PUD_UP);
break;
/* Set output-high or output-low */
case PIN_CONFIG_OUTPUT:
bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin);
break;
default:
return -EINVAL;
} /* switch param type */
} /* for each config */
return 0;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Berlin BG2 pinctrl driver.
*
* Copyright (C) 2014 Marvell Technology Group Ltd.
*
* Antoine Ténart <antoine.tenart@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/init.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Berlin BG2CD pinctrl driver.
*
* Copyright (C) 2014 Marvell Technology Group Ltd.
*
* Antoine Ténart <antoine.tenart@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/init.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Berlin BG2Q pinctrl driver
*
* Copyright (C) 2014 Marvell Technology Group Ltd.
*
* Antoine Ténart <antoine.tenart@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/init.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell berlin4ct pinctrl driver
*
* Copyright (C) 2015 Marvell Technology Group Ltd.
*
* Author: Jisheng Zhang <jszhang@marvell.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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/init.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Berlin SoC pinctrl core driver
*
* Copyright (C) 2014 Marvell Technology Group Ltd.
*
* Antoine Ténart <antoine.tenart@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/io.h>
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Marvell Berlin SoC pinctrl driver.
*
* Copyright (C) 2014 Marvell Technology Group Ltd.
*
* Antoine Ténart <antoine.tenart@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __PINCTRL_BERLIN_H
......
/*
* Core driver for the imx pin controller
*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Core driver for the imx pin controller
//
// Copyright (C) 2012 Freescale Semiconductor, Inc.
// Copyright (C) 2012 Linaro Ltd.
//
// Author: Dong Aisheng <dong.aisheng@linaro.org>
#include <linux/err.h>
#include <linux/init.h>
......@@ -371,7 +366,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
unsigned long config;
if (!pin_reg || pin_reg->conf_reg == -1) {
seq_printf(s, "N/A");
seq_puts(s, "N/A");
return;
}
......@@ -390,7 +385,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
if (group > pctldev->num_groups)
return;
seq_printf(s, "\n");
seq_puts(s, "\n");
grp = pinctrl_generic_get_group(pctldev, group);
if (!grp)
return;
......@@ -414,11 +409,18 @@ static const struct pinconf_ops imx_pinconf_ops = {
};
/*
* Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
* 1 u32 CONFIG, so 24 types in total for each pin.
* Each pin represented in fsl,pins consists of a number of u32 PIN_FUNC_ID
* and 1 u32 CONFIG, the total size is PIN_FUNC_ID + CONFIG for each pin.
* For generic_pinconf case, there's no extra u32 CONFIG.
*
* PIN_FUNC_ID format:
* Default:
* <mux_reg conf_reg input_reg mux_mode input_val>
* SHARE_MUX_CONF_REG:
* <mux_conf_reg input_reg mux_mode input_val>
*/
#define FSL_PIN_SIZE 24
#define SHARE_FSL_PIN_SIZE 20
#define FSL_PIN_SHARE_SIZE 20
static int imx_pinctrl_parse_groups(struct device_node *np,
struct group_desc *grp,
......@@ -434,7 +436,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
dev_dbg(ipctl->dev, "group(%d): %s\n", index, np->name);
if (info->flags & SHARE_MUX_CONF_REG)
pin_size = SHARE_FSL_PIN_SIZE;
pin_size = FSL_PIN_SHARE_SIZE;
else
pin_size = FSL_PIN_SIZE;
......@@ -617,7 +619,7 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
nfuncs = 1;
} else {
nfuncs = of_get_child_count(np);
if (nfuncs <= 0) {
if (nfuncs == 0) {
dev_err(&pdev->dev, "no functions defined\n");
return -EINVAL;
}
......
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* IMX pinmux core definitions
*
......@@ -5,11 +6,6 @@
* Copyright (C) 2012 Linaro Ltd.
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __DRIVERS_PINCTRL_IMX_H
......
/*
* Core driver for the imx pin controller in imx1/21/27
*
* Copyright (C) 2013 Pengutronix
* Author: Markus Pargmann <mpa@pengutronix.de>
*
* Based on pinctrl-imx.c:
* Author: Dong Aisheng <dong.aisheng@linaro.org>
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Core driver for the imx pin controller in imx1/21/27
//
// Copyright (C) 2013 Pengutronix
// Author: Markus Pargmann <mpa@pengutronix.de>
//
// Based on pinctrl-imx.c:
// Author: Dong Aisheng <dong.aisheng@linaro.org>
// Copyright (C) 2012 Freescale Semiconductor, Inc.
// Copyright (C) 2012 Linaro Ltd.
#include <linux/bitops.h>
#include <linux/err.h>
......
/*
* i.MX1 pinctrl driver based on imx pinmux core
*
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// i.MX1 pinctrl driver based on imx pinmux core
//
// Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
#include <linux/init.h>
#include <linux/of.h>
......
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* IMX pinmux core definitions
*
......@@ -5,11 +6,6 @@
* Copyright (C) 2012 Linaro Ltd.
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __DRIVERS_PINCTRL_IMX1_H
......
/*
* i.MX21 pinctrl driver based on imx pinmux core
*
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// i.MX21 pinctrl driver based on imx pinmux core
//
// Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
#include <linux/init.h>
#include <linux/of.h>
......
/*
* Freescale i.MX23 pinctrl driver
*
* Author: Shawn Guo <shawn.guo@linaro.org>
* Copyright 2012 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Freescale i.MX23 pinctrl driver
//
// Author: Shawn Guo <shawn.guo@linaro.org>
// Copyright 2012 Freescale Semiconductor, Inc.
#include <linux/init.h>
#include <linux/of_device.h>
......
/*
* imx25 pinctrl driver.
*
* Copyright 2013 Eukréa Electromatique <denis@eukrea.com>
*
* This driver was mostly copied from the imx51 pinctrl driver which has:
*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro, Inc.
*
* Author: Denis Carikli <denis@eukrea.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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// imx25 pinctrl driver.
//
// Copyright 2013 Eukréa Electromatique <denis@eukrea.com>
//
// This driver was mostly copied from the imx51 pinctrl driver which has:
//
// Copyright (C) 2012 Freescale Semiconductor, Inc.
// Copyright (C) 2012 Linaro, Inc.
//
// Author: Denis Carikli <denis@eukrea.com>
#include <linux/err.h>
#include <linux/init.h>
......
/*
* imx27 pinctrl driver based on imx pinmux core
*
* Copyright (C) 2013 Pengutronix
*
* Author: Markus Pargmann <mpa@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// imx27 pinctrl driver based on imx pinmux core
//
// Copyright (C) 2013 Pengutronix
//
// Author: Markus Pargmann <mpa@pengutronix.de>
#include <linux/err.h>
#include <linux/init.h>
......
/*
* Freescale i.MX28 pinctrl driver
*
* Author: Shawn Guo <shawn.guo@linaro.org>
* Copyright 2012 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Freescale i.MX28 pinctrl driver
//
// Author: Shawn Guo <shawn.guo@linaro.org>
// Copyright 2012 Freescale Semiconductor, Inc.
#include <linux/init.h>
#include <linux/of_device.h>
......
/*
* imx35 pinctrl driver.
*
* This driver was mostly copied from the imx51 pinctrl driver which has:
*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro, Inc.
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// imx35 pinctrl driver.
//
// This driver was mostly copied from the imx51 pinctrl driver which has:
//
// Copyright (C) 2012 Freescale Semiconductor, Inc.
// Copyright (C) 2012 Linaro, Inc.
//
// Author: Dong Aisheng <dong.aisheng@linaro.org>
#include <linux/err.h>
#include <linux/init.h>
......
/*
* imx50 pinctrl driver based on imx pinmux core
*
* Copyright (C) 2013 Greg Ungerer <gerg@uclinux.org>
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// imx50 pinctrl driver based on imx pinmux core
//
// Copyright (C) 2013 Greg Ungerer <gerg@uclinux.org>
// Copyright (C) 2012 Freescale Semiconductor, Inc.
// Copyright (C) 2012 Linaro, Inc.
#include <linux/err.h>
#include <linux/init.h>
......
/*
* imx51 pinctrl driver based on imx pinmux core
*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro, Inc.
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// imx51 pinctrl driver based on imx pinmux core
//
// Copyright (C) 2012 Freescale Semiconductor, Inc.
// Copyright (C) 2012 Linaro, Inc.
//
// Author: Dong Aisheng <dong.aisheng@linaro.org>
#include <linux/err.h>
#include <linux/init.h>
......
/*
* imx53 pinctrl driver based on imx pinmux core
*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro, Inc.
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// imx53 pinctrl driver based on imx pinmux core
//
// Copyright (C) 2012 Freescale Semiconductor, Inc.
// Copyright (C) 2012 Linaro, Inc.
//
// Author: Dong Aisheng <dong.aisheng@linaro.org>
#include <linux/err.h>
#include <linux/init.h>
......
/*
* Freescale imx6dl pinctrl driver
*
* Author: Shawn Guo <shawn.guo@linaro.org>
* Copyright (C) 2013 Freescale Semiconductor, Inc.
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale imx6dl pinctrl driver
//
// Author: Shawn Guo <shawn.guo@linaro.org>
// Copyright (C) 2013 Freescale Semiconductor, Inc.
#include <linux/err.h>
#include <linux/init.h>
......
/*
* imx6q pinctrl driver based on imx pinmux core
*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro, Inc.
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// imx6q pinctrl driver based on imx pinmux core
//
// Copyright (C) 2012 Freescale Semiconductor, Inc.
// Copyright (C) 2012 Linaro, Inc.
//
// Author: Dong Aisheng <dong.aisheng@linaro.org>
#include <linux/err.h>
#include <linux/init.h>
......
/*
* Freescale imx6sl pinctrl driver
*
* Author: Shawn Guo <shawn.guo@linaro.org>
* Copyright (C) 2013 Freescale Semiconductor, Inc.
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale imx6sl pinctrl driver
//
// Author: Shawn Guo <shawn.guo@linaro.org>
// Copyright (C) 2013 Freescale Semiconductor, Inc.
#include <linux/err.h>
#include <linux/init.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017-2018 NXP.
*
*/
//
// Copyright (C) 2016 Freescale Semiconductor, Inc.
// Copyright 2017-2018 NXP.
#include <linux/err.h>
#include <linux/init.h>
......
/*
* Freescale imx6sx pinctrl driver
*
* Author: Anson Huang <Anson.Huang@freescale.com>
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale imx6sx pinctrl driver
//
// Author: Anson Huang <Anson.Huang@freescale.com>
// Copyright (C) 2014 Freescale Semiconductor, Inc.
#include <linux/err.h>
#include <linux/init.h>
......
/*
* Freescale imx6ul pinctrl driver
*
* Author: Anson Huang <Anson.Huang@freescale.com>
* Copyright (C) 2015 Freescale Semiconductor, Inc.
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale imx6ul pinctrl driver
//
// Author: Anson Huang <Anson.Huang@freescale.com>
// Copyright (C) 2015 Freescale Semiconductor, Inc.
#include <linux/err.h>
#include <linux/init.h>
......
/*
* Freescale imx7d pinctrl driver
*
* Author: Anson Huang <Anson.Huang@freescale.com>
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale imx7d pinctrl driver
//
// Author: Anson Huang <Anson.Huang@freescale.com>
// Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
#include <linux/err.h>
#include <linux/init.h>
......
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright (C) 2017 NXP
*
* Author: Dong Aisheng <aisheng.dong@nxp.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.
*
*/
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (C) 2016 Freescale Semiconductor, Inc.
// Copyright (C) 2017 NXP
//
// Author: Dong Aisheng <aisheng.dong@nxp.com>
#include <linux/err.h>
#include <linux/init.h>
......
/*
* Copyright 2012 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright 2012 Freescale Semiconductor, Inc.
#include <linux/err.h>
#include <linux/init.h>
......
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2012 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __PINCTRL_MXS_H
......
/*
* VF610 pinctrl driver based on imx pinmux and pinconf core
*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// VF610 pinctrl driver based on imx pinmux and pinconf core
//
// Copyright 2013 Freescale Semiconductor, Inc.
#include <linux/err.h>
#include <linux/init.h>
......
......@@ -1527,6 +1527,7 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_Strago"),
DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
},
},
{
......@@ -1534,6 +1535,7 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"),
DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
},
},
{
......@@ -1541,6 +1543,7 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"),
DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
},
},
{
......@@ -1548,6 +1551,7 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
},
},
{}
......
menu "MediaTek pinctrl drivers"
depends on ARCH_MEDIATEK || COMPILE_TEST
config EINT_MTK
bool "MediaTek External Interrupt Support"
depends on PINCTRL_MTK || PINCTRL_MT7622 || COMPILE_TEST
select IRQ_DOMAIN
config PINCTRL_MTK
bool
depends on OF
select PINMUX
select GENERIC_PINCONF
select GPIOLIB
select EINT_MTK
select OF_GPIO
# For ARMv7 SoCs
......
# SPDX-License-Identifier: GPL-2.0
# Core
obj-$(CONFIG_EINT_MTK) += mtk-eint.o
obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o
# SoC Drivers
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2014-2018 MediaTek Inc.
/*
* Library for MediaTek External Interrupt Support
*
* Author: Maoguang Meng <maoguang.meng@mediatek.com>
* Sean Wang <sean.wang@mediatek.com>
*
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include "mtk-eint.h"
#define MTK_EINT_EDGE_SENSITIVE 0
#define MTK_EINT_LEVEL_SENSITIVE 1
#define MTK_EINT_DBNC_SET_DBNC_BITS 4
#define MTK_EINT_DBNC_RST_BIT (0x1 << 1)
#define MTK_EINT_DBNC_SET_EN (0x1 << 0)
static const struct mtk_eint_regs mtk_generic_eint_regs = {
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
.mask_set = 0x0c0,
.mask_clr = 0x100,
.sens = 0x140,
.sens_set = 0x180,
.sens_clr = 0x1c0,
.soft = 0x200,
.soft_set = 0x240,
.soft_clr = 0x280,
.pol = 0x300,
.pol_set = 0x340,
.pol_clr = 0x380,
.dom_en = 0x400,
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
};
static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
unsigned int eint_num,
unsigned int offset)
{
unsigned int eint_base = 0;
void __iomem *reg;
if (eint_num >= eint->hw->ap_num)
eint_base = eint->hw->ap_num;
reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
return reg;
}
static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint,
unsigned int eint_num)
{
unsigned int sens;
unsigned int bit = BIT(eint_num % 32);
void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
eint->regs->sens);
if (readl(reg) & bit)
sens = MTK_EINT_LEVEL_SENSITIVE;
else
sens = MTK_EINT_EDGE_SENSITIVE;
if (eint_num < eint->hw->db_cnt && sens != MTK_EINT_EDGE_SENSITIVE)
return 1;
else
return 0;
}
static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
{
int start_level, curr_level;
unsigned int reg_offset;
u32 mask = BIT(hwirq & 0x1f);
u32 port = (hwirq >> 5) & eint->hw->port_mask;
void __iomem *reg = eint->base + (port << 2);
curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
do {
start_level = curr_level;
if (start_level)
reg_offset = eint->regs->pol_clr;
else
reg_offset = eint->regs->pol_set;
writel(mask, reg + reg_offset);
curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
hwirq);
} while (start_level != curr_level);
return start_level;
}
static void mtk_eint_mask(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
u32 mask = BIT(d->hwirq & 0x1f);
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_set);
writel(mask, reg);
}
static void mtk_eint_unmask(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
u32 mask = BIT(d->hwirq & 0x1f);
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_clr);
writel(mask, reg);
if (eint->dual_edge[d->hwirq])
mtk_eint_flip_edge(eint, d->hwirq);
}
static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
unsigned int eint_num)
{
unsigned int bit = BIT(eint_num % 32);
void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
eint->regs->mask);
return !!(readl(reg) & bit);
}
static void mtk_eint_ack(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
u32 mask = BIT(d->hwirq & 0x1f);
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->ack);
writel(mask, reg);
}
static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
u32 mask = BIT(d->hwirq & 0x1f);
void __iomem *reg;
if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
((type & IRQ_TYPE_LEVEL_MASK) == IRQ_TYPE_LEVEL_MASK)) {
dev_err(eint->dev,
"Can't configure IRQ%d (EINT%lu) for type 0x%X\n",
d->irq, d->hwirq, type);
return -EINVAL;
}
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
eint->dual_edge[d->hwirq] = 1;
else
eint->dual_edge[d->hwirq] = 0;
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_clr);
writel(mask, reg);
} else {
reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_set);
writel(mask, reg);
}
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_clr);
writel(mask, reg);
} else {
reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_set);
writel(mask, reg);
}
if (eint->dual_edge[d->hwirq])
mtk_eint_flip_edge(eint, d->hwirq);
return 0;
}
static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
int shift = d->hwirq & 0x1f;
int reg = d->hwirq >> 5;
if (on)
eint->wake_mask[reg] |= BIT(shift);
else
eint->wake_mask[reg] &= ~BIT(shift);
return 0;
}
static void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
void __iomem *base, u32 *buf)
{
int port;
void __iomem *reg;
for (port = 0; port < eint->hw->ports; port++) {
reg = base + (port << 2);
writel_relaxed(~buf[port], reg + eint->regs->mask_set);
writel_relaxed(buf[port], reg + eint->regs->mask_clr);
}
}
static void mtk_eint_chip_read_mask(const struct mtk_eint *eint,
void __iomem *base, u32 *buf)
{
int port;
void __iomem *reg;
for (port = 0; port < eint->hw->ports; port++) {
reg = base + eint->regs->mask + (port << 2);
buf[port] = ~readl_relaxed(reg);
/* Mask is 0 when irq is enabled, and 1 when disabled. */
}
}
static int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
struct gpio_chip *gpio_c;
unsigned int gpio_n;
int err;
err = eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq,
&gpio_n, &gpio_c);
if (err < 0) {
dev_err(eint->dev, "Can not find pin\n");
return err;
}
err = gpiochip_lock_as_irq(gpio_c, gpio_n);
if (err < 0) {
dev_err(eint->dev, "unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
return err;
}
err = eint->gpio_xlate->set_gpio_as_eint(eint->pctl, d->hwirq);
if (err < 0) {
dev_err(eint->dev, "Can not eint mode\n");
return err;
}
return 0;
}
static void mtk_eint_irq_release_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
struct gpio_chip *gpio_c;
unsigned int gpio_n;
eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq, &gpio_n,
&gpio_c);
gpiochip_unlock_as_irq(gpio_c, gpio_n);
}
static struct irq_chip mtk_eint_irq_chip = {
.name = "mt-eint",
.irq_disable = mtk_eint_mask,
.irq_mask = mtk_eint_mask,
.irq_unmask = mtk_eint_unmask,
.irq_ack = mtk_eint_ack,
.irq_set_type = mtk_eint_set_type,
.irq_set_wake = mtk_eint_irq_set_wake,
.irq_request_resources = mtk_eint_irq_request_resources,
.irq_release_resources = mtk_eint_irq_release_resources,
};
static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
{
void __iomem *reg = eint->base + eint->regs->dom_en;
unsigned int i;
for (i = 0; i < eint->hw->ap_num; i += 32) {
writel(0xffffffff, reg);
reg += 4;
}
return 0;
}
static inline void
mtk_eint_debounce_process(struct mtk_eint *eint, int index)
{
unsigned int rst, ctrl_offset;
unsigned int bit, dbnc;
ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl;
dbnc = readl(eint->base + ctrl_offset);
bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8);
if ((bit & dbnc) > 0) {
ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_set;
rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8);
writel(rst, eint->base + ctrl_offset);
}
}
static void mtk_eint_irq_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct mtk_eint *eint = irq_desc_get_handler_data(desc);
unsigned int status, eint_num;
int offset, index, virq;
void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
int dual_edge, start_level, curr_level;
chained_irq_enter(chip, desc);
for (eint_num = 0; eint_num < eint->hw->ap_num; eint_num += 32,
reg += 4) {
status = readl(reg);
while (status) {
offset = __ffs(status);
index = eint_num + offset;
virq = irq_find_mapping(eint->domain, index);
status &= ~BIT(offset);
dual_edge = eint->dual_edge[index];
if (dual_edge) {
/*
* Clear soft-irq in case we raised it last
* time.
*/
writel(BIT(offset), reg - eint->regs->stat +
eint->regs->soft_clr);
start_level =
eint->gpio_xlate->get_gpio_state(eint->pctl,
index);
}
generic_handle_irq(virq);
if (dual_edge) {
curr_level = mtk_eint_flip_edge(eint, index);
/*
* If level changed, we might lost one edge
* interrupt, raised it through soft-irq.
*/
if (start_level != curr_level)
writel(BIT(offset), reg -
eint->regs->stat +
eint->regs->soft_set);
}
if (index < eint->hw->db_cnt)
mtk_eint_debounce_process(eint, index);
}
}
chained_irq_exit(chip, desc);
}
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask);
mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
return 0;
}
int mtk_eint_do_resume(struct mtk_eint *eint)
{
mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
return 0;
}
int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
unsigned int debounce)
{
int virq, eint_offset;
unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
dbnc;
static const unsigned int debounce_time[] = {500, 1000, 16000, 32000,
64000, 128000, 256000};
struct irq_data *d;
virq = irq_find_mapping(eint->domain, eint_num);
eint_offset = (eint_num % 4) * 8;
d = irq_get_irq_data(virq);
set_offset = (eint_num / 4) * 4 + eint->regs->dbnc_set;
clr_offset = (eint_num / 4) * 4 + eint->regs->dbnc_clr;
if (!mtk_eint_can_en_debounce(eint, eint_num))
return -EINVAL;
dbnc = ARRAY_SIZE(debounce_time);
for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
if (debounce <= debounce_time[i]) {
dbnc = i;
break;
}
}
if (!mtk_eint_get_mask(eint, eint_num)) {
mtk_eint_mask(d);
unmask = 1;
} else {
unmask = 0;
}
clr_bit = 0xff << eint_offset;
writel(clr_bit, eint->base + clr_offset);
bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) <<
eint_offset;
rst = MTK_EINT_DBNC_RST_BIT << eint_offset;
writel(rst | bit, eint->base + set_offset);
/*
* Delay a while (more than 2T) to wait for hw debounce counter reset
* work correctly.
*/
udelay(1);
if (unmask == 1)
mtk_eint_unmask(d);
return 0;
}
int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
int irq;
irq = irq_find_mapping(eint->domain, eint_n);
if (!irq)
return -EINVAL;
return irq;
}
int mtk_eint_do_init(struct mtk_eint *eint)
{
int i;
/* If clients don't assign a specific regs, let's use generic one */
if (!eint->regs)
eint->regs = &mtk_generic_eint_regs;
eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
sizeof(*eint->wake_mask), GFP_KERNEL);
if (!eint->wake_mask)
return -ENOMEM;
eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
sizeof(*eint->cur_mask), GFP_KERNEL);
if (!eint->cur_mask)
return -ENOMEM;
eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
sizeof(int), GFP_KERNEL);
if (!eint->dual_edge)
return -ENOMEM;
eint->domain = irq_domain_add_linear(eint->dev->of_node,
eint->hw->ap_num,
&irq_domain_simple_ops, NULL);
if (!eint->domain)
return -ENOMEM;
mtk_eint_hw_init(eint);
for (i = 0; i < eint->hw->ap_num; i++) {
int virq = irq_create_mapping(eint->domain, i);
irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
handle_level_irq);
irq_set_chip_data(virq, eint);
}
irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
eint);
return 0;
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2014-2018 MediaTek Inc.
*
* Author: Maoguang Meng <maoguang.meng@mediatek.com>
* Sean Wang <sean.wang@mediatek.com>
*
*/
#ifndef __MTK_EINT_H
#define __MTK_EINT_H
#include <linux/irqdomain.h>
struct mtk_eint_regs {
unsigned int stat;
unsigned int ack;
unsigned int mask;
unsigned int mask_set;
unsigned int mask_clr;
unsigned int sens;
unsigned int sens_set;
unsigned int sens_clr;
unsigned int soft;
unsigned int soft_set;
unsigned int soft_clr;
unsigned int pol;
unsigned int pol_set;
unsigned int pol_clr;
unsigned int dom_en;
unsigned int dbnc_ctrl;
unsigned int dbnc_set;
unsigned int dbnc_clr;
};
struct mtk_eint_hw {
u8 port_mask;
u8 ports;
unsigned int ap_num;
unsigned int db_cnt;
};
struct mtk_eint;
struct mtk_eint_xt {
int (*get_gpio_n)(void *data, unsigned long eint_n,
unsigned int *gpio_n,
struct gpio_chip **gpio_chip);
int (*get_gpio_state)(void *data, unsigned long eint_n);
int (*set_gpio_as_eint)(void *data, unsigned long eint_n);
};
struct mtk_eint {
struct device *dev;
void __iomem *base;
struct irq_domain *domain;
int irq;
int *dual_edge;
u32 *wake_mask;
u32 *cur_mask;
/* Used to fit into various EINT device */
const struct mtk_eint_hw *hw;
const struct mtk_eint_regs *regs;
/* Used to fit into various pinctrl device */
void *pctl;
const struct mtk_eint_xt *gpio_xlate;
};
#if IS_ENABLED(CONFIG_EINT_MTK)
int mtk_eint_do_init(struct mtk_eint *eint);
int mtk_eint_do_suspend(struct mtk_eint *eint);
int mtk_eint_do_resume(struct mtk_eint *eint);
int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
unsigned int debounce);
int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n);
#else
static inline int mtk_eint_do_init(struct mtk_eint *eint)
{
return -EOPNOTSUPP;
}
static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
{
return -EOPNOTSUPP;
}
static inline int mtk_eint_do_resume(struct mtk_eint *eint)
{
return -EOPNOTSUPP;
}
int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
unsigned int debounce)
{
return -EOPNOTSUPP;
}
int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
return -EOPNOTSUPP;
}
#endif
#endif /* __MTK_EINT_H */
......@@ -531,31 +531,12 @@ static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
.port_shf = 4,
.port_mask = 0x1f,
.port_align = 4,
.eint_offsets = {
.name = "mt2701_eint",
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
.mask_set = 0x0c0,
.mask_clr = 0x100,
.sens = 0x140,
.sens_set = 0x180,
.sens_clr = 0x1c0,
.soft = 0x200,
.soft_set = 0x240,
.soft_clr = 0x280,
.pol = 0x300,
.pol_set = 0x340,
.pol_clr = 0x380,
.dom_en = 0x400,
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
.eint_hw = {
.port_mask = 6,
.ports = 6,
.ap_num = 169,
.db_cnt = 16,
},
.ap_num = 169,
.db_cnt = 16,
};
static int mt2701_pinctrl_probe(struct platform_device *pdev)
......
......@@ -576,31 +576,12 @@ static const struct mtk_pinctrl_devdata mt2712_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
.eint_offsets = {
.name = "mt2712_eint",
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
.mask_set = 0x0c0,
.mask_clr = 0x100,
.sens = 0x140,
.sens_set = 0x180,
.sens_clr = 0x1c0,
.soft = 0x200,
.soft_set = 0x240,
.soft_clr = 0x280,
.pol = 0x300,
.pol_set = 0x340,
.pol_clr = 0x380,
.dom_en = 0x400,
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
.eint_hw = {
.port_mask = 0xf,
.ports = 8,
.ap_num = 229,
.db_cnt = 40,
},
.ap_num = 229,
.db_cnt = 40,
};
static int mt2712_pinctrl_probe(struct platform_device *pdev)
......
......@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
......@@ -30,6 +31,7 @@
#include "../core.h"
#include "../pinconf.h"
#include "../pinmux.h"
#include "mtk-eint.h"
#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME
#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
......@@ -123,6 +125,8 @@ struct mtk_pin_soc {
unsigned int ngrps;
const struct function_desc *funcs;
unsigned int nfuncs;
const struct mtk_eint_regs *eint_regs;
const struct mtk_eint_hw *eint_hw;
};
struct mtk_pinctrl {
......@@ -131,6 +135,7 @@ struct mtk_pinctrl {
struct device *dev;
struct gpio_chip chip;
const struct mtk_pin_soc *soc;
struct mtk_eint *eint;
};
static const struct mtk_pin_field_calc mt7622_pin_mode_range[] = {
......@@ -913,6 +918,13 @@ static const struct pin_config_item mtk_conf_items[] = {
};
#endif
static const struct mtk_eint_hw mt7622_eint_hw = {
.port_mask = 7,
.ports = 7,
.ap_num = ARRAY_SIZE(mt7622_pins),
.db_cnt = 20,
};
static const struct mtk_pin_soc mt7622_data = {
.reg_cal = mt7622_reg_cals,
.pins = mt7622_pins,
......@@ -921,6 +933,7 @@ static const struct mtk_pin_soc mt7622_data = {
.ngrps = ARRAY_SIZE(mt7622_groups),
.funcs = mt7622_functions,
.nfuncs = ARRAY_SIZE(mt7622_functions),
.eint_hw = &mt7622_eint_hw,
};
static void mtk_w32(struct mtk_pinctrl *pctl, u32 reg, u32 val)
......@@ -1441,6 +1454,32 @@ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
return pinctrl_gpio_direction_output(chip->base + gpio);
}
static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
{
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
unsigned long eint_n;
eint_n = offset;
return mtk_eint_find_irq(hw->eint, eint_n);
}
static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
unsigned long config)
{
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
unsigned long eint_n;
u32 debounce;
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
return -ENOTSUPP;
debounce = pinconf_to_config_argument(config);
eint_n = offset;
return mtk_eint_set_debounce(hw->eint, eint_n, debounce);
}
static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
{
struct gpio_chip *chip = &hw->chip;
......@@ -1454,6 +1493,8 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
chip->direction_output = mtk_gpio_direction_output;
chip->get = mtk_gpio_get;
chip->set = mtk_gpio_set;
chip->to_irq = mtk_gpio_to_irq,
chip->set_config = mtk_gpio_set_config,
chip->base = -1;
chip->ngpio = hw->soc->npins;
chip->of_node = np;
......@@ -1514,6 +1555,103 @@ static int mtk_build_functions(struct mtk_pinctrl *hw)
return 0;
}
static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
unsigned int *gpio_n,
struct gpio_chip **gpio_chip)
{
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
*gpio_chip = &hw->chip;
*gpio_n = eint_n;
return 0;
}
static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
{
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
struct gpio_chip *gpio_chip;
unsigned int gpio_n;
int err;
err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
if (err)
return err;
return mtk_gpio_get(gpio_chip, gpio_n);
}
static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
{
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
struct gpio_chip *gpio_chip;
unsigned int gpio_n;
int err;
err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
if (err)
return err;
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_MODE,
MTK_GPIO_MODE);
if (err)
return err;
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_DIR, MTK_INPUT);
if (err)
return err;
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_SMT, MTK_ENABLE);
if (err)
return err;
return 0;
}
static const struct mtk_eint_xt mtk_eint_xt = {
.get_gpio_n = mtk_xt_get_gpio_n,
.get_gpio_state = mtk_xt_get_gpio_state,
.set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
};
static int
mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct resource *res;
if (!IS_ENABLED(CONFIG_EINT_MTK))
return 0;
if (!of_property_read_bool(np, "interrupt-controller"))
return -ENODEV;
hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
if (!hw->eint)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint");
if (!res) {
dev_err(&pdev->dev, "Unable to get eint resource\n");
return -ENODEV;
}
hw->eint->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->eint->base))
return PTR_ERR(hw->eint->base);
hw->eint->irq = irq_of_parse_and_map(np, 0);
if (!hw->eint->irq)
return -EINVAL;
hw->eint->dev = &pdev->dev;
hw->eint->hw = hw->soc->eint_hw;
hw->eint->pctl = hw;
hw->eint->gpio_xlate = &mtk_eint_xt;
return mtk_eint_do_init(hw->eint);
}
static const struct of_device_id mtk_pinctrl_of_match[] = {
{ .compatible = "mediatek,mt7622-pinctrl", .data = &mt7622_data},
{ }
......@@ -1577,6 +1715,11 @@ static int mtk_pinctrl_probe(struct platform_device *pdev)
return err;
}
err = mtk_build_eint(hw, pdev);
if (err)
dev_warn(&pdev->dev,
"Failed to add EINT, but pinctrl still can work\n");
platform_set_drvdata(pdev, hw);
return 0;
......
......@@ -300,31 +300,12 @@ static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
.eint_offsets = {
.name = "mt8127_eint",
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
.mask_set = 0x0c0,
.mask_clr = 0x100,
.sens = 0x140,
.sens_set = 0x180,
.sens_clr = 0x1c0,
.soft = 0x200,
.soft_set = 0x240,
.soft_clr = 0x280,
.pol = 0x300,
.pol_set = 0x340,
.pol_clr = 0x380,
.dom_en = 0x400,
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
.eint_hw = {
.port_mask = 7,
.ports = 6,
.ap_num = 143,
.db_cnt = 16,
},
.ap_num = 143,
.db_cnt = 16,
};
static int mt8127_pinctrl_probe(struct platform_device *pdev)
......
......@@ -313,31 +313,12 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
.eint_offsets = {
.name = "mt8135_eint",
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
.mask_set = 0x0c0,
.mask_clr = 0x100,
.sens = 0x140,
.sens_set = 0x180,
.sens_clr = 0x1c0,
.soft = 0x200,
.soft_set = 0x240,
.soft_clr = 0x280,
.pol = 0x300,
.pol_set = 0x340,
.pol_clr = 0x380,
.dom_en = 0x400,
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
.eint_hw = {
.port_mask = 7,
.ports = 6,
.ap_num = 192,
.db_cnt = 16,
},
.ap_num = 192,
.db_cnt = 16,
};
static int mt8135_pinctrl_probe(struct platform_device *pdev)
......
......@@ -340,31 +340,12 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
.eint_offsets = {
.name = "mt8173_eint",
.stat = 0x000,
.ack = 0x040,
.mask = 0x080,
.mask_set = 0x0c0,
.mask_clr = 0x100,
.sens = 0x140,
.sens_set = 0x180,
.sens_clr = 0x1c0,
.soft = 0x200,
.soft_set = 0x240,
.soft_clr = 0x280,
.pol = 0x300,
.pol_set = 0x340,
.pol_clr = 0x380,
.dom_en = 0x400,
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
.eint_hw = {
.port_mask = 7,
.ports = 6,
.ap_num = 224,
.db_cnt = 16,
},
.ap_num = 224,
.db_cnt = 16,
};
static int mt8173_pinctrl_probe(struct platform_device *pdev)
......
......@@ -19,6 +19,8 @@
#include <linux/regmap.h>
#include <linux/pinctrl/pinconf-generic.h>
#include "mtk-eint.h"
#define NO_EINT_SUPPORT 255
#define MT_EDGE_SENSITIVE 0
#define MT_LEVEL_SENSITIVE 1
......@@ -258,9 +260,8 @@ struct mtk_pinctrl_devdata {
unsigned char port_shf;
unsigned char port_mask;
unsigned char port_align;
struct mtk_eint_offsets eint_offsets;
unsigned int ap_num;
unsigned int db_cnt;
struct mtk_eint_hw eint_hw;
struct mtk_eint_regs *eint_regs;
};
struct mtk_pinctrl {
......@@ -274,11 +275,7 @@ struct mtk_pinctrl {
const char **grp_names;
struct pinctrl_dev *pctl_dev;
const struct mtk_pinctrl_devdata *devdata;
void __iomem *eint_reg_base;
struct irq_domain *domain;
int *eint_dual_edges;
u32 *wake_mask;
u32 *cur_mask;
struct mtk_eint *eint;
};
int mtk_pctrl_init(struct platform_device *pdev,
......
......@@ -627,8 +627,8 @@ static const char * const sdio_groups[] = {
};
static const char * const nand_groups[] = {
"nand_ce0", "nand_ce1", "nand_rb0", "nand_ale", "nand_cle",
"nand_wen_clk", "nand_ren_wr", "nand_dqs",
"emmc_nand_d07", "nand_ce0", "nand_ce1", "nand_rb0", "nand_ale",
"nand_cle", "nand_wen_clk", "nand_ren_wr", "nand_dqs",
};
static const char * const uart_a_groups[] = {
......
......@@ -617,8 +617,8 @@ static const char * const sdio_groups[] = {
};
static const char * const nand_groups[] = {
"nand_ce0", "nand_ce1", "nand_rb0", "nand_ale", "nand_cle",
"nand_wen_clk", "nand_ren_wr", "nand_dqs",
"emmc_nand_d07", "nand_ce0", "nand_ce1", "nand_rb0", "nand_ale",
"nand_cle", "nand_wen_clk", "nand_ren_wr", "nand_dqs",
};
static const char * const uart_a_groups[] = {
......
/*
* Pin controller and GPIO driver for Amlogic Meson8.
* Pin controller and GPIO driver for Amlogic Meson8 and Meson8m2.
*
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
*
......@@ -299,6 +299,10 @@ static const unsigned int spi_mosi_1_pins[] = { GPIOZ_12 };
static const unsigned int spi_miso_1_pins[] = { GPIOZ_13 };
static const unsigned int spi_ss2_1_pins[] = { GPIOZ_14 };
static const unsigned int eth_txd3_pins[] = { GPIOZ_0 };
static const unsigned int eth_txd2_pins[] = { GPIOZ_1 };
static const unsigned int eth_rxd3_pins[] = { GPIOZ_2 };
static const unsigned int eth_rxd2_pins[] = { GPIOZ_3 };
static const unsigned int eth_tx_clk_50m_pins[] = { GPIOZ_4 };
static const unsigned int eth_tx_en_pins[] = { GPIOZ_5 };
static const unsigned int eth_txd1_pins[] = { GPIOZ_6 };
......@@ -650,6 +654,12 @@ static struct meson_pmx_group meson8_cbus_groups[] = {
GROUP(eth_mdio, 6, 6),
GROUP(eth_mdc, 6, 5),
/* NOTE: the following four groups are only available on Meson8m2: */
GROUP(eth_rxd2, 6, 3),
GROUP(eth_rxd3, 6, 2),
GROUP(eth_txd2, 6, 1),
GROUP(eth_txd3, 6, 0),
GROUP(i2c_sda_a0, 5, 31),
GROUP(i2c_sck_a0, 5, 30),
......@@ -877,7 +887,8 @@ static const char * const spi_groups[] = {
static const char * const ethernet_groups[] = {
"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"
"eth_rxd1", "eth_rxd0", "eth_mdio", "eth_mdc", "eth_rxd2",
"eth_rxd3", "eth_txd2", "eth_txd3"
};
static const char * const i2c_a_groups[] = {
......@@ -1080,6 +1091,14 @@ static const struct of_device_id meson8_pinctrl_dt_match[] = {
.compatible = "amlogic,meson8-aobus-pinctrl",
.data = &meson8_aobus_pinctrl_data,
},
{
.compatible = "amlogic,meson8m2-cbus-pinctrl",
.data = &meson8_cbus_pinctrl_data,
},
{
.compatible = "amlogic,meson8m2-aobus-pinctrl",
.data = &meson8_aobus_pinctrl_data,
},
{ },
};
......
......@@ -576,8 +576,10 @@ static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
for_each_child_of_node(np_config, np) {
ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map,
&reserved_maps, num_maps);
if (ret < 0)
if (ret < 0) {
of_node_put(np);
break;
}
}
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -5,6 +5,5 @@ obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o
obj-$(CONFIG_PINCTRL_EXYNOS_ARM) += pinctrl-exynos-arm.o
obj-$(CONFIG_PINCTRL_EXYNOS_ARM64) += pinctrl-exynos-arm64.o
obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o
obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o
obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o
......@@ -99,7 +99,7 @@
#define EXYNOS5433_PIN_BANK_EINTW_EXT(pins, reg, id, offs, pctl_idx) \
{ \
.type = &exynos5433_bank_type_alive, \
.type = &exynos5433_bank_type_off, \
.pctl_offset = reg, \
.nr_pins = pins, \
.eint_type = EINT_TYPE_WKUP, \
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册