Merge branch 'at91-3.4-cleanup2+DT' of git://github.com/at91linux/linux-at91 into next/dt

* 'at91-3.4-cleanup2+DT' of git://github.com/at91linux/linux-at91: (22 commits)
  ARM: at91: at91sam9x5cm/dt: add leds support
  ARM: at91: usb_a9g20/dt: add gpio-keys support
  ARM: at91: at91sam9m10g45ek/dt: add gpio-keys support
  ARM: at91: at91sam9m10g45ek/dt: add leds support
  ARM: at91: usb_a9g20/dt: add leds support
  ARM: at91/pio: add new PIO3 features
  ARM: at91: add sam9_smc.o to at91sam9x5 build
  ARM: at91/tc/clocksource: Add 32 bit variant to Timer Counter
  ARM: at91/tc: add device tree support to atmel_tclib
  ARM: at91/tclib: take iomem size from resource
  ARM: at91/pit: add traces in case of error
  ARM: at91: pit add DT support
  ARM: at91: AIC and GPIO IRQ device tree initialization
  ARM: at91/board-dt: remove AIC irq domain from board file
  ARM: at91/gpio: remove the static specification of gpio_chip.base
  ARM: at91/gpio: add .to_irq gpio_chip handler
  ARM: at91/gpio: non-DT builds do not have gpio_chip.of_node field
  ARM: at91/gpio: add irqdomain and DT support
  ARM: at91/gpio: change comments and one variable name
  ARM/USB: at91/ohci-at91: remove the use of irq_to_gpio
  ...
This commit is contained in:
Arnd Bergmann 2012-03-02 13:22:28 +00:00
commit 48b3b08e00
28 changed files with 1295 additions and 213 deletions

View file

@ -0,0 +1,38 @@
* Advanced Interrupt Controller (AIC)
Required properties:
- compatible: Should be "atmel,<chip>-aic"
- interrupt-controller: Identifies the node as an interrupt controller.
- interrupt-parent: For single AIC system, it is an empty property.
- #interrupt-cells: The number of cells to define the interrupts. It sould be 2.
The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
The second cell is used to specify flags:
bits[3:0] trigger type and level flags:
1 = low-to-high edge triggered.
2 = high-to-low edge triggered.
4 = active high level-sensitive.
8 = active low level-sensitive.
Valid combinations are 1, 2, 3, 4, 8.
Default flag for internal sources should be set to 4 (active high).
- reg: Should contain AIC registers location and length
Examples:
/*
* AIC
*/
aic: interrupt-controller@fffff000 {
compatible = "atmel,at91rm9200-aic";
interrupt-controller;
interrupt-parent;
#interrupt-cells = <2>;
reg = <0xfffff000 0x200>;
};
/*
* An interrupt generating device that is wired to an AIC.
*/
dma: dma-controller@ffffec00 {
compatible = "atmel,at91sam9g45-dma";
reg = <0xffffec00 0x200>;
interrupts = <21 4>;
};

View file

@ -0,0 +1,32 @@
Atmel AT91 device tree bindings.
================================
PIT Timer required properties:
- compatible: Should be "atmel,at91sam9260-pit"
- reg: Should contain registers location and length
- interrupts: Should contain interrupt for the PIT which is the IRQ line
shared across all System Controller members.
TC/TCLIB Timer required properties:
- compatible: Should be "atmel,<chip>-pit".
<chip> can be "at91rm9200" or "at91sam9x5"
- reg: Should contain registers location and length
- interrupts: Should contain all interrupts for the TC block
Note that you can specify several interrupt cells if the TC
block has one interrupt per channel.
Examples:
One interrupt per TC block:
tcb0: timer@fff7c000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
};
One interrupt per TC channel in a TC block:
tcb1: timer@fffdc000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfffdc000 0x100>;
interrupts = <26 4 27 4 28 4>;
};

View file

@ -0,0 +1,20 @@
* Atmel GPIO controller (PIO)
Required properties:
- compatible: "atmel,<chip>-gpio", where <chip> is at91rm9200 or at91sam9x5.
- reg: Should contain GPIO controller registers location and length
- interrupts: Should be the port interrupt shared by all the pins.
- #gpio-cells: Should be two. The first cell is the pin number and
the second cell is used to specify optional parameters (currently
unused).
- gpio-controller: Marks the device node as a GPIO controller.
Example:
pioA: gpio@fffff200 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff200 0x100>;
interrupts = <2 4>;
#gpio-cells = <2>;
gpio-controller;
};

View file

@ -322,6 +322,7 @@ config ARCH_AT91
select ARCH_REQUIRE_GPIOLIB
select HAVE_CLK
select CLKDEV_LOOKUP
select IRQ_DOMAIN
help
This enables support for systems based on the Atmel AT91RM9200,
AT91SAM9 processors.

View file

@ -23,6 +23,11 @@
serial4 = &usart3;
serial5 = &usart4;
serial6 = &usart5;
gpio0 = &pioA;
gpio1 = &pioB;
gpio2 = &pioC;
tcb0 = &tcb0;
tcb1 = &tcb1;
};
cpus {
cpu@0 {
@ -47,24 +52,69 @@
ranges;
aic: interrupt-controller@fffff000 {
#interrupt-cells = <1>;
#interrupt-cells = <2>;
compatible = "atmel,at91rm9200-aic";
interrupt-controller;
interrupt-parent;
reg = <0xfffff000 0x200>;
};
pit: timer@fffffd30 {
compatible = "atmel,at91sam9260-pit";
reg = <0xfffffd30 0xf>;
interrupts = <1 4>;
};
tcb0: timer@fffa0000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfffa0000 0x100>;
interrupts = <17 4 18 4 19 4>;
};
tcb1: timer@fffdc000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfffdc000 0x100>;
interrupts = <26 4 27 4 28 4>;
};
pioA: gpio@fffff400 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x100>;
interrupts = <2 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioB: gpio@fffff600 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff600 0x100>;
interrupts = <3 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioC: gpio@fffff800 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff800 0x100>;
interrupts = <4 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
dbgu: serial@fffff200 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffff200 0x200>;
interrupts = <1>;
interrupts = <1 4>;
status = "disabled";
};
usart0: serial@fffb0000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffb0000 0x200>;
interrupts = <6>;
interrupts = <6 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -73,7 +123,7 @@
usart1: serial@fffb4000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffb4000 0x200>;
interrupts = <7>;
interrupts = <7 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -82,7 +132,7 @@
usart2: serial@fffb8000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffb8000 0x200>;
interrupts = <8>;
interrupts = <8 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -91,7 +141,7 @@
usart3: serial@fffd0000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffd0000 0x200>;
interrupts = <23>;
interrupts = <23 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -100,7 +150,7 @@
usart4: serial@fffd4000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffd4000 0x200>;
interrupts = <24>;
interrupts = <24 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -109,7 +159,7 @@
usart5: serial@fffd8000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffd8000 0x200>;
interrupts = <25>;
interrupts = <25 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -118,7 +168,7 @@
macb0: ethernet@fffc4000 {
compatible = "cdns,at32ap7000-macb", "cdns,macb";
reg = <0xfffc4000 0x100>;
interrupts = <21>;
interrupts = <21 4>;
status = "disabled";
};
};

View file

@ -22,6 +22,13 @@
serial2 = &usart1;
serial3 = &usart2;
serial4 = &usart3;
gpio0 = &pioA;
gpio1 = &pioB;
gpio2 = &pioC;
gpio3 = &pioD;
gpio4 = &pioE;
tcb0 = &tcb0;
tcb1 = &tcb1;
};
cpus {
cpu@0 {
@ -46,30 +53,94 @@
ranges;
aic: interrupt-controller@fffff000 {
#interrupt-cells = <1>;
#interrupt-cells = <2>;
compatible = "atmel,at91rm9200-aic";
interrupt-controller;
interrupt-parent;
reg = <0xfffff000 0x200>;
};
pit: timer@fffffd30 {
compatible = "atmel,at91sam9260-pit";
reg = <0xfffffd30 0xf>;
interrupts = <1 4>;
};
tcb0: timer@fff7c000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
};
tcb1: timer@fffd4000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfffd4000 0x100>;
interrupts = <18 4>;
};
dma: dma-controller@ffffec00 {
compatible = "atmel,at91sam9g45-dma";
reg = <0xffffec00 0x200>;
interrupts = <21>;
interrupts = <21 4>;
};
pioA: gpio@fffff200 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff200 0x100>;
interrupts = <2 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioB: gpio@fffff400 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x100>;
interrupts = <3 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioC: gpio@fffff600 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff600 0x100>;
interrupts = <4 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioD: gpio@fffff800 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff800 0x100>;
interrupts = <5 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioE: gpio@fffffa00 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffffa00 0x100>;
interrupts = <5 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
dbgu: serial@ffffee00 {
compatible = "atmel,at91sam9260-usart";
reg = <0xffffee00 0x200>;
interrupts = <1>;
interrupts = <1 4>;
status = "disabled";
};
usart0: serial@fff8c000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfff8c000 0x200>;
interrupts = <7>;
interrupts = <7 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -78,7 +149,7 @@
usart1: serial@fff90000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfff90000 0x200>;
interrupts = <8>;
interrupts = <8 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -87,7 +158,7 @@
usart2: serial@fff94000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfff94000 0x200>;
interrupts = <9>;
interrupts = <9 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -96,7 +167,7 @@
usart3: serial@fff98000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfff98000 0x200>;
interrupts = <10>;
interrupts = <10 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
@ -105,7 +176,7 @@
macb0: ethernet@fffbc000 {
compatible = "cdns,at32ap7000-macb", "cdns,macb";
reg = <0xfffbc000 0x100>;
interrupts = <25>;
interrupts = <25 4>;
status = "disabled";
};
};

View file

@ -37,4 +37,76 @@
};
};
};
leds {
compatible = "gpio-leds";
d8 {
label = "d8";
gpios = <&pioD 30 0>;
linux,default-trigger = "heartbeat";
};
d6 {
label = "d6";
gpios = <&pioD 0 1>;
linux,default-trigger = "nand-disk";
};
d7 {
label = "d7";
gpios = <&pioD 31 1>;
linux,default-trigger = "mmc0";
};
};
gpio_keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
left_click {
label = "left_click";
gpios = <&pioB 6 1>;
linux,code = <272>;
gpio-key,wakeup;
};
right_click {
label = "right_click";
gpios = <&pioB 7 1>;
linux,code = <273>;
gpio-key,wakeup;
};
left {
label = "Joystick Left";
gpios = <&pioB 14 1>;
linux,code = <105>;
};
right {
label = "Joystick Right";
gpios = <&pioB 15 1>;
linux,code = <106>;
};
up {
label = "Joystick Up";
gpios = <&pioB 16 1>;
linux,code = <103>;
};
down {
label = "Joystick Down";
gpios = <&pioB 17 1>;
linux,code = <108>;
};
enter {
label = "Joystick Press";
gpios = <&pioB 18 1>;
linux,code = <28>;
};
};
};

View file

@ -89,35 +89,39 @@
};
pioA: gpio@fffff400 {
compatible = "atmel,at91rm9200-gpio";
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x100>;
interrupts = <2 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioB: gpio@fffff600 {
compatible = "atmel,at91rm9200-gpio";
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffff600 0x100>;
interrupts = <2 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioC: gpio@fffff800 {
compatible = "atmel,at91rm9200-gpio";
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffff800 0x100>;
interrupts = <3 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioD: gpio@fffffa00 {
compatible = "atmel,at91rm9200-gpio";
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffffa00 0x100>;
interrupts = <3 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
dbgu: serial@fffff200 {

View file

@ -11,4 +11,19 @@
memory@20000000 {
reg = <0x20000000 0x8000000>;
};
leds {
compatible = "gpio-leds";
pb18 {
label = "pb18";
gpios = <&pioB 18 1>;
linux,default-trigger = "heartbeat";
};
pd21 {
label = "pd21";
gpios = <&pioD 21 0>;
};
};
};

View file

@ -32,4 +32,27 @@
};
};
};
leds {
compatible = "gpio-leds";
user_led {
label = "user_led";
gpios = <&pioB 21 1>;
linux,default-trigger = "heartbeat";
};
};
gpio_keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
user_pb {
label = "user_pb";
gpios = <&pioB 10 1>;
linux,code = <28>;
gpio-key,wakeup;
};
};
};

View file

@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_d
obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o
obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
# AT91RM9200 board-specific support

View file

@ -209,6 +209,13 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
/* more tc lookup table for DT entries */
CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
CLKDEV_CON_DEV_ID("t0_clk", "fffdc000.timer", &tc3_clk),
CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),

View file

@ -642,7 +642,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
static struct resource tcb0_resources[] = {
[0] = {
.start = AT91SAM9260_BASE_TCB0,
.end = AT91SAM9260_BASE_TCB0 + SZ_16K - 1,
.end = AT91SAM9260_BASE_TCB0 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@ -672,7 +672,7 @@ static struct platform_device at91sam9260_tcb0_device = {
static struct resource tcb1_resources[] = {
[0] = {
.start = AT91SAM9260_BASE_TCB1,
.end = AT91SAM9260_BASE_TCB1 + SZ_16K - 1,
.end = AT91SAM9260_BASE_TCB1 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@ -699,8 +699,25 @@ static struct platform_device at91sam9260_tcb1_device = {
.num_resources = ARRAY_SIZE(tcb1_resources),
};
#if defined(CONFIG_OF)
static struct of_device_id tcb_ids[] = {
{ .compatible = "atmel,at91rm9200-tcb" },
{ /*sentinel*/ }
};
#endif
static void __init at91_add_device_tc(void)
{
#if defined(CONFIG_OF)
struct device_node *np;
np = of_find_matching_node(NULL, tcb_ids);
if (np) {
of_node_put(np);
return;
}
#endif
platform_device_register(&at91sam9260_tcb0_device);
platform_device_register(&at91sam9260_tcb1_device);
}

View file

@ -14,6 +14,9 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <asm/mach/time.h>
@ -133,7 +136,8 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
static struct irqaction at91sam926x_pit_irq = {
.name = "at91_tick",
.flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = at91sam926x_pit_interrupt
.handler = at91sam926x_pit_interrupt,
.irq = AT91_ID_SYS,
};
static void at91sam926x_pit_reset(void)
@ -149,6 +153,51 @@ static void at91sam926x_pit_reset(void)
pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
}
#ifdef CONFIG_OF
static struct of_device_id pit_timer_ids[] = {
{ .compatible = "atmel,at91sam9260-pit" },
{ /* sentinel */ }
};
static int __init of_at91sam926x_pit_init(void)
{
struct device_node *np;
int ret;
np = of_find_matching_node(NULL, pit_timer_ids);
if (!np)
goto err;
pit_base_addr = of_iomap(np, 0);
if (!pit_base_addr)
goto node_err;
/* Get the interrupts property */
ret = irq_of_parse_and_map(np, 0);
if (!ret) {
pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
goto ioremap_err;
}
at91sam926x_pit_irq.irq = ret;
of_node_put(np);
return 0;
ioremap_err:
iounmap(pit_base_addr);
node_err:
of_node_put(np);
err:
return -EINVAL;
}
#else
static int __init of_at91sam926x_pit_init(void)
{
return -EINVAL;
}
#endif
/*
* Set up both clocksource and clockevent support.
*/
@ -156,6 +205,10 @@ static void __init at91sam926x_pit_init(void)
{
unsigned long pit_rate;
unsigned bits;
int ret;
/* For device tree enabled device: initialize here */
of_at91sam926x_pit_init();
/*
* Use our actual MCK to figure out how many MCK/16 ticks per
@ -177,7 +230,9 @@ static void __init at91sam926x_pit_init(void)
clocksource_register_hz(&pit_clk, pit_rate);
/* Set up irq handler */
setup_irq(AT91_ID_SYS, &at91sam926x_pit_irq);
ret = setup_irq(at91sam926x_pit_irq.irq, &at91sam926x_pit_irq);
if (ret)
pr_crit("AT91: PIT: Unable to setup IRQ\n");
/* Set up and register clockevents */
pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift);
@ -193,6 +248,15 @@ static void at91sam926x_pit_suspend(void)
void __init at91sam926x_ioremap_pit(u32 addr)
{
#if defined(CONFIG_OF)
struct device_node *np =
of_find_matching_node(NULL, pit_timer_ids);
if (np) {
of_node_put(np);
return;
}
#endif
pit_base_addr = ioremap(addr, 16);
if (!pit_base_addr)

View file

@ -229,6 +229,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk),
/* more tc lookup table for DT entries */
CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),

View file

@ -1052,7 +1052,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
static struct resource tcb0_resources[] = {
[0] = {
.start = AT91SAM9G45_BASE_TCB0,
.end = AT91SAM9G45_BASE_TCB0 + SZ_16K - 1,
.end = AT91SAM9G45_BASE_TCB0 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@ -1073,7 +1073,7 @@ static struct platform_device at91sam9g45_tcb0_device = {
static struct resource tcb1_resources[] = {
[0] = {
.start = AT91SAM9G45_BASE_TCB1,
.end = AT91SAM9G45_BASE_TCB1 + SZ_16K - 1,
.end = AT91SAM9G45_BASE_TCB1 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@ -1090,8 +1090,25 @@ static struct platform_device at91sam9g45_tcb1_device = {
.num_resources = ARRAY_SIZE(tcb1_resources),
};
#if defined(CONFIG_OF)
static struct of_device_id tcb_ids[] = {
{ .compatible = "atmel,at91rm9200-tcb" },
{ /*sentinel*/ }
};
#endif
static void __init at91_add_device_tc(void)
{
#if defined(CONFIG_OF)
struct device_node *np;
np = of_find_matching_node(NULL, tcb_ids);
if (np) {
of_node_put(np);
return;
}
#endif
platform_device_register(&at91sam9g45_tcb0_device);
platform_device_register(&at91sam9g45_tcb1_device);
}

View file

@ -301,8 +301,6 @@ static void __init at91sam9x5_map_io(void)
static void __init at91sam9x5_ioremap_registers(void)
{
if (of_at91sam926x_pit_init() < 0)
panic("Impossible to find PIT\n");
at91_ioremap_ramc(0, AT91SAM9X5_BASE_DDRSDRC0, 512);
}

View file

@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
@ -82,15 +82,17 @@ static void __init ek_add_device_nand(void)
at91_add_device_nand(&ek_nand_data);
}
static const struct of_device_id aic_of_match[] __initconst = {
{ .compatible = "atmel,at91rm9200-aic", },
{},
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*/ }
};
static void __init at91_dt_init_irq(void)
{
irq_domain_generate_simple(aic_of_match, 0xfffff000, 0);
at91_init_irq_default();
of_irq_init(irq_of_match);
}
static void __init at91_dt_device_init(void)

View file

@ -145,11 +145,11 @@ static struct i2c_board_info __initdata snapper9260_i2c_devices[] = {
/* Audio codec */
I2C_BOARD_INFO("tlv320aic23", 0x1a),
},
{
};
static struct i2c_board_info __initdata snapper9260_i2c_isl1208 = {
/* RTC */
I2C_BOARD_INFO("isl1208", 0x6f),
.irq = gpio_to_irq(AT91_PIN_PA31),
},
};
static void __init snapper9260_add_device_nand(void)
@ -163,6 +163,10 @@ static void __init snapper9260_board_init(void)
{
at91_add_device_i2c(snapper9260_i2c_devices,
ARRAY_SIZE(snapper9260_i2c_devices));
snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31);
i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1);
at91_add_device_serial();
at91_add_device_usbh(&snapper9260_usbh_data);
at91_add_device_udc(&snapper9260_udc_data);

View file

@ -9,6 +9,7 @@
*/
#include <linux/clkdev.h>
#include <linux/of.h>
/* Map io */
extern void __init at91_map_io(void);
@ -25,6 +26,9 @@ extern void __init at91_init_irq_default(void);
extern void __init at91_init_interrupts(unsigned int priority[]);
extern void __init at91x40_init_interrupts(unsigned int priority[]);
extern void __init at91_aic_init(unsigned int priority[]);
extern int __init at91_aic_of_init(struct device_node *node,
struct device_node *parent);
/* Timer */
struct sys_timer;
@ -84,5 +88,7 @@ struct at91_gpio_bank {
};
extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks);
extern void __init at91_gpio_irq_setup(void);
extern int __init at91_gpio_of_irq_setup(struct device_node *node,
struct device_node *parent);
extern int at91_extern_irq;

View file

@ -11,6 +11,7 @@
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@ -20,6 +21,10 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <mach/hardware.h>
#include <mach/at91_pio.h>
@ -29,9 +34,12 @@
struct at91_gpio_chip {
struct gpio_chip chip;
struct at91_gpio_chip *next; /* Bank sharing same clock */
int id; /* ID of register bank */
void __iomem *regbase; /* Base of register bank */
int pioc_hwirq; /* PIO bank interrupt identifier on AIC */
int pioc_virq; /* PIO bank Linux virtual interrupt */
int pioc_idx; /* PIO bank index */
void __iomem *regbase; /* PIO bank virtual address */
struct clk *clock; /* associated clock */
struct irq_domain *domain; /* associated irq domain */
};
#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
@ -43,8 +51,9 @@ static int at91_gpiolib_direction_output(struct gpio_chip *chip,
unsigned offset, int val);
static int at91_gpiolib_direction_input(struct gpio_chip *chip,
unsigned offset);
static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio) \
#define AT91_GPIO_CHIP(name, nr_gpio) \
{ \
.chip = { \
.label = name, \
@ -53,20 +62,28 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
.get = at91_gpiolib_get, \
.set = at91_gpiolib_set, \
.dbg_show = at91_gpiolib_dbg_show, \
.base = base_gpio, \
.to_irq = at91_gpiolib_to_irq, \
.ngpio = nr_gpio, \
}, \
}
static struct at91_gpio_chip gpio_chip[] = {
AT91_GPIO_CHIP("pioA", 0x00, 32),
AT91_GPIO_CHIP("pioB", 0x20, 32),
AT91_GPIO_CHIP("pioC", 0x40, 32),
AT91_GPIO_CHIP("pioD", 0x60, 32),
AT91_GPIO_CHIP("pioE", 0x80, 32),
AT91_GPIO_CHIP("pioA", 32),
AT91_GPIO_CHIP("pioB", 32),
AT91_GPIO_CHIP("pioC", 32),
AT91_GPIO_CHIP("pioD", 32),
AT91_GPIO_CHIP("pioE", 32),
};
static int gpio_banks;
static unsigned long at91_gpio_caps;
/* All PIO controllers support PIO3 features */
#define AT91_GPIO_CAP_PIO3 (1 << 0)
#define has_pio3() (at91_gpio_caps & AT91_GPIO_CAP_PIO3)
/*--------------------------------------------------------------------------*/
static inline void __iomem *pin_to_controller(unsigned pin)
{
@ -83,6 +100,25 @@ static inline unsigned pin_to_mask(unsigned pin)
}
static char peripheral_function(void __iomem *pio, unsigned mask)
{
char ret = 'X';
u8 select;
if (pio) {
if (has_pio3()) {
select = !!(__raw_readl(pio + PIO_ABCDSR1) & mask);
select |= (!!(__raw_readl(pio + PIO_ABCDSR2) & mask) << 1);
ret = 'A' + select;
} else {
ret = __raw_readl(pio + PIO_ABSR) & mask ?
'B' : 'A';
}
}
return ret;
}
/*--------------------------------------------------------------------------*/
/* Not all hardware capabilities are exposed through these calls; they
@ -130,7 +166,14 @@ int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup)
__raw_writel(mask, pio + PIO_IDR);
__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
__raw_writel(mask, pio + PIO_ASR);
if (has_pio3()) {
__raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask,
pio + PIO_ABCDSR1);
__raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
pio + PIO_ABCDSR2);
} else {
__raw_writel(mask, pio + PIO_ASR);
}
__raw_writel(mask, pio + PIO_PDR);
return 0;
}
@ -150,7 +193,14 @@ int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup)
__raw_writel(mask, pio + PIO_IDR);
__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
__raw_writel(mask, pio + PIO_BSR);
if (has_pio3()) {
__raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask,
pio + PIO_ABCDSR1);
__raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
pio + PIO_ABCDSR2);
} else {
__raw_writel(mask, pio + PIO_BSR);
}
__raw_writel(mask, pio + PIO_PDR);
return 0;
}
@ -158,8 +208,50 @@ EXPORT_SYMBOL(at91_set_B_periph);
/*
* mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
* configure it for an input.
* mux the pin to the "C" internal peripheral role.
*/
int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio || !has_pio3())
return -EINVAL;
__raw_writel(mask, pio + PIO_IDR);
__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
__raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
__raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
__raw_writel(mask, pio + PIO_PDR);
return 0;
}
EXPORT_SYMBOL(at91_set_C_periph);
/*
* mux the pin to the "D" internal peripheral role.
*/
int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio || !has_pio3())
return -EINVAL;
__raw_writel(mask, pio + PIO_IDR);
__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
__raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
__raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
__raw_writel(mask, pio + PIO_PDR);
return 0;
}
EXPORT_SYMBOL(at91_set_D_periph);
/*
* mux the pin to the gpio controller (instead of "A", "B", "C"
* or "D" peripheral), and configure it for an input.
*/
int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup)
{
@ -179,8 +271,8 @@ EXPORT_SYMBOL(at91_set_gpio_input);
/*
* mux the pin to the gpio controller (instead of "A" or "B" peripheral),
* and configure it for an output.
* mux the pin to the gpio controller (instead of "A", "B", "C"
* or "D" peripheral), and configure it for an output.
*/
int __init_or_module at91_set_gpio_output(unsigned pin, int value)
{
@ -210,11 +302,36 @@ int __init_or_module at91_set_deglitch(unsigned pin, int is_on)
if (!pio)
return -EINVAL;
if (has_pio3() && is_on)
__raw_writel(mask, pio + PIO_IFSCDR);
__raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
return 0;
}
EXPORT_SYMBOL(at91_set_deglitch);
/*
* enable/disable the debounce filter;
*/
int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio || !has_pio3())
return -EINVAL;
if (is_on) {
__raw_writel(mask, pio + PIO_IFSCER);
__raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR);
__raw_writel(mask, pio + PIO_IFER);
} else {
__raw_writel(mask, pio + PIO_IFDR);
}
return 0;
}
EXPORT_SYMBOL(at91_set_debounce);
/*
* enable/disable the multi-driver; This is only valid for output and
* allows the output pin to run as an open collector output.
@ -232,6 +349,41 @@ int __init_or_module at91_set_multi_drive(unsigned pin, int is_on)
}
EXPORT_SYMBOL(at91_set_multi_drive);
/*
* enable/disable the pull-down.
* If pull-up already enabled while calling the function, we disable it.
*/
int __init_or_module at91_set_pulldown(unsigned pin, int is_on)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio || !has_pio3())
return -EINVAL;
/* Disable pull-up anyway */
__raw_writel(mask, pio + PIO_PUDR);
__raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
return 0;
}
EXPORT_SYMBOL(at91_set_pulldown);
/*
* disable Schmitt trigger
*/
int __init_or_module at91_disable_schmitt_trig(unsigned pin)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio || !has_pio3())
return -EINVAL;
__raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
return 0;
}
EXPORT_SYMBOL(at91_disable_schmitt_trig);
/*
* assuming the pin is muxed as a gpio output, set its value.
*/
@ -273,9 +425,9 @@ static u32 backups[MAX_GPIO_BANKS];
static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
{
unsigned pin = irq_to_gpio(d->irq);
unsigned mask = pin_to_mask(pin);
unsigned bank = pin / 32;
struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
unsigned mask = 1 << d->hwirq;
unsigned bank = at91_gpio->pioc_idx;
if (unlikely(bank >= MAX_GPIO_BANKS))
return -EINVAL;
@ -285,7 +437,7 @@ static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
else
wakeups[bank] &= ~mask;
irq_set_irq_wake(gpio_chip[bank].id, state);
irq_set_irq_wake(at91_gpio->pioc_virq, state);
return 0;
}
@ -301,9 +453,10 @@ void at91_gpio_suspend(void)
__raw_writel(backups[i], pio + PIO_IDR);
__raw_writel(wakeups[i], pio + PIO_IER);
if (!wakeups[i])
if (!wakeups[i]) {
clk_unprepare(gpio_chip[i].clock);
clk_disable(gpio_chip[i].clock);
else {
} else {
#ifdef CONFIG_PM_DEBUG
printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
#endif
@ -318,8 +471,10 @@ void at91_gpio_resume(void)
for (i = 0; i < gpio_banks; i++) {
void __iomem *pio = gpio_chip[i].regbase;
if (!wakeups[i])
clk_enable(gpio_chip[i].clock);
if (!wakeups[i]) {
if (clk_prepare(gpio_chip[i].clock) == 0)
clk_enable(gpio_chip[i].clock);
}
__raw_writel(wakeups[i], pio + PIO_IDR);
__raw_writel(backups[i], pio + PIO_IER);
@ -335,7 +490,10 @@ void at91_gpio_resume(void)
* To use any AT91_PIN_* as an externally triggered IRQ, first call
* at91_set_gpio_input() then maybe enable its glitch filter.
* Then just request_irq() with the pin ID; it works like any ARM IRQ
* handler, though it always triggers on rising and falling edges.
* handler.
* First implementation always triggers on rising and falling edges
* whereas the newer PIO3 can be additionally configured to trigger on
* level, edge with any polarity.
*
* Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
* configuring them with at91_set_a_periph() or at91_set_b_periph().
@ -344,9 +502,9 @@ void at91_gpio_resume(void)
static void gpio_irq_mask(struct irq_data *d)
{
unsigned pin = irq_to_gpio(d->irq);
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << d->hwirq;
if (pio)
__raw_writel(mask, pio + PIO_IDR);
@ -354,9 +512,9 @@ static void gpio_irq_mask(struct irq_data *d)
static void gpio_irq_unmask(struct irq_data *d)
{
unsigned pin = irq_to_gpio(d->irq);
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << d->hwirq;
if (pio)
__raw_writel(mask, pio + PIO_IER);
@ -373,23 +531,66 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
}
}
/* Alternate irq type for PIO3 support */
static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
{
struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << d->hwirq;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
__raw_writel(mask, pio + PIO_ESR);
__raw_writel(mask, pio + PIO_REHLSR);
break;
case IRQ_TYPE_EDGE_FALLING:
__raw_writel(mask, pio + PIO_ESR);
__raw_writel(mask, pio + PIO_FELLSR);
break;
case IRQ_TYPE_LEVEL_LOW:
__raw_writel(mask, pio + PIO_LSR);
__raw_writel(mask, pio + PIO_FELLSR);
break;
case IRQ_TYPE_LEVEL_HIGH:
__raw_writel(mask, pio + PIO_LSR);
__raw_writel(mask, pio + PIO_REHLSR);
break;
case IRQ_TYPE_EDGE_BOTH:
/*
* disable additional interrupt modes:
* fall back to default behavior
*/
__raw_writel(mask, pio + PIO_AIMDR);
return 0;
case IRQ_TYPE_NONE:
default:
pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
return -EINVAL;
}
/* enable additional interrupt modes */
__raw_writel(mask, pio + PIO_AIMER);
return 0;
}
static struct irq_chip gpio_irqchip = {
.name = "GPIO",
.irq_disable = gpio_irq_mask,
.irq_mask = gpio_irq_mask,
.irq_unmask = gpio_irq_unmask,
.irq_set_type = gpio_irq_type,
/* .irq_set_type is set dynamically */
.irq_set_wake = gpio_irq_set_wake,
};
static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
unsigned irq_pin;
struct irq_data *idata = irq_desc_get_irq_data(desc);
struct irq_chip *chip = irq_data_get_irq_chip(idata);
struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
void __iomem *pio = at91_gpio->regbase;
u32 isr;
unsigned long isr;
int n;
/* temporarily mask (level sensitive) parent IRQ */
chip->irq_ack(idata);
@ -407,13 +608,10 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
continue;
}
irq_pin = gpio_to_irq(at91_gpio->chip.base);
while (isr) {
if (isr & 1)
generic_handle_irq(irq_pin);
irq_pin++;
isr >>= 1;
n = find_first_bit(&isr, BITS_PER_LONG);
while (n < BITS_PER_LONG) {
generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
}
}
chip->irq_unmask(idata);
@ -424,6 +622,33 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
#ifdef CONFIG_DEBUG_FS
static void gpio_printf(struct seq_file *s, void __iomem *pio, unsigned mask)
{
char *trigger = NULL;
char *polarity = NULL;
if (__raw_readl(pio + PIO_IMR) & mask) {
if (!has_pio3() || !(__raw_readl(pio + PIO_AIMMR) & mask )) {
trigger = "edge";
polarity = "both";
} else {
if (__raw_readl(pio + PIO_ELSR) & mask) {
trigger = "level";
polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
"high" : "low";
} else {
trigger = "edge";
polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
"rising" : "falling";
}
}
seq_printf(s, "IRQ:%s-%s\t", trigger, polarity);
} else {
seq_printf(s, "GPIO:%s\t\t",
__raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
}
}
static int at91_gpio_show(struct seq_file *s, void *unused)
{
int bank, j;
@ -431,7 +656,7 @@ static int at91_gpio_show(struct seq_file *s, void *unused)
/* print heading */
seq_printf(s, "Pin\t");
for (bank = 0; bank < gpio_banks; bank++) {
seq_printf(s, "PIO%c\t", 'A' + bank);
seq_printf(s, "PIO%c\t\t", 'A' + bank);
};
seq_printf(s, "\n\n");
@ -445,11 +670,10 @@ static int at91_gpio_show(struct seq_file *s, void *unused)
unsigned mask = pin_to_mask(pin);
if (__raw_readl(pio + PIO_PSR) & mask)
seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
gpio_printf(s, pio, mask);
else
seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A");
seq_printf(s, "\t");
seq_printf(s, "%c\t\t",
peripheral_function(pio, mask));
}
seq_printf(s, "\n");
@ -488,46 +712,152 @@ 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
*/
static void __init at91_gpio_irqdomain(struct at91_gpio_chip *at91_gpio)
{
int irq_base;
irq_base = irq_alloc_descs(-1, 0, at91_gpio->chip.ngpio, 0);
if (irq_base < 0)
panic("at91_gpio.%d: error %d: couldn't allocate IRQ numbers.\n",
at91_gpio->pioc_idx, irq_base);
at91_gpio->domain = irq_domain_add_legacy(NULL, at91_gpio->chip.ngpio,
irq_base, 0,
&irq_domain_simple_ops, NULL);
if (!at91_gpio->domain)
panic("at91_gpio.%d: couldn't allocate irq domain.\n",
at91_gpio->pioc_idx);
}
/*
* Called from the processor-specific init to enable GPIO interrupt support.
*/
void __init at91_gpio_irq_setup(void)
{
unsigned pioc, irq = gpio_to_irq(0);
unsigned pioc;
int gpio_irqnbr = 0;
struct at91_gpio_chip *this, *prev;
/* 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;
for (pioc = 0, this = gpio_chip, prev = NULL;
pioc++ < gpio_banks;
prev = this, this++) {
unsigned id = this->id;
unsigned i;
int offset;
__raw_writel(~0, this->regbase + PIO_IDR);
for (i = 0, irq = gpio_to_irq(this->chip.base); i < 32;
i++, irq++) {
irq_set_lockdep_class(irq, &gpio_lock_class);
/* setup irq domain for this GPIO controller */
at91_gpio_irqdomain(this);
for (offset = 0; offset < this->chip.ngpio; offset++) {
unsigned int virq = irq_find_mapping(this->domain, offset);
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(irq, &gpio_irqchip,
irq_set_chip_and_handler(virq, &gpio_irqchip,
handle_simple_irq);
set_irq_flags(irq, IRQF_VALID);
set_irq_flags(virq, IRQF_VALID);
irq_set_chip_data(virq, this);
gpio_irqnbr++;
}
/* The toplevel handler handles one bank of GPIOs, except
* AT91SAM9263_ID_PIOCDE handles three... PIOC is first in
* the list, so we only set up that handler.
* 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 == this)
continue;
irq_set_chip_data(id, this);
irq_set_chained_handler(id, gpio_irq_handler);
this->pioc_virq = irq_create_mapping(NULL, this->pioc_hwirq);
irq_set_chip_data(this->pioc_virq, this);
irq_set_chained_handler(this->pioc_virq, gpio_irq_handler);
}
pr_info("AT91: %d gpio irqs in %d banks\n", irq - gpio_to_irq(0), gpio_banks);
pr_info("AT91: %d gpio irqs in %d banks\n", gpio_irqnbr, gpio_banks);
}
/* gpiolib support */
@ -593,48 +923,175 @@ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
at91_get_gpio_value(pin) ?
"set" : "clear");
else
seq_printf(s, "[periph %s]\n",
__raw_readl(pio + PIO_ABSR) &
mask ? "B" : "A");
seq_printf(s, "[periph %c]\n",
peripheral_function(pio, mask));
}
}
}
static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
int virq;
if (offset < chip->ngpio)
virq = irq_create_mapping(at91_gpio->domain, offset);
else
virq = -ENXIO;
dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
chip->label, offset + chip->base, virq);
return virq;
}
static int __init at91_gpio_setup_clk(int idx)
{
struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
/* retreive PIO controller's clock */
at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label);
if (IS_ERR(at91_gpio->clock)) {
pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", idx);
goto err;
}
if (clk_prepare(at91_gpio->clock))
goto clk_prep_err;
/* enable PIO controller's clock */
if (clk_enable(at91_gpio->clock)) {
pr_err("at91_gpio.%d, failed to enable clock, ignoring.\n", idx);
goto clk_err;
}
return 0;
clk_err:
clk_unprepare(at91_gpio->clock);
clk_prep_err:
clk_put(at91_gpio->clock);
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;
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 * at91_gpio->chip.ngpio;
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;
/* 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];
at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
at91_gpio->pioc_hwirq = pioc_hwirq;
at91_gpio->pioc_idx = idx;
at91_gpio->regbase = ioremap(regbase, 512);
if (!at91_gpio->regbase) {
pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", idx);
return;
}
if (at91_gpio_setup_clk(idx))
goto ioremap_err;
gpio_banks = max(gpio_banks, idx + 1);
return;
ioremap_err:
iounmap(at91_gpio->regbase);
}
/*
* Called from the processor-specific init to enable GPIO pin support.
*/
void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
{
unsigned i;
unsigned i;
struct at91_gpio_chip *at91_gpio, *last = NULL;
BUG_ON(nr_banks > MAX_GPIO_BANKS);
gpio_banks = nr_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);
}
for (i = 0; i < nr_banks; i++) {
for (i = 0; i < gpio_banks; i++) {
at91_gpio = &gpio_chip[i];
at91_gpio->id = data[i].id;
at91_gpio->chip.base = i * 32;
at91_gpio->regbase = ioremap(data[i].regbase, 512);
if (!at91_gpio->regbase) {
pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", i);
continue;
}
at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label);
if (!at91_gpio->clock) {
pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", i);
continue;
}
/* enable PIO controller's clock */
clk_enable(at91_gpio->clock);
/* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
if (last && last->id == at91_gpio->id)
/*
* GPIO controller are grouped on some SoC:
* PIOC, PIOD and PIOE can share the same IRQ line
*/
if (last && last->pioc_hwirq == at91_gpio->pioc_hwirq)
last->next = at91_gpio;
last = at91_gpio;

View file

@ -40,10 +40,35 @@
#define PIO_PUER 0x64 /* Pull-up Enable Register */
#define PIO_PUSR 0x68 /* Pull-up Status Register */
#define PIO_ASR 0x70 /* Peripheral A Select Register */
#define PIO_ABCDSR1 0x70 /* Peripheral ABCD Select Register 1 [some sam9 only] */
#define PIO_BSR 0x74 /* Peripheral B Select Register */
#define PIO_ABCDSR2 0x74 /* Peripheral ABCD Select Register 2 [some sam9 only] */
#define PIO_ABSR 0x78 /* AB Status Register */
#define PIO_IFSCDR 0x80 /* Input Filter Slow Clock Disable Register */
#define PIO_IFSCER 0x84 /* Input Filter Slow Clock Enable Register */
#define PIO_IFSCSR 0x88 /* Input Filter Slow Clock Status Register */
#define PIO_SCDR 0x8c /* Slow Clock Divider Debouncing Register */
#define PIO_SCDR_DIV (0x3fff << 0) /* Slow Clock Divider Mask */
#define PIO_PPDDR 0x90 /* Pad Pull-down Disable Register */
#define PIO_PPDER 0x94 /* Pad Pull-down Enable Register */
#define PIO_PPDSR 0x98 /* Pad Pull-down Status Register */
#define PIO_OWER 0xa0 /* Output Write Enable Register */
#define PIO_OWDR 0xa4 /* Output Write Disable Register */
#define PIO_OWSR 0xa8 /* Output Write Status Register */
#define PIO_AIMER 0xb0 /* Additional Interrupt Modes Enable Register */
#define PIO_AIMDR 0xb4 /* Additional Interrupt Modes Disable Register */
#define PIO_AIMMR 0xb8 /* Additional Interrupt Modes Mask Register */
#define PIO_ESR 0xc0 /* Edge Select Register */
#define PIO_LSR 0xc4 /* Level Select Register */
#define PIO_ELSR 0xc8 /* Edge/Level Status Register */
#define PIO_FELLSR 0xd0 /* Falling Edge/Low Level Select Register */
#define PIO_REHLSR 0xd4 /* Rising Edge/ High Level Select Register */
#define PIO_FRLHSR 0xd8 /* Fall/Rise - Low/High Status Register */
#define PIO_SCHMITT 0x100 /* Schmitt Trigger Register */
#define ABCDSR_PERIPH_A 0x0
#define ABCDSR_PERIPH_B 0x1
#define ABCDSR_PERIPH_C 0x2
#define ABCDSR_PERIPH_D 0x3
#endif

View file

@ -191,10 +191,15 @@
extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
extern int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div);
extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);
extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on);
extern int __init_or_module at91_disable_schmitt_trig(unsigned pin);
/* callable at any time */
extern int at91_set_gpio_value(unsigned pin, int value);
@ -204,18 +209,6 @@ extern int at91_get_gpio_value(unsigned pin);
extern void at91_gpio_suspend(void);
extern void at91_gpio_resume(void);
/*-------------------------------------------------------------------------*/
/* wrappers for "new style" GPIO calls. the old AT91-specific ones should
* eventually be removed (along with this errno.h inclusion), and the
* gpio request/free calls should probably be implemented.
*/
#include <asm/errno.h>
#define gpio_to_irq(gpio) (gpio + NR_AIC_IRQS)
#define irq_to_gpio(irq) (irq - NR_AIC_IRQS)
#endif /* __ASSEMBLY__ */
#endif

View file

@ -24,6 +24,12 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/types.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/irqdomain.h>
#include <linux/err.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@ -34,22 +40,24 @@
#include <asm/mach/map.h>
void __iomem *at91_aic_base;
static struct irq_domain *at91_aic_domain;
static struct device_node *at91_aic_np;
static void at91_aic_mask_irq(struct irq_data *d)
{
/* Disable interrupt on AIC */
at91_aic_write(AT91_AIC_IDCR, 1 << d->irq);
at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
}
static void at91_aic_unmask_irq(struct irq_data *d)
{
/* Enable interrupt on AIC */
at91_aic_write(AT91_AIC_IECR, 1 << d->irq);
at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
}
unsigned int at91_extern_irq;
#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq)
#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
static int at91_aic_set_type(struct irq_data *d, unsigned type)
{
@ -63,13 +71,13 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
srctype = AT91_AIC_SRCTYPE_RISING;
break;
case IRQ_TYPE_LEVEL_LOW:
if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq)) /* only supported on external interrupts */
if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
srctype = AT91_AIC_SRCTYPE_LOW;
else
return -EINVAL;
break;
case IRQ_TYPE_EDGE_FALLING:
if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq)) /* only supported on external interrupts */
if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
srctype = AT91_AIC_SRCTYPE_FALLING;
else
return -EINVAL;
@ -78,8 +86,8 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
return -EINVAL;
}
smr = at91_aic_read(AT91_AIC_SMR(d->irq)) & ~AT91_AIC_SRCTYPE;
at91_aic_write(AT91_AIC_SMR(d->irq), smr | srctype);
smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
return 0;
}
@ -90,13 +98,13 @@ static u32 backups;
static int at91_aic_set_wake(struct irq_data *d, unsigned value)
{
if (unlikely(d->irq >= 32))
if (unlikely(d->hwirq >= NR_AIC_IRQS))
return -EINVAL;
if (value)
wakeups |= (1 << d->irq);
wakeups |= (1 << d->hwirq);
else
wakeups &= ~(1 << d->irq);
wakeups &= ~(1 << d->hwirq);
return 0;
}
@ -127,41 +135,23 @@ static struct irq_chip at91_aic_chip = {
.irq_set_wake = at91_aic_set_wake,
};
/*
* Initialize the AIC interrupt controller.
*/
void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
static void __init at91_aic_hw_init(unsigned int spu_vector)
{
unsigned int i;
at91_aic_base = ioremap(AT91_AIC, 512);
if (!at91_aic_base)
panic("Impossible to ioremap AT91_AIC\n");
int i;
/*
* The IVR is used by macro get_irqnr_and_base to read and verify.
* The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
* Perform 8 End Of Interrupt Command to make sure AIC
* will not Lock out nIRQ
*/
for (i = 0; i < NR_AIC_IRQS; i++) {
/* Put irq number in Source Vector Register: */
at91_aic_write(AT91_AIC_SVR(i), i);
/* Active Low interrupt, with the specified priority */
at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
/* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */
if (i < 8)
at91_aic_write(AT91_AIC_EOICR, 0);
}
for (i = 0; i < 8; i++)
at91_aic_write(AT91_AIC_EOICR, 0);
/*
* Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS
* When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU
* Spurious Interrupt ID in Spurious Vector Register.
* When there is no current interrupt, the IRQ Vector Register
* reads the value stored in AIC_SPU
*/
at91_aic_write(AT91_AIC_SPU, NR_AIC_IRQS);
at91_aic_write(AT91_AIC_SPU, spu_vector);
/* No debugging in AIC: Debug (Protect) Control Register */
at91_aic_write(AT91_AIC_DCR, 0);
@ -170,3 +160,87 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
}
#if defined(CONFIG_OF)
static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
/* Put virq number in Source Vector Register */
at91_aic_write(AT91_AIC_SVR(hw), virq);
/* Active Low interrupt, without priority */
at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
return 0;
}
static struct irq_domain_ops at91_aic_irq_ops = {
.map = at91_aic_irq_map,
.xlate = irq_domain_xlate_twocell,
};
int __init at91_aic_of_init(struct device_node *node,
struct device_node *parent)
{
at91_aic_base = of_iomap(node, 0);
at91_aic_np = node;
at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
&at91_aic_irq_ops, NULL);
if (!at91_aic_domain)
panic("Unable to add AIC irq domain (DT)\n");
irq_set_default_host(at91_aic_domain);
at91_aic_hw_init(NR_AIC_IRQS);
return 0;
}
#endif
/*
* Initialize the AIC interrupt controller.
*/
void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
{
unsigned int i;
int irq_base;
at91_aic_base = ioremap(AT91_AIC, 512);
if (!at91_aic_base)
panic("Unable to ioremap AIC registers\n");
/* Add irq domain for AIC */
irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
if (irq_base < 0) {
WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
irq_base = 0;
}
at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
irq_base, 0,
&irq_domain_simple_ops, NULL);
if (!at91_aic_domain)
panic("Unable to add AIC irq domain\n");
irq_set_default_host(at91_aic_domain);
/*
* The IVR is used by macro get_irqnr_and_base to read and verify.
* The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
*/
for (i = 0; i < NR_AIC_IRQS; i++) {
/* Put hardware irq number in Source Vector Register: */
at91_aic_write(AT91_AIC_SVR(i), i);
/* Active Low interrupt, with the specified priority */
at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
at91_aic_hw_init(NR_AIC_IRQS);
}

View file

@ -19,6 +19,8 @@
* - Two channels combine to create a free-running 32 bit counter
* with a base rate of 5+ MHz, packaged as a clocksource (with
* resolution better than 200 nsec).
* - Some chips support 32 bit counter. A single channel is used for
* this 32 bit free-running counter. the second channel is not used.
*
* - The third channel may be used to provide a 16-bit clockevent
* source, used in either periodic or oneshot mode. This runs
@ -54,6 +56,11 @@ static cycle_t tc_get_cycles(struct clocksource *cs)
return (upper << 16) | lower;
}
static cycle_t tc_get_cycles32(struct clocksource *cs)
{
return __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
}
static struct clocksource clksrc = {
.name = "tcb_clksrc",
.rating = 200,
@ -209,6 +216,48 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
#endif
static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx)
{
/* channel 0: waveform mode, input mclk/8, clock TIOA0 on overflow */
__raw_writel(mck_divisor_idx /* likely divide-by-8 */
| ATMEL_TC_WAVE
| ATMEL_TC_WAVESEL_UP /* free-run */
| ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */
| ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */
tcaddr + ATMEL_TC_REG(0, CMR));
__raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
__raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
/* channel 1: waveform mode, input TIOA0 */
__raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */
| ATMEL_TC_WAVE
| ATMEL_TC_WAVESEL_UP, /* free-run */
tcaddr + ATMEL_TC_REG(1, CMR));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
/* chain channel 0 to channel 1*/
__raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
/* then reset all the timers */
__raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
}
static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx)
{
/* channel 0: waveform mode, input mclk/8 */
__raw_writel(mck_divisor_idx /* likely divide-by-8 */
| ATMEL_TC_WAVE
| ATMEL_TC_WAVESEL_UP, /* free-run */
tcaddr + ATMEL_TC_REG(0, CMR));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
/* then reset all the timers */
__raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
}
static int __init tcb_clksrc_init(void)
{
static char bootinfo[] __initdata
@ -260,34 +309,19 @@ static int __init tcb_clksrc_init(void)
divided_rate / 1000000,
((divided_rate + 500000) % 1000000) / 1000);
/* tclib will give us three clocks no matter what the
* underlying platform supports.
*/
clk_enable(tc->clk[1]);
/* channel 0: waveform mode, input mclk/8, clock TIOA0 on overflow */
__raw_writel(best_divisor_idx /* likely divide-by-8 */
| ATMEL_TC_WAVE
| ATMEL_TC_WAVESEL_UP /* free-run */
| ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */
| ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */
tcaddr + ATMEL_TC_REG(0, CMR));
__raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
__raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
/* channel 1: waveform mode, input TIOA0 */
__raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */
| ATMEL_TC_WAVE
| ATMEL_TC_WAVESEL_UP, /* free-run */
tcaddr + ATMEL_TC_REG(1, CMR));
__raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */
__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
/* chain channel 0 to channel 1, then reset all the timers */
__raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
__raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
if (tc->tcb_config && tc->tcb_config->counter_width == 32) {
/* use apropriate function to read 32 bit counter */
clksrc.read = tc_get_cycles32;
/* setup ony channel 0 */
tcb_setup_single_chan(tc, best_divisor_idx);
} else {
/* tclib will give us three clocks no matter what the
* underlying platform supports.
*/
clk_enable(tc->clk[1]);
/* setup both channel 0 & 1 */
tcb_setup_dual_chan(tc, best_divisor_idx);
}
/* and away we go! */
clocksource_register_hz(&clksrc, divided_rate);

View file

@ -6,12 +6,10 @@
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/export.h>
/* Number of bytes to reserve for the iomem resource */
#define ATMEL_TC_IOMEM_SIZE 256
#include <linux/of.h>
/*
* This is a thin library to solve the problem of how to portably allocate
@ -48,10 +46,17 @@ struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
struct atmel_tc *tc;
struct platform_device *pdev = NULL;
struct resource *r;
size_t size;
spin_lock(&tc_list_lock);
list_for_each_entry(tc, &tc_list, node) {
if (tc->pdev->id == block) {
if (tc->pdev->dev.of_node) {
if (of_alias_get_id(tc->pdev->dev.of_node, "tcb")
== block) {
pdev = tc->pdev;
break;
}
} else if (tc->pdev->id == block) {
pdev = tc->pdev;
break;
}
@ -61,11 +66,15 @@ struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
goto fail;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
if (!r)
goto fail;
tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
size = resource_size(r);
r = request_mem_region(r->start, size, name);
if (!r)
goto fail;
tc->regs = ioremap(r->start, size);
if (!tc->regs)
goto fail_ioremap;
@ -76,7 +85,7 @@ out:
return tc;
fail_ioremap:
release_mem_region(r->start, ATMEL_TC_IOMEM_SIZE);
release_mem_region(r->start, size);
fail:
tc = NULL;
goto out;
@ -96,7 +105,7 @@ void atmel_tc_free(struct atmel_tc *tc)
spin_lock(&tc_list_lock);
if (tc->regs) {
iounmap(tc->regs);
release_mem_region(tc->iomem->start, ATMEL_TC_IOMEM_SIZE);
release_mem_region(tc->iomem->start, resource_size(tc->iomem));
tc->regs = NULL;
tc->iomem = NULL;
}
@ -104,6 +113,30 @@ void atmel_tc_free(struct atmel_tc *tc)
}
EXPORT_SYMBOL_GPL(atmel_tc_free);
#if defined(CONFIG_OF)
static struct atmel_tcb_config tcb_rm9200_config = {
.counter_width = 16,
};
static struct atmel_tcb_config tcb_sam9x5_config = {
.counter_width = 32,
};
static const struct of_device_id atmel_tcb_dt_ids[] = {
{
.compatible = "atmel,at91rm9200-tcb",
.data = &tcb_rm9200_config,
}, {
.compatible = "atmel,at91sam9x5-tcb",
.data = &tcb_sam9x5_config,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, atmel_tcb_dt_ids);
#endif
static int __init tc_probe(struct platform_device *pdev)
{
struct atmel_tc *tc;
@ -129,6 +162,14 @@ static int __init tc_probe(struct platform_device *pdev)
return -EINVAL;
}
/* Now take SoC information if available */
if (pdev->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node);
if (match)
tc->tcb_config = match->data;
}
tc->clk[0] = clk;
tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
if (IS_ERR(tc->clk[1]))
@ -153,7 +194,10 @@ static int __init tc_probe(struct platform_device *pdev)
}
static struct platform_driver tc_driver = {
.driver.name = "atmel_tcb",
.driver = {
.name = "atmel_tcb",
.of_match_table = of_match_ptr(atmel_tcb_dt_ids),
},
};
static int __init tc_init(void)

View file

@ -448,10 +448,11 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
/* From the GPIO notifying the over-current situation, find
* out the corresponding port */
gpio = irq_to_gpio(irq);
for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
if (pdata->overcurrent_pin[port] == gpio)
if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) {
gpio = pdata->overcurrent_pin[port];
break;
}
}
if (port == ARRAY_SIZE(pdata->overcurrent_pin)) {

View file

@ -33,11 +33,20 @@
struct clk;
/**
* struct atmel_tcb_config - SoC data for a Timer/Counter Block
* @counter_width: size in bits of a timer counter register
*/
struct atmel_tcb_config {
size_t counter_width;
};
/**
* struct atmel_tc - information about a Timer/Counter Block
* @pdev: physical device
* @iomem: resource associated with the I/O register
* @regs: mapping through which the I/O registers can be accessed
* @tcb_config: configuration data from SoC
* @irq: irq for each of the three channels
* @clk: internal clock source for each of the three channels
* @node: list node, for tclib internal use
@ -54,6 +63,7 @@ struct atmel_tc {
struct platform_device *pdev;
struct resource *iomem;
void __iomem *regs;
struct atmel_tcb_config *tcb_config;
int irq[3];
struct clk *clk[3];
struct list_head node;