Merge commit 'pinctrl/devel 4ddb1c2' into spear-for-3.8
This merges dependency branch pinctrl/devel for SPEAr DT updates.
This commit is contained in:
commit
22595e2815
|
@ -75,4 +75,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
|
|||
gpio-controller;
|
||||
};
|
||||
|
||||
2.1) gpio-controller and pinctrl subsystem
|
||||
------------------------------------------
|
||||
|
||||
gpio-controller on a SOC might be tightly coupled with the pinctrl
|
||||
subsystem, in the sense that the pins can be used by other functions
|
||||
together with optional gpio feature.
|
||||
|
||||
While the pin allocation is totally managed by the pin ctrl subsystem,
|
||||
gpio (under gpiolib) is still maintained by gpio drivers. It may happen
|
||||
that different pin ranges in a SoC is managed by different gpio drivers.
|
||||
|
||||
This makes it logical to let gpio drivers announce their pin ranges to
|
||||
the pin ctrl subsystem and call 'pinctrl_request_gpio' in order to
|
||||
request the corresponding pin before any gpio usage.
|
||||
|
||||
For this, the gpio controller can use a pinctrl phandle and pins to
|
||||
announce the pinrange to the pin ctrl subsystem. For example,
|
||||
|
||||
qe_pio_e: gpio-controller@1460 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
|
||||
reg = <0x1460 0x18>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>;
|
||||
|
||||
}
|
||||
|
||||
where,
|
||||
&pinctrl1 and &pinctrl2 is the phandle to the pinctrl DT node.
|
||||
|
||||
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.
|
||||
|
||||
The pinctrl node must have "#gpio-range-cells" property to show number of
|
||||
arguments to pass with phandle from gpio controllers node.
|
||||
|
|
|
@ -439,6 +439,48 @@ slower clock delays the rising edge of SCK, and the I2C master adjusts its
|
|||
signaling rate accordingly.
|
||||
|
||||
|
||||
GPIO controllers and the pinctrl subsystem
|
||||
------------------------------------------
|
||||
|
||||
A GPIO controller on a SOC might be tightly coupled with the pinctrl
|
||||
subsystem, in the sense that the pins can be used by other functions
|
||||
together with an optional gpio feature. We have already covered the
|
||||
case where e.g. a GPIO controller need to reserve a pin or set the
|
||||
direction of a pin by calling any of:
|
||||
|
||||
pinctrl_request_gpio()
|
||||
pinctrl_free_gpio()
|
||||
pinctrl_gpio_direction_input()
|
||||
pinctrl_gpio_direction_output()
|
||||
|
||||
But how does the pin control subsystem cross-correlate the GPIO
|
||||
numbers (which are a global business) to a certain pin on a certain
|
||||
pin controller?
|
||||
|
||||
This is done by registering "ranges" of pins, which are essentially
|
||||
cross-reference tables. These are described in
|
||||
Documentation/pinctrl.txt
|
||||
|
||||
While the pin allocation is totally managed by the pinctrl subsystem,
|
||||
gpio (under gpiolib) is still maintained by gpio drivers. It may happen
|
||||
that different pin ranges in a SoC is managed by different gpio drivers.
|
||||
|
||||
This makes it logical to let gpio drivers announce their pin ranges to
|
||||
the pin ctrl subsystem before it will call 'pinctrl_request_gpio' in order
|
||||
to request the corresponding pin to be prepared by the pinctrl subsystem
|
||||
before any gpio usage.
|
||||
|
||||
For this, the gpio controller can register its pin range with pinctrl
|
||||
subsystem. There are two ways of doing it currently: with or without DT.
|
||||
|
||||
For with DT support refer to Documentation/devicetree/bindings/gpio/gpio.txt.
|
||||
|
||||
For non-DT support, user can call gpiochip_add_pin_range() with appropriate
|
||||
parameters to register a range of gpio pins with a pinctrl driver. For this
|
||||
exact name string of pinctrl device has to be passed as one of the
|
||||
argument to this routine.
|
||||
|
||||
|
||||
What do these conventions omit?
|
||||
===============================
|
||||
One of the biggest things these conventions omit is pin multiplexing, since
|
||||
|
|
|
@ -364,6 +364,9 @@ will get an pin number into its handled number range. Further it is also passed
|
|||
the range ID value, so that the pin controller knows which range it should
|
||||
deal with.
|
||||
|
||||
Calling pinctrl_add_gpio_range from pinctrl driver is DEPRECATED. Please see
|
||||
section 2.1 of Documentation/devicetree/bindings/gpio/gpio.txt on how to bind
|
||||
pinctrl and gpio drivers.
|
||||
|
||||
PINMUX interfaces
|
||||
=================
|
||||
|
@ -1193,4 +1196,6 @@ foo_switch()
|
|||
...
|
||||
}
|
||||
|
||||
The above has to be done from process context.
|
||||
The above has to be done from process context. The reservation of the pins
|
||||
will be done when the state is activated, so in effect one specific pin
|
||||
can be used by different functions at different times on a running system.
|
||||
|
|
|
@ -181,6 +181,10 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
gpio@d8400000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
i2c0: i2c@e0280000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -70,6 +70,12 @@
|
|||
status = "disabled";
|
||||
};
|
||||
|
||||
pinmux: pinmux@e0700000 {
|
||||
compatible = "st,spear1310-pinmux";
|
||||
reg = <0xe0700000 0x1000>;
|
||||
#gpio-range-cells = <2>;
|
||||
};
|
||||
|
||||
spi1: spi@5d400000 {
|
||||
compatible = "arm,pl022", "arm,primecell";
|
||||
reg = <0x5d400000 0x1000>;
|
||||
|
@ -179,6 +185,27 @@
|
|||
thermal@e07008c4 {
|
||||
st,thermal-flags = <0x7000>;
|
||||
};
|
||||
|
||||
gpiopinctrl: gpio@d8400000 {
|
||||
compatible = "st,spear-plgpio";
|
||||
reg = <0xd8400000 0x1000>;
|
||||
interrupts = <0 100 0x4>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinmux 0 246>;
|
||||
status = "disabled";
|
||||
|
||||
st-plgpio,ngpio = <246>;
|
||||
st-plgpio,enb-reg = <0xd0>;
|
||||
st-plgpio,wdata-reg = <0x90>;
|
||||
st-plgpio,dir-reg = <0xb0>;
|
||||
st-plgpio,ie-reg = <0x30>;
|
||||
st-plgpio,rdata-reg = <0x70>;
|
||||
st-plgpio,mis-reg = <0x10>;
|
||||
st-plgpio,eit-reg = <0x50>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -193,6 +193,10 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
gpio@e2800000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
i2c0: i2c@e0280000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
status = "disabled";
|
||||
};
|
||||
|
||||
pinmux: pinmux@e0700000 {
|
||||
compatible = "st,spear1340-pinmux";
|
||||
reg = <0xe0700000 0x1000>;
|
||||
#gpio-range-cells = <2>;
|
||||
};
|
||||
|
||||
spi1: spi@5d400000 {
|
||||
compatible = "arm,pl022", "arm,primecell";
|
||||
reg = <0x5d400000 0x1000>;
|
||||
|
@ -51,6 +57,26 @@
|
|||
thermal@e07008c4 {
|
||||
st,thermal-flags = <0x2a00>;
|
||||
};
|
||||
|
||||
gpiopinctrl: gpio@e2800000 {
|
||||
compatible = "st,spear-plgpio";
|
||||
reg = <0xe2800000 0x1000>;
|
||||
interrupts = <0 107 0x4>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinmux 0 252>;
|
||||
status = "disabled";
|
||||
|
||||
st-plgpio,ngpio = <250>;
|
||||
st-plgpio,wdata-reg = <0x40>;
|
||||
st-plgpio,dir-reg = <0x00>;
|
||||
st-plgpio,ie-reg = <0x80>;
|
||||
st-plgpio,rdata-reg = <0x20>;
|
||||
st-plgpio,mis-reg = <0xa0>;
|
||||
st-plgpio,eit-reg = <0x60>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -22,9 +22,10 @@
|
|||
0xb0000000 0xb0000000 0x10000000
|
||||
0xd0000000 0xd0000000 0x30000000>;
|
||||
|
||||
pinmux@b4000000 {
|
||||
pinmux: pinmux@b4000000 {
|
||||
compatible = "st,spear310-pinmux";
|
||||
reg = <0xb4000000 0x1000>;
|
||||
#gpio-range-cells = <2>;
|
||||
};
|
||||
|
||||
fsmc: flash@44000000 {
|
||||
|
@ -75,6 +76,25 @@
|
|||
reg = <0xb2200000 0x1000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gpiopinctrl: gpio@b4000000 {
|
||||
compatible = "st,spear-plgpio";
|
||||
reg = <0xb4000000 0x1000>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinmux 0 102>;
|
||||
status = "disabled";
|
||||
|
||||
st-plgpio,ngpio = <102>;
|
||||
st-plgpio,enb-reg = <0x10>;
|
||||
st-plgpio,wdata-reg = <0x20>;
|
||||
st-plgpio,dir-reg = <0x30>;
|
||||
st-plgpio,ie-reg = <0x50>;
|
||||
st-plgpio,rdata-reg = <0x40>;
|
||||
st-plgpio,mis-reg = <0x60>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
gpio@b3000000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
i2c0: i2c@d0180000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
ranges = <0x40000000 0x40000000 0x80000000
|
||||
0xd0000000 0xd0000000 0x30000000>;
|
||||
|
||||
pinmux@b3000000 {
|
||||
pinmux: pinmux@b3000000 {
|
||||
compatible = "st,spear320-pinmux";
|
||||
reg = <0xb3000000 0x1000>;
|
||||
#gpio-range-cells = <2>;
|
||||
};
|
||||
|
||||
clcd@90000000 {
|
||||
|
@ -90,6 +91,26 @@
|
|||
reg = <0xa4000000 0x1000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gpiopinctrl: gpio@b3000000 {
|
||||
compatible = "st,spear-plgpio";
|
||||
reg = <0xb3000000 0x1000>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinmux 0 102>;
|
||||
status = "disabled";
|
||||
|
||||
st-plgpio,ngpio = <102>;
|
||||
st-plgpio,enb-reg = <0x24>;
|
||||
st-plgpio,wdata-reg = <0x34>;
|
||||
st-plgpio,dir-reg = <0x44>;
|
||||
st-plgpio,ie-reg = <0x64>;
|
||||
st-plgpio,rdata-reg = <0x54>;
|
||||
st-plgpio,mis-reg = <0x84>;
|
||||
st-plgpio,eit-reg = <0x94>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1445,7 +1445,6 @@ static struct platform_device pinctrl_device = {
|
|||
static struct u300_gpio_platform u300_gpio_plat = {
|
||||
.ports = 7,
|
||||
.gpio_base = 0,
|
||||
.gpio_irq_base = IRQ_U300_GPIO_BASE,
|
||||
.pinctrl_device = &pinctrl_device,
|
||||
};
|
||||
|
||||
|
@ -1804,7 +1803,7 @@ MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board")
|
|||
/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
|
||||
.atag_offset = 0x100,
|
||||
.map_io = u300_map_io,
|
||||
.nr_irqs = NR_IRQS_U300,
|
||||
.nr_irqs = 0,
|
||||
.init_irq = u300_init_irq,
|
||||
.handle_irq = vic_handle_irq,
|
||||
.timer = &u300_timer,
|
||||
|
|
|
@ -12,79 +12,69 @@
|
|||
#ifndef __MACH_IRQS_H
|
||||
#define __MACH_IRQS_H
|
||||
|
||||
#define IRQ_U300_INTCON0_START 1
|
||||
#define IRQ_U300_INTCON1_START 33
|
||||
#define IRQ_U300_INTCON0_START 32
|
||||
#define IRQ_U300_INTCON1_START 64
|
||||
/* These are on INTCON0 - 30 lines */
|
||||
#define IRQ_U300_IRQ0_EXT 1
|
||||
#define IRQ_U300_IRQ1_EXT 2
|
||||
#define IRQ_U300_DMA 3
|
||||
#define IRQ_U300_VIDEO_ENC_0 4
|
||||
#define IRQ_U300_VIDEO_ENC_1 5
|
||||
#define IRQ_U300_AAIF_RX 6
|
||||
#define IRQ_U300_AAIF_TX 7
|
||||
#define IRQ_U300_AAIF_VGPIO 8
|
||||
#define IRQ_U300_AAIF_WAKEUP 9
|
||||
#define IRQ_U300_PCM_I2S0_FRAME 10
|
||||
#define IRQ_U300_PCM_I2S0_FIFO 11
|
||||
#define IRQ_U300_PCM_I2S1_FRAME 12
|
||||
#define IRQ_U300_PCM_I2S1_FIFO 13
|
||||
#define IRQ_U300_XGAM_GAMCON 14
|
||||
#define IRQ_U300_XGAM_CDI 15
|
||||
#define IRQ_U300_XGAM_CDICON 16
|
||||
#define IRQ_U300_XGAM_PDI 18
|
||||
#define IRQ_U300_XGAM_PDICON 19
|
||||
#define IRQ_U300_XGAM_GAMEACC 20
|
||||
#define IRQ_U300_XGAM_MCIDCT 21
|
||||
#define IRQ_U300_APEX 22
|
||||
#define IRQ_U300_UART0 23
|
||||
#define IRQ_U300_SPI 24
|
||||
#define IRQ_U300_TIMER_APP_OS 25
|
||||
#define IRQ_U300_TIMER_APP_DD 26
|
||||
#define IRQ_U300_TIMER_APP_GP1 27
|
||||
#define IRQ_U300_TIMER_APP_GP2 28
|
||||
#define IRQ_U300_TIMER_OS 29
|
||||
#define IRQ_U300_TIMER_MS 30
|
||||
#define IRQ_U300_KEYPAD_KEYBF 31
|
||||
#define IRQ_U300_KEYPAD_KEYBR 32
|
||||
#define IRQ_U300_IRQ0_EXT 32
|
||||
#define IRQ_U300_IRQ1_EXT 33
|
||||
#define IRQ_U300_DMA 34
|
||||
#define IRQ_U300_VIDEO_ENC_0 35
|
||||
#define IRQ_U300_VIDEO_ENC_1 36
|
||||
#define IRQ_U300_AAIF_RX 37
|
||||
#define IRQ_U300_AAIF_TX 38
|
||||
#define IRQ_U300_AAIF_VGPIO 39
|
||||
#define IRQ_U300_AAIF_WAKEUP 40
|
||||
#define IRQ_U300_PCM_I2S0_FRAME 41
|
||||
#define IRQ_U300_PCM_I2S0_FIFO 42
|
||||
#define IRQ_U300_PCM_I2S1_FRAME 43
|
||||
#define IRQ_U300_PCM_I2S1_FIFO 44
|
||||
#define IRQ_U300_XGAM_GAMCON 45
|
||||
#define IRQ_U300_XGAM_CDI 46
|
||||
#define IRQ_U300_XGAM_CDICON 47
|
||||
#define IRQ_U300_XGAM_PDI 49
|
||||
#define IRQ_U300_XGAM_PDICON 50
|
||||
#define IRQ_U300_XGAM_GAMEACC 51
|
||||
#define IRQ_U300_XGAM_MCIDCT 52
|
||||
#define IRQ_U300_APEX 53
|
||||
#define IRQ_U300_UART0 54
|
||||
#define IRQ_U300_SPI 55
|
||||
#define IRQ_U300_TIMER_APP_OS 56
|
||||
#define IRQ_U300_TIMER_APP_DD 57
|
||||
#define IRQ_U300_TIMER_APP_GP1 58
|
||||
#define IRQ_U300_TIMER_APP_GP2 59
|
||||
#define IRQ_U300_TIMER_OS 60
|
||||
#define IRQ_U300_TIMER_MS 61
|
||||
#define IRQ_U300_KEYPAD_KEYBF 62
|
||||
#define IRQ_U300_KEYPAD_KEYBR 63
|
||||
/* These are on INTCON1 - 32 lines */
|
||||
#define IRQ_U300_GPIO_PORT0 33
|
||||
#define IRQ_U300_GPIO_PORT1 34
|
||||
#define IRQ_U300_GPIO_PORT2 35
|
||||
#define IRQ_U300_GPIO_PORT0 64
|
||||
#define IRQ_U300_GPIO_PORT1 65
|
||||
#define IRQ_U300_GPIO_PORT2 66
|
||||
|
||||
/* These are for DB3150, DB3200 and DB3350 */
|
||||
#define IRQ_U300_WDOG 36
|
||||
#define IRQ_U300_EVHIST 37
|
||||
#define IRQ_U300_MSPRO 38
|
||||
#define IRQ_U300_MMCSD_MCIINTR0 39
|
||||
#define IRQ_U300_MMCSD_MCIINTR1 40
|
||||
#define IRQ_U300_I2C0 41
|
||||
#define IRQ_U300_I2C1 42
|
||||
#define IRQ_U300_RTC 43
|
||||
#define IRQ_U300_NFIF 44
|
||||
#define IRQ_U300_NFIF2 45
|
||||
#define IRQ_U300_WDOG 67
|
||||
#define IRQ_U300_EVHIST 68
|
||||
#define IRQ_U300_MSPRO 69
|
||||
#define IRQ_U300_MMCSD_MCIINTR0 70
|
||||
#define IRQ_U300_MMCSD_MCIINTR1 71
|
||||
#define IRQ_U300_I2C0 72
|
||||
#define IRQ_U300_I2C1 73
|
||||
#define IRQ_U300_RTC 74
|
||||
#define IRQ_U300_NFIF 75
|
||||
#define IRQ_U300_NFIF2 76
|
||||
|
||||
/* The DB3350-specific interrupt lines */
|
||||
#define IRQ_U300_ISP_F0 46
|
||||
#define IRQ_U300_ISP_F1 47
|
||||
#define IRQ_U300_ISP_F2 48
|
||||
#define IRQ_U300_ISP_F3 49
|
||||
#define IRQ_U300_ISP_F4 50
|
||||
#define IRQ_U300_GPIO_PORT3 51
|
||||
#define IRQ_U300_SYSCON_PLL_LOCK 52
|
||||
#define IRQ_U300_UART1 53
|
||||
#define IRQ_U300_GPIO_PORT4 54
|
||||
#define IRQ_U300_GPIO_PORT5 55
|
||||
#define IRQ_U300_GPIO_PORT6 56
|
||||
#define U300_VIC_IRQS_END 57
|
||||
|
||||
/* Maximum 8*7 GPIO lines */
|
||||
#ifdef CONFIG_PINCTRL_COH901
|
||||
#define IRQ_U300_GPIO_BASE (U300_VIC_IRQS_END)
|
||||
#define IRQ_U300_GPIO_END (IRQ_U300_GPIO_BASE + 56)
|
||||
#else
|
||||
#define IRQ_U300_GPIO_END (U300_VIC_IRQS_END)
|
||||
#endif
|
||||
|
||||
#define NR_IRQS_U300 (IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
|
||||
#define IRQ_U300_ISP_F0 77
|
||||
#define IRQ_U300_ISP_F1 78
|
||||
#define IRQ_U300_ISP_F2 79
|
||||
#define IRQ_U300_ISP_F3 80
|
||||
#define IRQ_U300_ISP_F4 81
|
||||
#define IRQ_U300_GPIO_PORT3 82
|
||||
#define IRQ_U300_SYSCON_PLL_LOCK 83
|
||||
#define IRQ_U300_UART1 84
|
||||
#define IRQ_U300_GPIO_PORT4 85
|
||||
#define IRQ_U300_GPIO_PORT5 86
|
||||
#define IRQ_U300_GPIO_PORT6 87
|
||||
#define U300_VIC_IRQS_END 88
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Private data structure for of_gpiochip_find_and_xlate */
|
||||
|
@ -216,6 +217,42 @@ err0:
|
|||
}
|
||||
EXPORT_SYMBOL(of_mm_gpiochip_add);
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
||||
{
|
||||
struct device_node *np = chip->of_node;
|
||||
struct of_phandle_args pinspec;
|
||||
struct pinctrl_dev *pctldev;
|
||||
int index = 0, ret;
|
||||
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
do {
|
||||
ret = of_parse_phandle_with_args(np, "gpio-ranges",
|
||||
"#gpio-range-cells", index, &pinspec);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
pctldev = of_pinctrl_get(pinspec.np);
|
||||
if (!pctldev)
|
||||
break;
|
||||
|
||||
ret = gpiochip_add_pin_range(chip,
|
||||
pinctrl_dev_get_name(pctldev),
|
||||
pinspec.args[0],
|
||||
pinspec.args[1]);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
} while (index++);
|
||||
}
|
||||
|
||||
#else
|
||||
static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {}
|
||||
#endif
|
||||
|
||||
void of_gpiochip_add(struct gpio_chip *chip)
|
||||
{
|
||||
if ((!chip->of_node) && (chip->dev))
|
||||
|
@ -229,11 +266,14 @@ void of_gpiochip_add(struct gpio_chip *chip)
|
|||
chip->of_xlate = of_gpio_simple_xlate;
|
||||
}
|
||||
|
||||
of_gpiochip_add_pin_range(chip);
|
||||
of_node_get(chip->of_node);
|
||||
}
|
||||
|
||||
void of_gpiochip_remove(struct gpio_chip *chip)
|
||||
{
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
|
||||
if (chip->of_node)
|
||||
of_node_put(chip->of_node);
|
||||
}
|
||||
|
|
|
@ -1083,6 +1083,10 @@ int gpiochip_add(struct gpio_chip *chip)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
INIT_LIST_HEAD(&chip->pin_ranges);
|
||||
#endif
|
||||
|
||||
of_gpiochip_add(chip);
|
||||
|
||||
unlock:
|
||||
|
@ -1123,6 +1127,7 @@ int gpiochip_remove(struct gpio_chip *chip)
|
|||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
|
||||
for (id = chip->base; id < chip->base + chip->ngpio; id++) {
|
||||
|
@ -1180,6 +1185,47 @@ struct gpio_chip *gpiochip_find(void *data,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_find);
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
|
||||
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
||||
unsigned int pin_base, unsigned int npins)
|
||||
{
|
||||
struct gpio_pin_range *pin_range;
|
||||
|
||||
pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), GFP_KERNEL);
|
||||
if (!pin_range) {
|
||||
pr_err("%s: GPIO chip: failed to allocate pin ranges\n",
|
||||
chip->label);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pin_range->range.name = chip->label;
|
||||
pin_range->range.base = chip->base;
|
||||
pin_range->range.pin_base = pin_base;
|
||||
pin_range->range.npins = npins;
|
||||
pin_range->pctldev = find_pinctrl_and_add_gpio_range(pinctl_name,
|
||||
&pin_range->range);
|
||||
|
||||
list_add_tail(&pin_range->node, &chip->pin_ranges);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
|
||||
|
||||
void gpiochip_remove_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
struct gpio_pin_range *pin_range, *tmp;
|
||||
|
||||
list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) {
|
||||
list_del(&pin_range->node);
|
||||
pinctrl_remove_gpio_range(pin_range->pctldev,
|
||||
&pin_range->range);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
|
||||
|
||||
#endif /* CONFIG_PINCTRL */
|
||||
|
||||
/* These "optional" allocation calls help prevent drivers from stomping
|
||||
* on each other, and help provide better diagnostics in debugfs.
|
||||
* They're called even less than the "set direction" calls.
|
||||
|
|
|
@ -143,8 +143,8 @@ config PINCTRL_SINGLE
|
|||
This selects the device tree based generic pinctrl driver.
|
||||
|
||||
config PINCTRL_SIRF
|
||||
bool "CSR SiRFprimaII pin controller driver"
|
||||
depends on ARCH_PRIMA2
|
||||
bool "CSR SiRFprimaII/SiRFmarco pin controller driver"
|
||||
depends on ARCH_SIRF
|
||||
select PINMUX
|
||||
|
||||
config PINCTRL_TEGRA
|
||||
|
@ -188,27 +188,7 @@ config PINCTRL_EXYNOS4
|
|||
depends on OF && GPIOLIB
|
||||
select PINCTRL_SAMSUNG
|
||||
|
||||
config PINCTRL_MVEBU
|
||||
bool
|
||||
depends on ARCH_MVEBU
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
|
||||
config PINCTRL_DOVE
|
||||
bool
|
||||
select PINCTRL_MVEBU
|
||||
|
||||
config PINCTRL_KIRKWOOD
|
||||
bool
|
||||
select PINCTRL_MVEBU
|
||||
|
||||
config PINCTRL_ARMADA_370
|
||||
bool
|
||||
select PINCTRL_MVEBU
|
||||
|
||||
config PINCTRL_ARMADA_XP
|
||||
bool
|
||||
select PINCTRL_MVEBU
|
||||
source "drivers/pinctrl/mvebu/Kconfig"
|
||||
|
||||
source "drivers/pinctrl/spear/Kconfig"
|
||||
|
||||
|
|
|
@ -36,12 +36,8 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
|
|||
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
|
||||
obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
|
||||
obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o
|
||||
obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
|
||||
obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o
|
||||
obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
|
||||
obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
|
||||
obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o
|
||||
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
|
||||
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
|
||||
|
||||
obj-$(CONFIG_PLAT_ORION) += mvebu/
|
||||
obj-$(CONFIG_PLAT_SPEAR) += spear/
|
||||
|
|
|
@ -345,6 +345,33 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
|
||||
|
||||
struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname,
|
||||
struct pinctrl_gpio_range *range)
|
||||
{
|
||||
struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname);
|
||||
|
||||
if (!pctldev)
|
||||
return NULL;
|
||||
|
||||
pinctrl_add_gpio_range(pctldev, range);
|
||||
return pctldev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(find_pinctrl_and_add_gpio_range);
|
||||
|
||||
/**
|
||||
* pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
|
||||
* @pctldev: pin controller device to remove the range from
|
||||
* @range: the GPIO range to remove
|
||||
*/
|
||||
void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range)
|
||||
{
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
list_del(&range->node);
|
||||
mutex_unlock(&pinctrl_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
|
||||
|
||||
/**
|
||||
* pinctrl_get_group_selector() - returns the group selector for a group
|
||||
* @pctldev: the pin controller handling the group
|
||||
|
@ -563,6 +590,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
|
|||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
setting->dev_name = map->dev_name;
|
||||
|
||||
switch (map->type) {
|
||||
case PIN_MAP_TYPE_MUX_GROUP:
|
||||
ret = pinmux_map_to_setting(map, setting);
|
||||
|
|
|
@ -105,12 +105,14 @@ struct pinctrl_setting_configs {
|
|||
* @type: the type of setting
|
||||
* @pctldev: pin control device handling to be programmed. Not used for
|
||||
* PIN_MAP_TYPE_DUMMY_STATE.
|
||||
* @dev_name: the name of the device using this state
|
||||
* @data: Data specific to the setting type
|
||||
*/
|
||||
struct pinctrl_setting {
|
||||
struct list_head node;
|
||||
enum pinctrl_map_type type;
|
||||
struct pinctrl_dev *pctldev;
|
||||
const char *dev_name;
|
||||
union {
|
||||
struct pinctrl_setting_mux mux;
|
||||
struct pinctrl_setting_configs configs;
|
||||
|
|
|
@ -106,6 +106,17 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
|
||||
{
|
||||
struct pinctrl_dev *pctldev;
|
||||
|
||||
pctldev = find_pinctrl_by_of_node(np);
|
||||
if (!pctldev)
|
||||
return NULL;
|
||||
|
||||
return pctldev;
|
||||
}
|
||||
|
||||
static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
|
||||
struct device_node *np_config)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
if PLAT_ORION
|
||||
|
||||
config PINCTRL_MVEBU
|
||||
bool
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
|
||||
config PINCTRL_DOVE
|
||||
bool
|
||||
select PINCTRL_MVEBU
|
||||
|
||||
config PINCTRL_KIRKWOOD
|
||||
bool
|
||||
select PINCTRL_MVEBU
|
||||
|
||||
config PINCTRL_ARMADA_370
|
||||
bool
|
||||
select PINCTRL_MVEBU
|
||||
|
||||
config PINCTRL_ARMADA_XP
|
||||
bool
|
||||
select PINCTRL_MVEBU
|
||||
|
||||
endif
|
|
@ -0,0 +1,5 @@
|
|||
obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
|
||||
obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o
|
||||
obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
|
||||
obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
|
||||
obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "pinctrl-mvebu.h"
|
||||
|
||||
#define MPPS_PER_REG 8
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -64,10 +65,8 @@ struct u300_gpio {
|
|||
struct gpio_chip chip;
|
||||
struct list_head port_list;
|
||||
struct clk *clk;
|
||||
struct resource *memres;
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
int irq_base;
|
||||
u32 stride;
|
||||
/* Register offsets */
|
||||
u32 pcr;
|
||||
|
@ -83,6 +82,7 @@ struct u300_gpio_port {
|
|||
struct list_head node;
|
||||
struct u300_gpio *gpio;
|
||||
char name[8];
|
||||
struct irq_domain *domain;
|
||||
int irq;
|
||||
int number;
|
||||
u8 toggle_edge_mode;
|
||||
|
@ -314,10 +314,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
|||
static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct u300_gpio *gpio = to_u300_gpio(chip);
|
||||
int retirq = gpio->irq_base + offset;
|
||||
int portno = offset >> 3;
|
||||
struct u300_gpio_port *port = NULL;
|
||||
struct list_head *p;
|
||||
int retirq;
|
||||
|
||||
dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset,
|
||||
retirq);
|
||||
list_for_each(p, &gpio->port_list) {
|
||||
port = list_entry(p, struct u300_gpio_port, node);
|
||||
if (port->number == portno)
|
||||
break;
|
||||
}
|
||||
if (port == NULL) {
|
||||
dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
|
||||
offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The local hwirqs on the port are the lower three bits, there
|
||||
* are exactly 8 IRQs per port since they are 8-bit
|
||||
*/
|
||||
retirq = irq_find_mapping(port->domain, (offset & 0x7));
|
||||
|
||||
dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n",
|
||||
offset, retirq, port->number);
|
||||
return retirq;
|
||||
}
|
||||
|
||||
|
@ -467,7 +487,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
|
|||
{
|
||||
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
|
||||
struct u300_gpio *gpio = port->gpio;
|
||||
int offset = d->irq - gpio->irq_base;
|
||||
int offset = (port->number << 3) + d->hwirq;
|
||||
u32 val;
|
||||
|
||||
if ((trigger & IRQF_TRIGGER_RISING) &&
|
||||
|
@ -503,10 +523,12 @@ static void u300_gpio_irq_enable(struct irq_data *d)
|
|||
{
|
||||
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
|
||||
struct u300_gpio *gpio = port->gpio;
|
||||
int offset = d->irq - gpio->irq_base;
|
||||
int offset = (port->number << 3) + d->hwirq;
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
|
||||
d->hwirq, port->name, offset);
|
||||
local_irq_save(flags);
|
||||
val = readl(U300_PIN_REG(offset, ien));
|
||||
writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
|
||||
|
@ -517,7 +539,7 @@ static void u300_gpio_irq_disable(struct irq_data *d)
|
|||
{
|
||||
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
|
||||
struct u300_gpio *gpio = port->gpio;
|
||||
int offset = d->irq - gpio->irq_base;
|
||||
int offset = (port->number << 3) + d->hwirq;
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -555,8 +577,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
|||
int irqoffset;
|
||||
|
||||
for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
|
||||
int pin_irq = gpio->irq_base + (port->number << 3)
|
||||
+ irqoffset;
|
||||
int pin_irq = irq_find_mapping(port->domain, irqoffset);
|
||||
int offset = pinoffset + irqoffset;
|
||||
|
||||
dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
|
||||
|
@ -631,6 +652,8 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio)
|
|||
list_for_each_safe(p, n, &gpio->port_list) {
|
||||
port = list_entry(p, struct u300_gpio_port, node);
|
||||
list_del(&port->node);
|
||||
if (port->domain)
|
||||
irq_domain_remove(port->domain);
|
||||
kfree(port);
|
||||
}
|
||||
}
|
||||
|
@ -639,56 +662,46 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev);
|
||||
struct u300_gpio *gpio;
|
||||
struct resource *memres;
|
||||
int err = 0;
|
||||
int portno;
|
||||
u32 val;
|
||||
u32 ifr;
|
||||
int i;
|
||||
|
||||
gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL);
|
||||
if (gpio == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(struct u300_gpio), GFP_KERNEL);
|
||||
if (gpio == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
gpio->chip = u300_gpio_chip;
|
||||
gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT;
|
||||
gpio->irq_base = plat->gpio_irq_base;
|
||||
gpio->chip.dev = &pdev->dev;
|
||||
gpio->chip.base = plat->gpio_base;
|
||||
gpio->dev = &pdev->dev;
|
||||
|
||||
/* Get GPIO clock */
|
||||
gpio->clk = clk_get(gpio->dev, NULL);
|
||||
memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!memres) {
|
||||
dev_err(gpio->dev, "could not get GPIO memory resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gpio->base = devm_request_and_ioremap(&pdev->dev, memres);
|
||||
if (!gpio->base) {
|
||||
dev_err(gpio->dev, "could not get remap memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
gpio->clk = devm_clk_get(gpio->dev, NULL);
|
||||
if (IS_ERR(gpio->clk)) {
|
||||
err = PTR_ERR(gpio->clk);
|
||||
dev_err(gpio->dev, "could not get GPIO clock\n");
|
||||
goto err_no_clk;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(gpio->clk);
|
||||
if (err) {
|
||||
dev_err(gpio->dev, "could not enable GPIO clock\n");
|
||||
goto err_no_clk_enable;
|
||||
}
|
||||
|
||||
gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!gpio->memres) {
|
||||
dev_err(gpio->dev, "could not get GPIO memory resource\n");
|
||||
err = -ENODEV;
|
||||
goto err_no_resource;
|
||||
}
|
||||
|
||||
if (!request_mem_region(gpio->memres->start,
|
||||
resource_size(gpio->memres),
|
||||
"GPIO Controller")) {
|
||||
err = -ENODEV;
|
||||
goto err_no_ioregion;
|
||||
}
|
||||
|
||||
gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres));
|
||||
if (!gpio->base) {
|
||||
err = -ENOMEM;
|
||||
goto err_no_ioremap;
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_info(gpio->dev,
|
||||
|
@ -732,18 +745,26 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
|
|||
port->irq = platform_get_irq_byname(pdev,
|
||||
port->name);
|
||||
|
||||
dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq,
|
||||
dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq,
|
||||
port->name);
|
||||
|
||||
port->domain = irq_domain_add_linear(pdev->dev.of_node,
|
||||
U300_GPIO_PINS_PER_PORT,
|
||||
&irq_domain_simple_ops,
|
||||
port);
|
||||
if (!port->domain)
|
||||
goto err_no_domain;
|
||||
|
||||
irq_set_chained_handler(port->irq, u300_gpio_irq_handler);
|
||||
irq_set_handler_data(port->irq, port);
|
||||
|
||||
/* For each GPIO pin set the unique IRQ handler */
|
||||
for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) {
|
||||
int irqno = gpio->irq_base + (portno << 3) + i;
|
||||
int irqno = irq_create_mapping(port->domain, i);
|
||||
|
||||
dev_dbg(gpio->dev, "handler for IRQ %d on %s\n",
|
||||
irqno, port->name);
|
||||
dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n",
|
||||
gpio->chip.base + (port->number << 3) + i,
|
||||
port->name, irqno);
|
||||
irq_set_chip_and_handler(irqno, &u300_gpio_irqchip,
|
||||
handle_simple_irq);
|
||||
set_irq_flags(irqno, IRQF_VALID);
|
||||
|
@ -776,18 +797,10 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
|
|||
err_no_pinctrl:
|
||||
err = gpiochip_remove(&gpio->chip);
|
||||
err_no_chip:
|
||||
err_no_domain:
|
||||
err_no_port:
|
||||
u300_gpio_free_ports(gpio);
|
||||
iounmap(gpio->base);
|
||||
err_no_ioremap:
|
||||
release_mem_region(gpio->memres->start, resource_size(gpio->memres));
|
||||
err_no_ioregion:
|
||||
err_no_resource:
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
err_no_clk_enable:
|
||||
clk_put(gpio->clk);
|
||||
err_no_clk:
|
||||
kfree(gpio);
|
||||
dev_info(&pdev->dev, "module ERROR:%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
@ -806,13 +819,8 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
u300_gpio_free_ports(gpio);
|
||||
iounmap(gpio->base);
|
||||
release_mem_region(gpio->memres->start,
|
||||
resource_size(gpio->memres));
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
clk_put(gpio->clk);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
/* list of external wakeup controllers supported */
|
||||
static const struct of_device_id exynos_wkup_irq_ids[] = {
|
||||
{ .compatible = "samsung,exynos4210-wakeup-eint", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void exynos_gpio_irq_unmask(struct irq_data *irqd)
|
||||
|
|
|
@ -32,10 +32,10 @@
|
|||
#define SIRFSOC_NUM_PADS 622
|
||||
#define SIRFSOC_RSC_PIN_MUX 0x4
|
||||
|
||||
#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
|
||||
#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
|
||||
#define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90)
|
||||
#define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4)
|
||||
#define SIRFSOC_GPIO_DSP_EN0 (0x80)
|
||||
#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
|
||||
#define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C)
|
||||
|
||||
#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1
|
||||
|
@ -60,6 +60,7 @@ struct sirfsoc_gpio_bank {
|
|||
int id;
|
||||
int parent_irq;
|
||||
spinlock_t lock;
|
||||
bool is_marco; /* for marco, some registers are different with prima2 */
|
||||
};
|
||||
|
||||
static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
|
||||
|
@ -191,6 +192,7 @@ struct sirfsoc_pmx {
|
|||
struct pinctrl_dev *pmx;
|
||||
void __iomem *gpio_virtbase;
|
||||
void __iomem *rsc_virtbase;
|
||||
bool is_marco;
|
||||
};
|
||||
|
||||
/* SIRFSOC_GPIO_PAD_EN set */
|
||||
|
@ -1088,12 +1090,21 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector
|
|||
|
||||
for (i = 0; i < mux->muxmask_counts; i++) {
|
||||
u32 muxval;
|
||||
muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
|
||||
if (enable)
|
||||
muxval = muxval & ~mask[i].mask;
|
||||
else
|
||||
muxval = muxval | mask[i].mask;
|
||||
writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
|
||||
if (!spmx->is_marco) {
|
||||
muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
|
||||
if (enable)
|
||||
muxval = muxval & ~mask[i].mask;
|
||||
else
|
||||
muxval = muxval | mask[i].mask;
|
||||
writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
|
||||
} else {
|
||||
if (enable)
|
||||
writel(mask[i].mask, spmx->gpio_virtbase +
|
||||
SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group));
|
||||
else
|
||||
writel(mask[i].mask, spmx->gpio_virtbase +
|
||||
SIRFSOC_GPIO_PAD_EN(mask[i].group));
|
||||
}
|
||||
}
|
||||
|
||||
if (mux->funcmask && enable) {
|
||||
|
@ -1158,9 +1169,14 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
|
|||
|
||||
spmx = pinctrl_dev_get_drvdata(pmxdev);
|
||||
|
||||
muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
|
||||
muxval = muxval | (1 << (offset - range->pin_base));
|
||||
writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
|
||||
if (!spmx->is_marco) {
|
||||
muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
|
||||
muxval = muxval | (1 << (offset - range->pin_base));
|
||||
writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
|
||||
} else {
|
||||
writel(1 << (offset - range->pin_base), spmx->gpio_virtbase +
|
||||
SIRFSOC_GPIO_PAD_EN(group));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1218,6 +1234,7 @@ static void __iomem *sirfsoc_rsc_of_iomap(void)
|
|||
{
|
||||
const struct of_device_id rsc_ids[] = {
|
||||
{ .compatible = "sirf,prima2-rsc" },
|
||||
{ .compatible = "sirf,marco-rsc" },
|
||||
{}
|
||||
};
|
||||
struct device_node *np;
|
||||
|
@ -1259,6 +1276,9 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev)
|
|||
goto out_no_rsc_remap;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
|
||||
spmx->is_marco = 1;
|
||||
|
||||
/* Now register the pin controller and all pins it handles */
|
||||
spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
|
||||
if (!spmx->pmx) {
|
||||
|
@ -1287,6 +1307,7 @@ out_no_gpio_remap:
|
|||
|
||||
static const struct of_device_id pinmux_ids[] __devinitconst = {
|
||||
{ .compatible = "sirf,prima2-pinctrl" },
|
||||
{ .compatible = "sirf,marco-pinctrl" },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -1621,8 +1642,8 @@ static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
|
|||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
}
|
||||
|
||||
int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct sirfsoc_gpio_bank *bank = d->host_data;
|
||||
|
||||
|
@ -1648,6 +1669,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
|
|||
struct sirfsoc_gpio_bank *bank;
|
||||
void *regs;
|
||||
struct platform_device *pdev;
|
||||
bool is_marco = false;
|
||||
|
||||
pdev = of_find_device_by_node(np);
|
||||
if (!pdev)
|
||||
|
@ -1657,6 +1679,9 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
|
|||
if (!regs)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
|
||||
is_marco = 1;
|
||||
|
||||
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
|
||||
bank = &sgpio_bank[i];
|
||||
spin_lock_init(&bank->lock);
|
||||
|
@ -1673,6 +1698,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
|
|||
bank->chip.gc.of_node = np;
|
||||
bank->chip.regs = regs;
|
||||
bank->id = i;
|
||||
bank->is_marco = is_marco;
|
||||
bank->parent_irq = platform_get_irq(pdev, i);
|
||||
if (bank->parent_irq < 0) {
|
||||
err = bank->parent_irq;
|
||||
|
|
|
@ -663,8 +663,6 @@ static const struct pinctrl_pin_desc u300_pads[] = {
|
|||
struct u300_pmx {
|
||||
struct device *dev;
|
||||
struct pinctrl_dev *pctl;
|
||||
u32 phybase;
|
||||
u32 physize;
|
||||
void __iomem *virtbase;
|
||||
};
|
||||
|
||||
|
@ -1054,9 +1052,8 @@ static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int u300_pin_config_get(struct pinctrl_dev *pctldev,
|
||||
unsigned pin,
|
||||
unsigned long *config)
|
||||
static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
|
||||
unsigned long *config)
|
||||
{
|
||||
struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
|
||||
|
||||
|
@ -1069,9 +1066,8 @@ int u300_pin_config_get(struct pinctrl_dev *pctldev,
|
|||
config);
|
||||
}
|
||||
|
||||
int u300_pin_config_set(struct pinctrl_dev *pctldev,
|
||||
unsigned pin,
|
||||
unsigned long config)
|
||||
static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
|
||||
unsigned long config)
|
||||
{
|
||||
struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
|
||||
int ret;
|
||||
|
@ -1110,7 +1106,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
|
|||
struct u300_pmx *upmx;
|
||||
struct resource *res;
|
||||
struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Create state holders etc for this driver */
|
||||
|
@ -1123,26 +1118,15 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
|
|||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
upmx->phybase = res->start;
|
||||
upmx->physize = resource_size(res);
|
||||
|
||||
if (request_mem_region(upmx->phybase, upmx->physize,
|
||||
DRIVER_NAME) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out_no_memregion;
|
||||
}
|
||||
|
||||
upmx->virtbase = ioremap(upmx->phybase, upmx->physize);
|
||||
if (!upmx->virtbase) {
|
||||
ret = -ENOMEM;
|
||||
goto out_no_remap;
|
||||
}
|
||||
upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!upmx->virtbase)
|
||||
return -ENOMEM;
|
||||
|
||||
upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
|
||||
if (!upmx->pctl) {
|
||||
dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
|
||||
ret = -EINVAL;
|
||||
goto out_no_pmx;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* We will handle a range of GPIO pins */
|
||||
|
@ -1156,14 +1140,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
|
|||
dev_info(&pdev->dev, "initialized U300 pin control driver\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out_no_pmx:
|
||||
iounmap(upmx->virtbase);
|
||||
out_no_remap:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
out_no_memregion:
|
||||
release_mem_region(upmx->phybase, upmx->physize);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit u300_pmx_remove(struct platform_device *pdev)
|
||||
|
@ -1171,8 +1147,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev)
|
|||
struct u300_pmx *upmx = platform_get_drvdata(pdev);
|
||||
|
||||
pinctrl_unregister(upmx->pctl);
|
||||
iounmap(upmx->virtbase);
|
||||
release_mem_region(upmx->phybase, upmx->physize);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -314,14 +314,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
|
|||
{
|
||||
struct pinctrl_dev *pctldev = setting->pctldev;
|
||||
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
char const * const *groups;
|
||||
unsigned num_groups;
|
||||
int ret;
|
||||
const char *group;
|
||||
int i;
|
||||
const unsigned *pins;
|
||||
unsigned num_pins;
|
||||
|
||||
if (!pmxops) {
|
||||
dev_err(pctldev->dev, "does not support mux function\n");
|
||||
|
@ -376,53 +373,12 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
|
|||
}
|
||||
setting->data.mux.group = ret;
|
||||
|
||||
ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins,
|
||||
&num_pins);
|
||||
if (ret) {
|
||||
dev_err(pctldev->dev,
|
||||
"could not get pins for device %s group selector %d\n",
|
||||
pinctrl_dev_get_name(pctldev), setting->data.mux.group);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Try to allocate all pins in this group, one by one */
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
ret = pin_request(pctldev, pins[i], map->dev_name, NULL);
|
||||
if (ret) {
|
||||
dev_err(pctldev->dev,
|
||||
"could not request pin %d on device %s\n",
|
||||
pins[i], pinctrl_dev_get_name(pctldev));
|
||||
/* On error release all taken pins */
|
||||
i--; /* this pin just failed */
|
||||
for (; i >= 0; i--)
|
||||
pin_free(pctldev, pins[i], NULL);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pinmux_free_setting(struct pinctrl_setting const *setting)
|
||||
{
|
||||
struct pinctrl_dev *pctldev = setting->pctldev;
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
const unsigned *pins;
|
||||
unsigned num_pins;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
|
||||
&pins, &num_pins);
|
||||
if (ret) {
|
||||
dev_err(pctldev->dev,
|
||||
"could not get pins for device %s group selector %d\n",
|
||||
pinctrl_dev_get_name(pctldev), setting->data.mux.group);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_pins; i++)
|
||||
pin_free(pctldev, pins[i], NULL);
|
||||
/* This function is currently unused */
|
||||
}
|
||||
|
||||
int pinmux_enable_setting(struct pinctrl_setting const *setting)
|
||||
|
@ -446,6 +402,22 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting)
|
|||
num_pins = 0;
|
||||
}
|
||||
|
||||
/* Try to allocate all pins in this group, one by one */
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);
|
||||
if (ret) {
|
||||
dev_err(pctldev->dev,
|
||||
"could not request pin %d on device %s\n",
|
||||
pins[i], pinctrl_dev_get_name(pctldev));
|
||||
/* On error release all taken pins */
|
||||
i--; /* this pin just failed */
|
||||
for (; i >= 0; i--)
|
||||
pin_free(pctldev, pins[i], NULL);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that we have acquired the pins, encode the mux setting */
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
desc = pin_desc_get(pctldev, pins[i]);
|
||||
if (desc == NULL) {
|
||||
|
@ -482,6 +454,7 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
|
|||
num_pins = 0;
|
||||
}
|
||||
|
||||
/* Flag the descs that no setting is active */
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
desc = pin_desc_get(pctldev, pins[i]);
|
||||
if (desc == NULL) {
|
||||
|
@ -493,6 +466,10 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
|
|||
desc->mux_setting = NULL;
|
||||
}
|
||||
|
||||
/* And release the pins */
|
||||
for (i = 0; i < num_pins; i++)
|
||||
pin_free(pctldev, pins[i], NULL);
|
||||
|
||||
if (ops->disable)
|
||||
ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group);
|
||||
}
|
||||
|
|
|
@ -25,20 +25,31 @@ config PINCTRL_SPEAR310
|
|||
bool "ST Microelectronics SPEAr310 SoC pin controller driver"
|
||||
depends on MACH_SPEAR310
|
||||
select PINCTRL_SPEAR3XX
|
||||
select PINCTRL_SPEAR_PLGPIO
|
||||
|
||||
config PINCTRL_SPEAR320
|
||||
bool "ST Microelectronics SPEAr320 SoC pin controller driver"
|
||||
depends on MACH_SPEAR320
|
||||
select PINCTRL_SPEAR3XX
|
||||
select PINCTRL_SPEAR_PLGPIO
|
||||
|
||||
config PINCTRL_SPEAR1310
|
||||
bool "ST Microelectronics SPEAr1310 SoC pin controller driver"
|
||||
depends on MACH_SPEAR1310
|
||||
select PINCTRL_SPEAR
|
||||
select PINCTRL_SPEAR_PLGPIO
|
||||
|
||||
config PINCTRL_SPEAR1340
|
||||
bool "ST Microelectronics SPEAr1340 SoC pin controller driver"
|
||||
depends on MACH_SPEAR1340
|
||||
select PINCTRL_SPEAR
|
||||
select PINCTRL_SPEAR_PLGPIO
|
||||
|
||||
config PINCTRL_SPEAR_PLGPIO
|
||||
bool "SPEAr SoC PLGPIO Controller"
|
||||
depends on GPIOLIB && PINCTRL_SPEAR
|
||||
help
|
||||
Say yes here to support PLGPIO controller on ST Microelectronics SPEAr
|
||||
SoCs.
|
||||
|
||||
endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# SPEAr pinmux support
|
||||
|
||||
obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO) += pinctrl-plgpio.o
|
||||
obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o
|
||||
obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o
|
||||
obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o
|
||||
|
|
|
@ -0,0 +1,746 @@
|
|||
/*
|
||||
* SPEAr platform PLGPIO driver
|
||||
*
|
||||
* Copyright (C) 2012 ST Microelectronics
|
||||
* Viresh Kumar <viresh.kumar@linaro.org>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#define MAX_GPIO_PER_REG 32
|
||||
#define PIN_OFFSET(pin) (pin % MAX_GPIO_PER_REG)
|
||||
#define REG_OFFSET(base, reg, pin) (base + reg + (pin / MAX_GPIO_PER_REG) \
|
||||
* sizeof(int *))
|
||||
|
||||
/*
|
||||
* plgpio pins in all machines are not one to one mapped, bitwise with registers
|
||||
* bits. These set of macros define register masks for which below functions
|
||||
* (pin_to_offset and offset_to_pin) are required to be called.
|
||||
*/
|
||||
#define PTO_ENB_REG 0x001
|
||||
#define PTO_WDATA_REG 0x002
|
||||
#define PTO_DIR_REG 0x004
|
||||
#define PTO_IE_REG 0x008
|
||||
#define PTO_RDATA_REG 0x010
|
||||
#define PTO_MIS_REG 0x020
|
||||
|
||||
struct plgpio_regs {
|
||||
u32 enb; /* enable register */
|
||||
u32 wdata; /* write data register */
|
||||
u32 dir; /* direction set register */
|
||||
u32 rdata; /* read data register */
|
||||
u32 ie; /* interrupt enable register */
|
||||
u32 mis; /* mask interrupt status register */
|
||||
u32 eit; /* edge interrupt type */
|
||||
};
|
||||
|
||||
/*
|
||||
* struct plgpio: plgpio driver specific structure
|
||||
*
|
||||
* lock: lock for guarding gpio registers
|
||||
* base: base address of plgpio block
|
||||
* irq_base: irq number of plgpio0
|
||||
* chip: gpio framework specific chip information structure
|
||||
* p2o: function ptr for pin to offset conversion. This is required only for
|
||||
* machines where mapping b/w pin and offset is not 1-to-1.
|
||||
* o2p: function ptr for offset to pin conversion. This is required only for
|
||||
* machines where mapping b/w pin and offset is not 1-to-1.
|
||||
* p2o_regs: mask of registers for which p2o and o2p are applicable
|
||||
* regs: register offsets
|
||||
* csave_regs: context save registers for standby/sleep/hibernate cases
|
||||
*/
|
||||
struct plgpio {
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
unsigned irq_base;
|
||||
struct irq_domain *irq_domain;
|
||||
struct gpio_chip chip;
|
||||
int (*p2o)(int pin); /* pin_to_offset */
|
||||
int (*o2p)(int offset); /* offset_to_pin */
|
||||
u32 p2o_regs;
|
||||
struct plgpio_regs regs;
|
||||
#ifdef CONFIG_PM
|
||||
struct plgpio_regs *csave_regs;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* register manipulation inline functions */
|
||||
static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg)
|
||||
{
|
||||
u32 offset = PIN_OFFSET(pin);
|
||||
void __iomem *reg_off = REG_OFFSET(base, reg, pin);
|
||||
u32 val = readl_relaxed(reg_off);
|
||||
|
||||
return !!(val & (1 << offset));
|
||||
}
|
||||
|
||||
static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg)
|
||||
{
|
||||
u32 offset = PIN_OFFSET(pin);
|
||||
void __iomem *reg_off = REG_OFFSET(base, reg, pin);
|
||||
u32 val = readl_relaxed(reg_off);
|
||||
|
||||
writel_relaxed(val | (1 << offset), reg_off);
|
||||
}
|
||||
|
||||
static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg)
|
||||
{
|
||||
u32 offset = PIN_OFFSET(pin);
|
||||
void __iomem *reg_off = REG_OFFSET(base, reg, pin);
|
||||
u32 val = readl_relaxed(reg_off);
|
||||
|
||||
writel_relaxed(val & ~(1 << offset), reg_off);
|
||||
}
|
||||
|
||||
/* gpio framework specific routines */
|
||||
static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
|
||||
unsigned long flags;
|
||||
|
||||
/* get correct offset for "offset" pin */
|
||||
if (plgpio->p2o && (plgpio->p2o_regs & PTO_DIR_REG)) {
|
||||
offset = plgpio->p2o(offset);
|
||||
if (offset == -1)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&plgpio->lock, flags);
|
||||
plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir);
|
||||
spin_unlock_irqrestore(&plgpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
|
||||
unsigned long flags;
|
||||
unsigned dir_offset = offset, wdata_offset = offset, tmp;
|
||||
|
||||
/* get correct offset for "offset" pin */
|
||||
if (plgpio->p2o && (plgpio->p2o_regs & (PTO_DIR_REG | PTO_WDATA_REG))) {
|
||||
tmp = plgpio->p2o(offset);
|
||||
if (tmp == -1)
|
||||
return -EINVAL;
|
||||
|
||||
if (plgpio->p2o_regs & PTO_DIR_REG)
|
||||
dir_offset = tmp;
|
||||
if (plgpio->p2o_regs & PTO_WDATA_REG)
|
||||
wdata_offset = tmp;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&plgpio->lock, flags);
|
||||
if (value)
|
||||
plgpio_reg_set(plgpio->base, wdata_offset,
|
||||
plgpio->regs.wdata);
|
||||
else
|
||||
plgpio_reg_reset(plgpio->base, wdata_offset,
|
||||
plgpio->regs.wdata);
|
||||
|
||||
plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir);
|
||||
spin_unlock_irqrestore(&plgpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
|
||||
|
||||
if (offset >= chip->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
/* get correct offset for "offset" pin */
|
||||
if (plgpio->p2o && (plgpio->p2o_regs & PTO_RDATA_REG)) {
|
||||
offset = plgpio->p2o(offset);
|
||||
if (offset == -1)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata);
|
||||
}
|
||||
|
||||
static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
|
||||
|
||||
if (offset >= chip->ngpio)
|
||||
return;
|
||||
|
||||
/* get correct offset for "offset" pin */
|
||||
if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) {
|
||||
offset = plgpio->p2o(offset);
|
||||
if (offset == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (value)
|
||||
plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata);
|
||||
else
|
||||
plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata);
|
||||
}
|
||||
|
||||
static int plgpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
|
||||
int gpio = chip->base + offset;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (offset >= chip->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pinctrl_request_gpio(gpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!IS_ERR(plgpio->clk)) {
|
||||
ret = clk_prepare_enable(plgpio->clk);
|
||||
if (ret)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (plgpio->regs.enb == -1)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* put gpio in IN mode before enabling it. This make enabling gpio safe
|
||||
*/
|
||||
ret = plgpio_direction_input(chip, offset);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
/* get correct offset for "offset" pin */
|
||||
if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) {
|
||||
offset = plgpio->p2o(offset);
|
||||
if (offset == -1) {
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&plgpio->lock, flags);
|
||||
plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb);
|
||||
spin_unlock_irqrestore(&plgpio->lock, flags);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
clk_disable_unprepare(plgpio->clk);
|
||||
err0:
|
||||
pinctrl_free_gpio(gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void plgpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
|
||||
int gpio = chip->base + offset;
|
||||
unsigned long flags;
|
||||
|
||||
if (offset >= chip->ngpio)
|
||||
return;
|
||||
|
||||
if (plgpio->regs.enb == -1)
|
||||
goto disable_clk;
|
||||
|
||||
/* get correct offset for "offset" pin */
|
||||
if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) {
|
||||
offset = plgpio->p2o(offset);
|
||||
if (offset == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&plgpio->lock, flags);
|
||||
plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb);
|
||||
spin_unlock_irqrestore(&plgpio->lock, flags);
|
||||
|
||||
disable_clk:
|
||||
if (!IS_ERR(plgpio->clk))
|
||||
clk_disable_unprepare(plgpio->clk);
|
||||
|
||||
pinctrl_free_gpio(gpio);
|
||||
}
|
||||
|
||||
static int plgpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
|
||||
|
||||
if (plgpio->irq_base < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return irq_find_mapping(plgpio->irq_domain, offset);
|
||||
}
|
||||
|
||||
/* PLGPIO IRQ */
|
||||
static void plgpio_irq_disable(struct irq_data *d)
|
||||
{
|
||||
struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = d->irq - plgpio->irq_base;
|
||||
unsigned long flags;
|
||||
|
||||
/* get correct offset for "offset" pin */
|
||||
if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) {
|
||||
offset = plgpio->p2o(offset);
|
||||
if (offset == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&plgpio->lock, flags);
|
||||
plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie);
|
||||
spin_unlock_irqrestore(&plgpio->lock, flags);
|
||||
}
|
||||
|
||||
static void plgpio_irq_enable(struct irq_data *d)
|
||||
{
|
||||
struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = d->irq - plgpio->irq_base;
|
||||
unsigned long flags;
|
||||
|
||||
/* get correct offset for "offset" pin */
|
||||
if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) {
|
||||
offset = plgpio->p2o(offset);
|
||||
if (offset == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&plgpio->lock, flags);
|
||||
plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie);
|
||||
spin_unlock_irqrestore(&plgpio->lock, flags);
|
||||
}
|
||||
|
||||
static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger)
|
||||
{
|
||||
struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = d->irq - plgpio->irq_base;
|
||||
void __iomem *reg_off;
|
||||
unsigned int supported_type = 0, val;
|
||||
|
||||
if (offset >= plgpio->chip.ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
if (plgpio->regs.eit == -1)
|
||||
supported_type = IRQ_TYPE_LEVEL_HIGH;
|
||||
else
|
||||
supported_type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
|
||||
if (!(trigger & supported_type))
|
||||
return -EINVAL;
|
||||
|
||||
if (plgpio->regs.eit == -1)
|
||||
return 0;
|
||||
|
||||
reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset);
|
||||
val = readl_relaxed(reg_off);
|
||||
|
||||
offset = PIN_OFFSET(offset);
|
||||
if (trigger & IRQ_TYPE_EDGE_RISING)
|
||||
writel_relaxed(val | (1 << offset), reg_off);
|
||||
else
|
||||
writel_relaxed(val & ~(1 << offset), reg_off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip plgpio_irqchip = {
|
||||
.name = "PLGPIO",
|
||||
.irq_enable = plgpio_irq_enable,
|
||||
.irq_disable = plgpio_irq_disable,
|
||||
.irq_set_type = plgpio_irq_set_type,
|
||||
};
|
||||
|
||||
static void plgpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||
{
|
||||
struct plgpio *plgpio = irq_get_handler_data(irq);
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
int regs_count, count, pin, offset, i = 0;
|
||||
unsigned long pending;
|
||||
|
||||
count = plgpio->chip.ngpio;
|
||||
regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG);
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
/* check all plgpio MIS registers for a possible interrupt */
|
||||
for (; i < regs_count; i++) {
|
||||
pending = readl_relaxed(plgpio->base + plgpio->regs.mis +
|
||||
i * sizeof(int *));
|
||||
if (!pending)
|
||||
continue;
|
||||
|
||||
/* clear interrupts */
|
||||
writel_relaxed(~pending, plgpio->base + plgpio->regs.mis +
|
||||
i * sizeof(int *));
|
||||
/*
|
||||
* clear extra bits in last register having gpios < MAX/REG
|
||||
* ex: Suppose there are max 102 plgpios. then last register
|
||||
* must have only (102 - MAX_GPIO_PER_REG * 3) = 6 relevant bits
|
||||
* so, we must not take other 28 bits into consideration for
|
||||
* checking interrupt. so clear those bits.
|
||||
*/
|
||||
count = count - i * MAX_GPIO_PER_REG;
|
||||
if (count < MAX_GPIO_PER_REG)
|
||||
pending &= (1 << count) - 1;
|
||||
|
||||
for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) {
|
||||
/* get correct pin for "offset" */
|
||||
if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) {
|
||||
pin = plgpio->o2p(offset);
|
||||
if (pin == -1)
|
||||
continue;
|
||||
} else
|
||||
pin = offset;
|
||||
|
||||
/* get correct irq line number */
|
||||
pin = i * MAX_GPIO_PER_REG + pin;
|
||||
generic_handle_irq(plgpio_to_irq(&plgpio->chip, pin));
|
||||
}
|
||||
}
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* pin to offset and offset to pin converter functions
|
||||
*
|
||||
* In spear310 there is inconsistency among bit positions in plgpio regiseters,
|
||||
* for different plgpio pins. For example: for pin 27, bit offset is 23, pin
|
||||
* 28-33 are not supported, pin 95 has offset bit 95, bit 100 has offset bit 1
|
||||
*/
|
||||
static int spear310_p2o(int pin)
|
||||
{
|
||||
int offset = pin;
|
||||
|
||||
if (pin <= 27)
|
||||
offset += 4;
|
||||
else if (pin <= 33)
|
||||
offset = -1;
|
||||
else if (pin <= 97)
|
||||
offset -= 2;
|
||||
else if (pin <= 101)
|
||||
offset = 101 - pin;
|
||||
else
|
||||
offset = -1;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int spear310_o2p(int offset)
|
||||
{
|
||||
if (offset <= 3)
|
||||
return 101 - offset;
|
||||
else if (offset <= 31)
|
||||
return offset - 4;
|
||||
else
|
||||
return offset + 2;
|
||||
}
|
||||
|
||||
static int __devinit plgpio_probe_dt(struct platform_device *pdev,
|
||||
struct plgpio *plgpio)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret = -EINVAL;
|
||||
u32 val;
|
||||
|
||||
if (of_machine_is_compatible("st,spear310")) {
|
||||
plgpio->p2o = spear310_p2o;
|
||||
plgpio->o2p = spear310_o2p;
|
||||
plgpio->p2o_regs = PTO_WDATA_REG | PTO_DIR_REG | PTO_IE_REG |
|
||||
PTO_RDATA_REG | PTO_MIS_REG;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "st-plgpio,ngpio", &val)) {
|
||||
plgpio->chip.ngpio = val;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "DT: Invalid ngpio field\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "st-plgpio,enb-reg", &val))
|
||||
plgpio->regs.enb = val;
|
||||
else
|
||||
plgpio->regs.enb = -1;
|
||||
|
||||
if (!of_property_read_u32(np, "st-plgpio,wdata-reg", &val)) {
|
||||
plgpio->regs.wdata = val;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "DT: Invalid wdata reg\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "st-plgpio,dir-reg", &val)) {
|
||||
plgpio->regs.dir = val;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "DT: Invalid dir reg\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "st-plgpio,ie-reg", &val)) {
|
||||
plgpio->regs.ie = val;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "DT: Invalid ie reg\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "st-plgpio,rdata-reg", &val)) {
|
||||
plgpio->regs.rdata = val;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "DT: Invalid rdata reg\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "st-plgpio,mis-reg", &val)) {
|
||||
plgpio->regs.mis = val;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "DT: Invalid mis reg\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "st-plgpio,eit-reg", &val))
|
||||
plgpio->regs.eit = val;
|
||||
else
|
||||
plgpio->regs.eit = -1;
|
||||
|
||||
return 0;
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
static int __devinit plgpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct plgpio *plgpio;
|
||||
struct resource *res;
|
||||
int ret, irq, i;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL);
|
||||
if (!plgpio) {
|
||||
dev_err(&pdev->dev, "memory allocation fail\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
plgpio->base = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!plgpio->base) {
|
||||
dev_err(&pdev->dev, "request and ioremap fail\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = plgpio_probe_dt(pdev, plgpio);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "DT probe failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
plgpio->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(plgpio->clk))
|
||||
dev_warn(&pdev->dev, "clk_get() failed, work without it\n");
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
plgpio->csave_regs = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*plgpio->csave_regs) *
|
||||
DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG),
|
||||
GFP_KERNEL);
|
||||
if (!plgpio->csave_regs) {
|
||||
dev_err(&pdev->dev, "csave registers memory allocation fail\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
platform_set_drvdata(pdev, plgpio);
|
||||
spin_lock_init(&plgpio->lock);
|
||||
|
||||
plgpio->irq_base = -1;
|
||||
plgpio->chip.base = -1;
|
||||
plgpio->chip.request = plgpio_request;
|
||||
plgpio->chip.free = plgpio_free;
|
||||
plgpio->chip.direction_input = plgpio_direction_input;
|
||||
plgpio->chip.direction_output = plgpio_direction_output;
|
||||
plgpio->chip.get = plgpio_get_value;
|
||||
plgpio->chip.set = plgpio_set_value;
|
||||
plgpio->chip.to_irq = plgpio_to_irq;
|
||||
plgpio->chip.label = dev_name(&pdev->dev);
|
||||
plgpio->chip.dev = &pdev->dev;
|
||||
plgpio->chip.owner = THIS_MODULE;
|
||||
|
||||
ret = gpiochip_add(&plgpio->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to add gpio chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_info(&pdev->dev, "irqs not supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
plgpio->irq_base = irq_alloc_descs(-1, 0, plgpio->chip.ngpio, 0);
|
||||
if (IS_ERR_VALUE(plgpio->irq_base)) {
|
||||
/* we would not support irq for gpio */
|
||||
dev_warn(&pdev->dev, "couldn't allocate irq base\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
plgpio->irq_domain = irq_domain_add_legacy(np, plgpio->chip.ngpio,
|
||||
plgpio->irq_base, 0, &irq_domain_simple_ops, NULL);
|
||||
if (WARN_ON(!plgpio->irq_domain)) {
|
||||
dev_err(&pdev->dev, "irq domain init failed\n");
|
||||
irq_free_descs(plgpio->irq_base, plgpio->chip.ngpio);
|
||||
ret = -ENXIO;
|
||||
goto remove_gpiochip;
|
||||
}
|
||||
|
||||
irq_set_chained_handler(irq, plgpio_irq_handler);
|
||||
for (i = 0; i < plgpio->chip.ngpio; i++) {
|
||||
irq_set_chip_and_handler(i + plgpio->irq_base, &plgpio_irqchip,
|
||||
handle_simple_irq);
|
||||
set_irq_flags(i + plgpio->irq_base, IRQF_VALID);
|
||||
irq_set_chip_data(i + plgpio->irq_base, plgpio);
|
||||
}
|
||||
|
||||
irq_set_handler_data(irq, plgpio);
|
||||
dev_info(&pdev->dev, "PLGPIO registered with IRQs\n");
|
||||
|
||||
return 0;
|
||||
|
||||
remove_gpiochip:
|
||||
dev_info(&pdev->dev, "Remove gpiochip\n");
|
||||
if (gpiochip_remove(&plgpio->chip))
|
||||
dev_err(&pdev->dev, "unable to remove gpiochip\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int plgpio_suspend(struct device *dev)
|
||||
{
|
||||
struct plgpio *plgpio = dev_get_drvdata(dev);
|
||||
int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
|
||||
void __iomem *off;
|
||||
|
||||
for (i = 0; i < reg_count; i++) {
|
||||
off = plgpio->base + i * sizeof(int *);
|
||||
|
||||
if (plgpio->regs.enb != -1)
|
||||
plgpio->csave_regs[i].enb =
|
||||
readl_relaxed(plgpio->regs.enb + off);
|
||||
if (plgpio->regs.eit != -1)
|
||||
plgpio->csave_regs[i].eit =
|
||||
readl_relaxed(plgpio->regs.eit + off);
|
||||
plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata +
|
||||
off);
|
||||
plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir +
|
||||
off);
|
||||
plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to correct the values in end registers. End registers contain
|
||||
* extra bits that might be used for other purpose in platform. So, we shouldn't
|
||||
* overwrite these bits. This macro, reads given register again, preserves other
|
||||
* bit values (non-plgpio bits), and retain captured value (plgpio bits).
|
||||
*/
|
||||
#define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \
|
||||
{ \
|
||||
_tmp = readl_relaxed(plgpio->regs.__reg + _off); \
|
||||
_tmp &= ~_mask; \
|
||||
plgpio->csave_regs[i].__reg = \
|
||||
_tmp | (plgpio->csave_regs[i].__reg & _mask); \
|
||||
}
|
||||
|
||||
static int plgpio_resume(struct device *dev)
|
||||
{
|
||||
struct plgpio *plgpio = dev_get_drvdata(dev);
|
||||
int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
|
||||
void __iomem *off;
|
||||
u32 mask, tmp;
|
||||
|
||||
for (i = 0; i < reg_count; i++) {
|
||||
off = plgpio->base + i * sizeof(int *);
|
||||
|
||||
if (i == reg_count - 1) {
|
||||
mask = (1 << (plgpio->chip.ngpio - i *
|
||||
MAX_GPIO_PER_REG)) - 1;
|
||||
|
||||
if (plgpio->regs.enb != -1)
|
||||
plgpio_prepare_reg(enb, off, mask, tmp);
|
||||
|
||||
if (plgpio->regs.eit != -1)
|
||||
plgpio_prepare_reg(eit, off, mask, tmp);
|
||||
|
||||
plgpio_prepare_reg(wdata, off, mask, tmp);
|
||||
plgpio_prepare_reg(dir, off, mask, tmp);
|
||||
plgpio_prepare_reg(ie, off, mask, tmp);
|
||||
}
|
||||
|
||||
writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata +
|
||||
off);
|
||||
writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir +
|
||||
off);
|
||||
|
||||
if (plgpio->regs.eit != -1)
|
||||
writel_relaxed(plgpio->csave_regs[i].eit,
|
||||
plgpio->regs.eit + off);
|
||||
|
||||
writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off);
|
||||
|
||||
if (plgpio->regs.enb != -1)
|
||||
writel_relaxed(plgpio->csave_regs[i].enb,
|
||||
plgpio->regs.enb + off);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(plgpio_dev_pm_ops, plgpio_suspend, plgpio_resume);
|
||||
|
||||
static const struct of_device_id plgpio_of_match[] = {
|
||||
{ .compatible = "st,spear-plgpio" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, plgpio_of_match);
|
||||
|
||||
static struct platform_driver plgpio_driver = {
|
||||
.probe = plgpio_probe,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "spear-plgpio",
|
||||
.pm = &plgpio_dev_pm_ops,
|
||||
.of_match_table = of_match_ptr(plgpio_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init plgpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&plgpio_driver);
|
||||
}
|
||||
subsys_initcall(plgpio_init);
|
||||
|
||||
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
|
||||
MODULE_DESCRIPTION("ST Microlectronics SPEAr PLGPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
|
@ -38,6 +39,28 @@ static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
|
|||
writel_relaxed(val, pmx->vbase + reg);
|
||||
}
|
||||
|
||||
static void muxregs_endisable(struct spear_pmx *pmx,
|
||||
struct spear_muxreg *muxregs, u8 count, bool enable)
|
||||
{
|
||||
struct spear_muxreg *muxreg;
|
||||
u32 val, temp, j;
|
||||
|
||||
for (j = 0; j < count; j++) {
|
||||
muxreg = &muxregs[j];
|
||||
|
||||
val = pmx_readl(pmx, muxreg->reg);
|
||||
val &= ~muxreg->mask;
|
||||
|
||||
if (enable)
|
||||
temp = muxreg->val;
|
||||
else
|
||||
temp = ~muxreg->val;
|
||||
|
||||
val |= muxreg->mask & temp;
|
||||
pmx_writel(pmx, val, muxreg->reg);
|
||||
}
|
||||
}
|
||||
|
||||
static int set_mode(struct spear_pmx *pmx, int mode)
|
||||
{
|
||||
struct spear_pmx_mode *pmx_mode = NULL;
|
||||
|
@ -70,6 +93,17 @@ static int set_mode(struct spear_pmx *pmx, int mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __devinit
|
||||
pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
|
||||
unsigned count, u16 reg)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
|
||||
for (; i < count; i++)
|
||||
for (; j < gpio_pingroup[i].nmuxregs; j++)
|
||||
gpio_pingroup[i].muxregs[j].reg = reg;
|
||||
}
|
||||
|
||||
void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
|
||||
{
|
||||
struct spear_pingroup *pgroup;
|
||||
|
@ -216,9 +250,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
|
|||
struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
const struct spear_pingroup *pgroup;
|
||||
const struct spear_modemux *modemux;
|
||||
struct spear_muxreg *muxreg;
|
||||
u32 val, temp;
|
||||
int i, j;
|
||||
int i;
|
||||
bool found = false;
|
||||
|
||||
pgroup = pmx->machdata->groups[group];
|
||||
|
@ -233,20 +265,8 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
found = true;
|
||||
for (j = 0; j < modemux->nmuxregs; j++) {
|
||||
muxreg = &modemux->muxregs[j];
|
||||
|
||||
val = pmx_readl(pmx, muxreg->reg);
|
||||
val &= ~muxreg->mask;
|
||||
|
||||
if (enable)
|
||||
temp = muxreg->val;
|
||||
else
|
||||
temp = ~muxreg->val;
|
||||
|
||||
val |= muxreg->mask & temp;
|
||||
pmx_writel(pmx, val, muxreg->reg);
|
||||
}
|
||||
muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs,
|
||||
enable);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
|
@ -270,12 +290,65 @@ static void spear_pinctrl_disable(struct pinctrl_dev *pctldev,
|
|||
spear_pinctrl_endisable(pctldev, function, group, false);
|
||||
}
|
||||
|
||||
/* gpio with pinmux */
|
||||
static struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx,
|
||||
unsigned pin)
|
||||
{
|
||||
struct spear_gpio_pingroup *gpio_pingroup;
|
||||
int i = 0, j;
|
||||
|
||||
if (!pmx->machdata->gpio_pingroups)
|
||||
return NULL;
|
||||
|
||||
for (; i < pmx->machdata->ngpio_pingroups; i++) {
|
||||
gpio_pingroup = &pmx->machdata->gpio_pingroups[i];
|
||||
|
||||
for (j = 0; j < gpio_pingroup->npins; j++) {
|
||||
if (gpio_pingroup->pins[j] == pin)
|
||||
return gpio_pingroup;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static int gpio_request_endisable(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range, unsigned offset, bool enable)
|
||||
{
|
||||
struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct spear_gpio_pingroup *gpio_pingroup;
|
||||
|
||||
gpio_pingroup = get_gpio_pingroup(pmx, offset);
|
||||
if (IS_ERR(gpio_pingroup))
|
||||
return PTR_ERR(gpio_pingroup);
|
||||
|
||||
if (gpio_pingroup)
|
||||
muxregs_endisable(pmx, gpio_pingroup->muxregs,
|
||||
gpio_pingroup->nmuxregs, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_request_enable(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range, unsigned offset)
|
||||
{
|
||||
return gpio_request_endisable(pctldev, range, offset, true);
|
||||
}
|
||||
|
||||
static void gpio_disable_free(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range, unsigned offset)
|
||||
{
|
||||
gpio_request_endisable(pctldev, range, offset, false);
|
||||
}
|
||||
|
||||
static 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,
|
||||
.enable = spear_pinctrl_enable,
|
||||
.disable = spear_pinctrl_disable,
|
||||
.gpio_request_enable = gpio_request_enable,
|
||||
.gpio_disable_free = gpio_disable_free,
|
||||
};
|
||||
|
||||
static struct pinctrl_desc spear_pinctrl_desc = {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef __PINMUX_SPEAR_H__
|
||||
#define __PINMUX_SPEAR_H__
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
@ -46,6 +47,44 @@ struct spear_muxreg {
|
|||
u32 val;
|
||||
};
|
||||
|
||||
struct spear_gpio_pingroup {
|
||||
const unsigned *pins;
|
||||
unsigned npins;
|
||||
struct spear_muxreg *muxregs;
|
||||
u8 nmuxregs;
|
||||
};
|
||||
|
||||
/* ste: set to enable */
|
||||
#define DEFINE_MUXREG(__pins, __muxreg, __mask, __ste) \
|
||||
static struct spear_muxreg __pins##_muxregs[] = { \
|
||||
{ \
|
||||
.reg = __muxreg, \
|
||||
.mask = __mask, \
|
||||
.val = __ste ? __mask : 0, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define DEFINE_2_MUXREG(__pins, __muxreg1, __muxreg2, __mask, __ste1, __ste2) \
|
||||
static struct spear_muxreg __pins##_muxregs[] = { \
|
||||
{ \
|
||||
.reg = __muxreg1, \
|
||||
.mask = __mask, \
|
||||
.val = __ste1 ? __mask : 0, \
|
||||
}, { \
|
||||
.reg = __muxreg2, \
|
||||
.mask = __mask, \
|
||||
.val = __ste2 ? __mask : 0, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define GPIO_PINGROUP(__pins) \
|
||||
{ \
|
||||
.pins = __pins, \
|
||||
.npins = ARRAY_SIZE(__pins), \
|
||||
.muxregs = __pins##_muxregs, \
|
||||
.nmuxregs = ARRAY_SIZE(__pins##_muxregs), \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct spear_modemux - SPEAr mode mux configuration
|
||||
* @modes: mode ids supported by this group of muxregs
|
||||
|
@ -100,6 +139,8 @@ struct spear_function {
|
|||
* @nfunctions: The numbmer of entries in @functions.
|
||||
* @groups: An array describing all pin groups the pin SoC supports.
|
||||
* @ngroups: The numbmer of entries in @groups.
|
||||
* @gpio_pingroups: gpio pingroups
|
||||
* @ngpio_pingroups: gpio pingroups count
|
||||
*
|
||||
* @modes_supported: Does SoC support modes
|
||||
* @mode: mode configured from probe
|
||||
|
@ -113,6 +154,8 @@ struct spear_pinctrl_machdata {
|
|||
unsigned nfunctions;
|
||||
struct spear_pingroup **groups;
|
||||
unsigned ngroups;
|
||||
struct spear_gpio_pingroup *gpio_pingroups;
|
||||
unsigned ngpio_pingroups;
|
||||
|
||||
bool modes_supported;
|
||||
u16 mode;
|
||||
|
@ -136,6 +179,9 @@ struct spear_pmx {
|
|||
|
||||
/* exported routines */
|
||||
void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
|
||||
void __devinit
|
||||
pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
|
||||
unsigned count, u16 reg);
|
||||
int __devinit spear_pinctrl_probe(struct platform_device *pdev,
|
||||
struct spear_pinctrl_machdata *machdata);
|
||||
int __devexit spear_pinctrl_remove(struct platform_device *pdev);
|
||||
|
|
|
@ -2418,6 +2418,268 @@ static struct spear_function *spear1310_functions[] = {
|
|||
&gpt64_function,
|
||||
};
|
||||
|
||||
static const unsigned pin18[] = { 18, };
|
||||
static const unsigned pin19[] = { 19, };
|
||||
static const unsigned pin20[] = { 20, };
|
||||
static const unsigned pin21[] = { 21, };
|
||||
static const unsigned pin22[] = { 22, };
|
||||
static const unsigned pin23[] = { 23, };
|
||||
static const unsigned pin54[] = { 54, };
|
||||
static const unsigned pin55[] = { 55, };
|
||||
static const unsigned pin56[] = { 56, };
|
||||
static const unsigned pin57[] = { 57, };
|
||||
static const unsigned pin58[] = { 58, };
|
||||
static const unsigned pin59[] = { 59, };
|
||||
static const unsigned pin60[] = { 60, };
|
||||
static const unsigned pin61[] = { 61, };
|
||||
static const unsigned pin62[] = { 62, };
|
||||
static const unsigned pin63[] = { 63, };
|
||||
static const unsigned pin143[] = { 143, };
|
||||
static const unsigned pin144[] = { 144, };
|
||||
static const unsigned pin145[] = { 145, };
|
||||
static const unsigned pin146[] = { 146, };
|
||||
static const unsigned pin147[] = { 147, };
|
||||
static const unsigned pin148[] = { 148, };
|
||||
static const unsigned pin149[] = { 149, };
|
||||
static const unsigned pin150[] = { 150, };
|
||||
static const unsigned pin151[] = { 151, };
|
||||
static const unsigned pin152[] = { 152, };
|
||||
static const unsigned pin205[] = { 205, };
|
||||
static const unsigned pin206[] = { 206, };
|
||||
static const unsigned pin211[] = { 211, };
|
||||
static const unsigned pin212[] = { 212, };
|
||||
static const unsigned pin213[] = { 213, };
|
||||
static const unsigned pin214[] = { 214, };
|
||||
static const unsigned pin215[] = { 215, };
|
||||
static const unsigned pin216[] = { 216, };
|
||||
static const unsigned pin217[] = { 217, };
|
||||
static const unsigned pin218[] = { 218, };
|
||||
static const unsigned pin219[] = { 219, };
|
||||
static const unsigned pin220[] = { 220, };
|
||||
static const unsigned pin221[] = { 221, };
|
||||
static const unsigned pin222[] = { 222, };
|
||||
static const unsigned pin223[] = { 223, };
|
||||
static const unsigned pin224[] = { 224, };
|
||||
static const unsigned pin225[] = { 225, };
|
||||
static const unsigned pin226[] = { 226, };
|
||||
static const unsigned pin227[] = { 227, };
|
||||
static const unsigned pin228[] = { 228, };
|
||||
static const unsigned pin229[] = { 229, };
|
||||
static const unsigned pin230[] = { 230, };
|
||||
static const unsigned pin231[] = { 231, };
|
||||
static const unsigned pin232[] = { 232, };
|
||||
static const unsigned pin233[] = { 233, };
|
||||
static const unsigned pin234[] = { 234, };
|
||||
static const unsigned pin235[] = { 235, };
|
||||
static const unsigned pin236[] = { 236, };
|
||||
static const unsigned pin237[] = { 237, };
|
||||
static const unsigned pin238[] = { 238, };
|
||||
static const unsigned pin239[] = { 239, };
|
||||
static const unsigned pin240[] = { 240, };
|
||||
static const unsigned pin241[] = { 241, };
|
||||
static const unsigned pin242[] = { 242, };
|
||||
static const unsigned pin243[] = { 243, };
|
||||
static const unsigned pin244[] = { 244, };
|
||||
static const unsigned pin245[] = { 245, };
|
||||
|
||||
static const unsigned pin_grp0[] = { 173, 174, };
|
||||
static const unsigned pin_grp1[] = { 175, 185, 188, 197, 198, };
|
||||
static const unsigned pin_grp2[] = { 176, 177, 178, 179, 184, 186, 187, 189,
|
||||
190, 191, 192, };
|
||||
static const unsigned pin_grp3[] = { 180, 181, 182, 183, 193, 194, 195, 196, };
|
||||
static const unsigned pin_grp4[] = { 199, 200, };
|
||||
static const unsigned pin_grp5[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
||||
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, };
|
||||
static const unsigned pin_grp6[] = { 86, 87, 88, 89, 90, 91, 92, 93, };
|
||||
static const unsigned pin_grp7[] = { 98, 99, };
|
||||
static const unsigned pin_grp8[] = { 158, 159, 160, 161, 162, 163, 164, 165,
|
||||
166, 167, 168, 169, 170, 171, 172, };
|
||||
|
||||
/* Define muxreg arrays */
|
||||
DEFINE_2_MUXREG(i2c0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2C0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(ssp0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SSP0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(ssp0_cs0_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(ssp0_cs1_2_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS1_2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(i2s0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2S0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(i2s1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_I2S1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(clcd_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_CLCD1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(clcd_high_res_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_CLCD2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin18, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO15_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin19, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO14_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin20, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO13_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin21, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO12_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin22, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO11_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin23, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO10_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin143, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO00_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin144, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO01_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin145, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO02_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin146, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO03_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin147, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO04_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin148, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO05_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin149, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO06_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin150, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO07_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin151, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO08_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin152, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO09_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(smi_2_chips_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SMI_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin54, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS3_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin55, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin56, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFRSTPWDWN3_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin57, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin58, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin59, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin60, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFWPRT3_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin61, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFCE3_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin62, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD25_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin63, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD24_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp0, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICLK_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp1, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp2, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_RXCLK_RDV_TXEN_D03_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp3, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIID47_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp4, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MDC_MDIO_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp5, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD23_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp6, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MCI_DATA8_15_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp7, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFCE2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin_grp8, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND8_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(nand_16bit_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND16BIT_1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin205, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL1_MASK | PMX_NFCE1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin206, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL0_MASK | PMX_NFCE2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin211, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW1_MASK | PMX_NFWPRT1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin212, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW0_MASK | PMX_NFWPRT2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin213, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin214, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin215, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin216, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA3_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin217, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA4_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin218, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA5_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin219, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA6_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin220, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA7_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin221, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA1SD_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin222, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA2SD_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin223, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA3SD_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin224, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR0ALE_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin225, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR1CLECLK_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin226, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin227, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICECF_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin228, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICEXD_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin229, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICESDMMC_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin230, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin231, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF2_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin232, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDXD_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin233, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDSDMMC_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin234, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATADIR_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin235, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMARQWP_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin236, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDRE_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin237, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIOWRWE_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin238, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIRESETCF_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin239, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS0CE_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin240, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICFINTR_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin241, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDY_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin242, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin243, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMAACK_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin244, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCISDCMD_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(pin245, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCILEDS_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(keyboard_rowcol6_8_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROWCOL68_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(uart0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_UART0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(uart0_modem_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_UART0_MODEM_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(gpt0_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(gpt0_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(gpt1_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR0_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(gpt1_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR1_MASK, 0, 1);
|
||||
DEFINE_2_MUXREG(touch_xy_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_TOUCH_XY_MASK, 0, 1);
|
||||
|
||||
static struct spear_gpio_pingroup spear1310_gpio_pingroup[] = {
|
||||
GPIO_PINGROUP(i2c0_pins),
|
||||
GPIO_PINGROUP(ssp0_pins),
|
||||
GPIO_PINGROUP(ssp0_cs0_pins),
|
||||
GPIO_PINGROUP(ssp0_cs1_2_pins),
|
||||
GPIO_PINGROUP(i2s0_pins),
|
||||
GPIO_PINGROUP(i2s1_pins),
|
||||
GPIO_PINGROUP(clcd_pins),
|
||||
GPIO_PINGROUP(clcd_high_res_pins),
|
||||
GPIO_PINGROUP(pin18),
|
||||
GPIO_PINGROUP(pin19),
|
||||
GPIO_PINGROUP(pin20),
|
||||
GPIO_PINGROUP(pin21),
|
||||
GPIO_PINGROUP(pin22),
|
||||
GPIO_PINGROUP(pin23),
|
||||
GPIO_PINGROUP(pin143),
|
||||
GPIO_PINGROUP(pin144),
|
||||
GPIO_PINGROUP(pin145),
|
||||
GPIO_PINGROUP(pin146),
|
||||
GPIO_PINGROUP(pin147),
|
||||
GPIO_PINGROUP(pin148),
|
||||
GPIO_PINGROUP(pin149),
|
||||
GPIO_PINGROUP(pin150),
|
||||
GPIO_PINGROUP(pin151),
|
||||
GPIO_PINGROUP(pin152),
|
||||
GPIO_PINGROUP(smi_2_chips_pins),
|
||||
GPIO_PINGROUP(pin54),
|
||||
GPIO_PINGROUP(pin55),
|
||||
GPIO_PINGROUP(pin56),
|
||||
GPIO_PINGROUP(pin57),
|
||||
GPIO_PINGROUP(pin58),
|
||||
GPIO_PINGROUP(pin59),
|
||||
GPIO_PINGROUP(pin60),
|
||||
GPIO_PINGROUP(pin61),
|
||||
GPIO_PINGROUP(pin62),
|
||||
GPIO_PINGROUP(pin63),
|
||||
GPIO_PINGROUP(pin_grp0),
|
||||
GPIO_PINGROUP(pin_grp1),
|
||||
GPIO_PINGROUP(pin_grp2),
|
||||
GPIO_PINGROUP(pin_grp3),
|
||||
GPIO_PINGROUP(pin_grp4),
|
||||
GPIO_PINGROUP(pin_grp5),
|
||||
GPIO_PINGROUP(pin_grp6),
|
||||
GPIO_PINGROUP(pin_grp7),
|
||||
GPIO_PINGROUP(pin_grp8),
|
||||
GPIO_PINGROUP(nand_16bit_pins),
|
||||
GPIO_PINGROUP(pin205),
|
||||
GPIO_PINGROUP(pin206),
|
||||
GPIO_PINGROUP(pin211),
|
||||
GPIO_PINGROUP(pin212),
|
||||
GPIO_PINGROUP(pin213),
|
||||
GPIO_PINGROUP(pin214),
|
||||
GPIO_PINGROUP(pin215),
|
||||
GPIO_PINGROUP(pin216),
|
||||
GPIO_PINGROUP(pin217),
|
||||
GPIO_PINGROUP(pin218),
|
||||
GPIO_PINGROUP(pin219),
|
||||
GPIO_PINGROUP(pin220),
|
||||
GPIO_PINGROUP(pin221),
|
||||
GPIO_PINGROUP(pin222),
|
||||
GPIO_PINGROUP(pin223),
|
||||
GPIO_PINGROUP(pin224),
|
||||
GPIO_PINGROUP(pin225),
|
||||
GPIO_PINGROUP(pin226),
|
||||
GPIO_PINGROUP(pin227),
|
||||
GPIO_PINGROUP(pin228),
|
||||
GPIO_PINGROUP(pin229),
|
||||
GPIO_PINGROUP(pin230),
|
||||
GPIO_PINGROUP(pin231),
|
||||
GPIO_PINGROUP(pin232),
|
||||
GPIO_PINGROUP(pin233),
|
||||
GPIO_PINGROUP(pin234),
|
||||
GPIO_PINGROUP(pin235),
|
||||
GPIO_PINGROUP(pin236),
|
||||
GPIO_PINGROUP(pin237),
|
||||
GPIO_PINGROUP(pin238),
|
||||
GPIO_PINGROUP(pin239),
|
||||
GPIO_PINGROUP(pin240),
|
||||
GPIO_PINGROUP(pin241),
|
||||
GPIO_PINGROUP(pin242),
|
||||
GPIO_PINGROUP(pin243),
|
||||
GPIO_PINGROUP(pin244),
|
||||
GPIO_PINGROUP(pin245),
|
||||
GPIO_PINGROUP(keyboard_rowcol6_8_pins),
|
||||
GPIO_PINGROUP(uart0_pins),
|
||||
GPIO_PINGROUP(uart0_modem_pins),
|
||||
GPIO_PINGROUP(gpt0_tmr0_pins),
|
||||
GPIO_PINGROUP(gpt0_tmr1_pins),
|
||||
GPIO_PINGROUP(gpt1_tmr0_pins),
|
||||
GPIO_PINGROUP(gpt1_tmr1_pins),
|
||||
GPIO_PINGROUP(touch_xy_pins),
|
||||
};
|
||||
|
||||
static struct spear_pinctrl_machdata spear1310_machdata = {
|
||||
.pins = spear1310_pins,
|
||||
.npins = ARRAY_SIZE(spear1310_pins),
|
||||
|
@ -2425,6 +2687,8 @@ static struct spear_pinctrl_machdata spear1310_machdata = {
|
|||
.ngroups = ARRAY_SIZE(spear1310_pingroups),
|
||||
.functions = spear1310_functions,
|
||||
.nfunctions = ARRAY_SIZE(spear1310_functions),
|
||||
.gpio_pingroups = spear1310_gpio_pingroup,
|
||||
.ngpio_pingroups = ARRAY_SIZE(spear1310_gpio_pingroup),
|
||||
.modes_supported = false,
|
||||
};
|
||||
|
||||
|
|
|
@ -661,6 +661,8 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev)
|
|||
spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups);
|
||||
spear3xx_machdata.functions = spear300_functions;
|
||||
spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions);
|
||||
spear3xx_machdata.gpio_pingroups = NULL;
|
||||
spear3xx_machdata.ngpio_pingroups = 0;
|
||||
|
||||
spear3xx_machdata.modes_supported = true;
|
||||
spear3xx_machdata.pmx_modes = spear300_pmx_modes;
|
||||
|
|
|
@ -388,6 +388,8 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev)
|
|||
spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions);
|
||||
|
||||
pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
|
||||
pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups,
|
||||
spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG);
|
||||
|
||||
spear3xx_machdata.modes_supported = false;
|
||||
|
||||
|
|
|
@ -3431,6 +3431,8 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev)
|
|||
spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes);
|
||||
|
||||
pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
|
||||
pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups,
|
||||
spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG);
|
||||
|
||||
ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
|
||||
if (ret)
|
||||
|
|
|
@ -481,7 +481,44 @@ struct spear_function spear3xx_timer_2_3_function = {
|
|||
.ngroups = ARRAY_SIZE(timer_2_3_grps),
|
||||
};
|
||||
|
||||
/* Define muxreg arrays */
|
||||
DEFINE_MUXREG(firda_pins, 0, PMX_FIRDA_MASK, 0);
|
||||
DEFINE_MUXREG(i2c_pins, 0, PMX_I2C_MASK, 0);
|
||||
DEFINE_MUXREG(ssp_cs_pins, 0, PMX_SSP_CS_MASK, 0);
|
||||
DEFINE_MUXREG(ssp_pins, 0, PMX_SSP_MASK, 0);
|
||||
DEFINE_MUXREG(mii_pins, 0, PMX_MII_MASK, 0);
|
||||
DEFINE_MUXREG(gpio0_pin0_pins, 0, PMX_GPIO_PIN0_MASK, 0);
|
||||
DEFINE_MUXREG(gpio0_pin1_pins, 0, PMX_GPIO_PIN1_MASK, 0);
|
||||
DEFINE_MUXREG(gpio0_pin2_pins, 0, PMX_GPIO_PIN2_MASK, 0);
|
||||
DEFINE_MUXREG(gpio0_pin3_pins, 0, PMX_GPIO_PIN3_MASK, 0);
|
||||
DEFINE_MUXREG(gpio0_pin4_pins, 0, PMX_GPIO_PIN4_MASK, 0);
|
||||
DEFINE_MUXREG(gpio0_pin5_pins, 0, PMX_GPIO_PIN5_MASK, 0);
|
||||
DEFINE_MUXREG(uart0_ext_pins, 0, PMX_UART0_MODEM_MASK, 0);
|
||||
DEFINE_MUXREG(uart0_pins, 0, PMX_UART0_MASK, 0);
|
||||
DEFINE_MUXREG(timer_0_1_pins, 0, PMX_TIMER_0_1_MASK, 0);
|
||||
DEFINE_MUXREG(timer_2_3_pins, 0, PMX_TIMER_2_3_MASK, 0);
|
||||
|
||||
static struct spear_gpio_pingroup spear3xx_gpio_pingroup[] = {
|
||||
GPIO_PINGROUP(firda_pins),
|
||||
GPIO_PINGROUP(i2c_pins),
|
||||
GPIO_PINGROUP(ssp_cs_pins),
|
||||
GPIO_PINGROUP(ssp_pins),
|
||||
GPIO_PINGROUP(mii_pins),
|
||||
GPIO_PINGROUP(gpio0_pin0_pins),
|
||||
GPIO_PINGROUP(gpio0_pin1_pins),
|
||||
GPIO_PINGROUP(gpio0_pin2_pins),
|
||||
GPIO_PINGROUP(gpio0_pin3_pins),
|
||||
GPIO_PINGROUP(gpio0_pin4_pins),
|
||||
GPIO_PINGROUP(gpio0_pin5_pins),
|
||||
GPIO_PINGROUP(uart0_ext_pins),
|
||||
GPIO_PINGROUP(uart0_pins),
|
||||
GPIO_PINGROUP(timer_0_1_pins),
|
||||
GPIO_PINGROUP(timer_2_3_pins),
|
||||
};
|
||||
|
||||
struct spear_pinctrl_machdata spear3xx_machdata = {
|
||||
.pins = spear3xx_pins,
|
||||
.npins = ARRAY_SIZE(spear3xx_pins),
|
||||
.gpio_pingroups = spear3xx_gpio_pingroup,
|
||||
.ngpio_pingroups = ARRAY_SIZE(spear3xx_gpio_pingroup),
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
|
@ -134,6 +135,15 @@ struct gpio_chip {
|
|||
int (*of_xlate)(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec, u32 *flags);
|
||||
#endif
|
||||
#ifdef CONFIG_PINCTRL
|
||||
/*
|
||||
* If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
|
||||
* describe the actual pin range which they serve in an SoC. This
|
||||
* information would be used by pinctrl subsystem to configure
|
||||
* corresponding pins for gpio usage.
|
||||
*/
|
||||
struct list_head pin_ranges;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
|
||||
|
@ -257,4 +267,39 @@ static inline void gpio_unexport(unsigned gpio)
|
|||
}
|
||||
#endif /* CONFIG_GPIO_SYSFS */
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
|
||||
/**
|
||||
* struct gpio_pin_range - pin range controlled by a gpio chip
|
||||
* @head: list for maintaining set of pin ranges, used internally
|
||||
* @pctldev: pinctrl device which handles corresponding pins
|
||||
* @range: actual range of pins controlled by a gpio controller
|
||||
*/
|
||||
|
||||
struct gpio_pin_range {
|
||||
struct list_head node;
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct pinctrl_gpio_range range;
|
||||
};
|
||||
|
||||
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
||||
unsigned int pin_base, unsigned int npins);
|
||||
void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
||||
unsigned int pin_base, unsigned int npins)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gpiochip_remove_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PINCTRL */
|
||||
|
||||
#endif /* _ASM_GENERIC_GPIO_H */
|
||||
|
|
|
@ -72,9 +72,9 @@ static inline int irq_to_gpio(unsigned int irq)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */
|
||||
|
||||
#else
|
||||
#else /* ! CONFIG_GENERIC_GPIO */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -231,6 +231,20 @@ static inline int irq_to_gpio(unsigned irq)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
static inline int
|
||||
gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
||||
unsigned int pin_base, unsigned int npins)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gpiochip_remove_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
#endif /* ! CONFIG_GENERIC_GPIO */
|
||||
|
||||
#endif /* __LINUX_GPIO_H */
|
||||
|
|
|
@ -134,6 +134,22 @@ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
|
|||
extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *ranges,
|
||||
unsigned nranges);
|
||||
extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range);
|
||||
|
||||
extern struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname,
|
||||
struct pinctrl_gpio_range *range);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np);
|
||||
#else
|
||||
static inline
|
||||
struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
|
||||
extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
|
||||
#else
|
||||
|
|
|
@ -13,13 +13,11 @@
|
|||
* struct u300_gpio_platform - U300 GPIO platform data
|
||||
* @ports: number of GPIO block ports
|
||||
* @gpio_base: first GPIO number for this block (use a free range)
|
||||
* @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
|
||||
* @pinctrl_device: pin control device to spawn as child
|
||||
*/
|
||||
struct u300_gpio_platform {
|
||||
u8 ports;
|
||||
int gpio_base;
|
||||
int gpio_irq_base;
|
||||
struct platform_device *pinctrl_device;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue