Merge branch 'emev2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/renesas into next/soc
* 'emev2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/renesas: mach-shmobile: Use DT_MACHINE for KZM9D V3 mach-shmobile: Emma Mobile EV2 DT support V3 mach-shmobile: KZM9D board Ethernet support V3 mach-shmobile: Emma Mobile EV2 GPIO support V3 mach-shmobile: Emma Mobile EV2 SMP support V3 mach-shmobile: KZM9D board support V3 mach-shmobile: Emma Mobile EV2 SoC base support V3 gpio: Emma Mobile GPIO driver V2
This commit is contained in:
commit
0804dcb2af
26
arch/arm/boot/dts/emev2-kzm9d.dts
Normal file
26
arch/arm/boot/dts/emev2-kzm9d.dts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Device Tree Source for the KZM9D board
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Renesas Solutions Corp.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/include/ "emev2.dtsi"
|
||||||
|
|
||||||
|
/ {
|
||||||
|
model = "EMEV2 KZM9D Board";
|
||||||
|
compatible = "renesas,kzm9d", "renesas,emev2";
|
||||||
|
|
||||||
|
memory {
|
||||||
|
device_type = "memory";
|
||||||
|
reg = <0x40000000 0x8000000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
chosen {
|
||||||
|
bootargs = "console=ttyS1,115200n81";
|
||||||
|
};
|
||||||
|
};
|
63
arch/arm/boot/dts/emev2.dtsi
Normal file
63
arch/arm/boot/dts/emev2.dtsi
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Device Tree Source for the EMEV2 SoC
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Renesas Solutions Corp.
|
||||||
|
*
|
||||||
|
* 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/ "skeleton.dtsi"
|
||||||
|
|
||||||
|
/ {
|
||||||
|
compatible = "renesas,emev2";
|
||||||
|
interrupt-parent = <&gic>;
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
cpu@0 {
|
||||||
|
compatible = "arm,cortex-a9";
|
||||||
|
};
|
||||||
|
cpu@1 {
|
||||||
|
compatible = "arm,cortex-a9";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
gic: interrupt-controller@e0020000 {
|
||||||
|
compatible = "arm,cortex-a9-gic";
|
||||||
|
interrupt-controller;
|
||||||
|
#interrupt-cells = <3>;
|
||||||
|
reg = <0xe0028000 0x1000>,
|
||||||
|
<0xe0020000 0x0100>;
|
||||||
|
};
|
||||||
|
|
||||||
|
sti@e0180000 {
|
||||||
|
compatible = "renesas,em-sti";
|
||||||
|
reg = <0xe0180000 0x54>;
|
||||||
|
interrupts = <0 125 0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
uart@e1020000 {
|
||||||
|
compatible = "renesas,em-uart";
|
||||||
|
reg = <0xe1020000 0x38>;
|
||||||
|
interrupts = <0 8 0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
uart@e1030000 {
|
||||||
|
compatible = "renesas,em-uart";
|
||||||
|
reg = <0xe1030000 0x38>;
|
||||||
|
interrupts = <0 9 0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
uart@e1040000 {
|
||||||
|
compatible = "renesas,em-uart";
|
||||||
|
reg = <0xe1040000 0x38>;
|
||||||
|
interrupts = <0 10 0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
uart@e1050000 {
|
||||||
|
compatible = "renesas,em-uart";
|
||||||
|
reg = <0xe1050000 0x38>;
|
||||||
|
interrupts = <0 11 0>;
|
||||||
|
};
|
||||||
|
};
|
@ -41,6 +41,12 @@ config ARCH_R8A7779
|
|||||||
select ARM_GIC
|
select ARM_GIC
|
||||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||||
|
|
||||||
|
config ARCH_EMEV2
|
||||||
|
bool "Emma Mobile EV2"
|
||||||
|
select CPU_V7
|
||||||
|
select ARM_GIC
|
||||||
|
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||||
|
|
||||||
comment "SH-Mobile Board Type"
|
comment "SH-Mobile Board Type"
|
||||||
|
|
||||||
config MACH_G3EVM
|
config MACH_G3EVM
|
||||||
@ -98,6 +104,11 @@ config MACH_MARZEN
|
|||||||
depends on ARCH_R8A7779
|
depends on ARCH_R8A7779
|
||||||
select ARCH_REQUIRE_GPIOLIB
|
select ARCH_REQUIRE_GPIOLIB
|
||||||
|
|
||||||
|
config MACH_KZM9D
|
||||||
|
bool "KZM9D board"
|
||||||
|
depends on ARCH_EMEV2
|
||||||
|
select USE_OF
|
||||||
|
|
||||||
comment "SH-Mobile System Configuration"
|
comment "SH-Mobile System Configuration"
|
||||||
|
|
||||||
config CPU_HAS_INTEVT
|
config CPU_HAS_INTEVT
|
||||||
|
@ -12,12 +12,14 @@ obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o
|
|||||||
obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
|
obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
|
||||||
obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o
|
obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o
|
||||||
obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
|
obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
|
||||||
|
obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o
|
||||||
|
|
||||||
# SMP objects
|
# SMP objects
|
||||||
smp-y := platsmp.o headsmp.o
|
smp-y := platsmp.o headsmp.o
|
||||||
smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||||
smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
|
smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
|
||||||
smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o
|
smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o
|
||||||
|
smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o
|
||||||
|
|
||||||
# Pinmux setup
|
# Pinmux setup
|
||||||
pfc-y :=
|
pfc-y :=
|
||||||
@ -49,6 +51,7 @@ obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o
|
|||||||
obj-$(CONFIG_MACH_KOTA2) += board-kota2.o
|
obj-$(CONFIG_MACH_KOTA2) += board-kota2.o
|
||||||
obj-$(CONFIG_MACH_BONITO) += board-bonito.o
|
obj-$(CONFIG_MACH_BONITO) += board-bonito.o
|
||||||
obj-$(CONFIG_MACH_MARZEN) += board-marzen.o
|
obj-$(CONFIG_MACH_MARZEN) += board-marzen.o
|
||||||
|
obj-$(CONFIG_MACH_KZM9D) += board-kzm9d.o
|
||||||
|
|
||||||
# Framework support
|
# Framework support
|
||||||
obj-$(CONFIG_SMP) += $(smp-y)
|
obj-$(CONFIG_SMP) += $(smp-y)
|
||||||
|
85
arch/arm/mach-shmobile/board-kzm9d.c
Normal file
85
arch/arm/mach-shmobile/board-kzm9d.c
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* kzm9d board support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Renesas Solutions Corp.
|
||||||
|
* Copyright (C) 2012 Magnus Damm
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/smsc911x.h>
|
||||||
|
#include <mach/common.h>
|
||||||
|
#include <mach/emev2.h>
|
||||||
|
#include <asm/mach-types.h>
|
||||||
|
#include <asm/mach/arch.h>
|
||||||
|
#include <asm/hardware/gic.h>
|
||||||
|
|
||||||
|
/* Ether */
|
||||||
|
static struct resource smsc911x_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = 0x20000000,
|
||||||
|
.end = 0x2000ffff,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = EMEV2_GPIO_IRQ(1),
|
||||||
|
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct smsc911x_platform_config smsc911x_platdata = {
|
||||||
|
.flags = SMSC911X_USE_32BIT,
|
||||||
|
.irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
|
||||||
|
.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device smsc91x_device = {
|
||||||
|
.name = "smsc911x",
|
||||||
|
.id = 0,
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &smsc911x_platdata,
|
||||||
|
},
|
||||||
|
.num_resources = ARRAY_SIZE(smsc911x_resources),
|
||||||
|
.resource = smsc911x_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device *kzm9d_devices[] __initdata = {
|
||||||
|
&smsc91x_device,
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init kzm9d_add_standard_devices(void)
|
||||||
|
{
|
||||||
|
emev2_add_standard_devices();
|
||||||
|
|
||||||
|
platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *kzm9d_boards_compat_dt[] __initdata = {
|
||||||
|
"renesas,kzm9d",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
DT_MACHINE_START(KZM9D_DT, "kzm9d")
|
||||||
|
.map_io = emev2_map_io,
|
||||||
|
.init_early = emev2_add_early_devices,
|
||||||
|
.nr_irqs = NR_IRQS_LEGACY,
|
||||||
|
.init_irq = emev2_init_irq,
|
||||||
|
.handle_irq = gic_handle_irq,
|
||||||
|
.init_machine = kzm9d_add_standard_devices,
|
||||||
|
.timer = &shmobile_timer,
|
||||||
|
.dt_compat = kzm9d_boards_compat_dt,
|
||||||
|
MACHINE_END
|
249
arch/arm/mach-shmobile/clock-emev2.c
Normal file
249
arch/arm/mach-shmobile/clock-emev2.c
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* Emma Mobile EV2 clock framework support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Magnus Damm
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/sh_clk.h>
|
||||||
|
#include <linux/clkdev.h>
|
||||||
|
#include <mach/common.h>
|
||||||
|
|
||||||
|
#define EMEV2_SMU_BASE 0xe0110000
|
||||||
|
|
||||||
|
/* EMEV2 SMU registers */
|
||||||
|
#define USIAU0_RSTCTRL 0x094
|
||||||
|
#define USIBU1_RSTCTRL 0x0ac
|
||||||
|
#define USIBU2_RSTCTRL 0x0b0
|
||||||
|
#define USIBU3_RSTCTRL 0x0b4
|
||||||
|
#define STI_RSTCTRL 0x124
|
||||||
|
#define USIAU0GCLKCTRL 0x4a0
|
||||||
|
#define USIBU1GCLKCTRL 0x4b8
|
||||||
|
#define USIBU2GCLKCTRL 0x4bc
|
||||||
|
#define USIBU3GCLKCTRL 0x04c0
|
||||||
|
#define STIGCLKCTRL 0x528
|
||||||
|
#define USIAU0SCLKDIV 0x61c
|
||||||
|
#define USIB2SCLKDIV 0x65c
|
||||||
|
#define USIB3SCLKDIV 0x660
|
||||||
|
#define STI_CLKSEL 0x688
|
||||||
|
#define SMU_GENERAL_REG0 0x7c0
|
||||||
|
|
||||||
|
/* not pretty, but hey */
|
||||||
|
static void __iomem *smu_base;
|
||||||
|
|
||||||
|
static void emev2_smu_write(unsigned long value, int offs)
|
||||||
|
{
|
||||||
|
BUG_ON(!smu_base || (offs >= PAGE_SIZE));
|
||||||
|
iowrite32(value, smu_base + offs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emev2_set_boot_vector(unsigned long value)
|
||||||
|
{
|
||||||
|
emev2_smu_write(value, SMU_GENERAL_REG0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clk_mapping smu_mapping = {
|
||||||
|
.phys = EMEV2_SMU_BASE,
|
||||||
|
.len = PAGE_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Fixed 32 KHz root clock from C32K pin */
|
||||||
|
static struct clk c32k_clk = {
|
||||||
|
.rate = 32768,
|
||||||
|
.mapping = &smu_mapping,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* PLL3 multiplies C32K with 7000 */
|
||||||
|
static unsigned long pll3_recalc(struct clk *clk)
|
||||||
|
{
|
||||||
|
return clk->parent->rate * 7000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sh_clk_ops pll3_clk_ops = {
|
||||||
|
.recalc = pll3_recalc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct clk pll3_clk = {
|
||||||
|
.ops = &pll3_clk_ops,
|
||||||
|
.parent = &c32k_clk,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct clk *main_clks[] = {
|
||||||
|
&c32k_clk,
|
||||||
|
&pll3_clk,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3,
|
||||||
|
SCLKDIV_NR };
|
||||||
|
|
||||||
|
#define SCLKDIV(_reg, _shift) \
|
||||||
|
{ \
|
||||||
|
.parent = &pll3_clk, \
|
||||||
|
.enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
|
||||||
|
.enable_bit = _shift, \
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clk sclkdiv_clks[SCLKDIV_NR] = {
|
||||||
|
[SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0),
|
||||||
|
[SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16),
|
||||||
|
[SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0),
|
||||||
|
[SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK,
|
||||||
|
GCLK_STI_SCLK,
|
||||||
|
GCLK_NR };
|
||||||
|
|
||||||
|
#define GCLK_SCLK(_parent, _reg) \
|
||||||
|
{ \
|
||||||
|
.parent = _parent, \
|
||||||
|
.enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
|
||||||
|
.enable_bit = 1, /* SCLK_GCC */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clk gclk_clks[GCLK_NR] = {
|
||||||
|
[GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0],
|
||||||
|
USIAU0GCLKCTRL),
|
||||||
|
[GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1],
|
||||||
|
USIBU1GCLKCTRL),
|
||||||
|
[GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2],
|
||||||
|
USIBU2GCLKCTRL),
|
||||||
|
[GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3],
|
||||||
|
USIBU3GCLKCTRL),
|
||||||
|
[GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int emev2_gclk_enable(struct clk *clk)
|
||||||
|
{
|
||||||
|
iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
|
||||||
|
clk->mapped_reg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emev2_gclk_disable(struct clk *clk)
|
||||||
|
{
|
||||||
|
iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
|
||||||
|
clk->mapped_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sh_clk_ops emev2_gclk_clk_ops = {
|
||||||
|
.enable = emev2_gclk_enable,
|
||||||
|
.disable = emev2_gclk_disable,
|
||||||
|
.recalc = followparent_recalc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init emev2_gclk_register(struct clk *clks, int nr)
|
||||||
|
{
|
||||||
|
struct clk *clkp;
|
||||||
|
int ret = 0;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
for (k = 0; !ret && (k < nr); k++) {
|
||||||
|
clkp = clks + k;
|
||||||
|
clkp->ops = &emev2_gclk_clk_ops;
|
||||||
|
ret |= clk_register(clkp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long emev2_sclkdiv_recalc(struct clk *clk)
|
||||||
|
{
|
||||||
|
unsigned int sclk_div;
|
||||||
|
|
||||||
|
sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff;
|
||||||
|
|
||||||
|
return clk->parent->rate / (sclk_div + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sh_clk_ops emev2_sclkdiv_clk_ops = {
|
||||||
|
.recalc = emev2_sclkdiv_recalc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init emev2_sclkdiv_register(struct clk *clks, int nr)
|
||||||
|
{
|
||||||
|
struct clk *clkp;
|
||||||
|
int ret = 0;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
for (k = 0; !ret && (k < nr); k++) {
|
||||||
|
clkp = clks + k;
|
||||||
|
clkp->ops = &emev2_sclkdiv_clk_ops;
|
||||||
|
ret |= clk_register(clkp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clk_lookup lookups[] = {
|
||||||
|
CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]),
|
||||||
|
CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]),
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init emev2_clock_init(void)
|
||||||
|
{
|
||||||
|
int k, ret = 0;
|
||||||
|
static int is_setup;
|
||||||
|
|
||||||
|
/* yuck, this is ugly as hell, but the non-smp case of clocks
|
||||||
|
* code is now designed to rely on ioremap() instead of static
|
||||||
|
* entity maps. in the case of smp we need access to the SMU
|
||||||
|
* register earlier than ioremap() is actually working without
|
||||||
|
* any static maps. to enable SMP in ugly but with dynamic
|
||||||
|
* mappings we have to call emev2_clock_init() from different
|
||||||
|
* places depending on UP and SMP...
|
||||||
|
*/
|
||||||
|
if (is_setup++)
|
||||||
|
return;
|
||||||
|
|
||||||
|
smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
|
||||||
|
BUG_ON(!smu_base);
|
||||||
|
|
||||||
|
/* setup STI timer to run on 37.768 kHz and deassert reset */
|
||||||
|
emev2_smu_write(0, STI_CLKSEL);
|
||||||
|
emev2_smu_write(1, STI_RSTCTRL);
|
||||||
|
|
||||||
|
/* deassert reset for UART0->UART3 */
|
||||||
|
emev2_smu_write(2, USIAU0_RSTCTRL);
|
||||||
|
emev2_smu_write(2, USIBU1_RSTCTRL);
|
||||||
|
emev2_smu_write(2, USIBU2_RSTCTRL);
|
||||||
|
emev2_smu_write(2, USIBU3_RSTCTRL);
|
||||||
|
|
||||||
|
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
|
||||||
|
ret = clk_register(main_clks[k]);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
ret = emev2_gclk_register(gclk_clks, GCLK_NR);
|
||||||
|
|
||||||
|
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
shmobile_clk_init();
|
||||||
|
else
|
||||||
|
panic("failed to setup emev2 clocks\n");
|
||||||
|
}
|
19
arch/arm/mach-shmobile/include/mach/emev2.h
Normal file
19
arch/arm/mach-shmobile/include/mach/emev2.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef __ASM_EMEV2_H__
|
||||||
|
#define __ASM_EMEV2_H__
|
||||||
|
|
||||||
|
extern void emev2_map_io(void);
|
||||||
|
extern void emev2_init_irq(void);
|
||||||
|
extern void emev2_add_early_devices(void);
|
||||||
|
extern void emev2_add_standard_devices(void);
|
||||||
|
extern void emev2_clock_init(void);
|
||||||
|
extern void emev2_set_boot_vector(unsigned long value);
|
||||||
|
extern unsigned int emev2_get_core_count(void);
|
||||||
|
extern int emev2_platform_cpu_kill(unsigned int cpu);
|
||||||
|
extern void emev2_secondary_init(unsigned int cpu);
|
||||||
|
extern int emev2_boot_secondary(unsigned int cpu);
|
||||||
|
extern void emev2_smp_prepare_cpus(void);
|
||||||
|
|
||||||
|
#define EMEV2_GPIO_BASE 200
|
||||||
|
#define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n))
|
||||||
|
|
||||||
|
#endif /* __ASM_EMEV2_H__ */
|
@ -16,12 +16,15 @@
|
|||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <asm/hardware/gic.h>
|
#include <asm/hardware/gic.h>
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <mach/common.h>
|
#include <mach/common.h>
|
||||||
|
#include <mach/emev2.h>
|
||||||
|
|
||||||
#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2())
|
#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2())
|
||||||
#define is_r8a7779() machine_is_marzen()
|
#define is_r8a7779() machine_is_marzen()
|
||||||
|
#define is_emev2() of_machine_is_compatible("renesas,emev2")
|
||||||
|
|
||||||
static unsigned int __init shmobile_smp_get_core_count(void)
|
static unsigned int __init shmobile_smp_get_core_count(void)
|
||||||
{
|
{
|
||||||
@ -31,6 +34,9 @@ static unsigned int __init shmobile_smp_get_core_count(void)
|
|||||||
if (is_r8a7779())
|
if (is_r8a7779())
|
||||||
return r8a7779_get_core_count();
|
return r8a7779_get_core_count();
|
||||||
|
|
||||||
|
if (is_emev2())
|
||||||
|
return emev2_get_core_count();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +47,9 @@ static void __init shmobile_smp_prepare_cpus(void)
|
|||||||
|
|
||||||
if (is_r8a7779())
|
if (is_r8a7779())
|
||||||
r8a7779_smp_prepare_cpus();
|
r8a7779_smp_prepare_cpus();
|
||||||
|
|
||||||
|
if (is_emev2())
|
||||||
|
emev2_smp_prepare_cpus();
|
||||||
}
|
}
|
||||||
|
|
||||||
int shmobile_platform_cpu_kill(unsigned int cpu)
|
int shmobile_platform_cpu_kill(unsigned int cpu)
|
||||||
@ -48,6 +57,9 @@ int shmobile_platform_cpu_kill(unsigned int cpu)
|
|||||||
if (is_r8a7779())
|
if (is_r8a7779())
|
||||||
return r8a7779_platform_cpu_kill(cpu);
|
return r8a7779_platform_cpu_kill(cpu);
|
||||||
|
|
||||||
|
if (is_emev2())
|
||||||
|
return emev2_platform_cpu_kill(cpu);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +72,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
|
|||||||
|
|
||||||
if (is_r8a7779())
|
if (is_r8a7779())
|
||||||
r8a7779_secondary_init(cpu);
|
r8a7779_secondary_init(cpu);
|
||||||
|
|
||||||
|
if (is_emev2())
|
||||||
|
emev2_secondary_init(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
|
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||||
@ -70,6 +85,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
|
|||||||
if (is_r8a7779())
|
if (is_r8a7779())
|
||||||
return r8a7779_boot_secondary(cpu);
|
return r8a7779_boot_secondary(cpu);
|
||||||
|
|
||||||
|
if (is_emev2())
|
||||||
|
return emev2_boot_secondary(cpu);
|
||||||
|
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
452
arch/arm/mach-shmobile/setup-emev2.c
Normal file
452
arch/arm/mach-shmobile/setup-emev2.c
Normal file
@ -0,0 +1,452 @@
|
|||||||
|
/*
|
||||||
|
* Emma Mobile EV2 processor support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Magnus Damm
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/platform_data/gpio-em.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <mach/hardware.h>
|
||||||
|
#include <mach/common.h>
|
||||||
|
#include <mach/emev2.h>
|
||||||
|
#include <mach/irqs.h>
|
||||||
|
#include <asm/mach-types.h>
|
||||||
|
#include <asm/mach/arch.h>
|
||||||
|
#include <asm/mach/map.h>
|
||||||
|
#include <asm/mach/time.h>
|
||||||
|
#include <asm/hardware/gic.h>
|
||||||
|
|
||||||
|
static struct map_desc emev2_io_desc[] __initdata = {
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* 128K entity map for 0xe0100000 (SMU) */
|
||||||
|
{
|
||||||
|
.virtual = 0xe0100000,
|
||||||
|
.pfn = __phys_to_pfn(0xe0100000),
|
||||||
|
.length = SZ_128K,
|
||||||
|
.type = MT_DEVICE
|
||||||
|
},
|
||||||
|
/* 2M mapping for SCU + L2 controller */
|
||||||
|
{
|
||||||
|
.virtual = 0xf0000000,
|
||||||
|
.pfn = __phys_to_pfn(0x1e000000),
|
||||||
|
.length = SZ_2M,
|
||||||
|
.type = MT_DEVICE
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init emev2_map_io(void)
|
||||||
|
{
|
||||||
|
iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UART */
|
||||||
|
static struct resource uart0_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = 0xe1020000,
|
||||||
|
.end = 0xe1020037,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = 40,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device uart0_device = {
|
||||||
|
.name = "serial8250-em",
|
||||||
|
.id = 0,
|
||||||
|
.num_resources = ARRAY_SIZE(uart0_resources),
|
||||||
|
.resource = uart0_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource uart1_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = 0xe1030000,
|
||||||
|
.end = 0xe1030037,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = 41,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device uart1_device = {
|
||||||
|
.name = "serial8250-em",
|
||||||
|
.id = 1,
|
||||||
|
.num_resources = ARRAY_SIZE(uart1_resources),
|
||||||
|
.resource = uart1_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource uart2_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = 0xe1040000,
|
||||||
|
.end = 0xe1040037,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = 42,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device uart2_device = {
|
||||||
|
.name = "serial8250-em",
|
||||||
|
.id = 2,
|
||||||
|
.num_resources = ARRAY_SIZE(uart2_resources),
|
||||||
|
.resource = uart2_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource uart3_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = 0xe1050000,
|
||||||
|
.end = 0xe1050037,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = 43,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device uart3_device = {
|
||||||
|
.name = "serial8250-em",
|
||||||
|
.id = 3,
|
||||||
|
.num_resources = ARRAY_SIZE(uart3_resources),
|
||||||
|
.resource = uart3_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* STI */
|
||||||
|
static struct resource sti_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.name = "STI",
|
||||||
|
.start = 0xe0180000,
|
||||||
|
.end = 0xe0180053,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = 157,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device sti_device = {
|
||||||
|
.name = "em_sti",
|
||||||
|
.id = 0,
|
||||||
|
.resource = sti_resources,
|
||||||
|
.num_resources = ARRAY_SIZE(sti_resources),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* GIO */
|
||||||
|
static struct gpio_em_config gio0_config = {
|
||||||
|
.gpio_base = 0,
|
||||||
|
.irq_base = EMEV2_GPIO_IRQ(0),
|
||||||
|
.number_of_pins = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource gio0_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.name = "GIO_000",
|
||||||
|
.start = 0xe0050000,
|
||||||
|
.end = 0xe005002b,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.name = "GIO_000",
|
||||||
|
.start = 0xe0050040,
|
||||||
|
.end = 0xe005005f,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
.start = 99,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
.start = 100,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device gio0_device = {
|
||||||
|
.name = "em_gio",
|
||||||
|
.id = 0,
|
||||||
|
.resource = gio0_resources,
|
||||||
|
.num_resources = ARRAY_SIZE(gio0_resources),
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &gio0_config,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct gpio_em_config gio1_config = {
|
||||||
|
.gpio_base = 32,
|
||||||
|
.irq_base = EMEV2_GPIO_IRQ(32),
|
||||||
|
.number_of_pins = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource gio1_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.name = "GIO_032",
|
||||||
|
.start = 0xe0050080,
|
||||||
|
.end = 0xe00500ab,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.name = "GIO_032",
|
||||||
|
.start = 0xe00500c0,
|
||||||
|
.end = 0xe00500df,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
.start = 101,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
.start = 102,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device gio1_device = {
|
||||||
|
.name = "em_gio",
|
||||||
|
.id = 1,
|
||||||
|
.resource = gio1_resources,
|
||||||
|
.num_resources = ARRAY_SIZE(gio1_resources),
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &gio1_config,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct gpio_em_config gio2_config = {
|
||||||
|
.gpio_base = 64,
|
||||||
|
.irq_base = EMEV2_GPIO_IRQ(64),
|
||||||
|
.number_of_pins = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource gio2_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.name = "GIO_064",
|
||||||
|
.start = 0xe0050100,
|
||||||
|
.end = 0xe005012b,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.name = "GIO_064",
|
||||||
|
.start = 0xe0050140,
|
||||||
|
.end = 0xe005015f,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
.start = 103,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
.start = 104,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device gio2_device = {
|
||||||
|
.name = "em_gio",
|
||||||
|
.id = 2,
|
||||||
|
.resource = gio2_resources,
|
||||||
|
.num_resources = ARRAY_SIZE(gio2_resources),
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &gio2_config,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct gpio_em_config gio3_config = {
|
||||||
|
.gpio_base = 96,
|
||||||
|
.irq_base = EMEV2_GPIO_IRQ(96),
|
||||||
|
.number_of_pins = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource gio3_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.name = "GIO_096",
|
||||||
|
.start = 0xe0050100,
|
||||||
|
.end = 0xe005012b,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.name = "GIO_096",
|
||||||
|
.start = 0xe0050140,
|
||||||
|
.end = 0xe005015f,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
.start = 105,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
.start = 106,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device gio3_device = {
|
||||||
|
.name = "em_gio",
|
||||||
|
.id = 3,
|
||||||
|
.resource = gio3_resources,
|
||||||
|
.num_resources = ARRAY_SIZE(gio3_resources),
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &gio3_config,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct gpio_em_config gio4_config = {
|
||||||
|
.gpio_base = 128,
|
||||||
|
.irq_base = EMEV2_GPIO_IRQ(128),
|
||||||
|
.number_of_pins = 31,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource gio4_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.name = "GIO_128",
|
||||||
|
.start = 0xe0050200,
|
||||||
|
.end = 0xe005022b,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.name = "GIO_128",
|
||||||
|
.start = 0xe0050240,
|
||||||
|
.end = 0xe005025f,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
.start = 107,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
.start = 108,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device gio4_device = {
|
||||||
|
.name = "em_gio",
|
||||||
|
.id = 4,
|
||||||
|
.resource = gio4_resources,
|
||||||
|
.num_resources = ARRAY_SIZE(gio4_resources),
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &gio4_config,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device *emev2_early_devices[] __initdata = {
|
||||||
|
&uart0_device,
|
||||||
|
&uart1_device,
|
||||||
|
&uart2_device,
|
||||||
|
&uart3_device,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device *emev2_late_devices[] __initdata = {
|
||||||
|
&sti_device,
|
||||||
|
&gio0_device,
|
||||||
|
&gio1_device,
|
||||||
|
&gio2_device,
|
||||||
|
&gio3_device,
|
||||||
|
&gio4_device,
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init emev2_add_standard_devices(void)
|
||||||
|
{
|
||||||
|
emev2_clock_init();
|
||||||
|
|
||||||
|
platform_add_devices(emev2_early_devices,
|
||||||
|
ARRAY_SIZE(emev2_early_devices));
|
||||||
|
|
||||||
|
platform_add_devices(emev2_late_devices,
|
||||||
|
ARRAY_SIZE(emev2_late_devices));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init emev2_init_delay(void)
|
||||||
|
{
|
||||||
|
shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init emev2_add_early_devices(void)
|
||||||
|
{
|
||||||
|
emev2_init_delay();
|
||||||
|
|
||||||
|
early_platform_add_devices(emev2_early_devices,
|
||||||
|
ARRAY_SIZE(emev2_early_devices));
|
||||||
|
|
||||||
|
/* setup early console here as well */
|
||||||
|
shmobile_setup_console();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init emev2_init_irq(void)
|
||||||
|
{
|
||||||
|
void __iomem *gic_dist_base;
|
||||||
|
void __iomem *gic_cpu_base;
|
||||||
|
|
||||||
|
/* Static mappings, never released */
|
||||||
|
gic_dist_base = ioremap(0xe0028000, PAGE_SIZE);
|
||||||
|
gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE);
|
||||||
|
BUG_ON(!gic_dist_base || !gic_cpu_base);
|
||||||
|
|
||||||
|
/* Use GIC to handle interrupts */
|
||||||
|
gic_init(0, 29, gic_dist_base, gic_cpu_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_USE_OF
|
||||||
|
static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = {
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init emev2_add_standard_devices_dt(void)
|
||||||
|
{
|
||||||
|
of_platform_populate(NULL, of_default_bus_match_table,
|
||||||
|
emev2_auxdata_lookup, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id emev2_dt_irq_match[] = {
|
||||||
|
{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *emev2_boards_compat_dt[] __initdata = {
|
||||||
|
"renesas,emev2",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init emev2_init_irq_dt(void)
|
||||||
|
{
|
||||||
|
of_irq_init(emev2_dt_irq_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
|
||||||
|
.init_early = emev2_init_delay,
|
||||||
|
.nr_irqs = NR_IRQS_LEGACY,
|
||||||
|
.init_irq = emev2_init_irq_dt,
|
||||||
|
.handle_irq = gic_handle_irq,
|
||||||
|
.init_machine = emev2_add_standard_devices_dt,
|
||||||
|
.timer = &shmobile_timer,
|
||||||
|
.dt_compat = emev2_boards_compat_dt,
|
||||||
|
MACHINE_END
|
||||||
|
|
||||||
|
#endif /* CONFIG_USE_OF */
|
97
arch/arm/mach-shmobile/smp-emev2.c
Normal file
97
arch/arm/mach-shmobile/smp-emev2.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* SMP support for Emma Mobile EV2
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Renesas Solutions Corp.
|
||||||
|
* Copyright (C) 2012 Magnus Damm
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/smp.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <mach/common.h>
|
||||||
|
#include <mach/emev2.h>
|
||||||
|
#include <asm/smp_plat.h>
|
||||||
|
#include <asm/smp_scu.h>
|
||||||
|
#include <asm/hardware/gic.h>
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
|
|
||||||
|
#define EMEV2_SCU_BASE 0x1e000000
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(scu_lock);
|
||||||
|
static void __iomem *scu_base;
|
||||||
|
|
||||||
|
static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
|
||||||
|
{
|
||||||
|
unsigned long tmp;
|
||||||
|
|
||||||
|
/* we assume this code is running on a different cpu
|
||||||
|
* than the one that is changing coherency setting */
|
||||||
|
spin_lock(&scu_lock);
|
||||||
|
tmp = readl(scu_base + 8);
|
||||||
|
tmp &= ~clr;
|
||||||
|
tmp |= set;
|
||||||
|
writel(tmp, scu_base + 8);
|
||||||
|
spin_unlock(&scu_lock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int __init emev2_get_core_count(void)
|
||||||
|
{
|
||||||
|
if (!scu_base) {
|
||||||
|
scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE);
|
||||||
|
emev2_clock_init(); /* need ioremapped SMU */
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN_ON_ONCE(!scu_base);
|
||||||
|
|
||||||
|
return scu_base ? scu_get_core_count(scu_base) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emev2_platform_cpu_kill(unsigned int cpu)
|
||||||
|
{
|
||||||
|
return 0; /* not supported yet */
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cpuinit emev2_secondary_init(unsigned int cpu)
|
||||||
|
{
|
||||||
|
gic_secondary_init(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __cpuinit emev2_boot_secondary(unsigned int cpu)
|
||||||
|
{
|
||||||
|
cpu = cpu_logical_map(cpu);
|
||||||
|
|
||||||
|
/* enable cache coherency */
|
||||||
|
modify_scu_cpu_psr(0, 3 << (cpu * 8));
|
||||||
|
|
||||||
|
/* Tell ROM loader about our vector (in headsmp.S) */
|
||||||
|
emev2_set_boot_vector(__pa(shmobile_secondary_vector));
|
||||||
|
|
||||||
|
gic_raise_softirq(cpumask_of(cpu), 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init emev2_smp_prepare_cpus(void)
|
||||||
|
{
|
||||||
|
int cpu = cpu_logical_map(0);
|
||||||
|
|
||||||
|
scu_enable(scu_base);
|
||||||
|
|
||||||
|
/* enable cache coherency on CPU0 */
|
||||||
|
modify_scu_cpu_psr(0, 3 << (cpu * 8));
|
||||||
|
}
|
@ -91,6 +91,12 @@ config GPIO_IT8761E
|
|||||||
help
|
help
|
||||||
Say yes here to support GPIO functionality of IT8761E super I/O chip.
|
Say yes here to support GPIO functionality of IT8761E super I/O chip.
|
||||||
|
|
||||||
|
config GPIO_EM
|
||||||
|
tristate "Emma Mobile GPIO"
|
||||||
|
depends on ARM
|
||||||
|
help
|
||||||
|
Say yes here to support GPIO on Renesas Emma Mobile SoCs.
|
||||||
|
|
||||||
config GPIO_EP93XX
|
config GPIO_EP93XX
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on ARCH_EP93XX
|
depends on ARCH_EP93XX
|
||||||
|
@ -15,6 +15,7 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
|
|||||||
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
|
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
|
||||||
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
|
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
|
||||||
obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
|
obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
|
||||||
|
obj-$(CONFIG_GPIO_EM) += gpio-em.o
|
||||||
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
||||||
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
|
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
|
||||||
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
|
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
|
||||||
|
418
drivers/gpio/gpio-em.c
Normal file
418
drivers/gpio/gpio-em.c
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
/*
|
||||||
|
* Emma Mobile GPIO Support - GIO
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Magnus Damm
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_data/gpio-em.h>
|
||||||
|
|
||||||
|
struct em_gio_priv {
|
||||||
|
void __iomem *base0;
|
||||||
|
void __iomem *base1;
|
||||||
|
unsigned int irq_base;
|
||||||
|
spinlock_t sense_lock;
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct gpio_chip gpio_chip;
|
||||||
|
struct irq_chip irq_chip;
|
||||||
|
struct irq_domain *irq_domain;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GIO_E1 0x00
|
||||||
|
#define GIO_E0 0x04
|
||||||
|
#define GIO_EM 0x04
|
||||||
|
#define GIO_OL 0x08
|
||||||
|
#define GIO_OH 0x0c
|
||||||
|
#define GIO_I 0x10
|
||||||
|
#define GIO_IIA 0x14
|
||||||
|
#define GIO_IEN 0x18
|
||||||
|
#define GIO_IDS 0x1c
|
||||||
|
#define GIO_IIM 0x1c
|
||||||
|
#define GIO_RAW 0x20
|
||||||
|
#define GIO_MST 0x24
|
||||||
|
#define GIO_IIR 0x28
|
||||||
|
|
||||||
|
#define GIO_IDT0 0x40
|
||||||
|
#define GIO_IDT1 0x44
|
||||||
|
#define GIO_IDT2 0x48
|
||||||
|
#define GIO_IDT3 0x4c
|
||||||
|
#define GIO_RAWBL 0x50
|
||||||
|
#define GIO_RAWBH 0x54
|
||||||
|
#define GIO_IRBL 0x58
|
||||||
|
#define GIO_IRBH 0x5c
|
||||||
|
|
||||||
|
#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4))
|
||||||
|
|
||||||
|
static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs)
|
||||||
|
{
|
||||||
|
if (offs < GIO_IDT0)
|
||||||
|
return ioread32(p->base0 + offs);
|
||||||
|
else
|
||||||
|
return ioread32(p->base1 + (offs - GIO_IDT0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void em_gio_write(struct em_gio_priv *p, int offs,
|
||||||
|
unsigned long value)
|
||||||
|
{
|
||||||
|
if (offs < GIO_IDT0)
|
||||||
|
iowrite32(value, p->base0 + offs);
|
||||||
|
else
|
||||||
|
iowrite32(value, p->base1 + (offs - GIO_IDT0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct em_gio_priv *irq_to_priv(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct irq_chip *chip = irq_data_get_irq_chip(d);
|
||||||
|
return container_of(chip, struct em_gio_priv, irq_chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em_gio_irq_disable(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct em_gio_priv *p = irq_to_priv(d);
|
||||||
|
|
||||||
|
em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em_gio_irq_enable(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct em_gio_priv *p = irq_to_priv(d);
|
||||||
|
|
||||||
|
em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GIO_ASYNC(x) (x + 8)
|
||||||
|
|
||||||
|
static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
|
||||||
|
[IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00),
|
||||||
|
[IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01),
|
||||||
|
[IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02),
|
||||||
|
[IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03),
|
||||||
|
[IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||||
|
{
|
||||||
|
unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
|
||||||
|
struct em_gio_priv *p = irq_to_priv(d);
|
||||||
|
unsigned int reg, offset, shift;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned long tmp;
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
offset = irqd_to_hwirq(d);
|
||||||
|
|
||||||
|
pr_debug("gio: sense irq = %d, mode = %d\n", offset, value);
|
||||||
|
|
||||||
|
/* 8 x 4 bit fields in 4 IDT registers */
|
||||||
|
reg = GIO_IDT(offset >> 3);
|
||||||
|
shift = (offset & 0x07) << 4;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&p->sense_lock, flags);
|
||||||
|
|
||||||
|
/* disable the interrupt in IIA */
|
||||||
|
tmp = em_gio_read(p, GIO_IIA);
|
||||||
|
tmp &= ~BIT(offset);
|
||||||
|
em_gio_write(p, GIO_IIA, tmp);
|
||||||
|
|
||||||
|
/* change the sense setting in IDT */
|
||||||
|
tmp = em_gio_read(p, reg);
|
||||||
|
tmp &= ~(0xf << shift);
|
||||||
|
tmp |= value << shift;
|
||||||
|
em_gio_write(p, reg, tmp);
|
||||||
|
|
||||||
|
/* clear pending interrupts */
|
||||||
|
em_gio_write(p, GIO_IIR, BIT(offset));
|
||||||
|
|
||||||
|
/* enable the interrupt in IIA */
|
||||||
|
tmp = em_gio_read(p, GIO_IIA);
|
||||||
|
tmp |= BIT(offset);
|
||||||
|
em_gio_write(p, GIO_IIA, tmp);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&p->sense_lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct em_gio_priv *p = dev_id;
|
||||||
|
unsigned long pending;
|
||||||
|
unsigned int offset, irqs_handled = 0;
|
||||||
|
|
||||||
|
while ((pending = em_gio_read(p, GIO_MST))) {
|
||||||
|
offset = __ffs(pending);
|
||||||
|
em_gio_write(p, GIO_IIR, BIT(offset));
|
||||||
|
generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
|
||||||
|
irqs_handled++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
|
||||||
|
{
|
||||||
|
return container_of(chip, struct em_gio_priv, gpio_chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em_gio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
|
||||||
|
unsigned shift, int value)
|
||||||
|
{
|
||||||
|
/* upper 16 bits contains mask and lower 16 actual value */
|
||||||
|
em_gio_write(gpio_to_priv(chip), reg,
|
||||||
|
(1 << (shift + 16)) | (value << shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
{
|
||||||
|
/* output is split into two registers */
|
||||||
|
if (offset < 16)
|
||||||
|
__em_gio_set(chip, GIO_OL, offset, value);
|
||||||
|
else
|
||||||
|
__em_gio_set(chip, GIO_OH, offset - 16, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
/* write GPIO value to output before selecting output mode of pin */
|
||||||
|
em_gio_set(chip, offset, value);
|
||||||
|
em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
|
||||||
|
irq_hw_number_t hw)
|
||||||
|
{
|
||||||
|
struct em_gio_priv *p = h->host_data;
|
||||||
|
|
||||||
|
pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq);
|
||||||
|
|
||||||
|
irq_set_chip_data(virq, h->host_data);
|
||||||
|
irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
|
||||||
|
set_irq_flags(virq, IRQF_VALID); /* kill me now */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct irq_domain_ops em_gio_irq_domain_ops = {
|
||||||
|
.map = em_gio_irq_domain_map,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = p->pdev;
|
||||||
|
struct gpio_em_config *pdata = pdev->dev.platform_data;
|
||||||
|
|
||||||
|
p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
|
||||||
|
pdata->number_of_pins, numa_node_id());
|
||||||
|
if (IS_ERR_VALUE(p->irq_base)) {
|
||||||
|
dev_err(&pdev->dev, "cannot get irq_desc\n");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
|
||||||
|
pdata->gpio_base, pdata->number_of_pins, p->irq_base);
|
||||||
|
|
||||||
|
p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
|
||||||
|
pdata->number_of_pins,
|
||||||
|
p->irq_base, 0,
|
||||||
|
&em_gio_irq_domain_ops, p);
|
||||||
|
if (!p->irq_domain) {
|
||||||
|
irq_free_descs(p->irq_base, pdata->number_of_pins);
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
|
||||||
|
{
|
||||||
|
struct gpio_em_config *pdata = p->pdev->dev.platform_data;
|
||||||
|
|
||||||
|
irq_free_descs(p->irq_base, pdata->number_of_pins);
|
||||||
|
/* FIXME: irq domain wants to be freed! */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devinit em_gio_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct gpio_em_config *pdata = pdev->dev.platform_data;
|
||||||
|
struct em_gio_priv *p;
|
||||||
|
struct resource *io[2], *irq[2];
|
||||||
|
struct gpio_chip *gpio_chip;
|
||||||
|
struct irq_chip *irq_chip;
|
||||||
|
const char *name = dev_name(&pdev->dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||||
|
if (!p) {
|
||||||
|
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->pdev = pdev;
|
||||||
|
platform_set_drvdata(pdev, p);
|
||||||
|
spin_lock_init(&p->sense_lock);
|
||||||
|
|
||||||
|
io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||||
|
irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
|
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
|
||||||
|
|
||||||
|
if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
|
||||||
|
dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
|
||||||
|
if (!p->base0) {
|
||||||
|
dev_err(&pdev->dev, "failed to remap low I/O memory\n");
|
||||||
|
ret = -ENXIO;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
|
||||||
|
if (!p->base1) {
|
||||||
|
dev_err(&pdev->dev, "failed to remap high I/O memory\n");
|
||||||
|
ret = -ENXIO;
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_chip = &p->gpio_chip;
|
||||||
|
gpio_chip->direction_input = em_gio_direction_input;
|
||||||
|
gpio_chip->get = em_gio_get;
|
||||||
|
gpio_chip->direction_output = em_gio_direction_output;
|
||||||
|
gpio_chip->set = em_gio_set;
|
||||||
|
gpio_chip->to_irq = em_gio_to_irq;
|
||||||
|
gpio_chip->label = name;
|
||||||
|
gpio_chip->owner = THIS_MODULE;
|
||||||
|
gpio_chip->base = pdata->gpio_base;
|
||||||
|
gpio_chip->ngpio = pdata->number_of_pins;
|
||||||
|
|
||||||
|
irq_chip = &p->irq_chip;
|
||||||
|
irq_chip->name = name;
|
||||||
|
irq_chip->irq_mask = em_gio_irq_disable;
|
||||||
|
irq_chip->irq_unmask = em_gio_irq_enable;
|
||||||
|
irq_chip->irq_enable = em_gio_irq_enable;
|
||||||
|
irq_chip->irq_disable = em_gio_irq_disable;
|
||||||
|
irq_chip->irq_set_type = em_gio_irq_set_type;
|
||||||
|
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
|
||||||
|
|
||||||
|
ret = em_gio_irq_domain_init(p);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "cannot initialize irq domain\n");
|
||||||
|
goto err3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
|
||||||
|
dev_err(&pdev->dev, "failed to request low IRQ\n");
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto err4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
|
||||||
|
dev_err(&pdev->dev, "failed to request high IRQ\n");
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto err5;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpiochip_add(gpio_chip);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to add GPIO controller\n");
|
||||||
|
goto err6;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err6:
|
||||||
|
free_irq(irq[1]->start, pdev);
|
||||||
|
err5:
|
||||||
|
free_irq(irq[0]->start, pdev);
|
||||||
|
err4:
|
||||||
|
em_gio_irq_domain_cleanup(p);
|
||||||
|
err3:
|
||||||
|
iounmap(p->base1);
|
||||||
|
err2:
|
||||||
|
iounmap(p->base0);
|
||||||
|
err1:
|
||||||
|
kfree(p);
|
||||||
|
err0:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devexit em_gio_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct em_gio_priv *p = platform_get_drvdata(pdev);
|
||||||
|
struct resource *irq[2];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = gpiochip_remove(&p->gpio_chip);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
|
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
|
||||||
|
|
||||||
|
free_irq(irq[1]->start, pdev);
|
||||||
|
free_irq(irq[0]->start, pdev);
|
||||||
|
em_gio_irq_domain_cleanup(p);
|
||||||
|
iounmap(p->base1);
|
||||||
|
iounmap(p->base0);
|
||||||
|
kfree(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver em_gio_device_driver = {
|
||||||
|
.probe = em_gio_probe,
|
||||||
|
.remove = __devexit_p(em_gio_remove),
|
||||||
|
.driver = {
|
||||||
|
.name = "em_gio",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(em_gio_device_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Magnus Damm");
|
||||||
|
MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
10
include/linux/platform_data/gpio-em.h
Normal file
10
include/linux/platform_data/gpio-em.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __GPIO_EM_H__
|
||||||
|
#define __GPIO_EM_H__
|
||||||
|
|
||||||
|
struct gpio_em_config {
|
||||||
|
unsigned int gpio_base;
|
||||||
|
unsigned int irq_base;
|
||||||
|
unsigned int number_of_pins;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __GPIO_EM_H__ */
|
Loading…
x
Reference in New Issue
Block a user