Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
a663a71e
Commit
a663a71e
authored
Dec 20, 2008
by
Russell King
Committed by
Russell King
Dec 20, 2008
Browse files
Options
Browse Files
Download
Plain Diff
Merge
git://git.marvell.com/orion
into devel
parents
828aac2e
b95a13d7
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
642 additions
and
443 deletions
+642
-443
arch/arm/Kconfig
arch/arm/Kconfig
+2
-0
arch/arm/mach-kirkwood/include/mach/gpio.h
arch/arm/mach-kirkwood/include/mach/gpio.h
+38
-0
arch/arm/mach-kirkwood/include/mach/irqs.h
arch/arm/mach-kirkwood/include/mach/irqs.h
+1
-3
arch/arm/mach-kirkwood/include/mach/kirkwood.h
arch/arm/mach-kirkwood/include/mach/kirkwood.h
+0
-3
arch/arm/mach-kirkwood/irq.c
arch/arm/mach-kirkwood/irq.c
+35
-0
arch/arm/mach-mv78xx0/include/mach/gpio.h
arch/arm/mach-mv78xx0/include/mach/gpio.h
+40
-0
arch/arm/mach-mv78xx0/include/mach/irqs.h
arch/arm/mach-mv78xx0/include/mach/irqs.h
+1
-3
arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
+0
-3
arch/arm/mach-mv78xx0/irq.c
arch/arm/mach-mv78xx0/irq.c
+29
-0
arch/arm/mach-orion5x/Makefile
arch/arm/mach-orion5x/Makefile
+1
-1
arch/arm/mach-orion5x/common.h
arch/arm/mach-orion5x/common.h
+0
-7
arch/arm/mach-orion5x/gpio.c
arch/arm/mach-orion5x/gpio.c
+0
-231
arch/arm/mach-orion5x/include/mach/gpio.h
arch/arm/mach-orion5x/include/mach/gpio.h
+19
-10
arch/arm/mach-orion5x/include/mach/irqs.h
arch/arm/mach-orion5x/include/mach/irqs.h
+1
-3
arch/arm/mach-orion5x/include/mach/orion5x.h
arch/arm/mach-orion5x/include/mach/orion5x.h
+0
-9
arch/arm/mach-orion5x/irq.c
arch/arm/mach-orion5x/irq.c
+14
-169
arch/arm/mach-orion5x/mpp.c
arch/arm/mach-orion5x/mpp.c
+5
-1
arch/arm/plat-orion/Makefile
arch/arm/plat-orion/Makefile
+2
-0
arch/arm/plat-orion/gpio.c
arch/arm/plat-orion/gpio.c
+415
-0
arch/arm/plat-orion/include/plat/gpio.h
arch/arm/plat-orion/include/plat/gpio.h
+39
-0
No files found.
arch/arm/Kconfig
View file @
a663a71e
...
...
@@ -387,6 +387,7 @@ config ARCH_KIRKWOOD
bool "Marvell Kirkwood"
select CPU_FEROCEON
select PCI
select GENERIC_GPIO
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select PLAT_ORION
...
...
@@ -429,6 +430,7 @@ config ARCH_MV78XX0
bool "Marvell MV78xx0"
select CPU_FEROCEON
select PCI
select GENERIC_GPIO
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select PLAT_ORION
...
...
arch/arm/mach-kirkwood/include/mach/gpio.h
0 → 100644
View file @
a663a71e
/*
* arch/asm-arm/mach-kirkwood/include/mach/gpio.h
*
* 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.
*/
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H
#include <mach/irqs.h>
#include <plat/gpio.h>
#include <asm-generic/gpio.h>
/* cansleep wrappers */
#define GPIO_MAX 50
#define GPIO_OFF(pin) (((pin) >> 5) ? 0x0140 : 0x0100)
#define GPIO_OUT(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x00)
#define GPIO_IO_CONF(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x04)
#define GPIO_BLINK_EN(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x08)
#define GPIO_IN_POL(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x0c)
#define GPIO_DATA_IN(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x10)
#define GPIO_EDGE_CAUSE(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x14)
#define GPIO_EDGE_MASK(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x18)
#define GPIO_LEVEL_MASK(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x1c)
static
inline
int
gpio_to_irq
(
int
pin
)
{
return
pin
+
IRQ_KIRKWOOD_GPIO_START
;
}
static
inline
int
irq_to_gpio
(
int
irq
)
{
return
irq
-
IRQ_KIRKWOOD_GPIO_START
;
}
#endif
arch/arm/mach-kirkwood/include/mach/irqs.h
View file @
a663a71e
...
...
@@ -11,8 +11,6 @@
#ifndef __ASM_ARCH_IRQS_H
#define __ASM_ARCH_IRQS_H
#include "kirkwood.h"
/* need GPIO_MAX */
/*
* Low Interrupt Controller
*/
...
...
@@ -57,7 +55,7 @@
* KIRKWOOD General Purpose Pins
*/
#define IRQ_KIRKWOOD_GPIO_START 64
#define NR_GPIO_IRQS
GPIO_MAX
#define NR_GPIO_IRQS
50
#define NR_IRQS (IRQ_KIRKWOOD_GPIO_START + NR_GPIO_IRQS)
...
...
arch/arm/mach-kirkwood/include/mach/kirkwood.h
View file @
a663a71e
...
...
@@ -117,7 +117,4 @@
#define SATA_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x80000)
#define GPIO_MAX 50
#endif
arch/arm/mach-kirkwood/irq.c
View file @
a663a71e
...
...
@@ -13,10 +13,45 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <plat/irq.h>
#include <asm/gpio.h>
#include "common.h"
static
void
gpio_irq_handler
(
unsigned
int
irq
,
struct
irq_desc
*
desc
)
{
BUG_ON
(
irq
<
IRQ_KIRKWOOD_GPIO_LOW_0_7
);
BUG_ON
(
irq
>
IRQ_KIRKWOOD_GPIO_HIGH_16_23
);
orion_gpio_irq_handler
((
irq
-
IRQ_KIRKWOOD_GPIO_LOW_0_7
)
<<
3
);
}
void
__init
kirkwood_init_irq
(
void
)
{
int
i
;
orion_irq_init
(
0
,
(
void
__iomem
*
)(
IRQ_VIRT_BASE
+
IRQ_MASK_LOW_OFF
));
orion_irq_init
(
32
,
(
void
__iomem
*
)(
IRQ_VIRT_BASE
+
IRQ_MASK_HIGH_OFF
));
/*
* Mask and clear GPIO IRQ interrupts.
*/
writel
(
0
,
GPIO_LEVEL_MASK
(
0
));
writel
(
0
,
GPIO_EDGE_MASK
(
0
));
writel
(
0
,
GPIO_EDGE_CAUSE
(
0
));
writel
(
0
,
GPIO_LEVEL_MASK
(
32
));
writel
(
0
,
GPIO_EDGE_MASK
(
32
));
writel
(
0
,
GPIO_EDGE_CAUSE
(
32
));
for
(
i
=
IRQ_KIRKWOOD_GPIO_START
;
i
<
NR_IRQS
;
i
++
)
{
set_irq_chip
(
i
,
&
orion_gpio_irq_level_chip
);
set_irq_handler
(
i
,
handle_level_irq
);
irq_desc
[
i
].
status
|=
IRQ_LEVEL
;
set_irq_flags
(
i
,
IRQF_VALID
);
}
set_irq_chained_handler
(
IRQ_KIRKWOOD_GPIO_LOW_0_7
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_KIRKWOOD_GPIO_LOW_8_15
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_KIRKWOOD_GPIO_LOW_16_23
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_KIRKWOOD_GPIO_LOW_24_31
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_KIRKWOOD_GPIO_HIGH_0_7
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_KIRKWOOD_GPIO_HIGH_8_15
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_KIRKWOOD_GPIO_HIGH_16_23
,
gpio_irq_handler
);
}
arch/arm/mach-mv78xx0/include/mach/gpio.h
0 → 100644
View file @
a663a71e
/*
* arch/asm-arm/mach-mv78xx0/include/mach/gpio.h
*
* 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.
*/
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H
#include <mach/irqs.h>
#include <plat/gpio.h>
#include <asm-generic/gpio.h>
/* cansleep wrappers */
extern
int
mv78xx0_core_index
(
void
);
#define GPIO_MAX 32
#define GPIO_OUT(pin) (DEV_BUS_VIRT_BASE + 0x0100)
#define GPIO_IO_CONF(pin) (DEV_BUS_VIRT_BASE + 0x0104)
#define GPIO_BLINK_EN(pin) (DEV_BUS_VIRT_BASE + 0x0108)
#define GPIO_IN_POL(pin) (DEV_BUS_VIRT_BASE + 0x010c)
#define GPIO_DATA_IN(pin) (DEV_BUS_VIRT_BASE + 0x0110)
#define GPIO_EDGE_CAUSE(pin) (DEV_BUS_VIRT_BASE + 0x0114)
#define GPIO_MASK_OFF (mv78xx0_core_index() ? 0x18 : 0)
#define GPIO_EDGE_MASK(pin) (DEV_BUS_VIRT_BASE + 0x0118 + GPIO_MASK_OFF)
#define GPIO_LEVEL_MASK(pin) (DEV_BUS_VIRT_BASE + 0x011c + GPIO_MASK_OFF)
static
inline
int
gpio_to_irq
(
int
pin
)
{
return
pin
+
IRQ_MV78XX0_GPIO_START
;
}
static
inline
int
irq_to_gpio
(
int
irq
)
{
return
irq
-
IRQ_MV78XX0_GPIO_START
;
}
#endif
arch/arm/mach-mv78xx0/include/mach/irqs.h
View file @
a663a71e
...
...
@@ -11,8 +11,6 @@
#ifndef __ASM_ARCH_IRQS_H
#define __ASM_ARCH_IRQS_H
#include "mv78xx0.h"
/* need GPIO_MAX */
/*
* MV78xx0 Low Interrupt Controller
*/
...
...
@@ -88,7 +86,7 @@
* MV78XX0 General Purpose Pins
*/
#define IRQ_MV78XX0_GPIO_START 96
#define NR_GPIO_IRQS
GPIO_MAX
#define NR_GPIO_IRQS
32
#define NR_IRQS (IRQ_MV78XX0_GPIO_START + NR_GPIO_IRQS)
...
...
arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
View file @
a663a71e
...
...
@@ -122,7 +122,4 @@
#define SATA_PHYS_BASE (MV78XX0_REGS_PHYS_BASE | 0xa0000)
#define GPIO_MAX 32
#endif
arch/arm/mach-mv78xx0/irq.c
View file @
a663a71e
...
...
@@ -11,13 +11,42 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/irq.h>
#include <asm/gpio.h>
#include <mach/mv78xx0.h>
#include <plat/irq.h>
#include "common.h"
static
void
gpio_irq_handler
(
unsigned
int
irq
,
struct
irq_desc
*
desc
)
{
BUG_ON
(
irq
<
IRQ_MV78XX0_GPIO_0_7
||
irq
>
IRQ_MV78XX0_GPIO_24_31
);
orion_gpio_irq_handler
((
irq
-
IRQ_MV78XX0_GPIO_0_7
)
<<
3
);
}
void
__init
mv78xx0_init_irq
(
void
)
{
int
i
;
orion_irq_init
(
0
,
(
void
__iomem
*
)(
IRQ_VIRT_BASE
+
IRQ_MASK_LOW_OFF
));
orion_irq_init
(
32
,
(
void
__iomem
*
)(
IRQ_VIRT_BASE
+
IRQ_MASK_HIGH_OFF
));
orion_irq_init
(
64
,
(
void
__iomem
*
)(
IRQ_VIRT_BASE
+
IRQ_MASK_ERR_OFF
));
/*
* Mask and clear GPIO IRQ interrupts.
*/
writel
(
0
,
GPIO_LEVEL_MASK
(
0
));
writel
(
0
,
GPIO_EDGE_MASK
(
0
));
writel
(
0
,
GPIO_EDGE_CAUSE
(
0
));
for
(
i
=
IRQ_MV78XX0_GPIO_START
;
i
<
NR_IRQS
;
i
++
)
{
set_irq_chip
(
i
,
&
orion_gpio_irq_level_chip
);
set_irq_handler
(
i
,
handle_level_irq
);
irq_desc
[
i
].
status
|=
IRQ_LEVEL
;
set_irq_flags
(
i
,
IRQF_VALID
);
}
set_irq_chained_handler
(
IRQ_MV78XX0_GPIO_0_7
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_MV78XX0_GPIO_8_15
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_MV78XX0_GPIO_16_23
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_MV78XX0_GPIO_24_31
,
gpio_irq_handler
);
}
arch/arm/mach-orion5x/Makefile
View file @
a663a71e
obj-y
+=
common.o addr-map.o pci.o
gpio.o
irq.o mpp.o
obj-y
+=
common.o addr-map.o pci.o irq.o mpp.o
obj-$(CONFIG_MACH_DB88F5281)
+=
db88f5281-setup.o
obj-$(CONFIG_MACH_RD88F5182)
+=
rd88f5182-setup.o
obj-$(CONFIG_MACH_KUROBOX_PRO)
+=
kurobox_pro-setup.o
...
...
arch/arm/mach-orion5x/common.h
View file @
a663a71e
...
...
@@ -51,13 +51,6 @@ int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
struct
pci_bus
*
orion5x_pci_sys_scan_bus
(
int
nr
,
struct
pci_sys_data
*
sys
);
int
orion5x_pci_map_irq
(
struct
pci_dev
*
dev
,
u8
slot
,
u8
pin
);
/*
* Valid GPIO pins according to MPP setup, used by machine-setup.
* (/mach-orion/gpio.c).
*/
void
orion5x_gpio_set_valid
(
unsigned
pin
,
int
valid
);
void
gpio_display
(
void
);
/* debug */
struct
machine_desc
;
struct
meminfo
;
struct
tag
;
...
...
arch/arm/mach-orion5x/gpio.c
deleted
100644 → 0
View file @
828aac2e
/*
* arch/arm/mach-orion5x/gpio.c
*
* GPIO functions for Marvell Orion System On Chip
*
* Maintainer: Tzachi Perelstein <tzachi@marvell.com>
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <asm/gpio.h>
#include <mach/orion5x.h>
#include "common.h"
static
DEFINE_SPINLOCK
(
gpio_lock
);
static
unsigned
long
gpio_valid
[
BITS_TO_LONGS
(
GPIO_MAX
)];
static
const
char
*
gpio_label
[
GPIO_MAX
];
/* non null for allocated GPIOs */
void
__init
orion5x_gpio_set_valid
(
unsigned
pin
,
int
valid
)
{
if
(
valid
)
__set_bit
(
pin
,
gpio_valid
);
else
__clear_bit
(
pin
,
gpio_valid
);
}
/*
* GENERIC_GPIO primitives
*/
int
gpio_direction_input
(
unsigned
pin
)
{
unsigned
long
flags
;
if
(
pin
>=
GPIO_MAX
||
!
test_bit
(
pin
,
gpio_valid
))
{
pr_debug
(
"%s: invalid GPIO %d
\n
"
,
__func__
,
pin
);
return
-
EINVAL
;
}
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
/*
* Some callers might have not used the gpio_request(),
* so flag this pin as requested now.
*/
if
(
!
gpio_label
[
pin
])
gpio_label
[
pin
]
=
"?"
;
orion5x_setbits
(
GPIO_IO_CONF
,
1
<<
pin
);
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
return
0
;
}
EXPORT_SYMBOL
(
gpio_direction_input
);
int
gpio_direction_output
(
unsigned
pin
,
int
value
)
{
unsigned
long
flags
;
int
mask
;
if
(
pin
>=
GPIO_MAX
||
!
test_bit
(
pin
,
gpio_valid
))
{
pr_debug
(
"%s: invalid GPIO %d
\n
"
,
__func__
,
pin
);
return
-
EINVAL
;
}
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
/*
* Some callers might have not used the gpio_request(),
* so flag this pin as requested now.
*/
if
(
!
gpio_label
[
pin
])
gpio_label
[
pin
]
=
"?"
;
mask
=
1
<<
pin
;
orion5x_clrbits
(
GPIO_BLINK_EN
,
mask
);
if
(
value
)
orion5x_setbits
(
GPIO_OUT
,
mask
);
else
orion5x_clrbits
(
GPIO_OUT
,
mask
);
orion5x_clrbits
(
GPIO_IO_CONF
,
mask
);
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
return
0
;
}
EXPORT_SYMBOL
(
gpio_direction_output
);
int
gpio_get_value
(
unsigned
pin
)
{
int
val
,
mask
=
1
<<
pin
;
if
(
readl
(
GPIO_IO_CONF
)
&
mask
)
val
=
readl
(
GPIO_DATA_IN
)
^
readl
(
GPIO_IN_POL
);
else
val
=
readl
(
GPIO_OUT
);
return
val
&
mask
;
}
EXPORT_SYMBOL
(
gpio_get_value
);
void
gpio_set_value
(
unsigned
pin
,
int
value
)
{
unsigned
long
flags
;
int
mask
=
1
<<
pin
;
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
orion5x_clrbits
(
GPIO_BLINK_EN
,
mask
);
if
(
value
)
orion5x_setbits
(
GPIO_OUT
,
mask
);
else
orion5x_clrbits
(
GPIO_OUT
,
mask
);
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
}
EXPORT_SYMBOL
(
gpio_set_value
);
void
orion5x_gpio_set_blink
(
unsigned
pin
,
int
blink
)
{
unsigned
long
flags
;
int
mask
=
1
<<
pin
;
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
orion5x_clrbits
(
GPIO_OUT
,
mask
);
if
(
blink
)
orion5x_setbits
(
GPIO_BLINK_EN
,
mask
);
else
orion5x_clrbits
(
GPIO_BLINK_EN
,
mask
);
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
}
EXPORT_SYMBOL
(
orion5x_gpio_set_blink
);
int
gpio_request
(
unsigned
pin
,
const
char
*
label
)
{
int
ret
=
0
;
unsigned
long
flags
;
if
(
pin
>=
GPIO_MAX
||
!
test_bit
(
pin
,
gpio_valid
))
{
pr_debug
(
"%s: invalid GPIO %d
\n
"
,
__func__
,
pin
);
return
-
EINVAL
;
}
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
if
(
gpio_label
[
pin
])
{
pr_debug
(
"%s: GPIO %d already used as %s
\n
"
,
__func__
,
pin
,
gpio_label
[
pin
]);
ret
=
-
EBUSY
;
}
else
gpio_label
[
pin
]
=
label
?
label
:
"?"
;
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
gpio_request
);
void
gpio_free
(
unsigned
pin
)
{
might_sleep
();
if
(
pin
>=
GPIO_MAX
||
!
test_bit
(
pin
,
gpio_valid
))
{
pr_debug
(
"%s: invalid GPIO %d
\n
"
,
__func__
,
pin
);
return
;
}
if
(
!
gpio_label
[
pin
])
pr_warning
(
"%s: GPIO %d already freed
\n
"
,
__func__
,
pin
);
else
gpio_label
[
pin
]
=
NULL
;
}
EXPORT_SYMBOL
(
gpio_free
);
/* Debug helper */
void
gpio_display
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
GPIO_MAX
;
i
++
)
{
printk
(
KERN_DEBUG
"Pin-%d: "
,
i
);
if
(
!
test_bit
(
i
,
gpio_valid
))
{
printk
(
"non-GPIO
\n
"
);
}
else
if
(
!
gpio_label
[
i
])
{
printk
(
"GPIO, free
\n
"
);
}
else
{
printk
(
"GPIO, used by %s, "
,
gpio_label
[
i
]);
if
(
readl
(
GPIO_IO_CONF
)
&
(
1
<<
i
))
{
printk
(
"input, active %s, level %s, edge %s
\n
"
,
((
readl
(
GPIO_IN_POL
)
>>
i
)
&
1
)
?
"low"
:
"high"
,
((
readl
(
GPIO_LEVEL_MASK
)
>>
i
)
&
1
)
?
"enabled"
:
"masked"
,
((
readl
(
GPIO_EDGE_MASK
)
>>
i
)
&
1
)
?
"enabled"
:
"masked"
);
}
else
{
printk
(
"output, val=%d
\n
"
,
(
readl
(
GPIO_OUT
)
>>
i
)
&
1
);
}
}
}
printk
(
KERN_DEBUG
"MPP_0_7_CTRL (0x%08x) = 0x%08x
\n
"
,
MPP_0_7_CTRL
,
readl
(
MPP_0_7_CTRL
));
printk
(
KERN_DEBUG
"MPP_8_15_CTRL (0x%08x) = 0x%08x
\n
"
,
MPP_8_15_CTRL
,
readl
(
MPP_8_15_CTRL
));
printk
(
KERN_DEBUG
"MPP_16_19_CTRL (0x%08x) = 0x%08x
\n
"
,
MPP_16_19_CTRL
,
readl
(
MPP_16_19_CTRL
));
printk
(
KERN_DEBUG
"MPP_DEV_CTRL (0x%08x) = 0x%08x
\n
"
,
MPP_DEV_CTRL
,
readl
(
MPP_DEV_CTRL
));
printk
(
KERN_DEBUG
"GPIO_OUT (0x%08x) = 0x%08x
\n
"
,
GPIO_OUT
,
readl
(
GPIO_OUT
));
printk
(
KERN_DEBUG
"GPIO_IO_CONF (0x%08x) = 0x%08x
\n
"
,
GPIO_IO_CONF
,
readl
(
GPIO_IO_CONF
));
printk
(
KERN_DEBUG
"GPIO_BLINK_EN (0x%08x) = 0x%08x
\n
"
,
GPIO_BLINK_EN
,
readl
(
GPIO_BLINK_EN
));
printk
(
KERN_DEBUG
"GPIO_IN_POL (0x%08x) = 0x%08x
\n
"
,
GPIO_IN_POL
,
readl
(
GPIO_IN_POL
));
printk
(
KERN_DEBUG
"GPIO_DATA_IN (0x%08x) = 0x%08x
\n
"
,
GPIO_DATA_IN
,
readl
(
GPIO_DATA_IN
));
printk
(
KERN_DEBUG
"GPIO_LEVEL_MASK (0x%08x) = 0x%08x
\n
"
,
GPIO_LEVEL_MASK
,
readl
(
GPIO_LEVEL_MASK
));
printk
(
KERN_DEBUG
"GPIO_EDGE_CAUSE (0x%08x) = 0x%08x
\n
"
,
GPIO_EDGE_CAUSE
,
readl
(
GPIO_EDGE_CAUSE
));
printk
(
KERN_DEBUG
"GPIO_EDGE_MASK (0x%08x) = 0x%08x
\n
"
,
GPIO_EDGE_MASK
,
readl
(
GPIO_EDGE_MASK
));
}
arch/arm/mach-orion5x/include/mach/gpio.h
View file @
a663a71e
...
...
@@ -6,14 +6,22 @@
* warranty of any kind, whether express or implied.
*/
extern
int
gpio_request
(
unsigned
pin
,
const
char
*
label
);
extern
void
gpio_free
(
unsigned
pin
);
extern
int
gpio_direction_input
(
unsigned
pin
);
extern
int
gpio_direction_output
(
unsigned
pin
,
int
value
);
extern
int
gpio_get_value
(
unsigned
pin
);
extern
void
gpio_set_value
(
unsigned
pin
,
int
value
);
extern
void
orion5x_gpio_set_blink
(
unsigned
pin
,
int
blink
);
extern
void
gpio_display
(
void
);
/* debug */
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H
#include <mach/irqs.h>
#include <plat/gpio.h>
#include <asm-generic/gpio.h>
/* cansleep wrappers */
#define GPIO_MAX 32
#define GPIO_OUT(pin) ORION5X_DEV_BUS_REG(0x100)
#define GPIO_IO_CONF(pin) ORION5X_DEV_BUS_REG(0x104)
#define GPIO_BLINK_EN(pin) ORION5X_DEV_BUS_REG(0x108)
#define GPIO_IN_POL(pin) ORION5X_DEV_BUS_REG(0x10c)
#define GPIO_DATA_IN(pin) ORION5X_DEV_BUS_REG(0x110)
#define GPIO_EDGE_CAUSE(pin) ORION5X_DEV_BUS_REG(0x114)
#define GPIO_EDGE_MASK(pin) ORION5X_DEV_BUS_REG(0x118)
#define GPIO_LEVEL_MASK(pin) ORION5X_DEV_BUS_REG(0x11c)
static
inline
int
gpio_to_irq
(
int
pin
)
{
...
...
@@ -25,4 +33,5 @@ static inline int irq_to_gpio(int irq)
return
irq
-
IRQ_ORION5X_GPIO_START
;
}
#include <asm-generic/gpio.h>
/* cansleep wrappers */
#endif
arch/arm/mach-orion5x/include/mach/irqs.h
View file @
a663a71e
...
...
@@ -13,8 +13,6 @@
#ifndef __ASM_ARCH_IRQS_H
#define __ASM_ARCH_IRQS_H
#include "orion5x.h"
/* need GPIO_MAX */
/*
* Orion Main Interrupt Controller
*/
...
...
@@ -54,7 +52,7 @@
* Orion General Purpose Pins
*/
#define IRQ_ORION5X_GPIO_START 32
#define NR_GPIO_IRQS
GPIO_MAX
#define NR_GPIO_IRQS
32
#define NR_IRQS (IRQ_ORION5X_GPIO_START + NR_GPIO_IRQS)
...
...
arch/arm/mach-orion5x/include/mach/orion5x.h
View file @
a663a71e
...
...
@@ -134,14 +134,6 @@
#define MPP_16_19_CTRL ORION5X_DEV_BUS_REG(0x050)
#define MPP_DEV_CTRL ORION5X_DEV_BUS_REG(0x008)
#define MPP_RESET_SAMPLE ORION5X_DEV_BUS_REG(0x010)
#define GPIO_OUT ORION5X_DEV_BUS_REG(0x100)
#define GPIO_IO_CONF ORION5X_DEV_BUS_REG(0x104)
#define GPIO_BLINK_EN ORION5X_DEV_BUS_REG(0x108)
#define GPIO_IN_POL ORION5X_DEV_BUS_REG(0x10c)
#define GPIO_DATA_IN ORION5X_DEV_BUS_REG(0x110)
#define GPIO_EDGE_CAUSE ORION5X_DEV_BUS_REG(0x114)
#define GPIO_EDGE_MASK ORION5X_DEV_BUS_REG(0x118)
#define GPIO_LEVEL_MASK ORION5X_DEV_BUS_REG(0x11c)
#define DEV_BANK_0_PARAM ORION5X_DEV_BUS_REG(0x45c)
#define DEV_BANK_1_PARAM ORION5X_DEV_BUS_REG(0x460)
#define DEV_BANK_2_PARAM ORION5X_DEV_BUS_REG(0x464)
...
...
@@ -149,7 +141,6 @@
#define DEV_BUS_CTRL ORION5X_DEV_BUS_REG(0x4c0)
#define DEV_BUS_INT_CAUSE ORION5X_DEV_BUS_REG(0x4d0)
#define DEV_BUS_INT_MASK ORION5X_DEV_BUS_REG(0x4d4)
#define GPIO_MAX 32
/***************************************************************************
* Orion CPU Bridge Registers
...
...
arch/arm/mach-orion5x/irq.c
View file @
a663a71e
...
...
@@ -19,193 +19,38 @@
#include <plat/irq.h>
#include "common.h"
/*****************************************************************************
* Orion GPIO IRQ
*
* GPIO_IN_POL register controlls whether GPIO_DATA_IN will hold the same
* value of the line or the opposite value.
*
* Level IRQ handlers: DATA_IN is used directly as cause register.
* Interrupt are masked by LEVEL_MASK registers.
* Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE.
* Interrupt are masked by EDGE_MASK registers.
* Both-edge handlers: Similar to regular Edge handlers, but also swaps
* the polarity to catch the next line transaction.
* This is a race condition that might not perfectly
* work on some use cases.
*
* Every eight GPIO lines are grouped (OR'ed) before going up to main
* cause register.
*
* EDGE cause mask
* data-in /--------| |-----| |----\
* -----| |----- ---- to main cause reg
* X \----------------| |----/
* polarity LEVEL mask
*
****************************************************************************/
static
void
orion5x_gpio_irq_ack
(
u32
irq
)
{
int
pin
=
irq_to_gpio
(
irq
);
if
(
irq_desc
[
irq
].
status
&
IRQ_LEVEL
)
/*
* Mask bit for level interrupt
*/
orion5x_clrbits
(
GPIO_LEVEL_MASK
,
1
<<
pin
);
else
/*
* Clear casue bit for egde interrupt
*/
orion5x_clrbits
(
GPIO_EDGE_CAUSE
,
1
<<
pin
);
}
static
void
orion5x_gpio_irq_mask
(
u32
irq
)
static
void
gpio_irq_handler
(
unsigned
int
irq
,
struct
irq_desc
*
desc
)
{
int
pin
=
irq_to_gpio
(
irq
);
if
(
irq_desc
[
irq
].
status
&
IRQ_LEVEL
)
orion5x_clrbits
(
GPIO_LEVEL_MASK
,
1
<<
pin
);
else
orion5x_clrbits
(
GPIO_EDGE_MASK
,
1
<<
pin
);
}
static
void
orion5x_gpio_irq_unmask
(
u32
irq
)
{
int
pin
=
irq_to_gpio
(
irq
);
if
(
irq_desc
[
irq
].
status
&
IRQ_LEVEL
)
orion5x_setbits
(
GPIO_LEVEL_MASK
,
1
<<
pin
);
else
orion5x_setbits
(
GPIO_EDGE_MASK
,
1
<<
pin
);
}
static
int
orion5x_gpio_set_irq_type
(
u32
irq
,
u32
type
)
{
int
pin
=
irq_to_gpio
(
irq
);
struct
irq_desc
*
desc
;
if
((
readl
(
GPIO_IO_CONF
)
&
(
1
<<
pin
))
==
0
)
{
printk
(
KERN_ERR
"orion5x_gpio_set_irq_type failed "
"(irq %d, pin %d).
\n
"
,
irq
,
pin
);
return
-
EINVAL
;
}
desc
=
irq_desc
+
irq
;
switch
(
type
)
{
case
IRQ_TYPE_LEVEL_HIGH
:
desc
->
handle_irq
=
handle_level_irq
;
desc
->
status
|=
IRQ_LEVEL
;
orion5x_clrbits
(
GPIO_IN_POL
,
(
1
<<
pin
));
break
;
case
IRQ_TYPE_LEVEL_LOW
:
desc
->
handle_irq
=
handle_level_irq
;
desc
->
status
|=
IRQ_LEVEL
;
orion5x_setbits
(
GPIO_IN_POL
,
(
1
<<
pin
));
break
;
case
IRQ_TYPE_EDGE_RISING
:
desc
->
handle_irq
=
handle_edge_irq
;
desc
->
status
&=
~
IRQ_LEVEL
;
orion5x_clrbits
(
GPIO_IN_POL
,
(
1
<<
pin
));
break
;
case
IRQ_TYPE_EDGE_FALLING
:
desc
->
handle_irq
=
handle_edge_irq
;
desc
->
status
&=
~
IRQ_LEVEL
;
orion5x_setbits
(
GPIO_IN_POL
,
(
1
<<
pin
));
break
;
case
IRQ_TYPE_EDGE_BOTH
:
desc
->
handle_irq
=
handle_edge_irq
;
desc
->
status
&=
~
IRQ_LEVEL
;
/*
* set initial polarity based on current input level
*/
if
((
readl
(
GPIO_IN_POL
)
^
readl
(
GPIO_DATA_IN
))
&
(
1
<<
pin
))
orion5x_setbits
(
GPIO_IN_POL
,
(
1
<<
pin
));
/* falling */
else
orion5x_clrbits
(
GPIO_IN_POL
,
(
1
<<
pin
));
/* rising */
break
;
default:
printk
(
KERN_ERR
"failed to set irq=%d (type=%d)
\n
"
,
irq
,
type
);
return
-
EINVAL
;
}
desc
->
status
&=
~
IRQ_TYPE_SENSE_MASK
;
desc
->
status
|=
type
&
IRQ_TYPE_SENSE_MASK
;
return
0
;
}
static
struct
irq_chip
orion5x_gpio_irq_chip
=
{
.
name
=
"Orion-IRQ-GPIO"
,
.
ack
=
orion5x_gpio_irq_ack
,
.
mask
=
orion5x_gpio_irq_mask
,
.
unmask
=
orion5x_gpio_irq_unmask
,
.
set_type
=
orion5x_gpio_set_irq_type
,
};
static
void
orion5x_gpio_irq_handler
(
unsigned
int
irq
,
struct
irq_desc
*
desc
)
{
u32
cause
,
offs
,
pin
;
BUG_ON
(
irq
<
IRQ_ORION5X_GPIO_0_7
||
irq
>
IRQ_ORION5X_GPIO_24_31
);
offs
=
(
irq
-
IRQ_ORION5X_GPIO_0_7
)
*
8
;
cause
=
(
readl
(
GPIO_DATA_IN
)
&
readl
(
GPIO_LEVEL_MASK
))
|
(
readl
(
GPIO_EDGE_CAUSE
)
&
readl
(
GPIO_EDGE_MASK
));
for
(
pin
=
offs
;
pin
<
offs
+
8
;
pin
++
)
{
if
(
cause
&
(
1
<<
pin
))
{
irq
=
gpio_to_irq
(
pin
);
desc
=
irq_desc
+
irq
;
if
((
desc
->
status
&
IRQ_TYPE_SENSE_MASK
)
==
IRQ_TYPE_EDGE_BOTH
)
{
/* Swap polarity (race with GPIO line) */
u32
polarity
=
readl
(
GPIO_IN_POL
);
polarity
^=
1
<<
pin
;
writel
(
polarity
,
GPIO_IN_POL
);
}
generic_handle_irq
(
irq
);
}
}
orion_gpio_irq_handler
((
irq
-
IRQ_ORION5X_GPIO_0_7
)
<<
3
);
}
static
void
__init
orion5x_init_gpio
_irq
(
void
)
void
__init
orion5x_init
_irq
(
void
)
{
int
i
;
struct
irq_desc
*
desc
;
orion_irq_init
(
0
,
(
void
__iomem
*
)
MAIN_IRQ_MASK
);
/*
* Mask and clear GPIO IRQ interrupts
*/
writel
(
0x0
,
GPIO_LEVEL_MASK
);
writel
(
0x0
,
GPIO_EDGE_MASK
);
writel
(
0x0
,
GPIO_EDGE_CAUSE
);
writel
(
0x0
,
GPIO_LEVEL_MASK
(
0
)
);
writel
(
0x0
,
GPIO_EDGE_MASK
(
0
)
);
writel
(
0x0
,
GPIO_EDGE_CAUSE
(
0
)
);
/*
* Register chained level handlers for GPIO IRQs by default.
* User can use set_type() if he wants to use edge types handlers.
*/
for
(
i
=
IRQ_ORION5X_GPIO_START
;
i
<
NR_IRQS
;
i
++
)
{
set_irq_chip
(
i
,
&
orion
5x_gpio_irq
_chip
);
set_irq_chip
(
i
,
&
orion
_gpio_irq_level
_chip
);
set_irq_handler
(
i
,
handle_level_irq
);
desc
=
irq_desc
+
i
;
desc
->
status
|=
IRQ_LEVEL
;
irq_desc
[
i
].
status
|=
IRQ_LEVEL
;
set_irq_flags
(
i
,
IRQF_VALID
);
}
set_irq_chained_handler
(
IRQ_ORION5X_GPIO_0_7
,
orion5x_gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_ORION5X_GPIO_8_15
,
orion5x_gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_ORION5X_GPIO_16_23
,
orion5x_gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_ORION5X_GPIO_24_31
,
orion5x_gpio_irq_handler
);
}
/*****************************************************************************
* Orion Main IRQ
****************************************************************************/
static
void
__init
orion5x_init_main_irq
(
void
)
{
orion_irq_init
(
0
,
(
void
__iomem
*
)
MAIN_IRQ_MASK
);
}
void
__init
orion5x_init_irq
(
void
)
{
orion5x_init_main_irq
();
orion5x_init_gpio_irq
();
set_irq_chained_handler
(
IRQ_ORION5X_GPIO_0_7
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_ORION5X_GPIO_8_15
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_ORION5X_GPIO_16_23
,
gpio_irq_handler
);
set_irq_chained_handler
(
IRQ_ORION5X_GPIO_24_31
,
gpio_irq_handler
);
}
arch/arm/mach-orion5x/mpp.c
View file @
a663a71e
...
...
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/mbus.h>
#include <linux/io.h>
#include <asm/gpio.h>
#include <mach/hardware.h>
#include "common.h"
#include "mpp.h"
...
...
@@ -152,7 +153,10 @@ void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
*
reg
&=
~
(
0xf
<<
shift
);
*
reg
|=
(
num_type
&
0xf
)
<<
shift
;
orion5x_gpio_set_valid
(
mode
->
mpp
,
!!
(
mode
->
type
==
MPP_GPIO
));
if
(
mode
->
type
==
MPP_UNUSED
&&
(
mode
->
mpp
<
16
||
is_5182
()))
orion_gpio_set_unused
(
mode
->
mpp
);
orion_gpio_set_valid
(
mode
->
mpp
,
!!
(
mode
->
type
==
MPP_GPIO
));
mode
++
;
}
...
...
arch/arm/plat-orion/Makefile
View file @
a663a71e
...
...
@@ -6,3 +6,5 @@ obj-y := irq.o pcie.o time.o
obj-m
:=
obj-n
:=
obj-
:=
obj-$(CONFIG_GENERIC_GPIO)
+=
gpio.o
arch/arm/plat-orion/gpio.c
0 → 100644
View file @
a663a71e
/*
* arch/arm/plat-orion/gpio.c
*
* Marvell Orion SoC GPIO handling.
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <asm/gpio.h>
static
DEFINE_SPINLOCK
(
gpio_lock
);
static
const
char
*
gpio_label
[
GPIO_MAX
];
/* non null for allocated GPIOs */
static
unsigned
long
gpio_valid
[
BITS_TO_LONGS
(
GPIO_MAX
)];
static
inline
void
__set_direction
(
unsigned
pin
,
int
input
)
{
u32
u
;
u
=
readl
(
GPIO_IO_CONF
(
pin
));
if
(
input
)
u
|=
1
<<
(
pin
&
31
);
else
u
&=
~
(
1
<<
(
pin
&
31
));
writel
(
u
,
GPIO_IO_CONF
(
pin
));
}
static
void
__set_level
(
unsigned
pin
,
int
high
)
{
u32
u
;
u
=
readl
(
GPIO_OUT
(
pin
));
if
(
high
)
u
|=
1
<<
(
pin
&
31
);
else
u
&=
~
(
1
<<
(
pin
&
31
));
writel
(
u
,
GPIO_OUT
(
pin
));
}
/*
* GENERIC_GPIO primitives.
*/
int
gpio_direction_input
(
unsigned
pin
)
{
unsigned
long
flags
;
if
(
pin
>=
GPIO_MAX
||
!
test_bit
(
pin
,
gpio_valid
))
{
pr_debug
(
"%s: invalid GPIO %d
\n
"
,
__func__
,
pin
);
return
-
EINVAL
;
}
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
/*
* Some callers might not have used gpio_request(),
* so flag this pin as requested now.
*/
if
(
gpio_label
[
pin
]
==
NULL
)
gpio_label
[
pin
]
=
"?"
;
/*
* Configure GPIO direction.
*/
__set_direction
(
pin
,
1
);
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
return
0
;
}
EXPORT_SYMBOL
(
gpio_direction_input
);
int
gpio_direction_output
(
unsigned
pin
,
int
value
)
{
unsigned
long
flags
;
u32
u
;
if
(
pin
>=
GPIO_MAX
||
!
test_bit
(
pin
,
gpio_valid
))
{
pr_debug
(
"%s: invalid GPIO %d
\n
"
,
__func__
,
pin
);
return
-
EINVAL
;
}
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
/*
* Some callers might not have used gpio_request(),
* so flag this pin as requested now.
*/
if
(
gpio_label
[
pin
]
==
NULL
)
gpio_label
[
pin
]
=
"?"
;
/*
* Disable blinking.
*/
u
=
readl
(
GPIO_BLINK_EN
(
pin
));
u
&=
~
(
1
<<
(
pin
&
31
));
writel
(
u
,
GPIO_BLINK_EN
(
pin
));
/*
* Configure GPIO output value.
*/
__set_level
(
pin
,
value
);
/*
* Configure GPIO direction.
*/
__set_direction
(
pin
,
0
);
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
return
0
;
}
EXPORT_SYMBOL
(
gpio_direction_output
);
int
gpio_get_value
(
unsigned
pin
)
{
int
val
;
if
(
readl
(
GPIO_IO_CONF
(
pin
))
&
(
1
<<
(
pin
&
31
)))
val
=
readl
(
GPIO_DATA_IN
(
pin
))
^
readl
(
GPIO_IN_POL
(
pin
));
else
val
=
readl
(
GPIO_OUT
(
pin
));
return
(
val
>>
(
pin
&
31
))
&
1
;
}
EXPORT_SYMBOL
(
gpio_get_value
);
void
gpio_set_value
(
unsigned
pin
,
int
value
)
{
unsigned
long
flags
;
u32
u
;
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
/*
* Disable blinking.
*/
u
=
readl
(
GPIO_BLINK_EN
(
pin
));
u
&=
~
(
1
<<
(
pin
&
31
));
writel
(
u
,
GPIO_BLINK_EN
(
pin
));
/*
* Configure GPIO output value.
*/
__set_level
(
pin
,
value
);
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
}
EXPORT_SYMBOL
(
gpio_set_value
);
int
gpio_request
(
unsigned
pin
,
const
char
*
label
)
{
unsigned
long
flags
;
int
ret
;
if
(
pin
>=
GPIO_MAX
||
!
test_bit
(
pin
,
gpio_valid
))
{
pr_debug
(
"%s: invalid GPIO %d
\n
"
,
__func__
,
pin
);
return
-
EINVAL
;
}
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
if
(
gpio_label
[
pin
]
==
NULL
)
{
gpio_label
[
pin
]
=
label
?
label
:
"?"
;
ret
=
0
;
}
else
{
pr_debug
(
"%s: GPIO %d already used as %s
\n
"
,
__func__
,
pin
,
gpio_label
[
pin
]);
ret
=
-
EBUSY
;
}
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
gpio_request
);
void
gpio_free
(
unsigned
pin
)
{
if
(
pin
>=
GPIO_MAX
||
!
test_bit
(
pin
,
gpio_valid
))
{
pr_debug
(
"%s: invalid GPIO %d
\n
"
,
__func__
,
pin
);
return
;
}
if
(
gpio_label
[
pin
]
==
NULL
)
pr_warning
(
"%s: GPIO %d already freed
\n
"
,
__func__
,
pin
);
else
gpio_label
[
pin
]
=
NULL
;
}
EXPORT_SYMBOL
(
gpio_free
);
/*
* Orion-specific GPIO API extensions.
*/
void
__init
orion_gpio_set_unused
(
unsigned
pin
)
{
/*
* Configure as output, drive low.
*/
__set_level
(
pin
,
0
);
__set_direction
(
pin
,
0
);
}
void
__init
orion_gpio_set_valid
(
unsigned
pin
,
int
valid
)
{
if
(
valid
)
__set_bit
(
pin
,
gpio_valid
);
else
__clear_bit
(
pin
,
gpio_valid
);
}
void
orion_gpio_set_blink
(
unsigned
pin
,
int
blink
)
{
unsigned
long
flags
;
u32
u
;
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
/*
* Set output value to zero.
*/
__set_level
(
pin
,
0
);
u
=
readl
(
GPIO_BLINK_EN
(
pin
));
if
(
blink
)
u
|=
1
<<
(
pin
&
31
);
else
u
&=
~
(
1
<<
(
pin
&
31
));
writel
(
u
,
GPIO_BLINK_EN
(
pin
));
spin_unlock_irqrestore
(
&
gpio_lock
,
flags
);
}
EXPORT_SYMBOL
(
orion_gpio_set_blink
);
/*****************************************************************************
* Orion GPIO IRQ
*
* GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
* value of the line or the opposite value.
*
* Level IRQ handlers: DATA_IN is used directly as cause register.
* Interrupt are masked by LEVEL_MASK registers.
* Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE.
* Interrupt are masked by EDGE_MASK registers.
* Both-edge handlers: Similar to regular Edge handlers, but also swaps
* the polarity to catch the next line transaction.
* This is a race condition that might not perfectly
* work on some use cases.
*
* Every eight GPIO lines are grouped (OR'ed) before going up to main
* cause register.
*
* EDGE cause mask
* data-in /--------| |-----| |----\
* -----| |----- ---- to main cause reg
* X \----------------| |----/
* polarity LEVEL mask
*
****************************************************************************/
static
void
gpio_irq_edge_ack
(
u32
irq
)
{
int
pin
=
irq_to_gpio
(
irq
);
writel
(
~
(
1
<<
(
pin
&
31
)),
GPIO_EDGE_CAUSE
(
pin
));
}
static
void
gpio_irq_edge_mask
(
u32
irq
)
{
int
pin
=
irq_to_gpio
(
irq
);
u32
u
;
u
=
readl
(
GPIO_EDGE_MASK
(
pin
));
u
&=
~
(
1
<<
(
pin
&
31
));
writel
(
u
,
GPIO_EDGE_MASK
(
pin
));
}
static
void
gpio_irq_edge_unmask
(
u32
irq
)
{
int
pin
=
irq_to_gpio
(
irq
);
u32
u
;
u
=
readl
(
GPIO_EDGE_MASK
(
pin
));
u
|=
1
<<
(
pin
&
31
);
writel
(
u
,
GPIO_EDGE_MASK
(
pin
));
}
static
void
gpio_irq_level_mask
(
u32
irq
)
{
int
pin
=
irq_to_gpio
(
irq
);
u32
u
;
u
=
readl
(
GPIO_LEVEL_MASK
(
pin
));
u
&=
~
(
1
<<
(
pin
&
31
));
writel
(
u
,
GPIO_LEVEL_MASK
(
pin
));
}
static
void
gpio_irq_level_unmask
(
u32
irq
)
{
int
pin
=
irq_to_gpio
(
irq
);
u32
u
;
u
=
readl
(
GPIO_LEVEL_MASK
(
pin
));
u
|=
1
<<
(
pin
&
31
);
writel
(
u
,
GPIO_LEVEL_MASK
(
pin
));
}
static
int
gpio_irq_set_type
(
u32
irq
,
u32
type
)
{
int
pin
=
irq_to_gpio
(
irq
);
struct
irq_desc
*
desc
;
u32
u
;
u
=
readl
(
GPIO_IO_CONF
(
pin
))
&
(
1
<<
(
pin
&
31
));
if
(
!
u
)
{
printk
(
KERN_ERR
"orion gpio_irq_set_type failed "
"(irq %d, pin %d).
\n
"
,
irq
,
pin
);
return
-
EINVAL
;
}
desc
=
irq_desc
+
irq
;
/*
* Set edge/level type.
*/
if
(
type
&
(
IRQ_TYPE_EDGE_RISING
|
IRQ_TYPE_EDGE_FALLING
))
{
desc
->
chip
=
&
orion_gpio_irq_edge_chip
;
}
else
if
(
type
&
(
IRQ_TYPE_LEVEL_HIGH
|
IRQ_TYPE_LEVEL_LOW
))
{
desc
->
chip
=
&
orion_gpio_irq_level_chip
;
}
else
{
printk
(
KERN_ERR
"failed to set irq=%d (type=%d)
\n
"
,
irq
,
type
);
return
-
EINVAL
;
}
/*
* Configure interrupt polarity.
*/
if
(
type
==
IRQ_TYPE_EDGE_RISING
||
type
==
IRQ_TYPE_LEVEL_HIGH
)
{
u
=
readl
(
GPIO_IN_POL
(
pin
));
u
&=
~
(
1
<<
(
pin
&
31
));
writel
(
u
,
GPIO_IN_POL
(
pin
));
}
else
if
(
type
==
IRQ_TYPE_EDGE_FALLING
||
type
==
IRQ_TYPE_LEVEL_LOW
)
{
u
=
readl
(
GPIO_IN_POL
(
pin
));
u
|=
1
<<
(
pin
&
31
);
writel
(
u
,
GPIO_IN_POL
(
pin
));
}
else
if
(
type
==
IRQ_TYPE_EDGE_BOTH
)
{
u32
v
;
v
=
readl
(
GPIO_IN_POL
(
pin
))
^
readl
(
GPIO_DATA_IN
(
pin
));
/*
* set initial polarity based on current input level
*/
u
=
readl
(
GPIO_IN_POL
(
pin
));
if
(
v
&
(
1
<<
(
pin
&
31
)))
u
|=
1
<<
(
pin
&
31
);
/* falling */
else
u
&=
~
(
1
<<
(
pin
&
31
));
/* rising */
writel
(
u
,
GPIO_IN_POL
(
pin
));
}
desc
->
status
=
(
desc
->
status
&
~
IRQ_TYPE_SENSE_MASK
)
|
type
;
return
0
;
}
struct
irq_chip
orion_gpio_irq_edge_chip
=
{
.
name
=
"orion_gpio_irq_edge"
,
.
ack
=
gpio_irq_edge_ack
,
.
mask
=
gpio_irq_edge_mask
,
.
unmask
=
gpio_irq_edge_unmask
,
.
set_type
=
gpio_irq_set_type
,
};
struct
irq_chip
orion_gpio_irq_level_chip
=
{
.
name
=
"orion_gpio_irq_level"
,
.
mask
=
gpio_irq_level_mask
,
.
mask_ack
=
gpio_irq_level_mask
,
.
unmask
=
gpio_irq_level_unmask
,
.
set_type
=
gpio_irq_set_type
,
};
void
orion_gpio_irq_handler
(
int
pinoff
)
{
u32
cause
;
int
pin
;
cause
=
readl
(
GPIO_DATA_IN
(
pinoff
))
&
readl
(
GPIO_LEVEL_MASK
(
pinoff
));
cause
|=
readl
(
GPIO_EDGE_CAUSE
(
pinoff
))
&
readl
(
GPIO_EDGE_MASK
(
pinoff
));
for
(
pin
=
pinoff
;
pin
<
pinoff
+
8
;
pin
++
)
{
int
irq
=
gpio_to_irq
(
pin
);
struct
irq_desc
*
desc
=
irq_desc
+
irq
;
if
(
!
(
cause
&
(
1
<<
(
pin
&
31
))))
continue
;
if
((
desc
->
status
&
IRQ_TYPE_SENSE_MASK
)
==
IRQ_TYPE_EDGE_BOTH
)
{
/* Swap polarity (race with GPIO line) */
u32
polarity
;
polarity
=
readl
(
GPIO_IN_POL
(
pin
));
polarity
^=
1
<<
(
pin
&
31
);
writel
(
polarity
,
GPIO_IN_POL
(
pin
));
}
desc_handle_irq
(
irq
,
desc
);
}
}
arch/arm/plat-orion/include/plat/gpio.h
0 → 100644
View file @
a663a71e
/*
* arch/arm/plat-orion/include/plat/gpio.h
*
* Marvell Orion SoC GPIO handling.
*
* 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.
*/
#ifndef __PLAT_GPIO_H
#define __PLAT_GPIO_H
/*
* GENERIC_GPIO primitives.
*/
int
gpio_request
(
unsigned
pin
,
const
char
*
label
);
void
gpio_free
(
unsigned
pin
);
int
gpio_direction_input
(
unsigned
pin
);
int
gpio_direction_output
(
unsigned
pin
,
int
value
);
int
gpio_get_value
(
unsigned
pin
);
void
gpio_set_value
(
unsigned
pin
,
int
value
);
/*
* Orion-specific GPIO API extensions.
*/
void
orion_gpio_set_unused
(
unsigned
pin
);
void
orion_gpio_set_valid
(
unsigned
pin
,
int
valid
);
void
orion_gpio_set_blink
(
unsigned
pin
,
int
blink
);
/*
* GPIO interrupt handling.
*/
extern
struct
irq_chip
orion_gpio_irq_edge_chip
;
extern
struct
irq_chip
orion_gpio_irq_level_chip
;
void
orion_gpio_irq_handler
(
int
irqoff
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment