You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'pinctrl-v4.9-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 the v4.9 cycle.
General improvements:
- nicer debugfs output with one pin/config pair per line.
- continued efforts to strictify module vs bool.
- constification and similar from Coccinelle engineers.
- return error from pinctrl_bind_pins()
- pulling in the ability to selectively disable mapping of unusable
IRQs from the GPIO subsystem.
New drivers:
- new driver for the Aspeed pin controller family: AST2400 (G4) and
AST2500 (G5) are supported. These are used by OpenBMC on the IBM
Witherspoon platform.
- new subdriver for the Allwinner sunxi GR8.
Driver improvements:
- drop default IRQ trigger types assigned during IRQ mapping on AT91
and Nomadik. This error was identified by improvements in the IRQ
core by Marc Zyngier.
- active high/low types on the GPIO IRQs for the ST pin controller.
- IRQ support on GPIOs on the STM32 pin controller.
- Renesas Super-H/ARM sh-pfc: continued massive developments.
- misc MXC improvements.
- SPDIF on the Allwiner A31 SoC
- IR remote and SPI NOR flash, NAND flash, I2C pins on the AMLogic
SoC.
- PWM pins on the Meson.
- do not map unusable IRQs (taken by BIOS) on the Intel Cherryview.
- add GPIO IRQ wakeup support to the Intel driver so we can wake up
from button pushes.
Deprecation:
- delete the obsolete STiH415/6 SoC support"
* tag 'pinctrl-v4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (75 commits)
pinctrl: qcom: fix masking of pinmux functions
pinctrl: intel: Configure GPIO chip IRQ as wakeup interrupts
pinctrl: cherryview: Convert to use devm_gpiochip_add_data()
pinctrl: cherryview: Do not add all southwest and north GPIOs to IRQ domain
gpiolib: Make it possible to exclude GPIOs from IRQ domain
pinctrl: nomadik: don't default-flag IRQs as falling
pinctrl: st: Remove obsolete platforms from pinctrl-st dt doc
pinctrl: st: Remove STiH415/6 SoC pinctrl driver support.
pinctrl: amlogic: gxbb: add i2c pins
pinctrl: amlogic: gxbb: add nand pins
pinctrl: stm32: add IRQ_DOMAIN_HIERARCHY dependency
pinctrl: amlogic: gxbb: add spi nor pins
pinctrl: sh-pfc: r8a7794: Implement voltage switching for SDHI
pinctrl: sh-pfc: r8a7791: Implement voltage switching for SDHI
pinctrl: sh-pfc: Add PORT_GP_24 helper macro
pinctrl: Fix "st,syscfg" definition for STM32 pinctrl
driver: base: pinctrl: return error from pinctrl_bind_pins()
pinctrl: meson-gxbb: add the missing SDIO interrupt pin
pinctrl: aspeed: fix regmap error handling
pinctrl: mediatek: constify gpio_chip structures
...
This commit is contained in:
@@ -23,6 +23,7 @@ Required properties:
|
||||
"allwinner,sun8i-h3-pinctrl"
|
||||
"allwinner,sun8i-h3-r-pinctrl"
|
||||
"allwinner,sun50i-a64-pinctrl"
|
||||
"nextthing,gr8-pinctrl"
|
||||
|
||||
- reg: Should contain the register physical address and length for the
|
||||
pin controller.
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
Aspeed Pin Controllers
|
||||
----------------------
|
||||
|
||||
The Aspeed SoCs vary in functionality inside a generation but have a common mux
|
||||
device register layout.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be any one of the following:
|
||||
"aspeed,ast2400-pinctrl"
|
||||
"aspeed,g4-pinctrl"
|
||||
"aspeed,ast2500-pinctrl"
|
||||
"aspeed,g5-pinctrl"
|
||||
|
||||
The pin controller node should be a child of a syscon node with the required
|
||||
property:
|
||||
- compatible: "syscon", "simple-mfd"
|
||||
|
||||
Refer to the the bindings described in
|
||||
Documentation/devicetree/bindings/mfd/syscon.txt
|
||||
|
||||
Subnode Format
|
||||
--------------
|
||||
|
||||
The required properties of child nodes are (as defined in pinctrl-bindings):
|
||||
- function
|
||||
- groups
|
||||
|
||||
Each function has only one associated pin group. Each group is named by its
|
||||
function. The following values for the function and groups properties are
|
||||
supported:
|
||||
|
||||
aspeed,ast2400-pinctrl, aspeed,g4-pinctrl:
|
||||
|
||||
ACPI BMCINT DDCCLK DDCDAT FLACK FLBUSY FLWP GPID0 GPIE0 GPIE2 GPIE4 GPIE6 I2C10
|
||||
I2C11 I2C12 I2C13 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8 I2C9 LPCPD LPCPME LPCSMI MDIO1
|
||||
MDIO2 NCTS1 NCTS3 NCTS4 NDCD1 NDCD3 NDCD4 NDSR1 NDSR3 NDTR1 NDTR3 NRI1 NRI3
|
||||
NRI4 NRTS1 NRTS3 PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 RGMII1 RMII1 ROM16
|
||||
ROM8 ROMCS1 ROMCS2 ROMCS3 ROMCS4 RXD1 RXD3 RXD4 SD1 SGPMI SIOPBI SIOPBO TIMER3
|
||||
TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD3 TXD4 UART6 VGAHS VGAVS VPI18 VPI24 VPI30
|
||||
VPO12 VPO24
|
||||
|
||||
aspeed,ast2500-pinctrl, aspeed,g5-pinctrl:
|
||||
|
||||
GPID0 GPID2 GPIE0 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8
|
||||
I2C9 MAC1LINK MDIO1 MDIO2 OSCCLK PEWAKE PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7
|
||||
RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 TIMER4 TIMER5 TIMER6 TIMER7 TIMER8
|
||||
|
||||
Examples:
|
||||
|
||||
syscon: scu@1e6e2000 {
|
||||
compatible = "syscon", "simple-mfd";
|
||||
reg = <0x1e6e2000 0x1a8>;
|
||||
|
||||
pinctrl: pinctrl {
|
||||
compatible = "aspeed,g4-pinctrl";
|
||||
|
||||
pinctrl_i2c3_default: i2c3_default {
|
||||
function = "I2C3";
|
||||
groups = "I2C3";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Please refer to pinctrl-bindings.txt in this directory for details of the
|
||||
common pinctrl bindings used by client devices.
|
||||
@@ -30,8 +30,7 @@ Second type has a dedicated interrupt per gpio bank.
|
||||
|
||||
Pin controller node:
|
||||
Required properties:
|
||||
- compatible : should be "st,<SOC>-<pio-block>-pinctrl"
|
||||
like st,stih415-sbc-pinctrl, st,stih415-front-pinctrl and so on.
|
||||
- compatible : should be "st,stih407-<pio-block>-pinctrl"
|
||||
- st,syscfg : Should be a phandle of the syscfg node.
|
||||
- st,retime-pin-mask : Should be mask to specify which pins can be retimed.
|
||||
If the property is not present, it is assumed that all the pins in the
|
||||
@@ -50,7 +49,11 @@ Optional properties:
|
||||
GPIO controller/bank node.
|
||||
Required properties:
|
||||
- gpio-controller : Indicates this device is a GPIO controller
|
||||
- #gpio-cells : Should be one. The first cell is the pin number.
|
||||
- #gpio-cells : Must be two.
|
||||
- First cell: specifies the pin number inside the controller
|
||||
- Second cell: specifies whether the pin is logically inverted.
|
||||
- 0 = active high
|
||||
- 1 = active low
|
||||
- st,bank-name : Should be a name string for this bank as specified in
|
||||
datasheet.
|
||||
|
||||
@@ -76,23 +79,23 @@ include/dt-bindings/interrupt-controller/irq.h
|
||||
|
||||
Example:
|
||||
pin-controller-sbc {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "st,stih415-sbc-pinctrl";
|
||||
st,syscfg = <&syscfg_sbc>;
|
||||
reg = <0xfe61f080 0x4>;
|
||||
reg-names = "irqmux";
|
||||
interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "irqmux";
|
||||
ranges = <0 0xfe610000 0x5000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "st,stih407-sbc-pinctrl";
|
||||
st,syscfg = <&syscfg_sbc>;
|
||||
reg = <0x0961f080 0x4>;
|
||||
reg-names = "irqmux";
|
||||
interrupts = <GIC_SPI 188 IRQ_TYPE_NONE>;
|
||||
interrupt-names = "irqmux";
|
||||
ranges = <0 0x09610000 0x6000>;
|
||||
|
||||
PIO0: gpio@fe610000 {
|
||||
pio0: gpio@09610000 {
|
||||
gpio-controller;
|
||||
#gpio-cells = <1>;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
reg = <0 0x100>;
|
||||
st,bank-name = "PIO0";
|
||||
reg = <0x0 0x100>;
|
||||
st,bank-name = "PIO0";
|
||||
};
|
||||
...
|
||||
pin-functions nodes follow...
|
||||
@@ -162,7 +165,7 @@ pin-controller {
|
||||
|
||||
sdhci0:sdhci@fe810000{
|
||||
...
|
||||
interrupt-parent = <&PIO3>;
|
||||
interrupt-parent = <&pio3>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; /* Interrupt line via PIO3-3 */
|
||||
interrupt-names = "card-detect";
|
||||
|
||||
@@ -17,6 +17,9 @@ PMIC's from Qualcomm.
|
||||
"qcom,pm8994-gpio"
|
||||
"qcom,pma8084-gpio"
|
||||
|
||||
And must contain either "qcom,spmi-gpio" or "qcom,ssbi-gpio"
|
||||
if the device is on an spmi bus or an ssbi bus respectively
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
@@ -183,7 +186,7 @@ to specify in a pin configuration subnode:
|
||||
Example:
|
||||
|
||||
pm8921_gpio: gpio@150 {
|
||||
compatible = "qcom,pm8921-gpio";
|
||||
compatible = "qcom,pm8921-gpio", "qcom,ssbi-gpio";
|
||||
reg = <0x150 0x160>;
|
||||
interrupts = <192 1>, <193 1>, <194 1>,
|
||||
<195 1>, <196 1>, <197 1>,
|
||||
|
||||
@@ -19,6 +19,9 @@ of PMIC's from Qualcomm.
|
||||
"qcom,pm8994-mpp",
|
||||
"qcom,pma8084-mpp",
|
||||
|
||||
And must contain either "qcom,spmi-mpp" or "qcom,ssbi-mpp"
|
||||
if the device is on an spmi bus or an ssbi bus respectively.
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
@@ -158,7 +161,7 @@ to specify in a pin configuration subnode:
|
||||
Example:
|
||||
|
||||
mpps@a000 {
|
||||
compatible = "qcom,pm8841-mpp";
|
||||
compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp";
|
||||
reg = <0xa000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
@@ -17,9 +17,11 @@ Required Properties:
|
||||
- "renesas,pfc-r8a7779": for R8A7779 (R-Car H1) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7790": for R8A7790 (R-Car H2) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7791": for R8A7791 (R-Car M2-W) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7792": for R8A7792 (R-Car V2H) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7793": for R8A7793 (R-Car M2-N) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7794": for R8A7794 (R-Car E2) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7795": for R8A7795 (R-Car H3) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7796": for R8A7796 (R-Car M3-W) compatible pin-controller.
|
||||
- "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller.
|
||||
|
||||
- reg: Base address and length of each memory resource used by the pin
|
||||
|
||||
@@ -14,6 +14,11 @@ Required properies:
|
||||
- #size-cells : The value of this property must be 1
|
||||
- ranges : defines mapping between pin controller node (parent) to
|
||||
gpio-bank node (children).
|
||||
- interrupt-parent: phandle of the interrupt parent to which the external
|
||||
GPIO interrupts are forwarded to.
|
||||
- st,syscfg: Should be phandle/offset pair. The phandle to the syscon node
|
||||
which includes IRQ mux selection register, and the offset of the IRQ mux
|
||||
selection register.
|
||||
- pins-are-numbered: Specify the subnodes are using numbered pinmux to
|
||||
specify pins.
|
||||
|
||||
|
||||
@@ -262,6 +262,12 @@ symbol:
|
||||
to the container using container_of().
|
||||
(See Documentation/driver-model/design-patterns.txt)
|
||||
|
||||
If there is a need to exclude certain GPIOs from the IRQ domain, one can
|
||||
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
|
||||
called. This allocates .irq_valid_mask with as many bits set as there are
|
||||
GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
|
||||
mask. The mask must be filled in before gpiochip_irqchip_add() is called.
|
||||
|
||||
* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
|
||||
gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
|
||||
data. (Notice handler data, since the irqchip data is likely used by the
|
||||
|
||||
@@ -91,9 +91,13 @@ cleanup_alloc:
|
||||
devm_kfree(dev, dev->pins);
|
||||
dev->pins = NULL;
|
||||
|
||||
/* Only return deferrals */
|
||||
if (ret != -EPROBE_DEFER)
|
||||
ret = 0;
|
||||
/* Return deferrals */
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
/* Return serious errors */
|
||||
if (ret == -EINVAL)
|
||||
return ret;
|
||||
/* We ignore errors like -ENOENT meaning no pinctrl state */
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -458,6 +458,11 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto out_bgio;
|
||||
|
||||
if (of_property_read_bool(np, "gpio-ranges")) {
|
||||
port->gc.request = gpiochip_generic_request;
|
||||
port->gc.free = gpiochip_generic_free;
|
||||
}
|
||||
|
||||
port->gc.to_irq = mxc_gpio_to_irq;
|
||||
port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
|
||||
pdev->id * 32;
|
||||
@@ -510,7 +515,7 @@ static int __init gpio_mxc_init(void)
|
||||
{
|
||||
return platform_driver_register(&mxc_gpio_driver);
|
||||
}
|
||||
postcore_initcall(gpio_mxc_init);
|
||||
subsys_initcall(gpio_mxc_init);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, "
|
||||
"Daniel Mack <danielncaiaq.de>, "
|
||||
|
||||
+63
-3
@@ -71,6 +71,8 @@ LIST_HEAD(gpio_devices);
|
||||
|
||||
static void gpiochip_free_hogs(struct gpio_chip *chip);
|
||||
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
|
||||
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
|
||||
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);
|
||||
|
||||
static bool gpiolib_initialized;
|
||||
|
||||
@@ -1167,6 +1169,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
|
||||
if (status)
|
||||
goto err_remove_from_list;
|
||||
|
||||
status = gpiochip_irqchip_init_valid_mask(chip);
|
||||
if (status)
|
||||
goto err_remove_from_list;
|
||||
|
||||
status = of_gpiochip_add(chip);
|
||||
if (status)
|
||||
goto err_remove_chip;
|
||||
@@ -1192,6 +1198,7 @@ err_remove_chip:
|
||||
acpi_gpiochip_remove(chip);
|
||||
gpiochip_free_hogs(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
gpiochip_irqchip_free_valid_mask(chip);
|
||||
err_remove_from_list:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
list_del(&gdev->list);
|
||||
@@ -1401,6 +1408,40 @@ static struct gpio_chip *find_chip_by_name(const char *name)
|
||||
* The following is irqchip helper code for gpiochips.
|
||||
*/
|
||||
|
||||
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!gpiochip->irq_need_valid_mask)
|
||||
return 0;
|
||||
|
||||
gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
|
||||
sizeof(long), GFP_KERNEL);
|
||||
if (!gpiochip->irq_valid_mask)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Assume by default all GPIOs are valid */
|
||||
for (i = 0; i < gpiochip->ngpio; i++)
|
||||
set_bit(i, gpiochip->irq_valid_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
kfree(gpiochip->irq_valid_mask);
|
||||
gpiochip->irq_valid_mask = NULL;
|
||||
}
|
||||
|
||||
static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* No mask means all valid */
|
||||
if (likely(!gpiochip->irq_valid_mask))
|
||||
return true;
|
||||
return test_bit(offset, gpiochip->irq_valid_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip
|
||||
* @gpiochip: the gpiochip to set the irqchip chain to
|
||||
@@ -1442,9 +1483,12 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||
}
|
||||
|
||||
/* Set the parent IRQ for all affected IRQs */
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++)
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
||||
if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
|
||||
continue;
|
||||
irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
|
||||
parent_irq);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
|
||||
|
||||
@@ -1551,9 +1595,12 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
|
||||
|
||||
/* Remove all IRQ mappings and delete the domain */
|
||||
if (gpiochip->irqdomain) {
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++)
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
||||
if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
|
||||
continue;
|
||||
irq_dispose_mapping(
|
||||
irq_find_mapping(gpiochip->irqdomain, offset));
|
||||
}
|
||||
irq_domain_remove(gpiochip->irqdomain);
|
||||
}
|
||||
|
||||
@@ -1562,6 +1609,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
|
||||
gpiochip->irqchip->irq_release_resources = NULL;
|
||||
gpiochip->irqchip = NULL;
|
||||
}
|
||||
|
||||
gpiochip_irqchip_free_valid_mask(gpiochip);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1597,6 +1646,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
||||
struct lock_class_key *lock_key)
|
||||
{
|
||||
struct device_node *of_node;
|
||||
bool irq_base_set = false;
|
||||
unsigned int offset;
|
||||
unsigned irq_base = 0;
|
||||
|
||||
@@ -1646,13 +1696,17 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
||||
* necessary to allocate descriptors for all IRQs.
|
||||
*/
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
||||
if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
|
||||
continue;
|
||||
irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
|
||||
if (offset == 0)
|
||||
if (!irq_base_set) {
|
||||
/*
|
||||
* Store the base into the gpiochip to be used when
|
||||
* unmapping the irqs.
|
||||
*/
|
||||
gpiochip->irq_base = irq_base;
|
||||
irq_base_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
acpi_gpiochip_request_interrupts(gpiochip);
|
||||
@@ -1664,6 +1718,12 @@ EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add);
|
||||
#else /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
|
||||
static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
|
||||
{ }
|
||||
|
||||
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
|
||||
@@ -254,6 +254,7 @@ config PINCTRL_ZYNQ
|
||||
help
|
||||
This selects the pinctrl driver for Xilinx Zynq.
|
||||
|
||||
source "drivers/pinctrl/aspeed/Kconfig"
|
||||
source "drivers/pinctrl/bcm/Kconfig"
|
||||
source "drivers/pinctrl/berlin/Kconfig"
|
||||
source "drivers/pinctrl/freescale/Kconfig"
|
||||
|
||||
@@ -37,6 +37,7 @@ obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
|
||||
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
|
||||
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
|
||||
|
||||
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
|
||||
obj-y += bcm/
|
||||
obj-$(CONFIG_PINCTRL_BERLIN) += berlin/
|
||||
obj-y += freescale/
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
config PINCTRL_ASPEED
|
||||
bool
|
||||
depends on (ARCH_ASPEED || COMPILE_TEST) && OF
|
||||
depends on MFD_SYSCON
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
select REGMAP_MMIO
|
||||
|
||||
config PINCTRL_ASPEED_G4
|
||||
bool "Aspeed G4 SoC pin control"
|
||||
depends on (MACH_ASPEED_G4 || COMPILE_TEST) && OF
|
||||
select PINCTRL_ASPEED
|
||||
help
|
||||
Say Y here to enable pin controller support for Aspeed's 4th
|
||||
generation SoCs. GPIO is provided by a separate GPIO driver.
|
||||
|
||||
config PINCTRL_ASPEED_G5
|
||||
bool "Aspeed G5 SoC pin control"
|
||||
depends on (MACH_ASPEED_G5 || COMPILE_TEST) && OF
|
||||
select PINCTRL_ASPEED
|
||||
help
|
||||
Say Y here to enable pin controller support for Aspeed's 5th
|
||||
generation SoCs. GPIO is provided by a separate GPIO driver.
|
||||
@@ -0,0 +1,6 @@
|
||||
# Aspeed pinctrl support
|
||||
|
||||
ccflags-y += -Woverride-init
|
||||
obj-$(CONFIG_PINCTRL_ASPEED) += pinctrl-aspeed.o
|
||||
obj-$(CONFIG_PINCTRL_ASPEED_G4) += pinctrl-aspeed-g4.o
|
||||
obj-$(CONFIG_PINCTRL_ASPEED_G5) += pinctrl-aspeed-g5.o
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Copyright (C) 2016 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include "../core.h"
|
||||
#include "pinctrl-aspeed.h"
|
||||
|
||||
int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
return pdata->ngroups;
|
||||
}
|
||||
|
||||
const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned int group)
|
||||
{
|
||||
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
return pdata->groups[group].name;
|
||||
}
|
||||
|
||||
int aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
unsigned int group, const unsigned int **pins,
|
||||
unsigned int *npins)
|
||||
{
|
||||
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
*pins = &pdata->groups[group].pins[0];
|
||||
*npins = pdata->groups[group].npins;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void aspeed_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s, unsigned int offset)
|
||||
{
|
||||
seq_printf(s, " %s", dev_name(pctldev->dev));
|
||||
}
|
||||
|
||||
int aspeed_pinmux_get_fn_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
return pdata->nfunctions;
|
||||
}
|
||||
|
||||
const char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev,
|
||||
unsigned int function)
|
||||
{
|
||||
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
return pdata->functions[function].name;
|
||||
}
|
||||
|
||||
int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev,
|
||||
unsigned int function,
|
||||
const char * const **groups,
|
||||
unsigned int * const num_groups)
|
||||
{
|
||||
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
*groups = pdata->functions[function].groups;
|
||||
*num_groups = pdata->functions[function].ngroups;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void aspeed_sig_desc_print_val(
|
||||
const struct aspeed_sig_desc *desc, bool enable, u32 rv)
|
||||
{
|
||||
pr_debug("SCU%x[0x%08x]=0x%x, got 0x%x from 0x%08x\n", desc->reg,
|
||||
desc->mask, enable ? desc->enable : desc->disable,
|
||||
(rv & desc->mask) >> __ffs(desc->mask), rv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the enabled or disabled state of a signal descriptor
|
||||
*
|
||||
* @desc: The signal descriptor of interest
|
||||
* @enabled: True to query the enabled state, false to query disabled state
|
||||
* @regmap: The SCU regmap instance
|
||||
*
|
||||
* @return True if the descriptor's bitfield is configured to the state
|
||||
* selected by @enabled, false otherwise
|
||||
*
|
||||
* Evaluation of descriptor state is non-trivial in that it is not a binary
|
||||
* outcome: The bitfields can be greater than one bit in size and thus can take
|
||||
* a value that is neither the enabled nor disabled state recorded in the
|
||||
* descriptor (typically this means a different function to the one of interest
|
||||
* is enabled). Thus we must explicitly test for either condition as required.
|
||||
*/
|
||||
static bool aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
|
||||
bool enabled, struct regmap *map)
|
||||
{
|
||||
unsigned int raw;
|
||||
u32 want;
|
||||
|
||||
if (regmap_read(map, desc->reg, &raw) < 0)
|
||||
return false;
|
||||
|
||||
aspeed_sig_desc_print_val(desc, enabled, raw);
|
||||
want = enabled ? desc->enable : desc->disable;
|
||||
|
||||
return ((raw & desc->mask) >> __ffs(desc->mask)) == want;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the enabled or disabled state for a mux function's signal on a pin
|
||||
*
|
||||
* @expr: An expression controlling the signal for a mux function on a pin
|
||||
* @enabled: True to query the enabled state, false to query disabled state
|
||||
* @regmap: The SCU regmap instance
|
||||
*
|
||||
* @return True if the expression composed by @enabled evaluates true, false
|
||||
* otherwise
|
||||
*
|
||||
* A mux function is enabled or disabled if the function's signal expression
|
||||
* for each pin in the function's pin group evaluates true for the desired
|
||||
* state. An signal expression evaluates true if all of its associated signal
|
||||
* descriptors evaluate true for the desired state.
|
||||
*
|
||||
* If an expression's state is described by more than one bit, either through
|
||||
* multi-bit bitfields in a single signal descriptor or through multiple signal
|
||||
* descriptors of a single bit then it is possible for the expression to be in
|
||||
* neither the enabled nor disabled state. Thus we must explicitly test for
|
||||
* either condition as required.
|
||||
*/
|
||||
static bool aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr,
|
||||
bool enabled, struct regmap *map)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < expr->ndescs; i++) {
|
||||
const struct aspeed_sig_desc *desc = &expr->descs[i];
|
||||
|
||||
if (!aspeed_sig_desc_eval(desc, enabled, map))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a pin's signal by applying an expression's descriptor state for
|
||||
* all descriptors in the expression.
|
||||
*
|
||||
* @expr: The expression associated with the function whose signal is to be
|
||||
* configured
|
||||
* @enable: true to enable an function's signal through a pin's signal
|
||||
* expression, false to disable the function's signal
|
||||
* @map: The SCU's regmap instance for pinmux register access.
|
||||
*
|
||||
* @return true if the expression is configured as requested, false otherwise
|
||||
*/
|
||||
static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr,
|
||||
bool enable, struct regmap *map)
|
||||
{
|
||||
int i;
|
||||
bool ret;
|
||||
|
||||
ret = aspeed_sig_expr_eval(expr, enable, map);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < expr->ndescs; i++) {
|
||||
const struct aspeed_sig_desc *desc = &expr->descs[i];
|
||||
u32 pattern = enable ? desc->enable : desc->disable;
|
||||
|
||||
/*
|
||||
* Strap registers are configured in hardware or by early-boot
|
||||
* firmware. Treat them as read-only despite that we can write
|
||||
* them. This may mean that certain functions cannot be
|
||||
* deconfigured and is the reason we re-evaluate after writing
|
||||
* all descriptor bits.
|
||||
*/
|
||||
if (desc->reg == HW_STRAP1 || desc->reg == HW_STRAP2)
|
||||
continue;
|
||||
|
||||
ret = regmap_update_bits(map, desc->reg, desc->mask,
|
||||
pattern << __ffs(desc->mask)) == 0;
|
||||
|
||||
if (!ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return aspeed_sig_expr_eval(expr, enable, map);
|
||||
}
|
||||
|
||||
static bool aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr,
|
||||
struct regmap *map)
|
||||
{
|
||||
return aspeed_sig_expr_set(expr, true, map);
|
||||
}
|
||||
|
||||
static bool aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr,
|
||||
struct regmap *map)
|
||||
{
|
||||
return aspeed_sig_expr_set(expr, false, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable a signal on a pin by disabling all provided signal expressions.
|
||||
*
|
||||
* @exprs: The list of signal expressions (from a priority level on a pin)
|
||||
* @map: The SCU's regmap instance for pinmux register access.
|
||||
*
|
||||
* @return true if all expressions in the list are successfully disabled, false
|
||||
* otherwise
|
||||
*/
|
||||
static bool aspeed_disable_sig(const struct aspeed_sig_expr **exprs,
|
||||
struct regmap *map)
|
||||
{
|
||||
bool disabled = true;
|
||||
|
||||
if (!exprs)
|
||||
return true;
|
||||
|
||||
while (*exprs) {
|
||||
bool ret;
|
||||
|
||||
ret = aspeed_sig_expr_disable(*exprs, map);
|
||||
disabled = disabled && ret;
|
||||
|
||||
exprs++;
|
||||
}
|
||||
|
||||
return disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the signal expression needed to enable the pin's signal for the
|
||||
* requested function.
|
||||
*
|
||||
* @exprs: List of signal expressions (haystack)
|
||||
* @name: The name of the requested function (needle)
|
||||
*
|
||||
* @return A pointer to the signal expression whose function tag matches the
|
||||
* provided name, otherwise NULL.
|
||||
*
|
||||
*/
|
||||
static const struct aspeed_sig_expr *aspeed_find_expr_by_name(
|
||||
const struct aspeed_sig_expr **exprs, const char *name)
|
||||
{
|
||||
while (*exprs) {
|
||||
if (strcmp((*exprs)->function, name) == 0)
|
||||
return *exprs;
|
||||
exprs++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *get_defined_attribute(const struct aspeed_pin_desc *pdesc,
|
||||
const char *(*get)(
|
||||
const struct aspeed_sig_expr *))
|
||||
{
|
||||
char *found = NULL;
|
||||
size_t len = 0;
|
||||
const struct aspeed_sig_expr ***prios, **funcs, *expr;
|
||||
|
||||
prios = pdesc->prios;
|
||||
|
||||
while ((funcs = *prios)) {
|
||||
while ((expr = *funcs)) {
|
||||
const char *str = get(expr);
|
||||
size_t delta = strlen(str) + 2;
|
||||
char *expanded;
|
||||
|
||||
expanded = krealloc(found, len + delta + 1, GFP_KERNEL);
|
||||
if (!expanded) {
|
||||
kfree(found);
|
||||
return expanded;
|
||||
}
|
||||
|
||||
found = expanded;
|
||||
found[len] = '\0';
|
||||
len += delta;
|
||||
|
||||
strcat(found, str);
|
||||
strcat(found, ", ");
|
||||
|
||||
funcs++;
|
||||
}
|
||||
prios++;
|
||||
}
|
||||
|
||||
if (len < 2) {
|
||||
kfree(found);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
found[len - 2] = '\0';
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static const char *aspeed_sig_expr_function(const struct aspeed_sig_expr *expr)
|
||||
{
|
||||
return expr->function;
|
||||
}
|
||||
|
||||
static char *get_defined_functions(const struct aspeed_pin_desc *pdesc)
|
||||
{
|
||||
return get_defined_attribute(pdesc, aspeed_sig_expr_function);
|
||||
}
|
||||
|
||||
static const char *aspeed_sig_expr_signal(const struct aspeed_sig_expr *expr)
|
||||
{
|
||||
return expr->signal;
|
||||
}
|
||||
|
||||
static char *get_defined_signals(const struct aspeed_pin_desc *pdesc)
|
||||
{
|
||||
return get_defined_attribute(pdesc, aspeed_sig_expr_signal);
|
||||
}
|
||||
|
||||
int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
|
||||
unsigned int group)
|
||||
{
|
||||
int i;
|
||||
const struct aspeed_pinctrl_data *pdata =
|
||||
pinctrl_dev_get_drvdata(pctldev);
|
||||
const struct aspeed_pin_group *pgroup = &pdata->groups[group];
|
||||
const struct aspeed_pin_function *pfunc =
|
||||
&pdata->functions[function];
|
||||
|
||||
for (i = 0; i < pgroup->npins; i++) {
|
||||
int pin = pgroup->pins[i];
|
||||
const struct aspeed_pin_desc *pdesc = pdata->pins[pin].drv_data;
|
||||
const struct aspeed_sig_expr *expr = NULL;
|
||||
const struct aspeed_sig_expr **funcs;
|
||||
const struct aspeed_sig_expr ***prios;
|
||||
|
||||
if (!pdesc)
|
||||
return -EINVAL;
|
||||
|
||||
prios = pdesc->prios;
|
||||
|
||||
if (!prios)
|
||||
continue;
|
||||
|
||||
/* Disable functions at a higher priority than that requested */
|
||||
while ((funcs = *prios)) {
|
||||
expr = aspeed_find_expr_by_name(funcs, pfunc->name);
|
||||
|
||||
if (expr)
|
||||
break;
|
||||
|
||||
if (!aspeed_disable_sig(funcs, pdata->map))
|
||||
return -EPERM;
|
||||
|
||||
prios++;
|
||||
}
|
||||
|
||||
if (!expr) {
|
||||
char *functions = get_defined_functions(pdesc);
|
||||
char *signals = get_defined_signals(pdesc);
|
||||
|
||||
pr_warn("No function %s found on pin %s (%d). Found signal(s) %s for function(s) %s\n",
|
||||
pfunc->name, pdesc->name, pin, signals,
|
||||
functions);
|
||||
kfree(signals);
|
||||
kfree(functions);
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (!aspeed_sig_expr_enable(expr, pdata->map))
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool aspeed_expr_is_gpio(const struct aspeed_sig_expr *expr)
|
||||
{
|
||||
/*
|
||||
* The signal type is GPIO if the signal name has "GPIO" as a prefix.
|
||||
* strncmp (rather than strcmp) is used to implement the prefix
|
||||
* requirement.
|
||||
*
|
||||
* expr->signal might look like "GPIOT3" in the GPIO case.
|
||||
*/
|
||||
return strncmp(expr->signal, "GPIO", 4) == 0;
|
||||
}
|
||||
|
||||
static bool aspeed_gpio_in_exprs(const struct aspeed_sig_expr **exprs)
|
||||
{
|
||||
if (!exprs)
|
||||
return false;
|
||||
|
||||
while (*exprs) {
|
||||
if (aspeed_expr_is_gpio(*exprs))
|
||||
return true;
|
||||
exprs++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range,
|
||||
unsigned int offset)
|
||||
{
|
||||
const struct aspeed_pinctrl_data *pdata =
|
||||
pinctrl_dev_get_drvdata(pctldev);
|
||||
const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data;
|
||||
const struct aspeed_sig_expr ***prios, **funcs, *expr;
|
||||
|
||||
if (!pdesc)
|
||||
return -EINVAL;
|
||||
|
||||
prios = pdesc->prios;
|
||||
|
||||
if (!prios)
|
||||
return -ENXIO;
|
||||
|
||||
/* Disable any functions of higher priority than GPIO */
|
||||
while ((funcs = *prios)) {
|
||||
if (aspeed_gpio_in_exprs(funcs))
|
||||
break;
|
||||
|
||||
if (!aspeed_disable_sig(funcs, pdata->map))
|
||||
return -EPERM;
|
||||
|
||||
prios++;
|
||||
}
|
||||
|
||||
if (!funcs) {
|
||||
char *signals = get_defined_signals(pdesc);
|
||||
|
||||
pr_warn("No GPIO signal type found on pin %s (%d). Found: %s\n",
|
||||
pdesc->name, offset, signals);
|
||||
kfree(signals);
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
expr = *funcs;
|
||||
|
||||
/*
|
||||
* Disabling all higher-priority expressions is enough to enable the
|
||||
* lowest-priority signal type. As such it has no associated
|
||||
* expression.
|
||||
*/
|
||||
if (!expr)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If GPIO is not the lowest priority signal type, assume there is only
|
||||
* one expression defined to enable the GPIO function
|
||||
*/
|
||||
if (!aspeed_sig_expr_enable(expr, pdata->map))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aspeed_pinctrl_probe(struct platform_device *pdev,
|
||||
struct pinctrl_desc *pdesc,
|
||||
struct aspeed_pinctrl_data *pdata)
|
||||
{
|
||||
struct device *parent;
|
||||
struct pinctrl_dev *pctl;
|
||||
|
||||
parent = pdev->dev.parent;
|
||||
if (!parent) {
|
||||
dev_err(&pdev->dev, "No parent for syscon pincontroller\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata->map = syscon_node_to_regmap(parent->of_node);
|
||||
if (IS_ERR(pdata->map)) {
|
||||
dev_err(&pdev->dev, "No regmap for syscon pincontroller parent\n");
|
||||
return PTR_ERR(pdata->map);
|
||||
}
|
||||
|
||||
pctl = pinctrl_register(pdesc, &pdev->dev, pdata);
|
||||
|
||||
if (IS_ERR(pctl)) {
|
||||
dev_err(&pdev->dev, "Failed to register pinctrl\n");
|
||||
return PTR_ERR(pctl);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1018,7 +1018,7 @@ static void bcm281xx_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
|
||||
seq_printf(s, " %s", dev_name(pctldev->dev));
|
||||
}
|
||||
|
||||
static struct pinctrl_ops bcm281xx_pinctrl_ops = {
|
||||
static const struct pinctrl_ops bcm281xx_pinctrl_ops = {
|
||||
.get_groups_count = bcm281xx_pinctrl_get_groups_count,
|
||||
.get_group_name = bcm281xx_pinctrl_get_group_name,
|
||||
.get_group_pins = bcm281xx_pinctrl_get_group_pins,
|
||||
@@ -1080,7 +1080,7 @@ static int bcm281xx_pinmux_set(struct pinctrl_dev *pctldev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = {
|
||||
static const struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = {
|
||||
.get_functions_count = bcm281xx_pinctrl_get_fcns_count,
|
||||
.get_function_name = bcm281xx_pinctrl_get_fcn_name,
|
||||
.get_function_groups = bcm281xx_pinctrl_get_fcn_groups,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user