Merge branch 'devel' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl into pinmux
This commit is contained in:
commit
a9324f6b83
|
@ -98,7 +98,7 @@ announce the pinrange to the pin ctrl subsystem. For example,
|
|||
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
|
||||
reg = <0x1460 0x18>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>;
|
||||
gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>;
|
||||
|
||||
}
|
||||
|
||||
|
@ -107,8 +107,8 @@ where,
|
|||
|
||||
Next values specify the base pin and number of pins for the range
|
||||
handled by 'qe_pio_e' gpio. In the given example from base pin 20 to
|
||||
pin 29 under pinctrl1 and pin 50 to pin 69 under pinctrl2 is handled
|
||||
by this gpio controller.
|
||||
pin 29 under pinctrl1 with gpio offset 0 and pin 50 to pin 69 under
|
||||
pinctrl2 with gpio offset 10 is handled by this gpio controller.
|
||||
|
||||
The pinctrl node must have "#gpio-range-cells" property to show number of
|
||||
arguments to pass with phandle from gpio controllers node.
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
One-register-per-pin type device tree based pinctrl driver
|
||||
|
||||
Required properties:
|
||||
- compatible : "pinctrl-single"
|
||||
- compatible : "pinctrl-single" or "pinconf-single".
|
||||
"pinctrl-single" means that pinconf isn't supported.
|
||||
"pinconf-single" means that generic pinconf is supported.
|
||||
|
||||
- reg : offset and length of the register set for the mux registers
|
||||
|
||||
|
@ -14,9 +16,61 @@ Optional properties:
|
|||
- pinctrl-single,function-off : function off mode for disabled state if
|
||||
available and same for all registers; if not specified, disabling of
|
||||
pin functions is ignored
|
||||
|
||||
- pinctrl-single,bit-per-mux : boolean to indicate that one register controls
|
||||
more than one pin
|
||||
|
||||
- pinctrl-single,drive-strength : array of value that are used to configure
|
||||
drive strength in the pinmux register. They're value of drive strength
|
||||
current and drive strength mask.
|
||||
|
||||
/* drive strength current, mask */
|
||||
pinctrl-single,power-source = <0x30 0xf0>;
|
||||
|
||||
- pinctrl-single,bias-pullup : array of value that are used to configure the
|
||||
input bias pullup in the pinmux register.
|
||||
|
||||
/* input, enabled pullup bits, disabled pullup bits, mask */
|
||||
pinctrl-single,bias-pullup = <0 1 0 1>;
|
||||
|
||||
- pinctrl-single,bias-pulldown : array of value that are used to configure the
|
||||
input bias pulldown in the pinmux register.
|
||||
|
||||
/* input, enabled pulldown bits, disabled pulldown bits, mask */
|
||||
pinctrl-single,bias-pulldown = <2 2 0 2>;
|
||||
|
||||
* Two bits to control input bias pullup and pulldown: User should use
|
||||
pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. One bit means
|
||||
pullup, and the other one bit means pulldown.
|
||||
* Three bits to control input bias enable, pullup and pulldown. User should
|
||||
use pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. Input bias
|
||||
enable bit should be included in pullup or pulldown bits.
|
||||
* Although driver could set PIN_CONFIG_BIAS_DISABLE, there's no property as
|
||||
pinctrl-single,bias-disable. Because pinctrl single driver could implement
|
||||
it by calling pulldown, pullup disabled.
|
||||
|
||||
- pinctrl-single,input-schmitt : array of value that are used to configure
|
||||
input schmitt in the pinmux register. In some silicons, there're two input
|
||||
schmitt value (rising-edge & falling-edge) in the pinmux register.
|
||||
|
||||
/* input schmitt value, mask */
|
||||
pinctrl-single,input-schmitt = <0x30 0x70>;
|
||||
|
||||
- pinctrl-single,input-schmitt-enable : array of value that are used to
|
||||
configure input schmitt enable or disable in the pinmux register.
|
||||
|
||||
/* input, enable bits, disable bits, mask */
|
||||
pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>;
|
||||
|
||||
- pinctrl-single,gpio-range : list of value that are used to configure a GPIO
|
||||
range. They're value of subnode phandle, pin base in pinctrl device, pin
|
||||
number in this range, GPIO function value of this GPIO range.
|
||||
The number of parameters is depend on #pinctrl-single,gpio-range-cells
|
||||
property.
|
||||
|
||||
/* pin base, nr pins & gpio function */
|
||||
pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1>;
|
||||
|
||||
This driver assumes that there is only one register for each pin (unless the
|
||||
pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as
|
||||
specified in the pinctrl-bindings.txt document in this directory.
|
||||
|
@ -42,6 +96,20 @@ Where 0xdc is the offset from the pinctrl register base address for the
|
|||
device pinctrl register, 0x18 is the desired value, and 0xff is the sub mask to
|
||||
be used when applying this change to the register.
|
||||
|
||||
|
||||
Optional sub-node: In case some pins could be configured as GPIO in the pinmux
|
||||
register, those pins could be defined as a GPIO range. This sub-node is required
|
||||
by pinctrl-single,gpio-range property.
|
||||
|
||||
Required properties in sub-node:
|
||||
- #pinctrl-single,gpio-range-cells : the number of parameters after phandle in
|
||||
pinctrl-single,gpio-range property.
|
||||
|
||||
range: gpio-range {
|
||||
#pinctrl-single,gpio-range-cells = <3>;
|
||||
};
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
/* SoC common file */
|
||||
|
@ -76,6 +144,29 @@ control_devconf0: pinmux@48002274 {
|
|||
pinctrl-single,function-mask = <0x5F>;
|
||||
};
|
||||
|
||||
/* third controller instance for pins in gpio domain */
|
||||
pmx_gpio: pinmux@d401e000 {
|
||||
compatible = "pinconf-single";
|
||||
reg = <0xd401e000 0x0330>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
pinctrl-single,register-width = <32>;
|
||||
pinctrl-single,function-mask = <7>;
|
||||
|
||||
/* sparse GPIO range could be supported */
|
||||
pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1
|
||||
&range 12 1 0 &range 13 29 1
|
||||
&range 43 1 0 &range 44 49 1
|
||||
&range 94 1 1 &range 96 2 1>;
|
||||
|
||||
range: gpio-range {
|
||||
#pinctrl-single,gpio-range-cells = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* board specific .dts file */
|
||||
|
||||
&pmx_core {
|
||||
|
@ -96,6 +187,15 @@ control_devconf0: pinmux@48002274 {
|
|||
>;
|
||||
};
|
||||
|
||||
uart0_pins: pinmux_uart0_pins {
|
||||
pinctrl-single,pins = <
|
||||
0x208 0 /* UART0_RXD (IOCFG138) */
|
||||
0x20c 0 /* UART0_TXD (IOCFG139) */
|
||||
>;
|
||||
pinctrl-single,bias-pulldown = <0 2 2>;
|
||||
pinctrl-single,bias-pullup = <0 1 1>;
|
||||
};
|
||||
|
||||
/* map uart2 pins */
|
||||
uart2_pins: pinmux_uart2_pins {
|
||||
pinctrl-single,pins = <
|
||||
|
@ -122,6 +222,11 @@ control_devconf0: pinmux@48002274 {
|
|||
|
||||
};
|
||||
|
||||
&uart1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart0_pins>;
|
||||
};
|
||||
|
||||
&uart2 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart2_pins>;
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
pinmux: pinmux@e0700000 {
|
||||
compatible = "st,spear1310-pinmux";
|
||||
reg = <0xe0700000 0x1000>;
|
||||
#gpio-range-cells = <2>;
|
||||
#gpio-range-cells = <3>;
|
||||
};
|
||||
|
||||
apb {
|
||||
|
@ -212,7 +212,7 @@
|
|||
interrupt-controller;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinmux 0 246>;
|
||||
gpio-ranges = <&pinmux 0 0 246>;
|
||||
status = "disabled";
|
||||
|
||||
st-plgpio,ngpio = <246>;
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
pinmux: pinmux@e0700000 {
|
||||
compatible = "st,spear1340-pinmux";
|
||||
reg = <0xe0700000 0x1000>;
|
||||
#gpio-range-cells = <2>;
|
||||
#gpio-range-cells = <3>;
|
||||
};
|
||||
|
||||
pwm: pwm@e0180000 {
|
||||
|
@ -127,7 +127,7 @@
|
|||
interrupt-controller;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinmux 0 252>;
|
||||
gpio-ranges = <&pinmux 0 0 252>;
|
||||
status = "disabled";
|
||||
|
||||
st-plgpio,ngpio = <250>;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
pinmux: pinmux@b4000000 {
|
||||
compatible = "st,spear310-pinmux";
|
||||
reg = <0xb4000000 0x1000>;
|
||||
#gpio-range-cells = <2>;
|
||||
#gpio-range-cells = <3>;
|
||||
};
|
||||
|
||||
fsmc: flash@44000000 {
|
||||
|
@ -102,7 +102,7 @@
|
|||
interrupt-controller;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinmux 0 102>;
|
||||
gpio-ranges = <&pinmux 0 0 102>;
|
||||
status = "disabled";
|
||||
|
||||
st-plgpio,ngpio = <102>;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
pinmux: pinmux@b3000000 {
|
||||
compatible = "st,spear320-pinmux";
|
||||
reg = <0xb3000000 0x1000>;
|
||||
#gpio-range-cells = <2>;
|
||||
#gpio-range-cells = <3>;
|
||||
};
|
||||
|
||||
clcd@90000000 {
|
||||
|
@ -130,7 +130,7 @@
|
|||
interrupt-controller;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinmux 0 102>;
|
||||
gpio-ranges = <&pinmux 0 0 102>;
|
||||
status = "disabled";
|
||||
|
||||
st-plgpio,ngpio = <102>;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/gpio.h>
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include <linux/amba/bus.h>
|
||||
#include <linux/amba/pl061.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
|
@ -51,8 +53,7 @@ struct pl061_gpio {
|
|||
spinlock_t lock;
|
||||
|
||||
void __iomem *base;
|
||||
int irq_base;
|
||||
struct irq_chip_generic *irq_gc;
|
||||
struct irq_domain *domain;
|
||||
struct gpio_chip gc;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
@ -60,6 +61,17 @@ struct pl061_gpio {
|
|||
#endif
|
||||
};
|
||||
|
||||
static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
/*
|
||||
* Map back to global GPIO space and request muxing, the direction
|
||||
* parameter does not matter for this controller.
|
||||
*/
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
return pinctrl_request_gpio(gpio);
|
||||
}
|
||||
|
||||
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||
|
@ -122,24 +134,20 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
|
|||
{
|
||||
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||
|
||||
if (chip->irq_base <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
return chip->irq_base + offset;
|
||||
return irq_create_mapping(chip->domain, offset);
|
||||
}
|
||||
|
||||
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct pl061_gpio *chip = gc->private;
|
||||
int offset = d->irq - chip->irq_base;
|
||||
struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
|
||||
int offset = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
u8 gpiois, gpioibe, gpioiev;
|
||||
|
||||
if (offset < 0 || offset >= PL061_GPIO_NR)
|
||||
return -EINVAL;
|
||||
|
||||
raw_spin_lock_irqsave(&gc->lock, flags);
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
|
||||
gpioiev = readb(chip->base + GPIOIEV);
|
||||
|
||||
|
@ -168,7 +176,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
|||
|
||||
writeb(gpioiev, chip->base + GPIOIEV);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gc->lock, flags);
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -192,31 +200,61 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
|
|||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
|
||||
static void pl061_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip_type *ct;
|
||||
struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
|
||||
u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
|
||||
u8 gpioie;
|
||||
|
||||
chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base,
|
||||
chip->base, handle_simple_irq);
|
||||
chip->irq_gc->private = chip;
|
||||
|
||||
ct = chip->irq_gc->chip_types;
|
||||
ct->chip.irq_mask = irq_gc_mask_clr_bit;
|
||||
ct->chip.irq_unmask = irq_gc_mask_set_bit;
|
||||
ct->chip.irq_set_type = pl061_irq_type;
|
||||
ct->chip.irq_set_wake = irq_gc_set_wake;
|
||||
ct->regs.mask = GPIOIE;
|
||||
|
||||
irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR),
|
||||
IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
|
||||
spin_lock(&chip->lock);
|
||||
gpioie = readb(chip->base + GPIOIE) & ~mask;
|
||||
writeb(gpioie, chip->base + GPIOIE);
|
||||
spin_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static void pl061_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
|
||||
u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
|
||||
u8 gpioie;
|
||||
|
||||
spin_lock(&chip->lock);
|
||||
gpioie = readb(chip->base + GPIOIE) | mask;
|
||||
writeb(gpioie, chip->base + GPIOIE);
|
||||
spin_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static struct irq_chip pl061_irqchip = {
|
||||
.name = "pl061 gpio",
|
||||
.irq_mask = pl061_irq_mask,
|
||||
.irq_unmask = pl061_irq_unmask,
|
||||
.irq_set_type = pl061_irq_type,
|
||||
};
|
||||
|
||||
static int pl061_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
struct pl061_gpio *chip = d->host_data;
|
||||
|
||||
irq_set_chip_and_handler_name(virq, &pl061_irqchip, handle_simple_irq,
|
||||
"pl061");
|
||||
irq_set_chip_data(virq, chip);
|
||||
irq_set_irq_type(virq, IRQ_TYPE_NONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops pl061_domain_ops = {
|
||||
.map = pl061_irq_map,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
{
|
||||
struct device *dev = &adev->dev;
|
||||
struct pl061_platform_data *pdata = dev->platform_data;
|
||||
struct pl061_gpio *chip;
|
||||
int ret, irq, i;
|
||||
int ret, irq, i, irq_base;
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (chip == NULL)
|
||||
|
@ -224,24 +262,31 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
|
||||
if (pdata) {
|
||||
chip->gc.base = pdata->gpio_base;
|
||||
chip->irq_base = pdata->irq_base;
|
||||
} else if (adev->dev.of_node) {
|
||||
irq_base = pdata->irq_base;
|
||||
if (irq_base <= 0)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
chip->gc.base = -1;
|
||||
chip->irq_base = 0;
|
||||
} else
|
||||
return -ENODEV;
|
||||
irq_base = 0;
|
||||
}
|
||||
|
||||
if (!devm_request_mem_region(dev, adev->res.start,
|
||||
resource_size(&adev->res), "pl061"))
|
||||
resource_size(&adev->res), "pl061"))
|
||||
return -EBUSY;
|
||||
|
||||
chip->base = devm_ioremap(dev, adev->res.start,
|
||||
resource_size(&adev->res));
|
||||
if (chip->base == NULL)
|
||||
resource_size(&adev->res));
|
||||
if (!chip->base)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR,
|
||||
irq_base, &pl061_domain_ops, chip);
|
||||
if (!chip->domain)
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
|
||||
chip->gc.request = pl061_gpio_request;
|
||||
chip->gc.direction_input = pl061_direction_input;
|
||||
chip->gc.direction_output = pl061_direction_output;
|
||||
chip->gc.get = pl061_get_value;
|
||||
|
@ -259,12 +304,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
/*
|
||||
* irq_chip support
|
||||
*/
|
||||
|
||||
if (chip->irq_base <= 0)
|
||||
return 0;
|
||||
|
||||
pl061_init_gc(chip, chip->irq_base);
|
||||
|
||||
writeb(0, chip->base + GPIOIE); /* disable irqs */
|
||||
irq = adev->irq[0];
|
||||
if (irq < 0)
|
||||
|
|
|
@ -203,22 +203,11 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
|||
if (!pctldev)
|
||||
break;
|
||||
|
||||
/*
|
||||
* This assumes that the n GPIO pins are consecutive in the
|
||||
* GPIO number space, and that the pins are also consecutive
|
||||
* in their local number space. Currently it is not possible
|
||||
* to add different ranges for one and the same GPIO chip,
|
||||
* as the code assumes that we have one consecutive range
|
||||
* on both, mapping 1-to-1.
|
||||
*
|
||||
* TODO: make the OF bindings handle multiple sparse ranges
|
||||
* on the same GPIO chip.
|
||||
*/
|
||||
ret = gpiochip_add_pin_range(chip,
|
||||
pinctrl_dev_get_devname(pctldev),
|
||||
0, /* offset in gpiochip */
|
||||
pinspec.args[0],
|
||||
pinspec.args[1]);
|
||||
pinspec.args[1],
|
||||
pinspec.args[2]);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
|
|
@ -166,6 +166,7 @@ config PINCTRL_SINGLE
|
|||
depends on OF
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
help
|
||||
This selects the device tree based generic pinctrl driver.
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <asm-generic/gpio.h>
|
||||
#include "core.h"
|
||||
#include "devicetree.h"
|
||||
#include "pinmux.h"
|
||||
|
@ -276,6 +277,39 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pinctrl_ready_for_gpio_range() - check if other GPIO pins of
|
||||
* the same GPIO chip are in range
|
||||
* @gpio: gpio pin to check taken from the global GPIO pin space
|
||||
*
|
||||
* This function is complement of pinctrl_match_gpio_range(). If the return
|
||||
* value of pinctrl_match_gpio_range() is NULL, this function could be used
|
||||
* to check whether pinctrl device is ready or not. Maybe some GPIO pins
|
||||
* of the same GPIO chip don't have back-end pinctrl interface.
|
||||
* If the return value is true, it means that pinctrl device is ready & the
|
||||
* certain GPIO pin doesn't have back-end pinctrl device. If the return value
|
||||
* is false, it means that pinctrl device may not be ready.
|
||||
*/
|
||||
static bool pinctrl_ready_for_gpio_range(unsigned gpio)
|
||||
{
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct pinctrl_gpio_range *range = NULL;
|
||||
struct gpio_chip *chip = gpio_to_chip(gpio);
|
||||
|
||||
/* Loop over the pin controllers */
|
||||
list_for_each_entry(pctldev, &pinctrldev_list, node) {
|
||||
/* Loop over the ranges */
|
||||
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
|
||||
/* Check if any gpio range overlapped with gpio chip */
|
||||
if (range->base + range->npins - 1 < chip->base ||
|
||||
range->base > chip->base + chip->ngpio - 1)
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* pinctrl_get_device_gpio_range() - find device for GPIO range
|
||||
* @gpio: the pin to locate the pin controller for
|
||||
|
@ -443,6 +477,8 @@ int pinctrl_request_gpio(unsigned gpio)
|
|||
|
||||
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
|
||||
if (ret) {
|
||||
if (pinctrl_ready_for_gpio_range(gpio))
|
||||
ret = 0;
|
||||
mutex_unlock(&pinctrl_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -979,9 +1015,8 @@ static int devm_pinctrl_match(struct device *dev, void *res, void *data)
|
|||
*/
|
||||
void devm_pinctrl_put(struct pinctrl *p)
|
||||
{
|
||||
WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
|
||||
WARN_ON(devres_release(p->dev, devm_pinctrl_release,
|
||||
devm_pinctrl_match, p));
|
||||
pinctrl_put(p);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pinctrl_put);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ static void dt_free_map(struct pinctrl_dev *pctldev,
|
|||
struct pinctrl_map *map, unsigned num_maps)
|
||||
{
|
||||
if (pctldev) {
|
||||
struct pinctrl_ops *ops = pctldev->desc->pctlops;
|
||||
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
|
||||
ops->dt_free_map(pctldev, map, num_maps);
|
||||
} else {
|
||||
/* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
|
||||
|
@ -122,7 +122,7 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
|
|||
{
|
||||
struct device_node *np_pctldev;
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct pinctrl_ops *ops;
|
||||
const struct pinctrl_ops *ops;
|
||||
int ret;
|
||||
struct pinctrl_map *map;
|
||||
unsigned num_maps;
|
||||
|
|
|
@ -263,7 +263,7 @@ static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
|
|||
return;
|
||||
}
|
||||
|
||||
static struct pinconf_ops mvebu_pinconf_ops = {
|
||||
static const struct pinconf_ops mvebu_pinconf_ops = {
|
||||
.pin_config_group_get = mvebu_pinconf_group_get,
|
||||
.pin_config_group_set = mvebu_pinconf_group_set,
|
||||
.pin_config_group_dbg_show = mvebu_pinconf_group_dbg_show,
|
||||
|
@ -369,7 +369,7 @@ static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static struct pinmux_ops mvebu_pinmux_ops = {
|
||||
static const struct pinmux_ops mvebu_pinmux_ops = {
|
||||
.get_functions_count = mvebu_pinmux_get_funcs_count,
|
||||
.get_function_name = mvebu_pinmux_get_func_name,
|
||||
.get_function_groups = mvebu_pinmux_get_groups,
|
||||
|
@ -470,7 +470,7 @@ static void mvebu_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
|
|||
kfree(map);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops mvebu_pinctrl_ops = {
|
||||
static const struct pinctrl_ops mvebu_pinctrl_ops = {
|
||||
.get_groups_count = mvebu_pinctrl_get_groups_count,
|
||||
.get_group_name = mvebu_pinctrl_get_group_name,
|
||||
.get_group_pins = mvebu_pinctrl_get_group_pins,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define pr_fmt(fmt) "generic pinconfig core: " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -120,4 +121,17 @@ void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
}
|
||||
|
||||
void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s, unsigned long config)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(conf_items); i++) {
|
||||
if (pinconf_to_config_param(config) != conf_items[i].param)
|
||||
continue;
|
||||
seq_printf(s, "%s: 0x%x", conf_items[i].display,
|
||||
pinconf_to_config_argument(config));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
|
||||
#endif
|
||||
|
|
|
@ -670,7 +670,7 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d)
|
|||
struct pinctrl_maps *maps_node;
|
||||
struct pinctrl_map const *map;
|
||||
struct pinctrl_dev *pctldev = NULL;
|
||||
struct pinconf_ops *confops = NULL;
|
||||
const struct pinconf_ops *confops = NULL;
|
||||
int i, j;
|
||||
bool found = false;
|
||||
|
||||
|
|
|
@ -98,6 +98,8 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
|
|||
void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s, const char *gname);
|
||||
|
||||
void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s, unsigned long config);
|
||||
#else
|
||||
|
||||
static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
|
||||
|
@ -114,4 +116,10 @@ static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
|
|||
return;
|
||||
}
|
||||
|
||||
static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s,
|
||||
unsigned long config)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -656,7 +656,7 @@ static void abx500_gpio_disable_free(struct pinctrl_dev *pctldev,
|
|||
{
|
||||
}
|
||||
|
||||
static struct pinmux_ops abx500_pinmux_ops = {
|
||||
static const struct pinmux_ops abx500_pinmux_ops = {
|
||||
.get_functions_count = abx500_pmx_get_funcs_cnt,
|
||||
.get_function_name = abx500_pmx_get_func_name,
|
||||
.get_function_groups = abx500_pmx_get_func_groups,
|
||||
|
@ -704,7 +704,7 @@ static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
|
|||
chip->base + offset - 1);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops abx500_pinctrl_ops = {
|
||||
static const struct pinctrl_ops abx500_pinctrl_ops = {
|
||||
.get_groups_count = abx500_get_groups_cnt,
|
||||
.get_group_name = abx500_get_group_name,
|
||||
.get_group_pins = abx500_get_group_pins,
|
||||
|
@ -778,7 +778,7 @@ int abx500_pin_config_set(struct pinctrl_dev *pctldev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct pinconf_ops abx500_pinconf_ops = {
|
||||
static const struct pinconf_ops abx500_pinconf_ops = {
|
||||
.pin_config_get = abx500_pin_config_get,
|
||||
.pin_config_set = abx500_pin_config_set,
|
||||
};
|
||||
|
@ -834,6 +834,7 @@ static const struct of_device_id abx500_gpio_match[] = {
|
|||
{ .compatible = "stericsson,ab8505-gpio", .data = (void *)PINCTRL_AB8505, },
|
||||
{ .compatible = "stericsson,ab8540-gpio", .data = (void *)PINCTRL_AB8540, },
|
||||
{ .compatible = "stericsson,ab9540-gpio", .data = (void *)PINCTRL_AB9540, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int abx500_gpio_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -294,7 +294,7 @@ static void at91_dt_free_map(struct pinctrl_dev *pctldev,
|
|||
{
|
||||
}
|
||||
|
||||
static struct pinctrl_ops at91_pctrl_ops = {
|
||||
static const struct pinctrl_ops at91_pctrl_ops = {
|
||||
.get_groups_count = at91_get_groups_count,
|
||||
.get_group_name = at91_get_group_name,
|
||||
.get_group_pins = at91_get_group_pins,
|
||||
|
@ -696,7 +696,7 @@ static void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
|
|||
/* Set the pin to some default state, GPIO is usually default */
|
||||
}
|
||||
|
||||
static struct pinmux_ops at91_pmx_ops = {
|
||||
static const struct pinmux_ops at91_pmx_ops = {
|
||||
.get_functions_count = at91_pmx_get_funcs_count,
|
||||
.get_function_name = at91_pmx_get_func_name,
|
||||
.get_function_groups = at91_pmx_get_groups,
|
||||
|
@ -776,7 +776,7 @@ static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
|
|||
{
|
||||
}
|
||||
|
||||
static struct pinconf_ops at91_pinconf_ops = {
|
||||
static const struct pinconf_ops at91_pinconf_ops = {
|
||||
.pin_config_get = at91_pinconf_get,
|
||||
.pin_config_set = at91_pinconf_set,
|
||||
.pin_config_dbg_show = at91_pinconf_dbg_show,
|
||||
|
|
|
@ -795,7 +795,7 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops bcm2835_pctl_ops = {
|
||||
static const struct pinctrl_ops bcm2835_pctl_ops = {
|
||||
.get_groups_count = bcm2835_pctl_get_groups_count,
|
||||
.get_group_name = bcm2835_pctl_get_group_name,
|
||||
.get_group_pins = bcm2835_pctl_get_group_pins,
|
||||
|
@ -872,7 +872,7 @@ static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinmux_ops bcm2835_pmx_ops = {
|
||||
static const struct pinmux_ops bcm2835_pmx_ops = {
|
||||
.get_functions_count = bcm2835_pmx_get_functions_count,
|
||||
.get_function_name = bcm2835_pmx_get_function_name,
|
||||
.get_function_groups = bcm2835_pmx_get_function_groups,
|
||||
|
@ -916,7 +916,7 @@ static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinconf_ops bcm2835_pinconf_ops = {
|
||||
static const struct pinconf_ops bcm2835_pinconf_ops = {
|
||||
.pin_config_get = bcm2835_pinconf_get,
|
||||
.pin_config_set = bcm2835_pinconf_set,
|
||||
};
|
||||
|
|
|
@ -286,7 +286,7 @@ static void exynos5440_dt_free_map(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
/* list of pinctrl callbacks for the pinctrl core */
|
||||
static struct pinctrl_ops exynos5440_pctrl_ops = {
|
||||
static const struct pinctrl_ops exynos5440_pctrl_ops = {
|
||||
.get_groups_count = exynos5440_get_group_count,
|
||||
.get_group_name = exynos5440_get_group_name,
|
||||
.get_group_pins = exynos5440_get_group_pins,
|
||||
|
@ -374,7 +374,7 @@ static int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
|
||||
static struct pinmux_ops exynos5440_pinmux_ops = {
|
||||
static const struct pinmux_ops exynos5440_pinmux_ops = {
|
||||
.get_functions_count = exynos5440_get_functions_count,
|
||||
.get_function_name = exynos5440_pinmux_get_fname,
|
||||
.get_function_groups = exynos5440_pinmux_get_groups,
|
||||
|
@ -523,7 +523,7 @@ static int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
|
||||
static struct pinconf_ops exynos5440_pinconf_ops = {
|
||||
static const struct pinconf_ops exynos5440_pinconf_ops = {
|
||||
.pin_config_get = exynos5440_pinconf_get,
|
||||
.pin_config_set = exynos5440_pinconf_set,
|
||||
.pin_config_group_get = exynos5440_pinconf_group_get,
|
||||
|
|
|
@ -353,7 +353,7 @@ static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev,
|
|||
{
|
||||
}
|
||||
|
||||
static struct pinconf_ops falcon_pinconf_ops = {
|
||||
static const struct pinconf_ops falcon_pinconf_ops = {
|
||||
.pin_config_get = falcon_pinconf_get,
|
||||
.pin_config_set = falcon_pinconf_set,
|
||||
.pin_config_group_get = falcon_pinconf_group_get,
|
||||
|
|
|
@ -207,7 +207,7 @@ static void imx_dt_free_map(struct pinctrl_dev *pctldev,
|
|||
kfree(map);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops imx_pctrl_ops = {
|
||||
static const struct pinctrl_ops imx_pctrl_ops = {
|
||||
.get_groups_count = imx_get_groups_count,
|
||||
.get_group_name = imx_get_group_name,
|
||||
.get_group_pins = imx_get_group_pins,
|
||||
|
@ -299,7 +299,7 @@ static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinmux_ops imx_pmx_ops = {
|
||||
static const struct pinmux_ops imx_pmx_ops = {
|
||||
.get_functions_count = imx_pmx_get_funcs_count,
|
||||
.get_function_name = imx_pmx_get_func_name,
|
||||
.get_function_groups = imx_pmx_get_groups,
|
||||
|
@ -397,7 +397,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
}
|
||||
|
||||
static struct pinconf_ops imx_pinconf_ops = {
|
||||
static const struct pinconf_ops imx_pinconf_ops = {
|
||||
.pin_config_get = imx_pinconf_get,
|
||||
.pin_config_set = imx_pinconf_set,
|
||||
.pin_config_dbg_show = imx_pinconf_dbg_show,
|
||||
|
|
|
@ -169,7 +169,7 @@ static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops ltq_pctrl_ops = {
|
||||
static const struct pinctrl_ops ltq_pctrl_ops = {
|
||||
.get_groups_count = ltq_get_group_count,
|
||||
.get_group_name = ltq_get_group_name,
|
||||
.get_group_pins = ltq_get_group_pins,
|
||||
|
@ -311,7 +311,7 @@ static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev,
|
|||
return info->apply_mux(pctrldev, mfp, pin_func);
|
||||
}
|
||||
|
||||
static struct pinmux_ops ltq_pmx_ops = {
|
||||
static const struct pinmux_ops ltq_pmx_ops = {
|
||||
.get_functions_count = ltq_pmx_func_count,
|
||||
.get_function_name = ltq_pmx_func_name,
|
||||
.get_function_groups = ltq_pmx_get_groups,
|
||||
|
|
|
@ -158,7 +158,7 @@ static void mxs_dt_free_map(struct pinctrl_dev *pctldev,
|
|||
kfree(map);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops mxs_pinctrl_ops = {
|
||||
static const struct pinctrl_ops mxs_pinctrl_ops = {
|
||||
.get_groups_count = mxs_get_groups_count,
|
||||
.get_group_name = mxs_get_group_name,
|
||||
.get_group_pins = mxs_get_group_pins,
|
||||
|
@ -219,7 +219,7 @@ static int mxs_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned selector,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinmux_ops mxs_pinmux_ops = {
|
||||
static const struct pinmux_ops mxs_pinmux_ops = {
|
||||
.get_functions_count = mxs_pinctrl_get_funcs_count,
|
||||
.get_function_name = mxs_pinctrl_get_func_name,
|
||||
.get_function_groups = mxs_pinctrl_get_func_groups,
|
||||
|
@ -319,7 +319,7 @@ static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
|
|||
seq_printf(s, "0x%lx", config);
|
||||
}
|
||||
|
||||
static struct pinconf_ops mxs_pinconf_ops = {
|
||||
static const struct pinconf_ops mxs_pinconf_ops = {
|
||||
.pin_config_get = mxs_pinconf_get,
|
||||
.pin_config_set = mxs_pinconf_set,
|
||||
.pin_config_group_get = mxs_pinconf_group_get,
|
||||
|
|
|
@ -1764,7 +1764,7 @@ int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops nmk_pinctrl_ops = {
|
||||
static const struct pinctrl_ops nmk_pinctrl_ops = {
|
||||
.get_groups_count = nmk_get_groups_cnt,
|
||||
.get_group_name = nmk_get_group_name,
|
||||
.get_group_pins = nmk_get_group_pins,
|
||||
|
@ -1975,7 +1975,7 @@ static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
|
|||
/* Set the pin to some default state, GPIO is usually default */
|
||||
}
|
||||
|
||||
static struct pinmux_ops nmk_pinmux_ops = {
|
||||
static const struct pinmux_ops nmk_pinmux_ops = {
|
||||
.get_functions_count = nmk_pmx_get_funcs_cnt,
|
||||
.get_function_name = nmk_pmx_get_func_name,
|
||||
.get_function_groups = nmk_pmx_get_func_groups,
|
||||
|
@ -2089,7 +2089,7 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinconf_ops nmk_pinconf_ops = {
|
||||
static const struct pinconf_ops nmk_pinconf_ops = {
|
||||
.pin_config_get = nmk_pin_config_get,
|
||||
.pin_config_set = nmk_pin_config_set,
|
||||
};
|
||||
|
|
|
@ -53,7 +53,7 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops pxa3xx_pctrl_ops = {
|
||||
static const struct pinctrl_ops pxa3xx_pctrl_ops = {
|
||||
.get_groups_count = pxa3xx_get_groups_count,
|
||||
.get_group_name = pxa3xx_get_group_name,
|
||||
.get_group_pins = pxa3xx_get_group_pins,
|
||||
|
@ -161,7 +161,7 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinmux_ops pxa3xx_pmx_ops = {
|
||||
static const struct pinmux_ops pxa3xx_pmx_ops = {
|
||||
.get_functions_count = pxa3xx_pmx_get_funcs_count,
|
||||
.get_function_name = pxa3xx_pmx_get_func_name,
|
||||
.get_function_groups = pxa3xx_pmx_get_groups,
|
||||
|
|
|
@ -214,7 +214,7 @@ static void samsung_dt_free_map(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
/* list of pinctrl callbacks for the pinctrl core */
|
||||
static struct pinctrl_ops samsung_pctrl_ops = {
|
||||
static const struct pinctrl_ops samsung_pctrl_ops = {
|
||||
.get_groups_count = samsung_get_group_count,
|
||||
.get_group_name = samsung_get_group_name,
|
||||
.get_group_pins = samsung_get_group_pins,
|
||||
|
@ -357,7 +357,7 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
|
||||
static struct pinmux_ops samsung_pinmux_ops = {
|
||||
static const struct pinmux_ops samsung_pinmux_ops = {
|
||||
.get_functions_count = samsung_get_functions_count,
|
||||
.get_function_name = samsung_pinmux_get_fname,
|
||||
.get_function_groups = samsung_pinmux_get_groups,
|
||||
|
@ -468,7 +468,7 @@ static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
|
||||
static struct pinconf_ops samsung_pinconf_ops = {
|
||||
static const struct pinconf_ops samsung_pinconf_ops = {
|
||||
.pin_config_get = samsung_pinconf_get,
|
||||
.pin_config_set = samsung_pinconf_set,
|
||||
.pin_config_group_get = samsung_pinconf_group_get,
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "pinconf.h"
|
||||
|
||||
#define DRIVER_NAME "pinctrl-single"
|
||||
#define PCS_MUX_PINS_NAME "pinctrl-single,pins"
|
||||
|
@ -58,6 +60,33 @@ struct pcs_func_vals {
|
|||
unsigned mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pcs_conf_vals - pinconf parameter, pinconf register offset
|
||||
* and value, enable, disable, mask
|
||||
* @param: config parameter
|
||||
* @val: user input bits in the pinconf register
|
||||
* @enable: enable bits in the pinconf register
|
||||
* @disable: disable bits in the pinconf register
|
||||
* @mask: mask bits in the register value
|
||||
*/
|
||||
struct pcs_conf_vals {
|
||||
enum pin_config_param param;
|
||||
unsigned val;
|
||||
unsigned enable;
|
||||
unsigned disable;
|
||||
unsigned mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pcs_conf_type - pinconf property name, pinconf param pair
|
||||
* @name: property name in DTS file
|
||||
* @param: config parameter
|
||||
*/
|
||||
struct pcs_conf_type {
|
||||
const char *name;
|
||||
enum pin_config_param param;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pcs_function - pinctrl function
|
||||
* @name: pinctrl function name
|
||||
|
@ -73,6 +102,22 @@ struct pcs_function {
|
|||
unsigned nvals;
|
||||
const char **pgnames;
|
||||
int npgnames;
|
||||
struct pcs_conf_vals *conf;
|
||||
int nconfs;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pcs_gpiofunc_range - pin ranges with same mux value of gpio function
|
||||
* @offset: offset base of pins
|
||||
* @npins: number pins with the same mux value of gpio function
|
||||
* @gpiofunc: mux value of gpio function
|
||||
* @node: list node
|
||||
*/
|
||||
struct pcs_gpiofunc_range {
|
||||
unsigned offset;
|
||||
unsigned npins;
|
||||
unsigned gpiofunc;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
|
@ -117,12 +162,14 @@ struct pcs_name {
|
|||
* @fshift: function register shift
|
||||
* @foff: value to turn mux off
|
||||
* @fmax: max number of functions in fmask
|
||||
* @is_pinconf: whether supports pinconf
|
||||
* @names: array of register names for pins
|
||||
* @pins: physical pins on the SoC
|
||||
* @pgtree: pingroup index radix tree
|
||||
* @ftree: function index radix tree
|
||||
* @pingroups: list of pingroups
|
||||
* @functions: list of functions
|
||||
* @gpiofuncs: list of gpio functions
|
||||
* @ngroups: number of pingroups
|
||||
* @nfuncs: number of functions
|
||||
* @desc: pin controller descriptor
|
||||
|
@ -142,12 +189,14 @@ struct pcs_device {
|
|||
unsigned foff;
|
||||
unsigned fmax;
|
||||
bool bits_per_mux;
|
||||
bool is_pinconf;
|
||||
struct pcs_name *names;
|
||||
struct pcs_data pins;
|
||||
struct radix_tree_root pgtree;
|
||||
struct radix_tree_root ftree;
|
||||
struct list_head pingroups;
|
||||
struct list_head functions;
|
||||
struct list_head gpiofuncs;
|
||||
unsigned ngroups;
|
||||
unsigned nfuncs;
|
||||
struct pinctrl_desc desc;
|
||||
|
@ -155,6 +204,16 @@ struct pcs_device {
|
|||
void (*write)(unsigned val, void __iomem *reg);
|
||||
};
|
||||
|
||||
static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
|
||||
unsigned long *config);
|
||||
static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
|
||||
unsigned long config);
|
||||
|
||||
static enum pin_config_param pcs_bias[] = {
|
||||
PIN_CONFIG_BIAS_PULL_DOWN,
|
||||
PIN_CONFIG_BIAS_PULL_UP,
|
||||
};
|
||||
|
||||
/*
|
||||
* REVISIT: Reads and writes could eventually use regmap or something
|
||||
* generic. But at least on omaps, some mux registers are performance
|
||||
|
@ -270,7 +329,7 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|||
struct device_node *np_config,
|
||||
struct pinctrl_map **map, unsigned *num_maps);
|
||||
|
||||
static struct pinctrl_ops pcs_pinctrl_ops = {
|
||||
static const struct pinctrl_ops pcs_pinctrl_ops = {
|
||||
.get_groups_count = pcs_get_groups_count,
|
||||
.get_group_name = pcs_get_group_name,
|
||||
.get_group_pins = pcs_get_group_pins,
|
||||
|
@ -326,6 +385,28 @@ static int pcs_get_function_groups(struct pinctrl_dev *pctldev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin,
|
||||
struct pcs_function **func)
|
||||
{
|
||||
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct pin_desc *pdesc = pin_desc_get(pctldev, pin);
|
||||
const struct pinctrl_setting_mux *setting;
|
||||
unsigned fselector;
|
||||
|
||||
/* If pin is not described in DTS & enabled, mux_setting is NULL. */
|
||||
setting = pdesc->mux_setting;
|
||||
if (!setting)
|
||||
return -ENOTSUPP;
|
||||
fselector = setting->func;
|
||||
*func = radix_tree_lookup(&pcs->ftree, fselector);
|
||||
if (!(*func)) {
|
||||
dev_err(pcs->dev, "%s could not find function%i\n",
|
||||
__func__, fselector);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
|
||||
unsigned group)
|
||||
{
|
||||
|
@ -334,6 +415,9 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
|
|||
int i;
|
||||
|
||||
pcs = pinctrl_dev_get_drvdata(pctldev);
|
||||
/* If function mask is null, needn't enable it. */
|
||||
if (!pcs->fmask)
|
||||
return 0;
|
||||
func = radix_tree_lookup(&pcs->ftree, fselector);
|
||||
if (!func)
|
||||
return -EINVAL;
|
||||
|
@ -368,6 +452,10 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
|
|||
int i;
|
||||
|
||||
pcs = pinctrl_dev_get_drvdata(pctldev);
|
||||
/* If function mask is null, needn't disable it. */
|
||||
if (!pcs->fmask)
|
||||
return;
|
||||
|
||||
func = radix_tree_lookup(&pcs->ftree, fselector);
|
||||
if (!func) {
|
||||
dev_err(pcs->dev, "%s could not find function%i\n",
|
||||
|
@ -403,12 +491,33 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
|
|||
}
|
||||
|
||||
static int pcs_request_gpio(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range, unsigned offset)
|
||||
struct pinctrl_gpio_range *range, unsigned pin)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct pcs_gpiofunc_range *frange = NULL;
|
||||
struct list_head *pos, *tmp;
|
||||
int mux_bytes = 0;
|
||||
unsigned data;
|
||||
|
||||
/* If function mask is null, return directly. */
|
||||
if (!pcs->fmask)
|
||||
return -ENOTSUPP;
|
||||
|
||||
list_for_each_safe(pos, tmp, &pcs->gpiofuncs) {
|
||||
frange = list_entry(pos, struct pcs_gpiofunc_range, node);
|
||||
if (pin >= frange->offset + frange->npins
|
||||
|| pin < frange->offset)
|
||||
continue;
|
||||
mux_bytes = pcs->width / BITS_PER_BYTE;
|
||||
data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
|
||||
data |= frange->gpiofunc;
|
||||
pcs->write(data, pcs->base + pin * mux_bytes);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pinmux_ops pcs_pinmux_ops = {
|
||||
static const struct pinmux_ops pcs_pinmux_ops = {
|
||||
.get_functions_count = pcs_get_functions_count,
|
||||
.get_function_name = pcs_get_function_name,
|
||||
.get_function_groups = pcs_get_function_groups,
|
||||
|
@ -417,32 +526,191 @@ static struct pinmux_ops pcs_pinmux_ops = {
|
|||
.gpio_request_enable = pcs_request_gpio,
|
||||
};
|
||||
|
||||
/* Clear BIAS value */
|
||||
static void pcs_pinconf_clear_bias(struct pinctrl_dev *pctldev, unsigned pin)
|
||||
{
|
||||
unsigned long config;
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
|
||||
config = pinconf_to_config_packed(pcs_bias[i], 0);
|
||||
pcs_pinconf_set(pctldev, pin, config);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether PIN_CONFIG_BIAS_DISABLE is valid.
|
||||
* It's depend on that PULL_DOWN & PULL_UP configs are all invalid.
|
||||
*/
|
||||
static bool pcs_pinconf_bias_disable(struct pinctrl_dev *pctldev, unsigned pin)
|
||||
{
|
||||
unsigned long config;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
|
||||
config = pinconf_to_config_packed(pcs_bias[i], 0);
|
||||
if (!pcs_pinconf_get(pctldev, pin, &config))
|
||||
goto out;
|
||||
}
|
||||
return true;
|
||||
out:
|
||||
return false;
|
||||
}
|
||||
|
||||
static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
|
||||
unsigned pin, unsigned long *config)
|
||||
{
|
||||
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct pcs_function *func;
|
||||
enum pin_config_param param;
|
||||
unsigned offset = 0, data = 0, i, j, ret;
|
||||
|
||||
ret = pcs_get_function(pctldev, pin, &func);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < func->nconfs; i++) {
|
||||
param = pinconf_to_config_param(*config);
|
||||
if (param == PIN_CONFIG_BIAS_DISABLE) {
|
||||
if (pcs_pinconf_bias_disable(pctldev, pin)) {
|
||||
*config = 0;
|
||||
return 0;
|
||||
} else {
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
} else if (param != func->conf[i].param) {
|
||||
continue;
|
||||
}
|
||||
|
||||
offset = pin * (pcs->width / BITS_PER_BYTE);
|
||||
data = pcs->read(pcs->base + offset) & func->conf[i].mask;
|
||||
switch (func->conf[i].param) {
|
||||
/* 4 parameters */
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
||||
if ((data != func->conf[i].enable) ||
|
||||
(data == func->conf[i].disable))
|
||||
return -ENOTSUPP;
|
||||
*config = 0;
|
||||
break;
|
||||
/* 2 parameters */
|
||||
case PIN_CONFIG_INPUT_SCHMITT:
|
||||
for (j = 0; j < func->nconfs; j++) {
|
||||
switch (func->conf[j].param) {
|
||||
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
||||
if (data != func->conf[j].enable)
|
||||
return -ENOTSUPP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*config = data;
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||
case PIN_CONFIG_SLEW_RATE:
|
||||
default:
|
||||
*config = data;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
|
||||
unsigned pin, unsigned long config)
|
||||
{
|
||||
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct pcs_function *func;
|
||||
unsigned offset = 0, shift = 0, arg = 0, i, data, ret;
|
||||
u16 argument;
|
||||
|
||||
ret = pcs_get_function(pctldev, pin, &func);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < func->nconfs; i++) {
|
||||
if (pinconf_to_config_param(config) == func->conf[i].param) {
|
||||
offset = pin * (pcs->width / BITS_PER_BYTE);
|
||||
data = pcs->read(pcs->base + offset);
|
||||
argument = pinconf_to_config_argument(config);
|
||||
switch (func->conf[i].param) {
|
||||
/* 2 parameters */
|
||||
case PIN_CONFIG_INPUT_SCHMITT:
|
||||
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||
case PIN_CONFIG_SLEW_RATE:
|
||||
shift = ffs(func->conf[i].mask) - 1;
|
||||
arg = pinconf_to_config_argument(config);
|
||||
data &= ~func->conf[i].mask;
|
||||
data |= (arg << shift) & func->conf[i].mask;
|
||||
break;
|
||||
/* 4 parameters */
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
pcs_pinconf_clear_bias(pctldev, pin);
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
if (argument)
|
||||
pcs_pinconf_clear_bias(pctldev, pin);
|
||||
/* fall through */
|
||||
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
||||
data &= ~func->conf[i].mask;
|
||||
if (argument)
|
||||
data |= func->conf[i].enable;
|
||||
else
|
||||
data |= func->conf[i].disable;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
pcs->write(data, pcs->base + offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
|
||||
unsigned group, unsigned long *config)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
const unsigned *pins;
|
||||
unsigned npins, old = 0;
|
||||
int i, ret;
|
||||
|
||||
ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (i = 0; i < npins; i++) {
|
||||
if (pcs_pinconf_get(pctldev, pins[i], config))
|
||||
return -ENOTSUPP;
|
||||
/* configs do not match between two pins */
|
||||
if (i && (old != *config))
|
||||
return -ENOTSUPP;
|
||||
old = *config;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
|
||||
unsigned group, unsigned long config)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
const unsigned *pins;
|
||||
unsigned npins;
|
||||
int i, ret;
|
||||
|
||||
ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (i = 0; i < npins; i++) {
|
||||
if (pcs_pinconf_set(pctldev, pins[i], config))
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcs_pinconf_dbg_show(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s, unsigned offset)
|
||||
struct seq_file *s, unsigned pin)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -451,13 +719,22 @@ static void pcs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
|
|||
{
|
||||
}
|
||||
|
||||
static struct pinconf_ops pcs_pinconf_ops = {
|
||||
static void pcs_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s,
|
||||
unsigned long config)
|
||||
{
|
||||
pinconf_generic_dump_config(pctldev, s, config);
|
||||
}
|
||||
|
||||
static const struct pinconf_ops pcs_pinconf_ops = {
|
||||
.pin_config_get = pcs_pinconf_get,
|
||||
.pin_config_set = pcs_pinconf_set,
|
||||
.pin_config_group_get = pcs_pinconf_group_get,
|
||||
.pin_config_group_set = pcs_pinconf_group_set,
|
||||
.pin_config_dbg_show = pcs_pinconf_dbg_show,
|
||||
.pin_config_group_dbg_show = pcs_pinconf_group_dbg_show,
|
||||
.pin_config_config_dbg_show = pcs_pinconf_config_dbg_show,
|
||||
.is_generic = true,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -648,11 +925,157 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
|
|||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* check whether data matches enable bits or disable bits
|
||||
* Return value: 1 for matching enable bits, 0 for matching disable bits,
|
||||
* and negative value for matching failure.
|
||||
*/
|
||||
static int pcs_config_match(unsigned data, unsigned enable, unsigned disable)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (data == enable)
|
||||
ret = 1;
|
||||
else if (data == disable)
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void add_config(struct pcs_conf_vals **conf, enum pin_config_param param,
|
||||
unsigned value, unsigned enable, unsigned disable,
|
||||
unsigned mask)
|
||||
{
|
||||
(*conf)->param = param;
|
||||
(*conf)->val = value;
|
||||
(*conf)->enable = enable;
|
||||
(*conf)->disable = disable;
|
||||
(*conf)->mask = mask;
|
||||
(*conf)++;
|
||||
}
|
||||
|
||||
static void add_setting(unsigned long **setting, enum pin_config_param param,
|
||||
unsigned arg)
|
||||
{
|
||||
**setting = pinconf_to_config_packed(param, arg);
|
||||
(*setting)++;
|
||||
}
|
||||
|
||||
/* add pinconf setting with 2 parameters */
|
||||
static void pcs_add_conf2(struct pcs_device *pcs, struct device_node *np,
|
||||
const char *name, enum pin_config_param param,
|
||||
struct pcs_conf_vals **conf, unsigned long **settings)
|
||||
{
|
||||
unsigned value[2];
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32_array(np, name, value, 2);
|
||||
if (ret)
|
||||
return;
|
||||
/* set value & mask */
|
||||
value[0] &= value[1];
|
||||
/* skip enable & disable */
|
||||
add_config(conf, param, value[0], 0, 0, value[1]);
|
||||
add_setting(settings, param, value[0]);
|
||||
}
|
||||
|
||||
/* add pinconf setting with 4 parameters */
|
||||
static void pcs_add_conf4(struct pcs_device *pcs, struct device_node *np,
|
||||
const char *name, enum pin_config_param param,
|
||||
struct pcs_conf_vals **conf, unsigned long **settings)
|
||||
{
|
||||
unsigned value[4];
|
||||
int ret;
|
||||
|
||||
/* value to set, enable, disable, mask */
|
||||
ret = of_property_read_u32_array(np, name, value, 4);
|
||||
if (ret)
|
||||
return;
|
||||
if (!value[3]) {
|
||||
dev_err(pcs->dev, "mask field of the property can't be 0\n");
|
||||
return;
|
||||
}
|
||||
value[0] &= value[3];
|
||||
value[1] &= value[3];
|
||||
value[2] &= value[3];
|
||||
ret = pcs_config_match(value[0], value[1], value[2]);
|
||||
if (ret < 0)
|
||||
dev_dbg(pcs->dev, "failed to match enable or disable bits\n");
|
||||
add_config(conf, param, value[0], value[1], value[2], value[3]);
|
||||
add_setting(settings, param, ret);
|
||||
}
|
||||
|
||||
static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
|
||||
struct pcs_function *func,
|
||||
struct pinctrl_map **map)
|
||||
|
||||
{
|
||||
struct pinctrl_map *m = *map;
|
||||
int i = 0, nconfs = 0;
|
||||
unsigned long *settings = NULL, *s = NULL;
|
||||
struct pcs_conf_vals *conf = NULL;
|
||||
struct pcs_conf_type prop2[] = {
|
||||
{ "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
|
||||
{ "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
|
||||
{ "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
|
||||
};
|
||||
struct pcs_conf_type prop4[] = {
|
||||
{ "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
|
||||
{ "pinctrl-single,bias-pulldown", PIN_CONFIG_BIAS_PULL_DOWN, },
|
||||
{ "pinctrl-single,input-schmitt-enable",
|
||||
PIN_CONFIG_INPUT_SCHMITT_ENABLE, },
|
||||
};
|
||||
|
||||
/* If pinconf isn't supported, don't parse properties in below. */
|
||||
if (!pcs->is_pinconf)
|
||||
return 0;
|
||||
|
||||
/* cacluate how much properties are supported in current node */
|
||||
for (i = 0; i < ARRAY_SIZE(prop2); i++) {
|
||||
if (of_find_property(np, prop2[i].name, NULL))
|
||||
nconfs++;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(prop4); i++) {
|
||||
if (of_find_property(np, prop4[i].name, NULL))
|
||||
nconfs++;
|
||||
}
|
||||
if (!nconfs)
|
||||
return 0;
|
||||
|
||||
func->conf = devm_kzalloc(pcs->dev,
|
||||
sizeof(struct pcs_conf_vals) * nconfs,
|
||||
GFP_KERNEL);
|
||||
if (!func->conf)
|
||||
return -ENOMEM;
|
||||
func->nconfs = nconfs;
|
||||
conf = &(func->conf[0]);
|
||||
m++;
|
||||
settings = devm_kzalloc(pcs->dev, sizeof(unsigned long) * nconfs,
|
||||
GFP_KERNEL);
|
||||
if (!settings)
|
||||
return -ENOMEM;
|
||||
s = &settings[0];
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(prop2); i++)
|
||||
pcs_add_conf2(pcs, np, prop2[i].name, prop2[i].param,
|
||||
&conf, &s);
|
||||
for (i = 0; i < ARRAY_SIZE(prop4); i++)
|
||||
pcs_add_conf4(pcs, np, prop4[i].name, prop4[i].param,
|
||||
&conf, &s);
|
||||
m->type = PIN_MAP_TYPE_CONFIGS_GROUP;
|
||||
m->data.configs.group_or_pin = np->name;
|
||||
m->data.configs.configs = settings;
|
||||
m->data.configs.num_configs = nconfs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcs_free_pingroups(struct pcs_device *pcs);
|
||||
|
||||
/**
|
||||
* smux_parse_one_pinctrl_entry() - parses a device tree mux entry
|
||||
* @pcs: pinctrl driver instance
|
||||
* @np: device node of the mux entry
|
||||
* @map: map entry
|
||||
* @num_maps: number of map
|
||||
* @pgnames: pingroup names
|
||||
*
|
||||
* Note that this binding currently supports only sets of one register + value.
|
||||
|
@ -669,6 +1092,7 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
|
|||
static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
|
||||
struct device_node *np,
|
||||
struct pinctrl_map **map,
|
||||
unsigned *num_maps,
|
||||
const char **pgnames)
|
||||
{
|
||||
struct pcs_func_vals *vals;
|
||||
|
@ -741,8 +1165,18 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
|
|||
(*map)->data.mux.group = np->name;
|
||||
(*map)->data.mux.function = np->name;
|
||||
|
||||
if (pcs->is_pinconf) {
|
||||
if (pcs_parse_pinconf(pcs, np, function, map))
|
||||
goto free_pingroups;
|
||||
*num_maps = 2;
|
||||
} else {
|
||||
*num_maps = 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
free_pingroups:
|
||||
pcs_free_pingroups(pcs);
|
||||
*num_maps = 1;
|
||||
free_function:
|
||||
pcs_remove_function(pcs, function);
|
||||
|
||||
|
@ -771,7 +1205,8 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|||
|
||||
pcs = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
*map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL);
|
||||
/* create 2 maps. One is for pinmux, and the other is for pinconf. */
|
||||
*map = devm_kzalloc(pcs->dev, sizeof(**map) * 2, GFP_KERNEL);
|
||||
if (!*map)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -783,13 +1218,13 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|||
goto free_map;
|
||||
}
|
||||
|
||||
ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, pgnames);
|
||||
ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps,
|
||||
pgnames);
|
||||
if (ret < 0) {
|
||||
dev_err(pcs->dev, "no pins entries for %s\n",
|
||||
np_config->name);
|
||||
goto free_pgnames;
|
||||
}
|
||||
*num_maps = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -879,6 +1314,37 @@ static void pcs_free_resources(struct pcs_device *pcs)
|
|||
|
||||
static struct of_device_id pcs_of_match[];
|
||||
|
||||
static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
|
||||
{
|
||||
const char *propname = "pinctrl-single,gpio-range";
|
||||
const char *cellname = "#pinctrl-single,gpio-range-cells";
|
||||
struct of_phandle_args gpiospec;
|
||||
struct pcs_gpiofunc_range *range;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
ret = of_parse_phandle_with_args(node, propname, cellname,
|
||||
i, &gpiospec);
|
||||
/* Do not treat it as error. Only treat it as end condition. */
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL);
|
||||
if (!range) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
range->offset = gpiospec.args[0];
|
||||
range->npins = gpiospec.args[1];
|
||||
range->gpiofunc = gpiospec.args[2];
|
||||
mutex_lock(&pcs->mutex);
|
||||
list_add_tail(&range->node, &pcs->gpiofuncs);
|
||||
mutex_unlock(&pcs->mutex);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcs_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
@ -900,14 +1366,23 @@ static int pcs_probe(struct platform_device *pdev)
|
|||
mutex_init(&pcs->mutex);
|
||||
INIT_LIST_HEAD(&pcs->pingroups);
|
||||
INIT_LIST_HEAD(&pcs->functions);
|
||||
INIT_LIST_HEAD(&pcs->gpiofuncs);
|
||||
pcs->is_pinconf = match->data;
|
||||
|
||||
PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width,
|
||||
"register width not specified\n");
|
||||
|
||||
PCS_GET_PROP_U32("pinctrl-single,function-mask", &pcs->fmask,
|
||||
"function register mask not specified\n");
|
||||
pcs->fshift = ffs(pcs->fmask) - 1;
|
||||
pcs->fmax = pcs->fmask >> pcs->fshift;
|
||||
ret = of_property_read_u32(np, "pinctrl-single,function-mask",
|
||||
&pcs->fmask);
|
||||
if (!ret) {
|
||||
pcs->fshift = ffs(pcs->fmask) - 1;
|
||||
pcs->fmax = pcs->fmask >> pcs->fshift;
|
||||
} else {
|
||||
/* If mask property doesn't exist, function mux is invalid. */
|
||||
pcs->fmask = 0;
|
||||
pcs->fshift = 0;
|
||||
pcs->fmax = 0;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "pinctrl-single,function-off",
|
||||
&pcs->foff);
|
||||
|
@ -961,7 +1436,8 @@ static int pcs_probe(struct platform_device *pdev)
|
|||
pcs->desc.name = DRIVER_NAME;
|
||||
pcs->desc.pctlops = &pcs_pinctrl_ops;
|
||||
pcs->desc.pmxops = &pcs_pinmux_ops;
|
||||
pcs->desc.confops = &pcs_pinconf_ops;
|
||||
if (pcs->is_pinconf)
|
||||
pcs->desc.confops = &pcs_pinconf_ops;
|
||||
pcs->desc.owner = THIS_MODULE;
|
||||
|
||||
ret = pcs_allocate_pin_table(pcs);
|
||||
|
@ -975,6 +1451,10 @@ static int pcs_probe(struct platform_device *pdev)
|
|||
goto free;
|
||||
}
|
||||
|
||||
ret = pcs_add_gpio_func(np, pcs);
|
||||
if (ret < 0)
|
||||
goto free;
|
||||
|
||||
dev_info(pcs->dev, "%i pins at pa %p size %u\n",
|
||||
pcs->desc.npins, pcs->base, pcs->size);
|
||||
|
||||
|
@ -999,7 +1479,8 @@ static int pcs_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static struct of_device_id pcs_of_match[] = {
|
||||
{ .compatible = DRIVER_NAME, },
|
||||
{ .compatible = "pinctrl-single", .data = (void *)false },
|
||||
{ .compatible = "pinconf-single", .data = (void *)true },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pcs_of_match);
|
||||
|
|
|
@ -979,7 +979,7 @@ static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev,
|
|||
kfree(map);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops sirfsoc_pctrl_ops = {
|
||||
static const struct pinctrl_ops sirfsoc_pctrl_ops = {
|
||||
.get_groups_count = sirfsoc_get_groups_count,
|
||||
.get_group_name = sirfsoc_get_group_name,
|
||||
.get_group_pins = sirfsoc_get_group_pins,
|
||||
|
@ -1181,7 +1181,7 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinmux_ops sirfsoc_pinmux_ops = {
|
||||
static const struct pinmux_ops sirfsoc_pinmux_ops = {
|
||||
.enable = sirfsoc_pinmux_enable,
|
||||
.disable = sirfsoc_pinmux_disable,
|
||||
.get_functions_count = sirfsoc_pinmux_get_funcs_count,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -316,7 +316,7 @@ static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops tegra_pinctrl_ops = {
|
||||
static const struct pinctrl_ops tegra_pinctrl_ops = {
|
||||
.get_groups_count = tegra_pinctrl_get_groups_count,
|
||||
.get_group_name = tegra_pinctrl_get_group_name,
|
||||
.get_group_pins = tegra_pinctrl_get_group_pins,
|
||||
|
@ -401,7 +401,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
|
|||
pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
|
||||
}
|
||||
|
||||
static struct pinmux_ops tegra_pinmux_ops = {
|
||||
static const struct pinmux_ops tegra_pinmux_ops = {
|
||||
.get_functions_count = tegra_pinctrl_get_funcs_count,
|
||||
.get_function_name = tegra_pinctrl_get_func_name,
|
||||
.get_function_groups = tegra_pinctrl_get_func_groups,
|
||||
|
@ -676,7 +676,7 @@ static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct pinconf_ops tegra_pinconf_ops = {
|
||||
static const struct pinconf_ops tegra_pinconf_ops = {
|
||||
.pin_config_get = tegra_pinconf_get,
|
||||
.pin_config_set = tegra_pinconf_set,
|
||||
.pin_config_group_get = tegra_pinconf_group_get,
|
||||
|
|
|
@ -860,7 +860,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
|
|||
seq_printf(s, " " DRIVER_NAME);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops u300_pctrl_ops = {
|
||||
static const struct pinctrl_ops u300_pctrl_ops = {
|
||||
.get_groups_count = u300_get_groups_count,
|
||||
.get_group_name = u300_get_group_name,
|
||||
.get_group_pins = u300_get_group_pins,
|
||||
|
@ -1003,7 +1003,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinmux_ops u300_pmx_ops = {
|
||||
static const struct pinmux_ops u300_pmx_ops = {
|
||||
.get_functions_count = u300_pmx_get_funcs_count,
|
||||
.get_function_name = u300_pmx_get_func_name,
|
||||
.get_function_groups = u300_pmx_get_groups,
|
||||
|
@ -1046,7 +1046,7 @@ static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pinconf_ops u300_pconf_ops = {
|
||||
static const struct pinconf_ops u300_pconf_ops = {
|
||||
.is_generic = true,
|
||||
.pin_config_get = u300_pin_config_get,
|
||||
.pin_config_set = u300_pin_config_set,
|
||||
|
|
|
@ -553,7 +553,7 @@ int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct pinconf_ops xway_pinconf_ops = {
|
||||
static const struct pinconf_ops xway_pinconf_ops = {
|
||||
.pin_config_get = xway_pinconf_get,
|
||||
.pin_config_set = xway_pinconf_set,
|
||||
.pin_config_group_set = xway_pinconf_group_set,
|
||||
|
|
|
@ -198,7 +198,7 @@ static void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
|
|||
kfree(map);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops spear_pinctrl_ops = {
|
||||
static const struct pinctrl_ops spear_pinctrl_ops = {
|
||||
.get_groups_count = spear_pinctrl_get_groups_cnt,
|
||||
.get_group_name = spear_pinctrl_get_group_name,
|
||||
.get_group_pins = spear_pinctrl_get_group_pins,
|
||||
|
@ -340,7 +340,7 @@ static void gpio_disable_free(struct pinctrl_dev *pctldev,
|
|||
gpio_request_endisable(pctldev, range, offset, false);
|
||||
}
|
||||
|
||||
static struct pinmux_ops spear_pinmux_ops = {
|
||||
static const struct pinmux_ops spear_pinmux_ops = {
|
||||
.get_functions_count = spear_pinctrl_get_funcs_count,
|
||||
.get_function_name = spear_pinctrl_get_func_name,
|
||||
.get_function_groups = spear_pinctrl_get_func_groups,
|
||||
|
|
|
@ -118,9 +118,9 @@ struct pinctrl_desc {
|
|||
const char *name;
|
||||
struct pinctrl_pin_desc const *pins;
|
||||
unsigned int npins;
|
||||
struct pinctrl_ops *pctlops;
|
||||
struct pinmux_ops *pmxops;
|
||||
struct pinconf_ops *confops;
|
||||
const struct pinctrl_ops *pctlops;
|
||||
const struct pinmux_ops *pmxops;
|
||||
const struct pinconf_ops *confops;
|
||||
struct module *owner;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue