mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
ARM: at91: add pinctrl support
This is also include the gpio controller as the IP share both. Each soc will have to describe the SoC limitation and pin configuration via DT. This will allow to do not need to touch the C code when adding new SoC if the IP version is supported. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
This commit is contained in:
parent
97e5e62524
commit
6732ae5cb4
136
Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
Normal file
136
Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
Normal file
@ -0,0 +1,136 @@
|
||||
* Atmel AT91 Pinmux Controller
|
||||
|
||||
The AT91 Pinmux Controler, enables the IC
|
||||
to share one PAD to several functional blocks. The sharing is done by
|
||||
multiplexing the PAD input/output signals. For each PAD there are up to
|
||||
8 muxing options (called periph modes). Since different modules require
|
||||
different PAD settings (like pull up, keeper, etc) the contoller controls
|
||||
also the PAD settings parameters.
|
||||
|
||||
Please refer to pinctrl-bindings.txt in this directory for details of the
|
||||
common pinctrl bindings used by client devices, including the meaning of the
|
||||
phrase "pin configuration node".
|
||||
|
||||
Atmel AT91 pin configuration node is a node of a group of pins which can be
|
||||
used for a specific device or function. This node represents both mux and config
|
||||
of the pins in that group. The 'pins' selects the function mode(also named pin
|
||||
mode) this pin can work on and the 'config' configures various pad settings
|
||||
such as pull-up, multi drive, etc.
|
||||
|
||||
Required properties for iomux controller:
|
||||
- compatible: "atmel,at91rm9200-pinctrl"
|
||||
- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
|
||||
configured in this periph mode. All the periph and bank need to be describe.
|
||||
|
||||
How to create such array:
|
||||
|
||||
Each column will represent the possible peripheral of the pinctrl
|
||||
Each line will represent a pio bank
|
||||
|
||||
Take an example on the 9260
|
||||
Peripheral: 2 ( A and B)
|
||||
Bank: 3 (A, B and C)
|
||||
=>
|
||||
|
||||
/* A B */
|
||||
0xffffffff 0xffc00c3b /* pioA */
|
||||
0xffffffff 0x7fff3ccf /* pioB */
|
||||
0xffffffff 0x007fffff /* pioC */
|
||||
|
||||
For each peripheral/bank we will descibe in a u32 if a pin can can be
|
||||
configured in it by putting 1 to the pin bit (1 << pin)
|
||||
|
||||
Let's take the pioA on peripheral B
|
||||
From the datasheet Table 10-2.
|
||||
Peripheral B
|
||||
PA0 MCDB0
|
||||
PA1 MCCDB
|
||||
PA2
|
||||
PA3 MCDB3
|
||||
PA4 MCDB2
|
||||
PA5 MCDB1
|
||||
PA6
|
||||
PA7
|
||||
PA8
|
||||
PA9
|
||||
PA10 ETX2
|
||||
PA11 ETX3
|
||||
PA12
|
||||
PA13
|
||||
PA14
|
||||
PA15
|
||||
PA16
|
||||
PA17
|
||||
PA18
|
||||
PA19
|
||||
PA20
|
||||
PA21
|
||||
PA22 ETXER
|
||||
PA23 ETX2
|
||||
PA24 ETX3
|
||||
PA25 ERX2
|
||||
PA26 ERX3
|
||||
PA27 ERXCK
|
||||
PA28 ECRS
|
||||
PA29 ECOL
|
||||
PA30 RXD4
|
||||
PA31 TXD4
|
||||
|
||||
=> 0xffc00c3b
|
||||
|
||||
Required properties for pin configuration node:
|
||||
- atmel,pins: 4 integers array, represents a group of pins mux and config
|
||||
setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
|
||||
The PERIPH 0 means gpio.
|
||||
|
||||
Bits used for CONFIG:
|
||||
PULL_UP(1 << 0): indicate this pin need a pull up.
|
||||
MULTIDRIVE(1 << 1): indicate this pin need to be configured as multidrive.
|
||||
|
||||
NOTE:
|
||||
Some requirements for using atmel,at91rm9200-pinctrl binding:
|
||||
1. We have pin function node defined under at91 controller node to represent
|
||||
what pinmux functions this SoC supports.
|
||||
2. The driver can use the function node's name and pin configuration node's
|
||||
name describe the pin function and group hierarchy.
|
||||
For example, Linux at91 pinctrl driver takes the function node's name
|
||||
as the function name and pin configuration node's name as group name to
|
||||
create the map table.
|
||||
3. Each pin configuration node should have a phandle, devices can set pins
|
||||
configurations by referring to the phandle of that pin configuration node.
|
||||
4. The gpio controller must be describe in the pinctrl simple-bus.
|
||||
|
||||
Examples:
|
||||
|
||||
pinctrl@fffff400 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
|
||||
reg = <0xfffff400 0x600>;
|
||||
|
||||
atmel,mux-mask = <
|
||||
/* A B */
|
||||
0xffffffff 0xffc00c3b /* pioA */
|
||||
0xffffffff 0x7fff3ccf /* pioB */
|
||||
0xffffffff 0x007fffff /* pioC */
|
||||
>;
|
||||
|
||||
/* shared pinctrl settings */
|
||||
dbgu {
|
||||
pinctrl_dbgu: dbgu-0 {
|
||||
atmel,pins =
|
||||
<1 14 0x1 0x0 /* PB14 periph A */
|
||||
1 15 0x1 0x1>; /* PB15 periph with pullup */
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dbgu: serial@fffff200 {
|
||||
compatible = "atmel,at91sam9260-usart";
|
||||
reg = <0xfffff200 0x200>;
|
||||
interrupts = <1 4 7>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_dbgu>;
|
||||
status = "disabled";
|
||||
};
|
@ -329,6 +329,8 @@ config ARCH_AT91
|
||||
select IRQ_DOMAIN
|
||||
select NEED_MACH_GPIO_H
|
||||
select NEED_MACH_IO_H if PCCARD
|
||||
select PINCTRL
|
||||
select PINCTRL_AT91 if USE_OF
|
||||
help
|
||||
This enables support for systems based on Atmel
|
||||
AT91RM9200 and AT91SAM9* processors.
|
||||
|
@ -30,8 +30,6 @@
|
||||
static const struct of_device_id irq_of_match[] __initconst = {
|
||||
|
||||
{ .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
|
||||
{ .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
|
||||
{ .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
|
||||
{ /*sentinel*/ }
|
||||
};
|
||||
|
||||
|
@ -23,8 +23,6 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
@ -717,80 +715,6 @@ postcore_initcall(at91_gpio_debugfs_init);
|
||||
*/
|
||||
static struct lock_class_key gpio_lock_class;
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
struct at91_gpio_chip *at91_gpio = h->host_data;
|
||||
|
||||
irq_set_lockdep_class(virq, &gpio_lock_class);
|
||||
|
||||
/*
|
||||
* Can use the "simple" and not "edge" handler since it's
|
||||
* shorter, and the AIC handles interrupts sanely.
|
||||
*/
|
||||
irq_set_chip_and_handler(virq, &gpio_irqchip,
|
||||
handle_simple_irq);
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
irq_set_chip_data(virq, at91_gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops at91_gpio_ops = {
|
||||
.map = at91_gpio_irq_map,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
int __init at91_gpio_of_irq_setup(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct at91_gpio_chip *prev = NULL;
|
||||
int alias_idx = of_alias_get_id(node, "gpio");
|
||||
struct at91_gpio_chip *at91_gpio = &gpio_chip[alias_idx];
|
||||
|
||||
/* Setup proper .irq_set_type function */
|
||||
if (has_pio3())
|
||||
gpio_irqchip.irq_set_type = alt_gpio_irq_type;
|
||||
else
|
||||
gpio_irqchip.irq_set_type = gpio_irq_type;
|
||||
|
||||
/* Disable irqs of this PIO controller */
|
||||
__raw_writel(~0, at91_gpio->regbase + PIO_IDR);
|
||||
|
||||
/* Setup irq domain */
|
||||
at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
|
||||
&at91_gpio_ops, at91_gpio);
|
||||
if (!at91_gpio->domain)
|
||||
panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
|
||||
at91_gpio->pioc_idx);
|
||||
|
||||
/* Setup chained handler */
|
||||
if (at91_gpio->pioc_idx)
|
||||
prev = &gpio_chip[at91_gpio->pioc_idx - 1];
|
||||
|
||||
/* The toplevel handler handles one bank of GPIOs, except
|
||||
* on some SoC it can handles up to three...
|
||||
* We only set up the handler for the first of the list.
|
||||
*/
|
||||
if (prev && prev->next == at91_gpio)
|
||||
return 0;
|
||||
|
||||
at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
|
||||
at91_gpio->pioc_hwirq);
|
||||
irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
|
||||
irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int __init at91_gpio_of_irq_setup(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* irqdomain initialization: pile up irqdomains on top of AIC range
|
||||
*/
|
||||
@ -989,85 +913,6 @@ err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
static void __init of_at91_gpio_init_one(struct device_node *np)
|
||||
{
|
||||
int alias_idx;
|
||||
struct at91_gpio_chip *at91_gpio;
|
||||
uint32_t ngpio;
|
||||
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
alias_idx = of_alias_get_id(np, "gpio");
|
||||
if (alias_idx >= MAX_GPIO_BANKS) {
|
||||
pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
|
||||
alias_idx, MAX_GPIO_BANKS);
|
||||
return;
|
||||
}
|
||||
|
||||
at91_gpio = &gpio_chip[alias_idx];
|
||||
at91_gpio->chip.base = alias_idx * MAX_NB_GPIO_PER_BANK;
|
||||
|
||||
at91_gpio->regbase = of_iomap(np, 0);
|
||||
if (!at91_gpio->regbase) {
|
||||
pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
|
||||
alias_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the interrupts property */
|
||||
if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
|
||||
pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
|
||||
alias_idx);
|
||||
goto ioremap_err;
|
||||
}
|
||||
|
||||
/* Get capabilities from compatibility property */
|
||||
if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
|
||||
at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
|
||||
|
||||
if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
|
||||
if (ngpio >= MAX_NB_GPIO_PER_BANK)
|
||||
pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
|
||||
alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
|
||||
else
|
||||
at91_gpio->chip.ngpio = ngpio;
|
||||
}
|
||||
|
||||
/* Setup clock */
|
||||
if (at91_gpio_setup_clk(alias_idx))
|
||||
goto ioremap_err;
|
||||
|
||||
at91_gpio->chip.of_node = np;
|
||||
gpio_banks = max(gpio_banks, alias_idx + 1);
|
||||
at91_gpio->pioc_idx = alias_idx;
|
||||
return;
|
||||
|
||||
ioremap_err:
|
||||
iounmap(at91_gpio->regbase);
|
||||
}
|
||||
|
||||
static int __init of_at91_gpio_init(void)
|
||||
{
|
||||
struct device_node *np = NULL;
|
||||
|
||||
/*
|
||||
* This isn't ideal, but it gets things hooked up until this
|
||||
* driver is converted into a platform_device
|
||||
*/
|
||||
for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
|
||||
of_at91_gpio_init_one(np);
|
||||
|
||||
return gpio_banks > 0 ? 0 : -EINVAL;
|
||||
}
|
||||
#else
|
||||
static int __init of_at91_gpio_init(void)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
|
||||
{
|
||||
struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
|
||||
@ -1102,11 +947,11 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
|
||||
|
||||
BUG_ON(nr_banks > MAX_GPIO_BANKS);
|
||||
|
||||
if (of_at91_gpio_init() < 0) {
|
||||
/* No GPIO controller found in device tree */
|
||||
for (i = 0; i < nr_banks; i++)
|
||||
at91_gpio_init_one(i, data[i].regbase, data[i].id);
|
||||
}
|
||||
if (of_have_populated_dt())
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr_banks; i++)
|
||||
at91_gpio_init_one(i, data[i].regbase, data[i].id);
|
||||
|
||||
for (i = 0; i < gpio_banks; i++) {
|
||||
at91_gpio = &gpio_chip[i];
|
||||
|
@ -26,6 +26,15 @@ config DEBUG_PINCTRL
|
||||
help
|
||||
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
|
||||
|
||||
config PINCTRL_AT91
|
||||
bool "AT91 pinctrl driver"
|
||||
depends on OF
|
||||
depends on ARCH_AT91
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
help
|
||||
Say Y here to enable the at91 pinctrl driver
|
||||
|
||||
config PINCTRL_BCM2835
|
||||
bool
|
||||
select PINMUX
|
||||
|
@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
|
||||
obj-$(CONFIG_PINCTRL) += devicetree.o
|
||||
endif
|
||||
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
|
||||
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
|
||||
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
|
||||
obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
|
||||
obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o
|
||||
|
1490
drivers/pinctrl/pinctrl-at91.c
Normal file
1490
drivers/pinctrl/pinctrl-at91.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user